1149 lines
42 KiB
CSS
1149 lines
42 KiB
CSS
/* ===========================================================================
|
||
Sidebar + Viewer + Editor Split Layout
|
||
自动从 src/styles.css 拆分(Stage 4a)
|
||
=========================================================================== */
|
||
|
||
/* ============================================================
|
||
Sidebar
|
||
============================================================ */
|
||
.sidebar {
|
||
background: var(--bg-sidebar);
|
||
border-right: 1px solid var(--border-subtle);
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 0;
|
||
z-index: var(--z-sidebar);
|
||
/* 宽度由 .app-shell 的 grid 模板通过 --sidebar-width 决定;这里不再写死 px */
|
||
min-width: 0;
|
||
/* container query 锚点:让 .sidebar 内部元素能根据侧栏实际宽度自适应。
|
||
下方可用 @container sidebar (max-width: ...) 写响应式规则,
|
||
跟随 .sidebar 实际渲染宽度,跟主窗口大小解耦。
|
||
命名空间 "sidebar" 与配套 @container 一致,避免与未来其他容器冲突 */
|
||
container-type: inline-size;
|
||
container-name: sidebar;
|
||
}
|
||
|
||
/* (.sidebar-header 已删除 —— 2026-09 设计优化:搜索框上移到工具栏,
|
||
侧栏垂直空间让给文件列表 + 排序条。首行直接是 sort + 新建笔记合并行) */
|
||
|
||
/* (.sidebar-new-row 已删除 —— 2026-09 设计优化:把「新建笔记」按钮合并到
|
||
.sidebar-sort 同一行的右端(用 .sidebar-new-btn--inline + margin-left:auto),
|
||
节省侧栏首屏的垂直空间。原独立行的顶部呼吸转移到了 .sidebar-sort 的 padding-top) */
|
||
|
||
/* 主操作按钮:全宽、带文字(accent 文字 + 软底色 + 1px accent 边框的主操作语义)。
|
||
新建文件 / 新建文件夹挪到右键菜单后,这个 base 类现在只被侧栏底部 AI 按钮(#btn-ai)复用。
|
||
2026-08 把字号从 12px 提到 14px、字重 500 → 600、加 8% accent 底色 + 32% accent 边框,
|
||
解决按钮文字发淡、按钮太瘦的问题 */
|
||
.sidebar-new-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
width: 100%;
|
||
height: 34px;
|
||
padding: 0 12px;
|
||
border-radius: var(--radius-sm);
|
||
/* audit fix (Round 9):font-size 13px (fs-sm) 的文字走 --accent-text(混色 65/70%),
|
||
不能用装饰色 token --accent(饱和度太高,13px 文字看着刺眼)。
|
||
见 [[feedback-colored-text-tier]]。background / border 仍走 --accent 因为
|
||
它们是装饰而非文字。 */
|
||
color: var(--accent-text);
|
||
background: color-mix(in srgb, var(--accent) 8%, transparent);
|
||
border: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
|
||
font-size: var(--fs-sm);
|
||
font-weight: 600;
|
||
letter-spacing: 0;
|
||
cursor: pointer;
|
||
transition: color var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
|
||
}
|
||
.sidebar-new-btn:hover {
|
||
/* audit fix (CSS P2 / sidebar new-btn hover):之前 color 走 --accent-hover
|
||
(纯 accent 饱和色),13px 小字直接用饱和色会"扎眼"、在 dark 调色板
|
||
还会出现 vibration(红绿高频抖动)现象。base 态已经走 --accent-text
|
||
(accent 65/70% 混色),hover 应当保持同套语义色 token 一致,只是
|
||
把混色比例上调一档或换更暖的 --accent-text 变体,让视觉权重随交互
|
||
上升但 chroma 仍温和(见 [[feedback-colored-text-tier]])。 */
|
||
color: var(--accent-text);
|
||
border-color: var(--accent);
|
||
background: var(--accent-soft-hover);
|
||
}
|
||
.sidebar-new-btn:active {
|
||
transform: scale(0.98);
|
||
}
|
||
.sidebar-new-btn:focus-visible {
|
||
outline: 2px solid var(--accent);
|
||
outline-offset: 1px;
|
||
}
|
||
|
||
/* (.sidebar-new-btn--inline 已删除 —— 2026-09 设计优化:新建文件 / 新建文件夹
|
||
从侧栏「+」按钮挪到右键菜单(侧栏空白右键、文件夹条目右键),内联变体
|
||
.sidebar-new-btn--inline 及其窄侧栏 container query 规则随之移除。base 类
|
||
.sidebar-new-btn 仍被侧栏底部 AI 按钮(#btn-ai)复用) */
|
||
|
||
/* (search-wrap / search-icon / search-input 已移到 04-toolbar.css —— 2026-09
|
||
设计优化:搜索框从侧栏上移到工具栏,样式跟随 HTML 一起走) */
|
||
|
||
/* ============================================================
|
||
Sidebar 排序工具条
|
||
紧贴它作用的 .file-list 上方 —— 这是「列表的工具」,
|
||
不应该埋进三层深的设置对话框(见 [[feedback-prefer-near-affected-area]])。
|
||
设计目标:紧凑到不抢搜索框注意力,active 态明确但不过重。
|
||
新建文件 / 新建文件夹已挪到右键菜单,侧栏首行只剩排序工具条。
|
||
============================================================ */
|
||
.sidebar-sort {
|
||
display: flex;
|
||
align-items: center;
|
||
/* gap:sort 触发器与未来同组控件之间的间距("列表的工具"成组) */
|
||
gap: 4px;
|
||
/* 顶 8px / 底 8px:sort 是侧栏首屏第一行,工具栏底边已经有 ~8px breathing,
|
||
这里再给 8px 顶距足够拉开层次(10px → 8px 省 2px 给文件列表);
|
||
上下对称让 sort 行居中感更强,border-bottom 自然分隔 */
|
||
padding: 8px 10px;
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
/* 切主题时 border-subtle 颜色变化需要 fade —— 否则 1px 分隔线在 body
|
||
320ms 慢淡变过程中硬切。背景是 transparent,没 background 跳变可淡 */
|
||
transition: border-color var(--transition-slow);
|
||
}
|
||
|
||
/* Sort 下拉容器:
|
||
2026-10 设计改造 —— 把原来并排两个 sort 按钮(.sidebar-sort-btn)换成下拉:
|
||
- 一个触发器占 sort 行左段,按内容宽度(flex:0 0 auto),不抢其它控件空间
|
||
- 菜单 absolute 定位在触发器下方,absolute 让它能浮在文件列表之上不受
|
||
flex 行高度限制,也不挤压下方列表布局
|
||
drop-shadow 比纯 border 更柔和:菜单浮起感强,与触发器同源色调一致
|
||
*/
|
||
.sidebar-sort-dropdown {
|
||
position: relative;
|
||
flex: 1 1 0;
|
||
min-width: 0;
|
||
}
|
||
|
||
.sidebar-sort-trigger {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
width: 100%;
|
||
min-width: 0;
|
||
padding: 5px 6px;
|
||
background: transparent;
|
||
border: 1px solid transparent;
|
||
border-radius: var(--radius-sm);
|
||
color: var(--fg-secondary);
|
||
font-size: var(--fs-sm);
|
||
font-weight: 600;
|
||
letter-spacing: var(--tracking-wide);
|
||
cursor: pointer;
|
||
/* 防止长 label「按修改时间→旧」在窄侧栏里换行塌成两行 */
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
transition:
|
||
background var(--transition-fast),
|
||
color var(--transition-fast),
|
||
border-color var(--transition-fast);
|
||
}
|
||
|
||
/* 触发器打开态:accent-soft 底色 + accent 边框让「选中的排序」在行内就有
|
||
视觉反馈,不必打开菜单也能看出当前排序 */
|
||
.sidebar-sort-trigger[aria-expanded="true"],
|
||
.sidebar-sort-trigger.is-active {
|
||
color: var(--accent-text);
|
||
background: var(--accent-soft);
|
||
border-color: color-mix(in srgb, var(--accent) 20%, transparent);
|
||
}
|
||
|
||
.sidebar-sort-trigger:hover {
|
||
color: var(--fg-secondary);
|
||
background: var(--bg-hover);
|
||
}
|
||
|
||
.sidebar-sort-trigger[aria-expanded="true"]:hover,
|
||
.sidebar-sort-trigger.is-active:hover {
|
||
/* accent-soft + bg-hover 18% 混合:暗色调色板上 hover 不冲掉选中底色 */
|
||
background: color-mix(in srgb, var(--accent) 18%, var(--bg-hover));
|
||
}
|
||
|
||
.sidebar-sort-trigger:focus-visible {
|
||
outline: 2px solid var(--accent);
|
||
outline-offset: 1px;
|
||
}
|
||
|
||
/* chevron 在打开时旋转 180°,暗示菜单已展开。
|
||
旋转而非切图标 —— 单一 SVG,CSS transform 更顺。
|
||
hover 提亮到 1.0:与 .status-chip-mode:hover svg 同源(默认 0.7 → 满透明),
|
||
鼠标停上时给 chevron 一抹"亮起来"的反馈,配合 trigger 底色变化更协调 */
|
||
.sidebar-sort-trigger-chevron {
|
||
flex: 0 0 auto;
|
||
margin-left: auto;
|
||
opacity: 0.7;
|
||
transition:
|
||
transform var(--transition-fast),
|
||
opacity var(--transition-fast);
|
||
}
|
||
.sidebar-sort-trigger[aria-expanded="true"] .sidebar-sort-trigger-chevron {
|
||
transform: rotate(180deg);
|
||
}
|
||
.sidebar-sort-trigger:hover .sidebar-sort-trigger-chevron {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* trigger label 同样吃掉多余宽度,触发器 overflow:hidden 时它先被截。
|
||
flex:1 1 auto + min-width:0 是 flex 子项允许收缩到 content 以下的标配 —— 不加 min-width:0,
|
||
label 默认 min-content 宽度(最长不可断行片段),触发器 overflow:hidden 时它不会缩,
|
||
而是溢出 trigger 边缘把 chevron 顶出去。ellipsis 也得在 label 自己被约束时才生效。 */
|
||
.sidebar-sort-trigger-label {
|
||
flex: 1 1 auto;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
/* Sort 菜单:
|
||
- absolute 在触发器下方 left:0 让左对齐(与触发器同宽),top:calc(100% + 4px) 留 4px gap
|
||
- min-width:100% 而不是 width:100%:菜单可超出触发器宽度,长 label 「按修改时间」不挤
|
||
- padding:4px 让菜单项四周呼吸,menu 自身 padding 不参与 grid 列表
|
||
bg-elevated + drop-shadow + radius-sm:浮起卡片感,区别于触发器内联工具条 */
|
||
.sidebar-sort-menu {
|
||
position: absolute;
|
||
left: 0;
|
||
top: calc(100% + 4px);
|
||
/* min-width 让菜单始终覆盖触发器宽度,长 label(如「按修改时间」)不挤压;
|
||
长 label 单独成项时菜单按最长一项自然变宽 */
|
||
min-width: 100%;
|
||
max-width: 240px;
|
||
margin: 0;
|
||
padding: 4px;
|
||
list-style: none;
|
||
background: var(--bg-elevated);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-sm);
|
||
/* var(--shadow-md) 与 .focus-exit-hint 同源(4px 12px + 2px 4px 投影组合),
|
||
浮层用它来给菜单"轻浮起"层次。原来的硬编码 0.18/0.08 透明度是 dark-only 的
|
||
调参值,亮主题下显得偏重;用 token 后亮 / 暗两套主题的阴影会自动套用
|
||
02-palettes.css 已校准好的 0.07-0.32 区间,色彩系统内自洽 */
|
||
box-shadow: var(--shadow-md);
|
||
z-index: 50;
|
||
/* 淡入比瞬切更柔和;50ms 极短避免拖慢菜单 */
|
||
animation: sidebar-sort-menu-in 80ms ease-out;
|
||
}
|
||
|
||
@keyframes sidebar-sort-menu-in {
|
||
from { opacity: 0; transform: translateY(-2px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
.sidebar-sort-menu-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 5px 8px;
|
||
border-radius: var(--radius-sm);
|
||
color: var(--fg-secondary);
|
||
font-size: var(--fs-sm);
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
transition: background var(--transition-fast), color var(--transition-fast);
|
||
}
|
||
|
||
.sidebar-sort-menu-item:hover,
|
||
.sidebar-sort-menu-item:focus-visible {
|
||
background: var(--bg-hover);
|
||
color: var(--fg-primary);
|
||
}
|
||
/* 键盘 focus 需要可见环 —— menuitem 默认 outline:none(tabindex="-1" 的 li
|
||
浏览器不再画默认环),用 :focus-visible 而非 :focus:点击菜单项瞬间
|
||
focus 会落到它身上,若用 :focus 也会触发"高亮",给视觉多余干扰。
|
||
负 offset 让环贴 item 内沿,与 trigger focus-visible 的 +1px 外环形成
|
||
"内 vs 外"层次(trigger 是浮起控件,环外贴;menu item 已有 padding 4px
|
||
的 ul 容器,环内贴不会跟外沿视觉挤在一起) */
|
||
.sidebar-sort-menu-item:focus-visible {
|
||
outline: 2px solid var(--accent);
|
||
outline-offset: -2px;
|
||
}
|
||
|
||
.sidebar-sort-menu-item.is-active {
|
||
/* 与触发器一致:accent-text + accent-soft;选中态双处呼应(触发器 + 菜单项) */
|
||
color: var(--accent-text);
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
.sidebar-sort-menu-item.is-active:hover {
|
||
background: color-mix(in srgb, var(--accent) 18%, var(--bg-hover));
|
||
}
|
||
|
||
/* 选中态左侧打勾;占位用 inline-block 让未选中项也对齐预留 13px + 8px gap。
|
||
比 flex 子项条件 display 更稳 —— 不参与排序语义,避免影响 item 高度 */
|
||
.sidebar-sort-menu-check {
|
||
display: inline-flex;
|
||
width: 13px;
|
||
height: 13px;
|
||
flex: 0 0 auto;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--accent);
|
||
opacity: 0;
|
||
}
|
||
.sidebar-sort-menu-item.is-active .sidebar-sort-menu-check {
|
||
opacity: 1;
|
||
}
|
||
|
||
.sidebar-sort-menu-text {
|
||
flex: 1 1 auto;
|
||
display: inline-flex;
|
||
align-items: baseline;
|
||
gap: 6px;
|
||
min-width: 0;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.sidebar-sort-menu-hint {
|
||
/* hint 用 fg-muted + 小字号,与主 label 拉开对比;不抢主 label 视觉重量 */
|
||
color: var(--fg-muted);
|
||
font-size: var(--fs-xs);
|
||
font-weight: 400;
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
/* 菜单分组分隔:1px 水平细线 + 上下各 4px 留白。
|
||
margin 而不是 padding 让 flex 容器布局不挤压 —— padding 会撑大 li 高度,
|
||
上下 4px margin 让「组间距」发生在 li 边缘,与菜单项 5px padding 对称。 */
|
||
.sidebar-sort-menu-separator {
|
||
list-style: none;
|
||
height: 1px;
|
||
margin: 4px 6px;
|
||
padding: 0;
|
||
background: var(--border-subtle);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.file-list {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
/* 上下 8px 比之前的 12px 更紧凑;列表项自身有 padding 已经够了 */
|
||
padding: 8px 10px;
|
||
/* 列表项间距:用 gap 而非 item 的 margin-bottom,避免 list 总高累加偏差。
|
||
1px gap 与原 margin-bottom:1px 视觉一致,但语义更清晰 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1px;
|
||
/* 滚动条预留空间 —— 让滚动条 hover 才出现,不抢视觉 */
|
||
scrollbar-gutter: stable;
|
||
/* audit fix (R7a P1-15):windowed render 需要把 .file-item 用
|
||
position:absolute + top:N*h 钉在指定位置,所以容器得 position:relative
|
||
作为锚点。flex + position:relative 不冲突(容器本身仍是 flex 布局,
|
||
决定 sentinel / 非 windowed 模式项的位置)。 */
|
||
position: relative;
|
||
}
|
||
|
||
/* audit fix (R7a P1-15):windowed 虚拟滚动 sentinel。
|
||
- 真实高度 = N * itemHeight,给滚动条撑出总高
|
||
- 默认 flex 项目,不抢视觉(aria-hidden + 0 padding)
|
||
- JS 切到 windowed 模式时 appendChild 它;切回 full / 空 状态时 remove
|
||
用 <li> 而非 <div> 是因为 <ul> 只能装 <li> 子元素,HTML 规范硬约束 */
|
||
.file-list-sentinel {
|
||
flex-shrink: 0;
|
||
padding: 0;
|
||
margin: 0;
|
||
list-style: none;
|
||
/* 高度由 JS 直接 style.height 设置;这里只保证不引入意外 padding */
|
||
pointer-events: none;
|
||
}
|
||
|
||
.file-list:empty::after {
|
||
/* 空列表:淡灰色提示。设置里改数据目录、或把 .md 拖到目录里都会自动消失。
|
||
原来用 --fg-muted 在 bg-sidebar 上仅 ~3.2:1(default dark),低于 WCAG AA。
|
||
提到 --fg-tertiary(~5.4:1)让这段引导文字真能"看清"——
|
||
无列表可看时用户全部注意力都落在这段字上,发淡等于无效提示 */
|
||
content: attr(data-empty);
|
||
display: block;
|
||
padding: var(--space-7) var(--space-3);
|
||
text-align: center;
|
||
color: var(--fg-tertiary);
|
||
font-size: var(--fs-sm);
|
||
line-height: var(--lh-relaxed);
|
||
/* 留点上方间距,与上方 sort 行拉开 */
|
||
margin-top: var(--space-2);
|
||
/* 避免一行字过长在窄侧栏里截断为半个字 */
|
||
word-break: break-word;
|
||
}
|
||
|
||
.file-item {
|
||
/* grid 两列:16px 图标 + 1fr 文本区。
|
||
用 grid 而不是 padding-left+absolute 是为了:
|
||
1) 文本区能正常占满剩余宽度(min-width:0 走 grid 才生效)
|
||
2) 图标列固定,文本列弹性,缩窄侧栏不挤图标 */
|
||
display: grid;
|
||
grid-template-columns: 16px 1fr;
|
||
align-items: center;
|
||
column-gap: 10px;
|
||
/* audit fix (R7a P1-15):windowed 虚拟滚动需要固定高度做索引 × h 的
|
||
位置数学。padding 仍由 box-sizing:border-box 包含在 height 内。
|
||
49px (12 padding + 37 content) → 显式 50px,差 1px 由 align-items:center
|
||
吸收,视觉无变化但 JS 可以用 N * 50 直接算 top/总高。 */
|
||
height: 50px;
|
||
/* 上下 padding 9px → 6px:原 9px 在 13px name + 13px meta 两行下让单条 file-item
|
||
撑到 ~60px,50 个文件就要 3000px 滚动,太松。压到 6px 后 ~50px/item,
|
||
列表更紧凑、可见项更多,仍保留点击区域与 hover 反馈呼吸 */
|
||
padding: 6px 12px 6px 10px;
|
||
/* margin-bottom 去掉,改用 file-list 的 gap 统一间距;
|
||
同时消除"两行间距靠 margin 累加"导致的列表总高计算偏差 */
|
||
border-radius: var(--radius-sm);
|
||
cursor: pointer;
|
||
/* transition 增加 border-color / box-shadow,让激活态色条 + 微弱内阴影的进入更顺滑 */
|
||
transition:
|
||
background var(--transition-fast),
|
||
color var(--transition-fast),
|
||
transform var(--transition-fast);
|
||
position: relative;
|
||
}
|
||
|
||
.file-text {
|
||
/* 文本列:name + meta 仍然竖排;min-width:0 让 ellipsis 真正生效 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
/* name↔meta gap 2px → 1px:与 file-item 上下 padding 同步收紧,让整条紧凑 */
|
||
gap: 1px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.file-icon {
|
||
/* 平时 muted,hover/active 时跟随主题升级。
|
||
用 grid 让图标"漂"在 item 左侧 + 上下居中,比 padding-left+absolute 更稳 */
|
||
color: var(--fg-tertiary);
|
||
flex-shrink: 0;
|
||
transition: color var(--transition-fast);
|
||
}
|
||
|
||
.file-item:hover .file-icon {
|
||
color: var(--fg-secondary);
|
||
}
|
||
|
||
.file-item:active {
|
||
transform: scale(0.985);
|
||
}
|
||
|
||
.file-item.is-active {
|
||
/* 激活态:accent-soft 底色 + 左侧 3px 色条。
|
||
用 accent-soft 替代 accent-soft-hover:hover 态是临时高亮(更深一档),
|
||
active 态是稳定选中,两者用不同 token 区分意图 */
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
.file-item.is-active:hover {
|
||
/* 激活态 hover 走更深一档 —— 与 idle 态 hover(bg-hover)形成层次差 */
|
||
background: var(--accent-soft-hover);
|
||
}
|
||
|
||
.file-item.is-active .file-icon {
|
||
/* 激活态:图标与正文同色,构成一致的视觉语言 */
|
||
color: var(--accent);
|
||
}
|
||
|
||
.file-item.is-active::before {
|
||
content: "";
|
||
position: absolute;
|
||
/* 从 -3px 移到 0,让色条贴着 item 内沿,更紧凑不"漂" */
|
||
left: 0;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 3px;
|
||
/* 60% → 70%:原 60% 在 13px name + 12px meta 共 31px 行高下占 18px,
|
||
加上色条本身的圆角显得"瘦长"。提到 70% (22px) 后,与 file-name +
|
||
meta 二行总高的占比更平衡,色条"贴"住视觉单元,不漂在 item 中央。
|
||
仍留 30% 上下气口,避免色条顶到 file-name / meta 行边沿 */
|
||
height: 70%;
|
||
border-radius: 0 2px 2px 0;
|
||
background: var(--accent);
|
||
/* 加微 box-shadow 让色条在 accent-soft 底色上"浮"起来一点 —
|
||
纯色 accent 在 #2a325c 类 accent-soft 背景下,RGB 距离很短,
|
||
加 4px 投影能把色条对比拉高一档 */
|
||
box-shadow: 0 0 4px color-mix(in srgb, var(--accent) 40%, transparent);
|
||
/* 选中态色条从左侧滑入:切换当前文件时给一点"落位"的过渡,
|
||
比硬切更有手感,又不拖沓(200ms)。reduced-motion 下被全局 .01ms 规则收掉 */
|
||
transform-origin: left center;
|
||
animation: file-active-bar 200ms var(--ease-out);
|
||
}
|
||
|
||
@keyframes file-active-bar {
|
||
from { transform: translateY(-50%) scaleX(0); opacity: 0; }
|
||
to { transform: translateY(-50%) scaleX(1); opacity: 1; }
|
||
}
|
||
|
||
|
||
.file-name {
|
||
font-size: var(--fs-sm);
|
||
color: var(--fg-primary);
|
||
/* 字重 500 → 600:让 file-name 成为主视觉。
|
||
之前 file-meta 也是 600 + 同字号,导致 meta 看起来比 name 还"实",
|
||
层级倒挂(次要信息喧宾夺主)。现在 name 600 / meta 500,名字优先 */
|
||
font-weight: 600;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
letter-spacing: var(--tracking-tight);
|
||
transition: color var(--transition-fast);
|
||
}
|
||
|
||
.file-item .file-name mark {
|
||
/* 搜索高亮:在文件名里命中搜索关键字时的视觉标识。
|
||
22% accent 背景已经给出"高亮"信号,文字再纯 accent 会与背景同色相"贴
|
||
一起"。改用 --accent-text —— 仍可识别色相(青蓝/紫/红等色调随 palette),
|
||
但 chroma 降到不会与底色"撞色"的程度。
|
||
字重保持 700,因为 mark 通常只有 1-3 字,需要靠粗细扛"高亮"识别。 */
|
||
background: color-mix(in srgb, var(--accent) 22%, transparent);
|
||
color: var(--accent-text);
|
||
padding: 0 2px;
|
||
border-radius: 3px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.file-item.is-active .file-name {
|
||
/* accent #5e6ad2 在 #08090a 上只有 ~4.0:1,作为正文偏暗。
|
||
用与正文链接同色相的 --md-link(已在 #08090a 上 ~5.5:1)替代 */
|
||
color: var(--md-link);
|
||
/* 已与 idle file-name 同字重(600),保持选中态只是颜色升级、不再额外加粗 */
|
||
font-weight: 600;
|
||
}
|
||
|
||
.file-meta {
|
||
/* 字号 13px → 12px(--fs-xs-readable),比 file-name 小一档;
|
||
字重 600 → 500 让 meta 视觉退到次级,与 file-name 的 600 形成对比。
|
||
两层降级(更小 + 更轻)让 meta 真正成为"辅助信息"而不是与 name 平级 */
|
||
font-size: var(--fs-xs-readable);
|
||
color: var(--fg-secondary);
|
||
font-weight: 500;
|
||
font-variant-numeric: tabular-nums;
|
||
letter-spacing: var(--tracking-wide);
|
||
/* 窄侧栏(拖到 180px)时 meta 行可能换行成两行,让 file-item 高度跳变。
|
||
强制单行 + 省略号,保持列表项高度稳定 */
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.file-item.is-active .file-meta {
|
||
color: var(--md-link);
|
||
opacity: 0.75;
|
||
}
|
||
|
||
.sidebar-footer {
|
||
/* 现在侧栏底部只剩 AI 一个按钮(文件夹管理已搬到状态栏左段,
|
||
见 [[feedback-folder-actions-to-statusbar]]),padding 收紧到 10px 12px
|
||
让按钮离文件列表稍近、视觉关系更紧 */
|
||
padding: 10px 12px;
|
||
border-top: 1px solid var(--border-subtle);
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
/* 与 .sidebar-sort 同源:footer 顶 1px 分隔线在切主题时也需 fade,
|
||
避免与 main 320ms 慢淡变错位 */
|
||
transition: border-color var(--transition-slow);
|
||
}
|
||
|
||
/* ============================================================
|
||
Viewer
|
||
============================================================ */
|
||
.viewer {
|
||
background: var(--bg-viewer);
|
||
overflow-y: auto;
|
||
min-width: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
.markdown-body {
|
||
flex: 1;
|
||
max-width: var(--w-reader-max);
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
padding: var(--space-9) var(--space-7) calc(var(--space-9) * 1.5);
|
||
font-family: var(--font-reading);
|
||
font-size: var(--reader-font-size);
|
||
line-height: var(--reader-line-height);
|
||
color: var(--fg-primary);
|
||
user-select: text;
|
||
letter-spacing: 0.005em;
|
||
word-wrap: break-word;
|
||
overflow-wrap: break-word;
|
||
}
|
||
|
||
/* ============================================================
|
||
阅读进度条:viewer 顶部的 3px 细线,随滚动从左向右填充。
|
||
- sticky top:0:作为 .viewer 滚动容器的首个子元素,滚动时钉在顶部,
|
||
正文从它下方滑过(markdown-body 顶部有 48px padding,细线落在留白里不压字)。
|
||
- pointer-events:none:纯视觉反馈,不挡滚动 / 点击。
|
||
- 底色透明,只有填充段可见;90ms linear 跟随滚动手感顺滑。
|
||
- 宽度由 JS(updateStatusScroll)按 scrollTop / (scrollHeight-client) 写入。
|
||
============================================================ */
|
||
.reading-progress {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 2;
|
||
flex: 0 0 auto;
|
||
width: 100%;
|
||
height: 3px;
|
||
background: transparent;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.reading-progress-bar {
|
||
display: block;
|
||
height: 100%;
|
||
width: 0%;
|
||
/* 渐变比纯 accent 多一档层次,末端圆角呼应 file-item 色条 */
|
||
background: linear-gradient(90deg, var(--accent) 0%, var(--accent-hover) 100%);
|
||
border-radius: 0 2px 2px 0;
|
||
/* 极轻辉光,让细线在深色底上"浮"起来一点,但不喧宾夺主 */
|
||
box-shadow: 0 0 6px color-mix(in srgb, var(--accent) 50%, transparent);
|
||
transform-origin: left center;
|
||
transition: width 90ms linear;
|
||
}
|
||
|
||
/* 空状态:更有温度的视觉 */
|
||
.empty-state {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
/* gap 用 0,靠各元素的 margin 控制间距:
|
||
- icon → 标题:靠 icon 自身的 margin-bottom
|
||
- 标题 → 主 hint:12px,让主信息与提示分隔
|
||
- 主 hint → 次 hint:6px,形成层次
|
||
用统一 gap 会让主 hint 与次 hint 之间也有 12px,反而拉得太平 */
|
||
gap: 0;
|
||
color: var(--fg-tertiary);
|
||
text-align: center;
|
||
padding: var(--space-7);
|
||
/* 顶部加一点点品牌色辉光,强化「这是 Notes 应用」的氛围 */
|
||
position: relative;
|
||
}
|
||
|
||
.empty-state-icon {
|
||
width: 88px;
|
||
height: 88px;
|
||
border-radius: 50%;
|
||
/* 三层渐变叠出「呼吸光晕」:从中心发散到外圈的柔光 */
|
||
background:
|
||
radial-gradient(circle at 50% 45%,
|
||
color-mix(in srgb, var(--accent) 22%, transparent) 0%,
|
||
color-mix(in srgb, var(--accent) 8%, transparent) 35%,
|
||
transparent 70%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--accent);
|
||
margin-bottom: var(--space-3);
|
||
position: relative;
|
||
/* 让 halo 缓慢呼吸,强化「等待/邀请」感。
|
||
1.04 → 1.02:旧值在 4s 周期下肉眼明显能看出"放大再缩回",
|
||
用户长时间停留空状态(常见:刚启动、刚切数据文件夹)会被这个 4% 缩放
|
||
持续吸引注意力;改 2% 后仍保留"呼吸"暗示,但不再"主动拉视线" */
|
||
animation: empty-halo 4s ease-in-out infinite;
|
||
}
|
||
.empty-state-icon::after {
|
||
/* 内圈实色圆 + 微阴影:让图标有「浮起」感 */
|
||
content: "";
|
||
position: absolute;
|
||
inset: 16px;
|
||
border-radius: 50%;
|
||
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
||
box-shadow:
|
||
inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent),
|
||
0 4px 12px color-mix(in srgb, var(--accent) 8%, transparent);
|
||
z-index: -1;
|
||
}
|
||
.empty-state-icon svg {
|
||
/* 图标本身略浮起,配合 halo 制造层次 */
|
||
filter: drop-shadow(0 2px 4px color-mix(in srgb, var(--accent) 18%, transparent));
|
||
}
|
||
|
||
@keyframes empty-halo {
|
||
/* 振幅 1 → 1.02(+2%):保留"呼吸"质感的同时不抢占视线。
|
||
透明度仍 0.95 ↔ 1,让 halo 在淡入淡出之间柔和过渡 */
|
||
0%, 100% {
|
||
transform: scale(1);
|
||
opacity: 0.95;
|
||
}
|
||
50% {
|
||
transform: scale(1.02);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.empty-state p {
|
||
margin: 0;
|
||
font-size: var(--fs-lg);
|
||
color: var(--fg-primary);
|
||
font-weight: 700;
|
||
/* 标题与下面 hint 之间的留白由 gap 控制,避免再加 margin */
|
||
letter-spacing: var(--tracking-tight);
|
||
/* 标题用次级 fg-primary 突出 —— primary 比 secondary 更有视觉重量 */
|
||
}
|
||
|
||
/* 标题("选择一个 Markdown 文件开始阅读")需要与图标 / 提示都拉出层次 */
|
||
.empty-state > p:not(.hint) {
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
|
||
.empty-state .hint {
|
||
font-size: var(--fs-sm);
|
||
/* 13px 提示文本:用 secondary(2026-08 提亮到 ~8.5:1),避开 tertiary 旧值的 3.5:1
|
||
—— 注释说要用 secondary 但实际代码仍是 tertiary,已修复 */
|
||
color: var(--fg-secondary);
|
||
/* max-width 从 360 提到 400:让"放进数据文件夹后," + ".md" chip 一行内放得下,
|
||
避免折成两行导致后段「自动出现」只剩一两个汉字成行(orphan 字)。
|
||
text-wrap: pretty 是 Chromium 114+ 的 CSS Text Level 4 优化,
|
||
优先避免单字成行(对 CJK 也生效:算法看 line-end penalty) */
|
||
max-width: 400px;
|
||
line-height: var(--lh-relaxed);
|
||
/* 主 hint 与标题之间已经由标题 margin-bottom 12px 撑开,
|
||
主 hint 自身的 margin-top 设为 0 避免与上面 margin 叠加 */
|
||
margin-top: 0;
|
||
text-wrap: pretty;
|
||
}
|
||
|
||
/* 二级提示:用 secondary + 略小字号,与主 hint 拉开视觉权重
|
||
P2-26:tertiary → secondary。dark palette 下
|
||
--fg-tertiary #8e95a1 vs --fg-secondary #b0b6c0
|
||
后者在 #08090a 底色上对比度 ~7.5:1(前者 ~5.0:1,边缘档)。
|
||
改 secondary 满足 WCAG AAA (7:1+),且不破坏主 hint(用 tertiary 仍
|
||
区分"主 → 次"权重)。其他 4 个 palette 同理。 */
|
||
.empty-state .hint.hint-secondary {
|
||
color: var(--fg-secondary);
|
||
font-size: var(--fs-xs-readable);
|
||
/* margin-top 6 → 10px:原 6px 让主 hint 与次 hint 之间几乎贴住,
|
||
加上两行 lh-relaxed (1.7) 后视觉上更挤。提到 10px 让两组 hint
|
||
之间形成明确的"主 → 次"层次(主是引导、次是补充操作) */
|
||
margin-top: 10px;
|
||
max-width: 380px;
|
||
/* 1.55 让次级提示的换行节奏与主 hint(1.6)接近,避免出现"次 hint 文字挤一行"的突兀感 */
|
||
line-height: 1.55;
|
||
}
|
||
|
||
/* 空状态 CTA ——「+ 新建笔记」按钮(audit P2-25)
|
||
与 .sidebar-new-btn 共享 accent 配色语义但不走 width:100%:
|
||
空状态是居中布局,紧凑 auto-width 让视觉重心聚焦在按钮上,
|
||
不会撑满整行让空白左右显得"摊"。
|
||
|
||
设计选择:
|
||
- 颜色用 --accent + --btn-on-accent(与 .btn-primary 一致)—— 走主按钮语义,
|
||
让"下一步该做什么"的指令最强
|
||
- padding 9px 16px:比 .btn (12px 20px) 收紧一点,与 .sidebar-new-btn 视觉重量一致
|
||
- hover 不上 transform scale —— 空状态按钮是用户在"看到指引后第一次行动",
|
||
缩放会让人犹豫到底点没点中;改用 box-shadow 上抬作"立起来"反馈
|
||
- focus-visible 沿用全局 .btn 的 2px accent outline(见 08-modal.css),
|
||
这里只声明 offset 让焦点环在按钮内贴边,与全局外 2px 视觉一致 */
|
||
.empty-state-cta {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
/* 9px 16px → 10px 18px:与下方 hint secondary 拉开一档垂直间距的同时,
|
||
比 .sidebar-new-btn (34px 高) 略紧凑 —— 空状态是「轻量引导」,
|
||
不需要 34px 那么"正式"的按钮高度 */
|
||
padding: 10px 18px;
|
||
margin-top: var(--space-4);
|
||
background: var(--accent);
|
||
color: var(--btn-on-accent, #ffffff);
|
||
border: 1px solid transparent;
|
||
border-radius: var(--radius-sm);
|
||
font-size: var(--fs-sm);
|
||
font-weight: 600;
|
||
letter-spacing: var(--tracking-tight);
|
||
cursor: pointer;
|
||
/* hover 时阴影抬升比 scale 更克制;同时阴影从 accent-soft 升级到
|
||
accent-soft-hover,给"按钮立起来"的微动效暗示 */
|
||
box-shadow: 0 2px 6px var(--accent-soft);
|
||
transition:
|
||
background var(--transition-fast),
|
||
box-shadow var(--transition-fast),
|
||
transform var(--transition-fast);
|
||
}
|
||
|
||
.empty-state-cta:hover {
|
||
background: var(--accent-hover);
|
||
box-shadow: 0 4px 12px var(--accent-soft-hover);
|
||
}
|
||
|
||
.empty-state-cta:active {
|
||
/* 0.97 比其它按钮的 0.96 略小 —— 空状态 CTA 是"重决策",按下时
|
||
反馈更明显一点,避免用户怀疑"按了没生效" */
|
||
transform: scale(0.97);
|
||
}
|
||
|
||
.empty-state-cta:focus-visible {
|
||
outline: 2px solid var(--accent);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.empty-state .hint kbd {
|
||
/* .md 这种代码 chip 用 kbd 标签更语义化 */
|
||
/* padding 2/7 → 1/6:在 12px 字号下原 2/7 让 kbd chip 显得"鼓鼓的",
|
||
跟相邻的中文小字节奏不齐。收 1px 上下让 chip 更贴字高基线 */
|
||
padding: 1px 6px;
|
||
background: var(--bg-hover);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-sm);
|
||
/* 2026-08 从 11px 提到 12px:11px 在低 DPI 上偏糊,挤在提示文本里看着小 */
|
||
font-size: var(--fs-xs-readable);
|
||
font-family: var(--font-mono);
|
||
color: var(--fg-secondary);
|
||
font-weight: 600;
|
||
box-shadow: 0 1px 0 var(--border-subtle);
|
||
/* 上下微 margin 让 kbd 与相邻文字垂直居中对齐(默认 baseline 会让 kbd 显得"沉") */
|
||
margin: 0 1px;
|
||
}
|
||
|
||
.empty-state code {
|
||
padding: 2px 8px;
|
||
background: var(--bg-hover);
|
||
border-radius: var(--radius-sm);
|
||
/* 0.85em of 13px ≈ 11px —— 提到 12px(--fs-xs-readable)让 .md chip 跟 kbd 同档 */
|
||
font-size: var(--fs-xs-readable);
|
||
font-family: var(--font-mono);
|
||
/* accent 文字在 bg-hover 上仅 ~4:1;改用 fg-secondary 满足 AA */
|
||
color: var(--fg-secondary);
|
||
}
|
||
|
||
/* ============================================================
|
||
Editor Pane & Split View
|
||
三种模式:preview(仅 viewer)/ edit(仅 editor)/ split(双栏 + 分割条)
|
||
============================================================ */
|
||
|
||
body[data-editor-mode="split"] .app-shell {
|
||
/* 五列:sidebar | sb-splitter | editor | splitter | viewer
|
||
editor 用 px (--w-editor) 由 app.js 拖动时写在 .app-shell 的 style 上;
|
||
viewer 用 1fr 自动填剩余空间。
|
||
这样在 split + AI 模式下拖 ai-splitter 不会挤编辑器(详见 src/app.js mountSplitter)。
|
||
minmax(280px, ...) 给编辑器最小宽度 —— 编辑器内容至少要够阅读宽度才不挤;
|
||
默认 var(--w-editor, 50%) 在 CSS fallback 阶段给一个等分初始值,
|
||
app.js 启动时根据 splitRatio 重算覆盖。 */
|
||
grid-template-columns:
|
||
var(--sidebar-width)
|
||
4px
|
||
minmax(280px, var(--w-editor, 50%))
|
||
4px
|
||
minmax(0, 1fr);
|
||
}
|
||
|
||
body[data-editor-mode="preview"] .app-shell {
|
||
/* 三列:sidebar | sb-splitter | viewer */
|
||
grid-template-columns: var(--sidebar-width) 4px minmax(0, 1fr);
|
||
}
|
||
|
||
body[data-editor-mode="edit"] .app-shell {
|
||
/* 三列:sidebar | sb-splitter | editor */
|
||
grid-template-columns: var(--sidebar-width) 4px minmax(0, 1fr);
|
||
}
|
||
|
||
.editor-pane {
|
||
background: var(--bg-viewer);
|
||
overflow: hidden; /* CM6 自己处理滚动 */
|
||
min-width: 0;
|
||
min-height: 0;
|
||
display: none; /* 默认隐藏(preview 模式) */
|
||
user-select: text;
|
||
}
|
||
|
||
body[data-editor-mode="edit"] .editor-pane,
|
||
body[data-editor-mode="split"] .editor-pane {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 让编辑器与预览区域保持一致的宽度处理:共用 --w-reader-max。
|
||
默认 token 设为 none(content 完全填满区域,最大限度显示内容),
|
||
若未来想恢复"最优阅读宽度"上限,把 01-tokens.css 里的 --w-reader-max
|
||
改回 px 值(如 720px)即可,不用改这里。margin auto 仍保留,方便
|
||
切回 px 上限后让内容在更宽的窗口里居中。 */
|
||
.editor-pane .cm-editor {
|
||
max-width: var(--w-reader-max);
|
||
margin: 0 auto;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 窄窗口(< 720px):三栏挤到 1xx px 时退化为「单栏 + 隐藏阅读视图」——
|
||
至少保留可读可编辑区域。minWidth: 600 仍由主进程限制,这里只处理 600~720 区间 */
|
||
@media (max-width: 720px) {
|
||
body[data-editor-mode="split"] .app-shell {
|
||
/* 侧栏 splitter 仍保留,方便用户把侧栏压到最小留更多编辑区 */
|
||
grid-template-columns: var(--sidebar-width) 4px minmax(0, 1fr);
|
||
}
|
||
/* 直接隐藏 editor/viewer 之间的 splitter 元素,避免它作为孤儿占据第 5 个 grid 单元 */
|
||
body[data-editor-mode="split"] .splitter {
|
||
display: none !important;
|
||
}
|
||
body[data-editor-mode="split"] .viewer {
|
||
display: none !important;
|
||
}
|
||
/* 窄屏默认侧栏宽度变窄 */
|
||
:root { --sidebar-width: var(--w-sidebar-narrow); }
|
||
}
|
||
|
||
/* edit 模式:隐藏阅读视图 —— 编辑器已经占据右侧,不需要再显示预览 */
|
||
body[data-editor-mode="edit"] .viewer {
|
||
display: none;
|
||
}
|
||
|
||
.splitter {
|
||
background: var(--border-subtle);
|
||
cursor: col-resize;
|
||
position: relative;
|
||
display: none;
|
||
transition: background var(--transition-fast);
|
||
}
|
||
|
||
body[data-editor-mode="split"] .splitter {
|
||
display: block;
|
||
}
|
||
|
||
.splitter:hover,
|
||
.splitter.is-dragging {
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
.splitter::after {
|
||
/* 抓握提示:两条短竖线 */
|
||
content: "";
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 1px;
|
||
height: 24px;
|
||
background: var(--border-default);
|
||
box-shadow: 3px 0 0 var(--border-default);
|
||
}
|
||
|
||
.splitter:hover::after,
|
||
.splitter.is-dragging::after {
|
||
background: var(--accent);
|
||
box-shadow: 3px 0 0 var(--accent);
|
||
}
|
||
|
||
/* 编辑器底色 / 文字色已由 editor-theme.js 的 spec(var(--bg-viewer) / var(--fg-primary))
|
||
覆盖;老的"dark 强制 bg-viewer、light 强制 bg-viewer"那段代码冗余且容易出错,删除。 */
|
||
|
||
.cm-editor .cm-tooltip {
|
||
background: var(--bg-elevated);
|
||
color: var(--fg-primary);
|
||
border: 1px solid var(--border-default);
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
.cm-editor .cm-tooltip-autocomplete ul li[aria-selected] {
|
||
background: var(--accent-soft);
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* ============================================================
|
||
Folder Browser(Stage 8):面包屑 + 文件夹 / 二进制条目样式
|
||
|
||
面包屑放在 .sidebar-sort 下方、.file-list 上方,贴近它作用的列表。
|
||
根目录时整个 <nav> hidden(HTML 里默认带 hidden 属性),
|
||
不需要 CSS 处理空态。
|
||
|
||
文件夹(.file-item.is-folder):
|
||
- 文件夹图标 + 名称略加粗(区别于普通文件)
|
||
- meta 行简化为「文件夹」
|
||
二进制(.file-item.is-binary):
|
||
- opacity 0.45 + cursor not-allowed —— 视觉与文件管理器对不可执行项的灰态一致
|
||
- 仍可被点击(事件不被禁用,渲染端弹 toast 提示)
|
||
============================================================ */
|
||
|
||
.sidebar-breadcrumb {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 6px 10px 4px;
|
||
/* 横向溢出 + 不换行:用户进入很深层子目录时(如 archive/2026/03/15)
|
||
末尾「当前段」是最重要的,前面的历史段可以横滑出可见区 */
|
||
overflow-x: auto;
|
||
overflow-y: hidden;
|
||
white-space: nowrap;
|
||
/* 让滚动条只在 hover 时更显眼,平时几乎不可见 —— 避免视觉噪音 */
|
||
scrollbar-width: thin;
|
||
scrollbar-color: transparent transparent;
|
||
}
|
||
.sidebar-breadcrumb:hover {
|
||
scrollbar-color: var(--border-subtle) transparent;
|
||
}
|
||
|
||
/* 回到根按钮:图标 + 文字,单独占左侧 */
|
||
.sidebar-breadcrumb-root {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
flex: 0 0 auto;
|
||
padding: 2px 6px;
|
||
border: none;
|
||
background: transparent;
|
||
color: var(--fg-secondary);
|
||
font-size: var(--fs-xs);
|
||
cursor: pointer;
|
||
border-radius: 3px;
|
||
font-family: inherit;
|
||
}
|
||
.sidebar-breadcrumb-root:hover {
|
||
background: var(--bg-hover);
|
||
color: var(--fg-primary);
|
||
}
|
||
.sidebar-breadcrumb-root:focus-visible {
|
||
outline: 2px solid var(--accent);
|
||
outline-offset: 1px;
|
||
}
|
||
.sidebar-breadcrumb-root svg {
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
/* 面包屑分段按钮(中间段,可点击跳转) */
|
||
.sidebar-breadcrumb-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
flex: 0 0 auto;
|
||
padding: 2px 6px;
|
||
border: none;
|
||
background: transparent;
|
||
color: var(--fg-secondary);
|
||
font-size: var(--fs-xs);
|
||
cursor: pointer;
|
||
border-radius: 3px;
|
||
font-family: inherit;
|
||
max-width: 120px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
.sidebar-breadcrumb-btn:hover {
|
||
background: var(--bg-hover);
|
||
color: var(--accent);
|
||
}
|
||
.sidebar-breadcrumb-btn:focus-visible {
|
||
outline: 2px solid var(--accent);
|
||
outline-offset: 1px;
|
||
}
|
||
|
||
/* 当前段(非可点击,纯文本):稍亮,与「根 / 中间段」做对比 */
|
||
.sidebar-breadcrumb-current {
|
||
flex: 0 0 auto;
|
||
padding: 2px 6px;
|
||
font-size: var(--fs-xs);
|
||
color: var(--fg-primary);
|
||
font-weight: 600;
|
||
max-width: 160px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.sidebar-breadcrumb-sep {
|
||
flex: 0 0 auto;
|
||
color: var(--fg-muted);
|
||
font-size: var(--fs-xs);
|
||
opacity: 0.6;
|
||
}
|
||
|
||
/* 文件夹条目:粗体名称 + 文件夹图标颜色稍亮 */
|
||
.file-item.is-folder .file-name {
|
||
font-weight: 600;
|
||
color: var(--fg-primary);
|
||
}
|
||
.file-item.is-folder .file-icon {
|
||
/* 文件夹图标用 accent 而不是 fg-muted:让「这是目录」的视觉信号更直接 */
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* 二进制条目:灰态 + cursor 提示不可编辑,但仍可点击(弹 toast) */
|
||
.file-item.is-binary {
|
||
opacity: 0.45;
|
||
cursor: not-allowed;
|
||
}
|
||
.file-item.is-binary .file-icon {
|
||
/* 与灰度视觉统一:图标也走 fg-muted */
|
||
color: var(--fg-muted);
|
||
}
|
||
.file-item.is-binary:hover {
|
||
/* 灰态项 hover 不要让背景喧宾夺主 —— 用更弱的 hover 背景 */
|
||
background: var(--bg-hover);
|
||
}
|
||
.file-item.is-binary.is-active {
|
||
/* 即使被键盘选中也不打破「不可编辑」的视觉信号 —— 不用 accent 高亮 */
|
||
background: var(--bg-hover);
|
||
}
|
||
.file-item.is-binary.is-active::before {
|
||
/* 不画左侧色条:用户已经看 opacity 知道这一项不可编辑 */
|
||
opacity: 0.4;
|
||
}
|
||
|
||
/* ============================================================
|
||
Folder Browser:拖拽 + 剪贴板视觉反馈
|
||
- .file-item 默认 draggable=true(文件 / 文件夹 / 二进制都可拖)
|
||
- 拖拽中源项 .is-dragging 半透明;合法投放目标 folder .is-drop-target 给
|
||
accent 虚线描边 + 软底高亮;剪切到剪贴板的源项 .is-clipboard-cut 用
|
||
虚线 + 弱化提示「将被移走」。
|
||
============================================================ */
|
||
|
||
.file-item[draggable="true"] {
|
||
/* 默认已是 cursor:pointer;拖拽态单独给 grabbing 反馈 */
|
||
cursor: grab;
|
||
}
|
||
|
||
.file-item.is-dragging {
|
||
opacity: 0.4;
|
||
cursor: grabbing;
|
||
}
|
||
|
||
.file-item.is-drop-target {
|
||
/* 合法投放目标:accent 虚线描边 + 软底,明显区别于 hover 态 */
|
||
outline: 2px dashed var(--accent);
|
||
outline-offset: -2px;
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
.file-item.is-clipboard-cut {
|
||
/* 已剪切待移动的源项:弱化 + 虚线边框,暗示「即将离开此处」 */
|
||
opacity: 0.6;
|
||
outline: 1px dashed var(--border-default);
|
||
outline-offset: -2px;
|
||
}
|
||
|
||
/* audit R7a P1-20:分页「加载更多」按钮
|
||
视觉上是一个普通 li 但居中、有虚线分隔;hover 时背景色加深 + cursor:pointer。
|
||
跟普通 .file-item 共享 padding / font 但不要 icon,简洁一些。 */
|
||
.file-list-load-more {
|
||
list-style: none;
|
||
padding: 10px 12px;
|
||
margin: 4px 8px;
|
||
border: 1px dashed var(--border-default);
|
||
border-radius: 6px;
|
||
text-align: center;
|
||
color: var(--fg-secondary);
|
||
font-size: var(--fs-sm);
|
||
cursor: pointer;
|
||
user-select: none;
|
||
transition: background 0.1s, border-color 0.1s;
|
||
}
|
||
.file-list-load-more:hover,
|
||
.file-list-load-more:focus-visible {
|
||
background: var(--bg-hover);
|
||
border-color: var(--accent);
|
||
color: var(--fg-primary);
|
||
outline: none;
|
||
}
|
||
|
||
|
||
/* audit R7a P1-15:windowed 虚拟滚动 —— JS 切到该模式时给 .file-item 加
|
||
.is-windowed 类,position:absolute 让 N*50 位置数学生效,left/right
|
||
撑满容器,padding 仍然在 .file-item 上(box-sizing:border-box,
|
||
height:50px 已含 padding)。
|
||
top 由 JS 直接 style.top = N*50+'px' 设置,不写进 CSS(每个 item 不同)。
|
||
切回 full 模式时 JS 移除 .is-windowed 与 style.top,flex 布局自然复位。 */
|
||
.file-item.is-windowed {
|
||
position: absolute;
|
||
left: 10px; /* 抵消 .file-list 的 padding-left 10px */
|
||
right: 10px; /* 抵消 .file-list 的 padding-right 10px */
|
||
}
|