/* =========================================================================== 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 用
  • 而非
    是因为