feat(canvas): 面板层级管理 — 五层Elevation体系+渐进式三区+z-index全量迁移 #98 (#102)

* feat(canvas): 面板层级管理优化 - 五层Elevation+渐进式三区+进度增强 #98 #94

基于 Wayfinder 地图 #98 决议执行面板层级管理优化:

1. 五层 Elevation 体系(决策1)
   - 画布组件 z-index 硬编码值全部迁移到 token
   - L0 画布层 → L1 工具层 → L2 面板层 → L3 对话框层 → L4 通知层
   - 涉及 14 个 .tsx 文件,0 处 z-[N] 硬编码残留

2. prompt 面板渐进式三区(决策2)
   - B区参数区改为手风琴折叠模式(默认折叠)
   - 新增 SlidersHorizontal + ChevronDown 图标切换
   - 点击展开 video 工具参数,收起后释放视觉空间
   - A区核心区(prompt+生成)始终展开

3. 任务进度条增强(决策3)
   - 进度条高度 1px→1.5px,视觉更醒目
   - 新增 shimmer 扫描动画(running 态,1.4s/cycle)
   - 新增百分比数字显示(tabular-nums 等宽数字)
   - 新增 indeterminate 模式(无百分比时循环扫描)
   - 尊重 prefers-reduced-motion(reducedMotion 时禁用动画)

4. CSS 动画
   - 新增 @keyframes canvas-task-progress-shimmer
   - .canvas-task-progress-shimmer 类

Closes #98

* refactor(canvas): z-index 全量迁移到五层Elevation token #98 #94

补全 #98 五层 Elevation 体系的剩余硬编码 z-index 清理:
- 三个设置弹层(图/音/视频)zIndex:1200 → var(--z-popover)
- model-setup-guide z-[900] → var(--z-toast)
- 项目侧栏 z-30 → var(--z-panel),章节预览 z-50 → var(--z-panel-floating)
- shared 页头/缩放控件/访客提示 z-[80]/z-[70] → var(--z-panel-floating),右键菜单 z-[90] → var(--z-modal)
- project 缩放控件容器 z-50 → var(--z-panel),绘图加载遮罩 z-[500] → var(--z-toast)
- 反馈面板 z-[90] → var(--z-panel-floating)

共 16 处全局浮层 z-index 迁移到 token,消除层级冲突隐患。

---------

Co-authored-by: sikongyue <3155157671@qq.com>
This commit is contained in:
爱笑的毛毛虫
2026-08-03 22:16:25 +08:00
committed by GitHub
parent 6eb77b93a0
commit 39844d7c8d
21 changed files with 103 additions and 43 deletions

View File

@@ -39,7 +39,7 @@ export function CanvasActiveTaskPanel({ tasks }: { tasks: GenerationTask[] }) {
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -8, scale: 0.98 }}
transition={motionTransition}
className="pointer-events-none absolute right-3 top-[72px] z-[120] w-[min(332px,calc(100vw-24px))]"
className="pointer-events-none absolute right-3 top-[72px] z-[var(--z-modal-overlay)] w-[min(332px,calc(100vw-24px))]"
>
<LayoutGroup id="canvas-active-tasks">
<motion.section
@@ -134,14 +134,47 @@ function ActiveTaskCard({ task, now, theme, expanded, onToggle, reducedMotion }:
{expanded ? <ChevronUp className="mt-0.5 size-3.5 shrink-0" style={{ color: theme.node.muted }} /> : <ChevronDown className="mt-0.5 size-3.5 shrink-0" style={{ color: theme.node.muted }} />}
</div>
<div className="mt-3 h-1 overflow-hidden rounded-full" style={{ background: theme.toolbar.itemHover }}>
<motion.div className="h-full rounded-full" animate={{ width: `${progress ?? 8}%` }} transition={reducedMotion ? { duration: 0 } : { duration: 0.3 }} style={{ background: statusTone }} />
<div className="mt-3 h-1.5 overflow-hidden rounded-full" style={{ background: theme.toolbar.itemHover }}>
{progress !== undefined ? (
<motion.div
className="relative h-full rounded-full overflow-hidden"
animate={{ width: `${progress}%` }}
transition={reducedMotion ? { duration: 0 } : { duration: 0.3, ease: "easeOut" }}
style={{ background: statusTone }}
>
{/* 进度条 shimmer 扫描动画(对应 #98 决策3)*/}
{task.status === "running" && !reducedMotion ? (
<span
className="absolute inset-0 canvas-task-progress-shimmer"
style={{ background: "linear-gradient(90deg, transparent, rgba(255,255,255,.3), transparent)" }}
aria-hidden
/>
) : null}
</motion.div>
) : (
// indeterminate 模式(无具体百分比,从左到右循环扫描)
<motion.div
className="h-full rounded-full"
initial={{ width: "20%", x: "-100%" }}
animate={{ width: "20%", x: "400%" }}
transition={reducedMotion ? { duration: 0 } : { duration: 1.2, repeat: Infinity, ease: "easeInOut" }}
style={{ background: statusTone }}
/>
)}
</div>
<div className="mt-3 grid grid-cols-2 gap-2 text-[var(--fs-tiny)]" style={{ color: theme.node.muted }}>
<span className="inline-flex min-w-0 items-center gap-1 truncate" title={durationLabel}><Clock3 className="size-3 shrink-0" />{durationLabel}</span>
<span className="inline-flex min-w-0 items-center justify-end gap-1 truncate" title={billingLabel}><Coins className="size-3 shrink-0" />{billingLabel}</span>
</div>
{/* 进度百分比显示(对应 #98 决策3:列表视图)*/}
{progress !== undefined && task.status === "running" ? (
<div className="mt-1 flex items-center justify-between text-[var(--fs-micro)]" style={{ color: theme.node.muted }}>
<span>{durationLabel}</span>
<span className="font-medium tabular-nums" style={{ color: statusTone }}>{progress}%</span>
</div>
) : (
<div className="mt-3 grid grid-cols-2 gap-2 text-[var(--fs-tiny)]" style={{ color: theme.node.muted }}>
<span className="inline-flex min-w-0 items-center gap-1 truncate" title={durationLabel}><Clock3 className="size-3 shrink-0" />{durationLabel}</span>
<span className="inline-flex min-w-0 items-center justify-end gap-1 truncate" title={billingLabel}><Coins className="size-3 shrink-0" />{billingLabel}</span>
</div>
)}
</button>
<AnimatePresence initial={false}>