Files
Clipboard/renderer/styles.css
2026-09-12 13:59:12 +08:00

953 lines
21 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 现代简约样式 —— 通过 token 系统接入 6 主题 / 5 强调色 */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
background: var(--bg-base);
color: var(--text);
font-family: var(--font-ui);
font-size: var(--fs-base);
line-height: var(--lh-base);
letter-spacing: var(--tracking-cn);
/* Windows + CJK 小字清晰度关键设置:
* - 默认 subpixel-antialiased 保留 RGB 子像素渲染,对中文笔画描边至关重要;
* 之前强制 antialiased/grayscale 会让 12px 以下的汉字变成"雾蒙蒙"的灰块。
* - text-rendering 用 auto让浏览器按字号自适应中文小字走 subpixel
* 英文大标题再走 optimizeLegibility 拿连字。
* - font-feature 只在 ≥14px 的西文场景开启,避免给小字号增加渲染负担。 */
-webkit-font-smoothing: subpixel-antialiased;
-moz-osx-font-smoothing: auto;
text-rendering: auto;
font-feature-settings: normal;
user-select: none;
}
/* 大字号西文(标题、关于页)单独开启连字,小字号不参与 */
#title, .about-name, .theme-preview-text {
-webkit-font-smoothing: subpixel-antialiased;
text-rendering: optimizeLegibility;
font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
}
#root {
display: flex;
flex-direction: column;
height: 100vh;
border: 1px solid var(--border);
border-radius: var(--radius-lg);
overflow: hidden;
}
/* ---------- 拖动区 ---------- */
#drag-bar {
-webkit-app-region: drag;
display: flex;
align-items: center;
gap: 6px;
padding: 8px 12px 7px;
border-bottom: 1px solid var(--border-soft);
background: var(--bg-base);
}
#title {
font-size: var(--fs-md);
font-weight: var(--fw-semibold);
color: var(--text);
letter-spacing: 0.2px;
/* 原本 margin-left: 4px 用来撑开标题与左边框的距离;
* 现在 #app-icon 在更左侧,由 #app-icon 的 margin-right 控制间隙更合理。 */
margin-left: 0;
/* 标题单行body 的 line-height=1.6 在这里会撑出多余空白,
* 关掉让标题跟按钮在同一基线。 */
line-height: 1;
}
/* 标题栏左上角小图标16×16 显示位,源是 32×32 PNG主进程从 .ico resize
* 而来),对常见 1.0/1.25/1.5/2x 缩放都锐利。
* 父级 #drag-bar 已设 -webkit-app-region: drag按住图标仍可拖动窗口。 */
#app-icon {
width: 16px;
height: 16px;
display: block;
flex-shrink: 0;
margin-right: 6px;
border-radius: 3px;
}
.spacer { flex: 1; }
.icon-btn {
-webkit-app-region: no-drag;
width: 26px;
height: 26px;
padding: 0;
background: transparent;
border: none;
border-radius: 6px;
color: var(--text-muted);
line-height: 1;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
transition: background var(--transition-fast), color var(--transition-fast);
}
/* SVG 图标:颜色继承 currentColor让 aria-pressed 状态色直接生效 */
.icon-btn svg {
display: block;
color: inherit;
}
.icon-btn:hover {
background: var(--bg-hover);
color: var(--text);
}
#close-btn:hover {
background: var(--danger-bg);
color: var(--danger);
}
/* 置顶开启:图标上色 + 轻微背景,关闭时回到 muted */
#pin-btn[aria-pressed="true"] {
color: var(--accent);
background: var(--accent-soft);
}
#pin-btn[aria-pressed="true"]:hover {
/* 开启态下 hover 不要洗掉上色,只把背景加深一点 */
background: var(--accent-hover);
color: var(--accent);
}
#refresh-btn.spinning svg {
animation: spin 0.8s linear infinite;
transform-origin: 50% 50%;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.ipc-dot {
display: inline-block;
width: 6px;
height: 6px;
margin: 0 4px 0 2px;
border-radius: 50%;
background: var(--text-muted);
transition: background var(--transition-base), box-shadow var(--transition-base);
}
.ipc-dot.connected {
background: var(--success);
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.15);
}
.ipc-dot.error {
background: var(--danger);
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.15);
}
/* ---------- Tab 栏 ---------- */
#tabs {
-webkit-app-region: no-drag;
display: flex;
gap: 2px;
padding: 0 12px;
background: var(--bg-base);
border-bottom: 1px solid var(--border-soft);
}
/* 历史窗口的 Tab —— 作用域限定到 #tabs避免被下面 settings 面板的
* 通用 .tab 规则覆盖(同一文件后写的同优先级规则会赢,导致 padding /
* transition 跟设计稿不一致)。 */
#tabs .tab {
padding: 8px 10px 7px;
border: none;
border-radius: 6px 6px 0 0;
background: transparent;
color: var(--text-soft);
font-size: var(--fs-sm);
font-weight: var(--fw-medium);
cursor: pointer;
transition: background var(--transition-fast), color var(--transition-fast);
border-bottom: 2px solid transparent;
margin-bottom: -1px;
/* 与 #title 一致:行高压成 1文字基线跟标题对齐不要靠 padding 顶。 */
line-height: 1;
}
#tabs .tab:hover {
color: var(--text);
}
#tabs .tab.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
.tab-count {
display: inline-block;
margin-left: 5px;
padding: 0 6px;
background: var(--bg-hover);
border-radius: 8px;
font-size: 10.5px;
color: var(--text-muted);
line-height: 16px;
height: 16px;
font-weight: var(--fw-medium);
vertical-align: 1px;
font-variant-numeric: tabular-nums;
transition: background var(--transition-fast), color var(--transition-fast);
}
#tabs .tab.active .tab-count {
background: var(--accent-soft);
color: var(--accent);
}
/* ---------- 搜索 ---------- */
#search-row {
padding: 8px 12px 10px;
background: var(--bg-base);
}
#search-wrap {
position: relative;
display: flex;
align-items: center;
}
#search-icon {
position: absolute;
left: 10px;
color: var(--text-muted);
pointer-events: none;
transition: color var(--transition-fast);
}
#search {
-webkit-app-region: no-drag;
width: 100%;
height: 32px;
padding: 0 32px 0 32px;
background: var(--bg-soft);
border: 1px solid transparent;
border-radius: 8px;
color: var(--text);
font-size: var(--fs-base);
line-height: 1.4;
outline: none;
transition: background var(--transition-base), border-color var(--transition-base), box-shadow var(--transition-base);
}
#search:focus {
background: var(--bg-overlay);
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-soft);
}
#search:focus + #search-clear,
#search-wrap:focus-within #search-icon {
color: var(--accent);
}
#search::placeholder {
color: var(--text-muted);
}
#search-clear {
-webkit-app-region: no-drag;
position: absolute;
right: 4px;
top: 50%;
transform: translateY(-50%);
width: 24px;
height: 24px;
padding: 0;
background: transparent;
border: none;
border-radius: 50%;
color: var(--text-muted);
line-height: 1;
cursor: pointer;
display: none;
align-items: center;
justify-content: center;
transition: background var(--transition-fast), color var(--transition-fast);
}
#search-clear.visible {
display: inline-flex;
}
#search-clear:hover {
background: var(--bg-hover);
color: var(--text);
}
/* ---------- 列表 ---------- */
#list-wrap {
flex: 1;
overflow-y: auto;
padding: 8px 12px 8px;
background: var(--bg-base);
scroll-behavior: smooth;
}
#list {
list-style: none;
display: flex;
flex-direction: column;
gap: 6px;
}
/* 自定义滚动条 */
#list-wrap::-webkit-scrollbar {
width: 8px;
}
#list-wrap::-webkit-scrollbar-track {
background: transparent;
}
#list-wrap::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 4px;
border: none;
}
#list-wrap::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
/* ---------- 卡片 ---------- */
.card {
background: var(--bg-base);
border: 1px solid var(--border-soft);
border-radius: var(--radius-md);
padding: 9px 12px 10px;
cursor: pointer;
transition: background var(--transition-base), border-color var(--transition-base), box-shadow var(--transition-base), transform var(--transition-fast);
outline: none;
position: relative;
}
.card:hover {
background: var(--bg-soft);
border-color: var(--border);
box-shadow: var(--shadow-sm);
}
.card.selected {
background: var(--bg-overlay);
border-color: var(--border-strong);
border-left: 2px solid var(--accent);
padding-left: 11px;
}
.card.selected:hover {
border-color: var(--accent);
}
.card-head {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 4px;
}
.time {
font-size: var(--fs-xs);
color: var(--text-soft);
font-family: var(--font-mono);
font-variant-numeric: tabular-nums;
}
.badge {
display: inline-flex;
align-items: center;
gap: 3px;
font-size: 10.5px;
color: var(--text-soft);
background: var(--bg-hover);
border-radius: 4px;
padding: 1px 6px 1px 5px;
font-weight: var(--fw-medium);
line-height: 1.5;
letter-spacing: 0;
}
.badge svg {
display: block;
flex-shrink: 0;
opacity: 0.75;
}
.badge-image {
color: var(--accent);
}
.badge-image svg {
color: var(--accent);
opacity: 0.85;
}
.slot {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 20px;
height: 20px;
padding: 0 5px;
font-size: 11px;
font-weight: var(--fw-semibold);
color: var(--accent-text);
background: var(--accent);
border-radius: 5px;
letter-spacing: 0;
font-family: var(--font-mono);
line-height: 1;
}
.action {
-webkit-app-region: no-drag;
display: inline-flex;
align-items: center;
gap: 4px;
font-size: var(--fs-xs);
color: var(--text-muted);
background: transparent;
border: none;
padding: 4px 8px;
border-radius: 6px;
cursor: pointer;
opacity: 0;
line-height: 1;
transition: opacity var(--transition-fast), background var(--transition-fast), color var(--transition-fast);
}
.action svg {
display: block;
flex-shrink: 0;
}
.card:hover .action,
.card.selected .action {
opacity: 1;
}
.action:hover {
color: var(--text);
background: var(--bg-hover);
}
.action.copy {
color: var(--accent);
padding-right: 10px;
}
.action.copy:hover {
color: var(--accent);
background: var(--accent-hover);
}
.action.fav {
padding: 5px 7px;
color: var(--text-muted);
}
.action.fav svg {
fill: none;
transition: fill var(--transition-fast), color var(--transition-fast);
}
.action.fav.favorited {
color: var(--warn);
}
.action.fav.favorited svg {
fill: var(--warn);
}
.action.fav:hover {
color: var(--warn);
background: var(--warn-bg);
}
.action.delete {
padding: 5px 7px;
}
.action.delete:hover {
color: var(--danger);
background: var(--danger-bg);
}
.card-body {
display: flex;
align-items: center;
gap: 10px;
}
.text-preview {
flex: 1;
min-width: 0;
font-size: var(--fs-base);
color: var(--text);
/* 中文正文行高 ≥1.55 才不会出现笔画"黏连",这里设 1.6 让 13px 中文清爽 */
line-height: 1.6;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
user-select: text;
cursor: text;
}
.image-preview {
width: 88px;
height: 88px;
border-radius: 8px;
border: 1px solid var(--border-soft);
object-fit: contain;
background:
linear-gradient(45deg, var(--bg-soft) 25%, transparent 25%),
linear-gradient(-45deg, var(--bg-soft) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, var(--bg-soft) 75%),
linear-gradient(-45deg, transparent 75%, var(--bg-soft) 75%);
background-size: 12px 12px;
background-position: 0 0, 0 6px, 6px -6px, -6px 0;
}
/* ---------- 空状态 ---------- */
#empty {
text-align: center;
padding: 64px 24px 56px;
color: var(--text-soft);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.empty-icon {
color: var(--text-muted);
opacity: 0.55;
margin-bottom: 14px;
}
.empty-title {
font-size: var(--fs-md);
color: var(--text-soft);
font-weight: var(--fw-medium);
margin-bottom: 6px;
}
#empty .muted {
font-size: var(--fs-sm);
color: var(--text-muted);
line-height: 1.5;
}
.hidden { display: none !important; }
/* ---------- 状态栏 ---------- */
#status {
display: flex;
justify-content: space-between;
align-items: center;
padding: 7px 14px;
border-top: 1px solid var(--border-soft);
background: var(--bg-base);
font-size: var(--fs-xs);
line-height: 1.4;
color: var(--text-muted);
user-select: none;
}
#status-left {
color: var(--text-soft);
}
.shortcuts {
display: inline-flex;
align-items: center;
gap: 4px;
flex-wrap: nowrap;
white-space: nowrap;
overflow: hidden;
}
.shortcuts .dot {
color: var(--text-muted);
opacity: 0.5;
margin: 0 1px;
}
kbd {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 18px;
height: 18px;
padding: 0 5px;
font-family: var(--font-mono);
font-size: 10.5px;
font-weight: var(--fw-medium);
color: var(--text-soft);
background: var(--bg-soft);
border: 1px solid var(--border);
border-radius: 4px;
line-height: 1;
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04);
}
/* ---------- 设置面板 ---------- */
#settings-body {
flex: 1;
min-height: 0;
overflow: hidden;
padding: 0;
background: var(--bg-base);
display: flex;
flex-direction: column;
}
/* ---------- 设置面板:标签栏 ---------- */
/* 用 #tab-bar 前缀隔离:上面「历史/收藏」Tab 也用 .tab但 padding/transition
* 跟设置页 Tab 不一样。两份样式同特异性时位置靠后的赢,会把主窗口 Tab
* 的 padding 从 5px 12px 改成 6px 10px 5px —— 显式框死作用域避免串味。 */
#tab-bar {
display: flex;
gap: 2px;
padding: 0 12px;
background: var(--bg-base);
border-bottom: 1px solid var(--border-soft);
}
#tab-bar .tab {
appearance: none;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
padding: 8px 10px 7px;
font-family: inherit;
font-size: var(--fs-sm);
color: var(--text-soft);
cursor: pointer;
line-height: 1;
margin-bottom: -1px;
transition: color 0.12s ease, border-color 0.12s ease;
}
#tab-bar .tab:hover { color: var(--text); }
#tab-bar .tab[aria-selected="true"] {
color: var(--text);
border-bottom-color: var(--accent);
font-weight: var(--fw-semibold);
}
#tab-bar .tab:focus-visible { outline: 1px solid var(--accent); outline-offset: -2px; }
.tab-panel {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 14px 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
/* 面板滚动条 —— 跟主列表统一 */
.tab-panel::-webkit-scrollbar { width: 8px; }
.tab-panel::-webkit-scrollbar-track { background: transparent; }
.tab-panel::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 4px;
}
.tab-panel::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
.tab-panel[hidden] { display: none !important; }
.setting-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 11px 14px;
border: 1px solid var(--border-soft);
border-radius: var(--radius-md);
background: var(--bg-base);
line-height: 1.4;
transition: border-color var(--transition-fast);
}
.setting-row:hover {
border-color: var(--border);
}
.setting-row.column {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.setting-label { font-size: var(--fs-base); color: var(--text); font-weight: var(--fw-medium); }
.setting-row select {
height: 30px;
padding: 0 28px 0 10px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-soft);
color: var(--text);
font-size: var(--fs-base);
line-height: 1.4;
outline: none;
cursor: pointer;
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
appearance: none;
-webkit-appearance: none;
background-image:
linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
linear-gradient(-45deg, transparent 50%, var(--text-muted) 50%);
background-position: calc(100% - 13px) 12px, calc(100% - 8px) 12px;
background-size: 5px 5px, 5px 5px;
background-repeat: no-repeat;
}
.setting-row select:hover { border-color: var(--border-strong); }
.setting-row select:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-soft);
}
.path-box {
margin-top: 4px;
padding: 9px 11px;
background: var(--bg-soft);
border-radius: 6px;
border: 1px solid var(--border-soft);
}
.path-text { font-size: var(--fs-sm); color: var(--text-soft); word-break: break-all; user-select: text; font-family: var(--font-mono); }
.btn-row { display: flex; gap: 8px; margin-top: 4px; }
.btn {
height: 30px;
padding: 0 12px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-base);
color: var(--text);
font-size: var(--fs-sm);
line-height: 1;
cursor: pointer;
transition: background var(--transition-fast), border-color var(--transition-fast);
font-weight: var(--fw-medium);
}
.btn:hover { background: var(--bg-hover); border-color: var(--border-strong); }
.btn:active { background: var(--bg-soft); }
.btn-danger { color: var(--danger); border-color: var(--danger-bg); background: var(--danger-bg); }
.btn-danger:hover { background: var(--danger); color: var(--accent-text); border-color: var(--danger); }
.danger-zone { border-color: var(--danger-bg); }
.danger-zone:hover { border-color: rgba(239, 68, 68, 0.4); }
/* 开关 */
.switch { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider-track {
position: absolute; inset: 0; cursor: pointer;
background: var(--border-strong); border-radius: 20px;
transition: background var(--transition-base);
}
.slider-track::before {
content: ""; position: absolute; height: 16px; width: 16px; left: 2px; top: 2px;
background: var(--bg-overlay); border-radius: 50%;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
transition: transform var(--transition-base);
}
.switch input:checked + .slider-track { background: var(--accent); }
.switch input:checked + .slider-track::before { transform: translateX(16px); }
.switch input:focus-visible + .slider-track { box-shadow: 0 0 0 3px var(--accent-soft); }
/* 主题网格 */
.theme-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin-top: 4px;
}
.theme-card {
cursor: pointer;
border: 2px solid var(--border-soft);
border-radius: var(--radius-md);
padding: 6px;
background: var(--bg-base);
transition: border-color var(--transition-base), transform var(--transition-fast), box-shadow var(--transition-base);
text-align: left;
}
.theme-card:hover {
border-color: var(--border-strong);
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.theme-card.active {
border-color: var(--accent);
box-shadow: 0 0 0 1px var(--accent) inset;
}
.theme-preview {
position: relative;
height: 56px;
border-radius: var(--radius-sm);
display: flex;
align-items: center;
justify-content: flex-start;
padding: 8px 12px;
border: 1px solid transparent;
overflow: hidden;
}
.theme-preview-text {
font-family: var(--font-ui);
font-weight: var(--fw-semibold);
font-size: 22px;
letter-spacing: -0.5px;
}
.theme-preview-accent {
position: absolute;
right: 10px;
top: 10px;
width: 12px;
height: 12px;
border-radius: 50%;
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
}
.theme-info {
margin-top: 7px;
}
.theme-name {
font-size: var(--fs-sm);
color: var(--text);
font-weight: var(--fw-medium);
}
.theme-desc {
font-size: 11px;
color: var(--text-muted);
margin-top: 1px;
}
/* 强调色 */
.accent-grid {
display: flex;
gap: 10px;
margin-top: 4px;
}
.accent-swatch {
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid var(--border-soft);
cursor: pointer;
padding: 0;
position: relative;
transition: transform var(--transition-fast), box-shadow var(--transition-base);
}
.accent-swatch:hover {
transform: scale(1.08);
}
.accent-swatch.active {
box-shadow: 0 0 0 2px var(--bg-base), 0 0 0 4px var(--text);
}
.accent-swatch.active::after {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3.5 8.5l3 3 6-6.5'/></svg>");
background-size: 16px 16px;
background-position: center;
background-repeat: no-repeat;
}
/* ---------- 设置面板:关于页 ---------- */
.about-head {
text-align: center;
padding: 18px 0 8px;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
}
.about-icon {
width: 44px;
height: 44px;
border-radius: 10px;
background: linear-gradient(135deg, var(--accent), var(--accent-hover));
display: flex;
align-items: center;
justify-content: center;
color: var(--accent-text);
margin-bottom: 6px;
box-shadow: 0 2px 8px var(--accent-soft);
}
.about-icon svg {
display: block;
}
.about-name {
font-size: var(--fs-lg);
font-weight: var(--fw-semibold);
color: var(--text);
letter-spacing: 0.2px;
}
.about-tagline {
font-size: var(--fs-xs);
color: var(--text-muted);
margin-top: 2px;
}
.about-devline {
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 10px;
margin-top: 4px;
}
.about-dev { font-size: var(--fs-base); color: var(--text); }
.ext-link {
font-size: var(--fs-sm);
color: var(--accent);
text-decoration: none;
word-break: break-all;
cursor: pointer;
transition: opacity var(--transition-fast);
}
.ext-link:hover { text-decoration: underline; opacity: 0.85; }