feat(canvas): 沉浸专注与短剧流程 - 支持专注模式与流程条并入顶栏体系 (#157)

- 沉浸专注:进入后隐藏顶部栏、Dock、缩放控件、小地图与素材托盘,保留专注胶囊可唤出工具与智能体;小屏默认进入,⇧⌘F 切换,Esc 在无选中与浮层时退出
- 智能体面板改贴边停靠并按顶栏让位,作为沉浸专注的配套依赖
- 短剧流程条并入顶栏:折叠入口移入顶栏按钮组,展开条锚定顶栏下缘,与工作模式开关互斥
- 流程步骤改为里程碑节点与状态轨道,新增 --flow-step-* Design Token

Co-authored-by: sikongyue <3155157671@qq.com>
This commit is contained in:
爱笑的毛毛虫
2026-08-06 08:32:38 +08:00
committed by GitHub
parent 6671c331e3
commit 971489a336
12 changed files with 519 additions and 255 deletions

View File

@@ -54,6 +54,8 @@ export const FloatingDock = forwardRef<HTMLDivElement, FloatingDockProps>(functi
const mouseX = useMotionValue(Number.POSITIVE_INFINITY);
const reducedMotion = useReducedMotion();
const [coarsePointer, setCoarsePointer] = useState(() => typeof window !== "undefined" && window.matchMedia("(pointer: coarse)").matches);
// 窄屏下 dock 按钮总宽易超出可用宽度:此时允许横向滚动并禁用放大(放大依赖 overflow-visible,与滚动互斥)
const [narrow, setNarrow] = useState(() => (typeof window !== "undefined" ? window.innerWidth < 768 : false));
useEffect(() => {
const media = window.matchMedia("(pointer: coarse)");
@@ -63,7 +65,15 @@ export const FloatingDock = forwardRef<HTMLDivElement, FloatingDockProps>(functi
return () => media.removeEventListener("change", update);
}, []);
const motionEnabled = !reducedMotion && !coarsePointer;
useEffect(() => {
const update = () => setNarrow(window.innerWidth < 768);
window.addEventListener("resize", update);
return () => window.removeEventListener("resize", update);
}, []);
// scrollable 场景(触屏或窄屏)禁用放大并允许横向滚动,保证按钮始终可达
const scrollable = coarsePointer || narrow;
const motionEnabled = !reducedMotion && !scrollable;
const metrics = coarsePointer ? TOUCH_DOCK_METRICS[size] : DOCK_METRICS[size];
return (
@@ -72,7 +82,8 @@ export const FloatingDock = forwardRef<HTMLDivElement, FloatingDockProps>(functi
role="toolbar"
aria-label={ariaLabel}
className={cn(
"aceternity-floating-dock flex overflow-visible",
"aceternity-floating-dock flex",
scrollable ? "overflow-x-auto" : "overflow-visible",
showLabels ? "items-center" : "items-end",
embedded ? "shadow-none" : "border backdrop-blur-2xl",
showLabels
@@ -163,6 +174,8 @@ function DockCommandButton({ command, mouseX, metrics, motionEnabled, compact, s
const iconSize = useSpring(iconTarget, aceternityMotion.spring.dock);
// 鼠标点击产生的 focus 不能阻塞提示收起,只有键盘可见焦点才持续显示提示。
const showTooltip = !showLabel && (hovered || focused) && !command.disabled;
// scrollable 场景自定义 tooltip 会被 overflow 裁剪,用原生 title 兜底
const nativeTitle = !motionEnabled ? command.label : undefined;
if (showLabel) {
return (
@@ -195,6 +208,7 @@ function DockCommandButton({ command, mouseX, metrics, motionEnabled, compact, s
<motion.button
type="button"
aria-label={command.label}
title={nativeTitle}
aria-expanded={command.expands ? command.active || undefined : undefined}
aria-pressed={command.expands ? undefined : command.active || undefined}
disabled={command.disabled}