Quest Map Section
蜿蜒的關卡地圖區塊,捲動時標記沿路徑闖關,抵達站點即彈出內容、升旗並蓋上完成印記。
載入預覽⋯
安裝
npx shadcn@latest add https://webberui.com/r/quest-map-section.json或在 components.json 設定 registries 後,改用 @webberui/quest-map-section 安裝。
安裝依賴後,從 registry JSON(/r/quest-map-section.json 的 files[0].content)複製 quest-map-section.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion lucide-react clsx tailwind-merge使用
以 QuestMapSection 包住若干 QuestNode,站點會自動左右交錯排列,一條蜿蜒路徑串起所有節點;捲動時標記沿路徑前進,抵達的站點依序點亮。
import {
QuestMapSection,
QuestNode,
} from "@/components/ui/quest-map-section";
<QuestMapSection className="text-indigo-500">
<QuestNode title="建立帳號" icon={<Compass className="h-4 w-4" />} flag="起點">
三十秒完成註冊。
</QuestNode>
<QuestNode title="首次部署" icon={<Rocket className="h-4 w-4" />} flag="通關">
推上第一版,預覽網址即時產生。
</QuestNode>
</QuestMapSection>強調色透過 currentColor 繼承:在 QuestMapSection 的 className 傳入任意 text-* 即可整體換色(路徑、標記、圓點、旗幟、印記同步跟著變)。
於捲動容器內使用
若地圖放在具 overflow-y-auto 的巢狀容器中,把該容器的 ref 傳給 container,捲動進度才會正確對應:
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[300px] overflow-y-auto">
<QuestMapSection container={scrollerRef}>{/* ...QuestNode */}</QuestMapSection>
</div>Props
QuestMapSection
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | ReactNode | — | 放入 QuestNode 子元件,每個為一個關卡站點 |
container | RefObject<HTMLElement | null> | — | 巢狀捲動容器的 ref;預設以視窗為捲動容器 |
offset | [string, string] | ["start 0.85", "end 0.55"] | useScroll 進度對應區間,決定標記何時開始/結束前進 |
aria-label | string | "關卡地圖" | 套用在清單容器上的無障礙標籤 |
className | string | — | 外層樣式;傳入 text-* 可設定強調色 |
QuestNode
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
title | ReactNode | — | 站點標題 |
children | ReactNode | — | 站點內容說明 |
icon | ReactNode | — | 標題前的圖示(建議傳入 lucide-react 圖示) |
flag | ReactNode | — | 抵達時升起的旗幟上顯示的短標籤 |
id | string | — | 套用在卡片上的錨點 id |
className | string | — | 套用在整列站點外層的 class |
細節
- 站點依索引自動左右交錯,路徑以相鄰節點的垂直控制點串成平滑 S 形,量測採實際 DOM 座標,內容高度不一也能貼合。
- 進度軌採
pathLength={1}正規化,strokeDashoffset隨捲動由 1 收到 0,讓填色恰好停在標記位置。 - 節點座標與尺寸以
ResizeObserver監看,字體載入或容器縮放後會自動重算路徑。
可及性
- 使用者系統開啟「減少動態效果」時,所有站點直接呈現為已完成、路徑填滿、標記隱藏,不播放行進與蓋章動畫。
- 容器為
role="list"、各站點為role="listitem",並帶data-complete與朗讀用的「(已完成)/(未解鎖)」狀態文字。 - 路徑 SVG 與行進標記皆
aria-hidden,不干擾輔助科技朗讀站點內容。