refactor(canvas): 画布工具栏 - 收敛 Dock 放大与交互状态
保留当前画布视觉体系,统一 Dock 按钮形态、状态反馈与子菜单展开关系。\n\nCloses #244
This commit is contained in:
@@ -192,8 +192,8 @@ export function CanvasToolbar({
|
||||
|
||||
<AnimatePresence>
|
||||
{appearanceOpen ? (
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: aceternityMotion.duration.instant }} className="pointer-events-auto absolute bottom-[var(--canvas-dock-popover-offset)] z-[var(--dock-z-popover)] w-[224px] max-w-[calc(100vw-24px)] -translate-x-1/2" style={{ left: panelX || "50%" }}>
|
||||
<SpotlightSurface spotlightColor={theme.toolbar.itemHover} initial={{ y: 6, scale: 0.97 }} animate={{ y: 0, scale: 1 }} exit={{ y: 4, scale: 0.98 }} transition={{ duration: aceternityMotion.duration.instant, ease: aceternityMotion.easing.enter }} className="aceternity-floating-panel overflow-hidden rounded-[var(--panel-radius)] border p-2.5 backdrop-blur-2xl" style={{ background: theme.spatial.elevated, borderColor: theme.toolbar.border, color: theme.toolbar.item }} onWheel={(event) => event.stopPropagation()}>
|
||||
<motion.div initial={{ opacity: 0, scaleY: 0.9, y: 8 }} animate={{ opacity: 1, scaleY: 1, y: 0 }} exit={{ opacity: 0, scaleY: 0.92, y: 6 }} transition={{ duration: aceternityMotion.duration.panel, ease: aceternityMotion.easing.enter }} className="pointer-events-auto absolute bottom-[var(--canvas-dock-popover-offset)] z-[var(--dock-z-popover)] w-[224px] max-w-[calc(100vw-24px)]" style={{ left: panelX || "50%", transformOrigin: "bottom center", x: "-50%" }}>
|
||||
<SpotlightSurface spotlightColor={theme.toolbar.itemHover} initial={{ opacity: 0, scale: 0.97 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.97, transition: { duration: 0 } }} transition={{ duration: aceternityMotion.duration.instant, ease: aceternityMotion.easing.enter }} className="aceternity-floating-panel overflow-hidden rounded-[var(--panel-radius)] border p-2.5 backdrop-blur-2xl" style={{ background: theme.spatial.elevated, borderColor: theme.toolbar.border, color: theme.toolbar.item }} onWheel={(event) => event.stopPropagation()}>
|
||||
<PanelHeading icon={<Palette className="size-4" />} title="画布外观" subtitle="调整整个创作空间" theme={theme} />
|
||||
<div className="mt-3 text-[var(--fs-micro)] font-semibold uppercase opacity-45">主题模式</div>
|
||||
<div className="mt-1 grid grid-cols-2 gap-1 rounded-[var(--dock-item-radius-labeled)] border p-1" style={{ background: theme.spatial.surface, borderColor: theme.toolbar.border }}>
|
||||
@@ -231,8 +231,8 @@ function AddNodeMenu({ x, theme, commands }: {
|
||||
commands: CanvasCreateCommand[];
|
||||
}) {
|
||||
return (
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: aceternityMotion.duration.instant }} className="pointer-events-auto absolute bottom-[var(--canvas-dock-popover-offset)] z-[var(--dock-z-popover)] w-[260px] max-w-[calc(100vw-24px)] -translate-x-1/2" style={{ left: x || "50%" }}>
|
||||
<SpotlightSurface spotlightColor={theme.toolbar.itemHover} initial={{ y: 6, scale: 0.97 }} animate={{ y: 0, scale: 1 }} exit={{ y: 4, scale: 0.98 }} transition={{ duration: aceternityMotion.duration.instant, ease: aceternityMotion.easing.enter }} className="aceternity-floating-panel overflow-hidden rounded-[var(--panel-radius)] border p-2 backdrop-blur-2xl" style={{ background: theme.spatial.elevated, borderColor: theme.toolbar.border, color: theme.node.text }} onWheel={(event) => event.stopPropagation()}>
|
||||
<motion.div initial={{ opacity: 0, scaleY: 0.9, y: 8 }} animate={{ opacity: 1, scaleY: 1, y: 0 }} exit={{ opacity: 0, scaleY: 0.92, y: 6 }} transition={{ duration: aceternityMotion.duration.panel, ease: aceternityMotion.easing.enter }} className="pointer-events-auto absolute bottom-[var(--canvas-dock-popover-offset)] z-[var(--dock-z-popover)] w-[260px] max-w-[calc(100vw-24px)]" style={{ left: x || "50%", transformOrigin: "bottom center", x: "-50%" }}>
|
||||
<SpotlightSurface spotlightColor={theme.toolbar.itemHover} initial={{ opacity: 0, scale: 0.97 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.97, transition: { duration: 0 } }} transition={{ duration: aceternityMotion.duration.instant, ease: aceternityMotion.easing.enter }} className="aceternity-floating-panel overflow-hidden rounded-[var(--panel-radius)] border p-2 backdrop-blur-2xl" style={{ background: theme.spatial.elevated, borderColor: theme.toolbar.border, color: theme.node.text }} onWheel={(event) => event.stopPropagation()}>
|
||||
<CanvasCreateMenu commands={commands} />
|
||||
</SpotlightSurface>
|
||||
</motion.div>
|
||||
|
||||
@@ -40,9 +40,11 @@ type DockMetrics = {
|
||||
distance: number;
|
||||
};
|
||||
|
||||
// magnification 收敛:base 略增以适配圆角方块,magnified 幅度从 +14 降到 +8,
|
||||
// 避免 dock 整体跳动,同时保留 Aceternity 接近放大身份。
|
||||
const DOCK_METRICS: Record<NonNullable<FloatingDockProps["size"]>, DockMetrics> = {
|
||||
default: { base: 29, magnified: 43, icon: 14, iconMagnified: 19, distance: 108 },
|
||||
compact: { base: 25, magnified: 35, icon: 13, iconMagnified: 17, distance: 88 },
|
||||
default: { base: 30, magnified: 38, icon: 15, iconMagnified: 18, distance: 100 },
|
||||
compact: { base: 26, magnified: 32, icon: 13, iconMagnified: 16, distance: 84 },
|
||||
};
|
||||
|
||||
const TOUCH_DOCK_METRICS: Record<NonNullable<FloatingDockProps["size"]>, DockMetrics> = {
|
||||
@@ -228,7 +230,7 @@ function DockCommandButton({ command, mouseX, metrics, motionEnabled, compact, s
|
||||
aria-expanded={command.expands ? command.active || undefined : undefined}
|
||||
aria-pressed={command.expands ? undefined : command.active || undefined}
|
||||
disabled={command.disabled}
|
||||
className={cn("aceternity-dock-command group relative grid size-full place-items-center rounded-full border outline-none", command.quiet && "is-quiet", command.active && "is-active", command.danger && "is-danger")}
|
||||
className={cn("aceternity-dock-command group relative grid size-full place-items-center rounded-[var(--dock-item-radius)] border outline-none", command.quiet && "is-quiet", command.active && "is-active", command.danger && "is-danger")}
|
||||
whileTap={motionEnabled && !command.disabled ? { scale: 0.92 } : undefined}
|
||||
transition={aceternityMotion.spring.dock}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
|
||||
@@ -5030,16 +5030,17 @@
|
||||
box-shadow: 0 24px 72px rgba(15, 23, 42, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
/* Dock 命令按钮:BottomMenu 式干净状态——透明默认 + hover/active 仅换底色,
|
||||
去掉描边/内阴影/发光阴影的多层反馈,hover 与 active 用同一套视觉语言,
|
||||
保持 dock 整体性(参考 uselayouts BottomMenu 的 bg-muted/bg-accent 切换)。*/
|
||||
.aceternity-dock-command {
|
||||
border-color: color-mix(in srgb, currentColor 11%, transparent);
|
||||
background: var(--dock-command-bg);
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 5px 15px rgba(15, 23, 42, 0.08);
|
||||
box-shadow: none;
|
||||
transition:
|
||||
border-color var(--motion-instant) ease-out,
|
||||
background-color var(--motion-instant) ease-out,
|
||||
color var(--motion-instant) ease-out,
|
||||
box-shadow var(--motion-instant) ease-out;
|
||||
color var(--motion-instant) ease-out;
|
||||
}
|
||||
|
||||
.aceternity-dock-command > span:first-child svg {
|
||||
@@ -5049,33 +5050,12 @@
|
||||
}
|
||||
|
||||
.aceternity-dock-command:hover:not(:disabled) {
|
||||
border-color: color-mix(in srgb, currentColor 20%, transparent);
|
||||
background: var(--dock-command-hover);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 12px 30px rgba(15, 23, 42, 0.14);
|
||||
}
|
||||
|
||||
.aceternity-dock-command.is-labeled {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.aceternity-dock-command.is-labeled:hover:not(:disabled) {
|
||||
border-color: transparent;
|
||||
background: var(--dock-command-hover);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.aceternity-dock-command.is-labeled.is-active {
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.aceternity-dock-command.is-active {
|
||||
border-color: color-mix(in srgb, var(--dock-command-active) 28%, transparent);
|
||||
background: var(--dock-command-active);
|
||||
color: var(--dock-command-active-text);
|
||||
box-shadow: 0 12px 30px color-mix(in srgb, var(--dock-command-active) 22%, transparent);
|
||||
}
|
||||
|
||||
.aceternity-dock-command.is-active > span:first-child,
|
||||
@@ -5085,19 +5065,6 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.aceternity-dock-command.is-quiet {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.aceternity-dock-command.is-quiet:hover:not(:disabled),
|
||||
.aceternity-dock-command.is-quiet.is-active {
|
||||
border-color: transparent;
|
||||
background: var(--dock-command-hover);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.aceternity-dock-command.is-danger {
|
||||
color: var(--dock-command-danger);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user