PC06▸🧭 Navigation · 導航▸Dock
Floating Dock
浮動 Dock
難度 ★★★★★標籤 dock · magnify · macOS3 min read
模式簡述
Floating Dock:macOS 風格的浮動工具列,滑鼠靠近會放大圖標。視覺上很 ‘Apple’,操作上其實要克制。
Claude Code Prompt
參考:PC06 floating-dock 組件:FloatingDock.tsx Floating Dock:macOS 風格的浮動工具列,滑鼠靠近會放大圖標。視覺上很 ‘Apple’,操作上其實要克制。 限制: - magnify 太誇張 - 鄰居沒跟著推開 - 移開後沒復原動畫
完整程式碼
"use client";
import { useRef, useState } from "react";
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
import { Home, Folder, Search, Settings, User, Mail, Music } from "lucide-react";
type State = "idle" | "hover";
const ICONS = [Home, Folder, Search, Mail, Music, User, Settings];
function DockIcon({
Icon,
mouseX,
}: {
Icon: typeof Home;
mouseX: ReturnType<typeof useMotionValue<number>>;
}) {
const ref = useRef<HTMLDivElement>(null);
const distance = useTransform(mouseX, (v) => {
const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 };
return v - bounds.x - bounds.width / 2;
});
const widthSync = useTransform(distance, [-100, 0, 100], [36, 56, 36]);
const width = useSpring(widthSync, { mass: 0.1, stiffness: 200, damping: 14 });
return (
<motion.div
ref={ref}
style={{ width, height: width }}
className="grid aspect-square place-items-center rounded-lg bg-background/60 border border-border/60"
>
<Icon className="h-1/2 w-1/2 text-muted-foreground" />
</motion.div>
);
}
export function FloatingDock({ state = "idle" }: { state?: State }) {
const mouseX = useMotionValue(state === "hover" ? 200 : Infinity);
return (
<div className="grid h-[200px] w-full max-w-md place-items-end">
<motion.div
onMouseMove={(e) => mouseX.set(e.clientX)}
onMouseLeave={() => mouseX.set(Infinity)}
className="mb-4 flex items-end gap-2 rounded-2xl border border-border bg-background/50 px-3 py-2 backdrop-blur"
>
{ICONS.map((Icon, i) => (
<DockIcon key={i} Icon={Icon} mouseX={mouseX} />
))}
</motion.div>
</div>
);
}何時用
- ✅ 想做 macOS 風格的 portfolio / brand 站
- ✅ 工具列項目 ≤ 8 個
- ✅ 桌面端為主
何時別用
- ❌ 手機端(沒 hover,magnify 無意義)
- ❌ 需要文字標籤(dock 太擠塞不下)
- ❌ 嚴肅商務介面(太花俏)
我踩過的坑
-
magnify 太誇張:放大 2x 看起來像玩具,1.4x 剛好。
-
鄰居沒跟著推開:應該整個 row 重新排列,否則重疊。
-
移開後沒復原動畫:spring 還原比直接跳更舒服。
相關模式
- PC07
- PG10