This commit is contained in:
2026-09-12 13:59:12 +08:00
commit 941ce4baab
71 changed files with 13037 additions and 0 deletions

952
renderer/styles.css Normal file
View File

@@ -0,0 +1,952 @@
/* 现代简约样式 —— 通过 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; }