Rank Shuffle Board
資料驅動的排名洗牌榜:分數更新時列以 FLIP 動畫互換位置、名次升降閃動箭頭,前三名帶金銀銅頒獎台語彙。
載入預覽⋯
安裝
npx shadcn@latest add https://webberui.com/r/rank-shuffle-board.json或在 components.json 設定 registries 後,改用 @webberui/rank-shuffle-board 安裝。
安裝依賴後,從 registry JSON(/r/rank-shuffle-board.json 的 files[0].content)複製 rank-shuffle-board.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
import { RankShuffleBoard } from "@/components/ui/rank-shuffle-board";
const entries = [
{ id: "amy", name: "Amy", score: 2480 },
{ id: "ben", name: "Ben", score: 2210 },
{ id: "cleo", name: "Cleo", score: 1975 },
];
<RankShuffleBoard entries={entries} unit="pt" />排序在元件內部完成——只要更新 entries 的分數,列就會自動以 FLIP 動畫換位。id 必須穩定(不要用陣列索引),FLIP 才能正確配對前後位置。
搭配頭像:
<RankShuffleBoard
unit="分"
entries={members.map((m) => ({
id: m.id,
name: m.name,
score: m.score,
avatar: <img src={m.avatarUrl} alt="" className="size-8 rounded-full" />,
}))}
/>Props
RankShuffleBoard
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
entries | RankShuffleEntry[] | — | 排行榜項目,元件內部依 score 由高到低穩定排序(同分保持原序) |
unit | string | — | 分數後的單位文字(例如 pt、分) |
className | string | — | 附加到最外層 <ol> 的 class |
RankShuffleEntry
| 欄位 | 型別 | 說明 |
|---|---|---|
id | string | 穩定唯一識別碼,FLIP 動畫據此配對列的前後位置 |
name | string | 顯示名稱 |
score | number | 分數,元件內部依此由高到低排序 |
avatar | React.ReactNode | 名稱左側的頭像(可選) |
細節
- FLIP 換位:列以 Motion
layout動畫(spring)連續滑到新名次,key 用穩定id配對前後位置,而非淡出重繪 - 升降箭頭:元件以 ref 記錄前一次名次,名次改變的列會短暫閃動箭頭(升 ↑ 綠 / 降 ↓ 紅),1.5 秒後由
AnimatePresence淡出;1.5 秒內再次變動會重置方向與倒數。箭頭放在固定寬度插槽中,出現/消失不會推擠分數 - 頒獎台語彙:前三名帶金(amber)/銀(slate)/銅(orange)左緣色帶,名次徽章放大並套用對應配色;第四名起為中性配色
- 分數 spring 補間:分數以 MotionValue 直接寫入 DOM(不觸發 React re-render),spring 過渡到新值,千分位逗號、捨入到整數顯示
- 穩定排序:以原始索引作 tiebreak,同分項目保持傳入順序,不會無故互換
可及性
- 使用者系統開啟「減少動態效果」時,FLIP 停用(列直接跳到新位置)、分數直接顯示最終值,箭頭不播淡入淡出(DOM 結構與 SSR 一致)
- 分數容器帶
aria-label(最終格式化值,含單位),補間中的動畫 span 對輔助科技隱藏(aria-hidden),螢幕閱讀器只會朗讀最終值 - 榜單為語意化的
<ol>有序清單;升降箭頭與色帶為裝飾性元素,皆標記aria-hidden