Case Study Dossier
卷宗式案例研究版面:左側 sticky 指標欄隨長文滾動逐一點亮並計數,全幅引言定期打斷雙欄節奏形成呼吸感。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
24
<CaseStudyDossier />
安裝
npx shadcn@latest add https://webberui.com/r/case-study-dossier.json或在 components.json 設定 registries 後,改用 @webberui/case-study-dossier 安裝。
安裝依賴後,從 registry JSON(/r/case-study-dossier.json 的 files[0].content)複製 case-study-dossier.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
由 CaseStudyDossier 包住若干 DossierSection,每節可綁定一個 metric;
DossierQuote 為打斷雙欄節奏的全幅引言。左側指標欄由各章節的 metric
自動生成,捲動到對應章節時該指標點亮並由 0 滾動計數。
import {
CaseStudyDossier,
DossierSection,
DossierQuote,
} from "@/components/ui/case-study-dossier";
<CaseStudyDossier eyebrow="案例研究" title="Northwind 導入成效">
<DossierSection
id="roi"
eyebrow="財務影響"
title="投資報酬率"
metric={{ label: "投資報酬率", value: 320, suffix: "%" }}
accentClassName="text-emerald-600 dark:text-emerald-400"
>
<p>以十二個月為期計算,平台帶來的節省合計達初始投入的 3.2 倍。</p>
</DossierSection>
<DossierQuote cite="Ada Lin,營運長">
資料在早餐前就已經到位,團隊得以把時間投回真正的決策。
</DossierQuote>
<DossierSection
id="retention"
title="淨收入留存率"
metric={{ label: "淨收入留存", value: 118, suffix: "%" }}
>
<p>更快的服務回應與更精準的續約提醒,讓留存率提升至 118%。</p>
</DossierSection>
</CaseStudyDossier>若版面置於巢狀捲動容器(overflow-y-auto)內,將容器的 ref 傳給
container,並視情況把 stickyTop 調小:
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[420px] overflow-y-auto">
<CaseStudyDossier container={scrollerRef} stickyTop={8}>
{/* … */}
</CaseStudyDossier>
</div>Props
CaseStudyDossier
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | React.ReactNode | — | 放入 DossierSection 與 DossierQuote |
container | RefObject<HTMLElement | null> | — | 巢狀捲動容器的 ref;預設以視窗為捲動容器 |
eyebrow | React.ReactNode | — | 指標欄頂端小標 |
title | React.ReactNode | — | 指標欄標題 |
label | string | "案例指標" | 指標欄 <aside> 的無障礙標籤 |
stickyTop | number | 24 | sticky 指標欄距捲動容器頂端的偏移(px) |
DossierSection
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | string | — | 章節錨點 id,指標點擊與觀察器以此對應 |
title | string | — | 章節標題 |
eyebrow | React.ReactNode | — | 標題上方分類小標 |
metric | DossierMetric | — | 綁定此章節的指標數字 |
accentClassName | string | — | 指標為當前章節時,數字的強調文字色 class |
DossierMetric
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
label | string | — | 指標說明 |
value | number | — | 目標數值,由 0 滾動計數至此 |
prefix | string | "" | 數字前綴,如 "$" |
suffix | string | "" | 數字後綴,如 "%"、"×" |
decimals | number | 0 | 小數位數 |
DossierQuote
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | React.ReactNode | — | 引言內容 |
cite | React.ReactNode | — | 引言出處 |
細節
- 指標欄以
IntersectionObserver取各章節可見比例,最高者為「當前章節」; 當前及其之前的指標視為已抵達(點亮)。 - 每個指標以
MotionValue逐格更新計數,不觸發 React re-render;首次抵達 該章節時由 0 計數至目標值。 - 全幅引言(
DossierQuote)在寬容器下以負邊距回收左側指標欄空間,橫跨整個 版面以打斷雙欄節奏。 - 左側指標欄使用
@container查詢,窄容器(< 34rem)時收合,並改由各章節 就地顯示其指標。
可及性
- 指標欄為
<aside>並帶無障礙標籤;每個指標為可聚焦按鈕,點擊平滑捲動至 對應章節,aria-label完整朗讀「章節,指標 值」。 - 計數中的動畫數字對輔助科技隱藏(
aria-hidden),朗讀時為最終值。 - 當前章節與其對應指標標記
aria-current。 - 使用者系統開啟「減少動態效果」時,數字直接顯示最終值不做計數,引言與 內文的浮出動畫停用,指標點亮改為即時切換。