feat(canvas): 交互可读性 - 优化连线、字号与工作条
This commit is contained in:
@@ -9,6 +9,7 @@ export type FloatingDockCommand = {
|
||||
id: string;
|
||||
label: string;
|
||||
displayLabel?: string;
|
||||
badge?: ReactNode;
|
||||
icon: ReactNode;
|
||||
wide?: boolean;
|
||||
quiet?: boolean;
|
||||
@@ -25,6 +26,7 @@ export type FloatingDockSwitchOption = {
|
||||
label: string;
|
||||
icon: ReactNode;
|
||||
value: string;
|
||||
displayLabel?: string;
|
||||
};
|
||||
|
||||
export type FloatingDockSwitch = {
|
||||
@@ -237,6 +239,7 @@ function DockCommandButton({ command, mouseX, metrics, motionEnabled, compact, s
|
||||
>
|
||||
<span className="grid size-3.5 shrink-0 place-items-center">{command.icon}</span>
|
||||
<span className="inline-flex h-4 items-center text-[var(--fs-label)] font-medium leading-none">{command.displayLabel || command.label}</span>
|
||||
{command.badge !== undefined ? <span className="aceternity-dock-command-badge inline-flex min-w-4 items-center justify-center rounded-full px-1 text-[var(--fs-micro)] font-bold leading-4">{command.badge}</span> : null}
|
||||
</motion.button>
|
||||
</motion.span>
|
||||
);
|
||||
@@ -292,15 +295,17 @@ function DockSwitch({ entry, compact, showLabel, motionEnabled, metrics }: { ent
|
||||
const [focusedId, setFocusedId] = useState<string | null>(null);
|
||||
const selectedIndex = Math.max(0, entry.options.findIndex((option) => option.value === entry.value));
|
||||
const touch = metrics.base >= 40;
|
||||
const slot = touch ? 32 : compact ? 24 : 26;
|
||||
const gap = touch ? 10 : compact ? 8 : 10;
|
||||
const padX = touch ? 7 : compact ? 6 : 7;
|
||||
const labeled = showLabel || entry.options.some((option) => option.displayLabel);
|
||||
const slot = labeled ? (touch ? 68 : compact ? 58 : 64) : touch ? 32 : compact ? 24 : 26;
|
||||
const slotHeight = labeled ? metrics.base : slot;
|
||||
const gap = labeled ? (touch ? 4 : 3) : touch ? 10 : compact ? 8 : 10;
|
||||
const padX = labeled ? (touch ? 5 : 4) : touch ? 7 : compact ? 6 : 7;
|
||||
|
||||
return (
|
||||
<span
|
||||
role="radiogroup"
|
||||
aria-label={entry.label}
|
||||
className="aceternity-dock-switch relative flex shrink-0 self-end items-center"
|
||||
className={cn("aceternity-dock-switch relative flex shrink-0 self-end items-center", labeled && "is-labeled")}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") return;
|
||||
event.preventDefault();
|
||||
@@ -315,25 +320,25 @@ function DockSwitch({ entry, compact, showLabel, motionEnabled, metrics }: { ent
|
||||
>
|
||||
<motion.span
|
||||
aria-hidden
|
||||
className="aceternity-dock-switch-thumb pointer-events-none absolute top-1/2 rounded-full"
|
||||
className={cn("aceternity-dock-switch-thumb pointer-events-none absolute top-1/2", labeled ? "rounded-[var(--dock-item-radius)]" : "rounded-full")}
|
||||
initial={false}
|
||||
animate={{ x: selectedIndex * (slot + gap), y: "-50%" }}
|
||||
transition={reducedMotion || !motionEnabled ? { duration: 0 } : aceternityMotion.spring.dock}
|
||||
style={{ width: slot, height: slot, left: padX }}
|
||||
style={{ width: slot, height: slotHeight, left: padX }}
|
||||
/>
|
||||
{entry.options.map((option) => {
|
||||
const checked = option.value === entry.value;
|
||||
const showTooltip = !showLabel && (hoveredId === option.id || focusedId === option.id);
|
||||
const showTooltip = !labeled && (hoveredId === option.id || focusedId === option.id);
|
||||
return (
|
||||
<span key={option.id} className="relative">
|
||||
<span key={option.id} className="relative inline-flex shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
role="radio"
|
||||
aria-checked={checked}
|
||||
aria-label={option.label}
|
||||
title={!motionEnabled ? option.label : undefined}
|
||||
className="aceternity-dock-switch-option relative z-[1] grid place-items-center rounded-full border-0 outline-none"
|
||||
style={{ width: slot, height: slot }}
|
||||
className={cn("aceternity-dock-switch-option relative z-[1] inline-flex items-center justify-center border-0 outline-none", labeled ? "gap-1 rounded-[var(--dock-item-radius)] px-2" : "rounded-full")}
|
||||
style={{ width: slot, height: slotHeight }}
|
||||
onMouseEnter={() => setHoveredId(option.id)}
|
||||
onMouseLeave={() => setHoveredId((current) => current === option.id ? null : current)}
|
||||
onFocus={(event) => {
|
||||
@@ -345,7 +350,8 @@ function DockSwitch({ entry, compact, showLabel, motionEnabled, metrics }: { ent
|
||||
if (!checked) entry.onChange(option.value);
|
||||
}}
|
||||
>
|
||||
<span className={cn("grid place-items-center", touch ? "[&_svg]:size-4" : "[&_svg]:size-[15px]")}>{option.icon}</span>
|
||||
<span className="grid size-4 shrink-0 place-items-center">{option.icon}</span>
|
||||
{labeled ? <span className="shrink-0 whitespace-nowrap text-[length:var(--fs-micro)] font-semibold leading-none">{option.displayLabel || option.label}</span> : null}
|
||||
</button>
|
||||
<AnimatePresence>
|
||||
{showTooltip ? (
|
||||
|
||||
Reference in New Issue
Block a user