Synced Outline Reader
內容+大綱雙欄閱讀版面:指示脊椎隨閱讀位置連續伸縮滑動,當前章節同步聚焦。
載入預覽⋯
安裝
npx shadcn@latest add https://webberui.com/r/synced-outline-reader.json安裝依賴後,從 registry JSON(/r/synced-outline-reader.json 的 files[0].content)複製 synced-outline-reader.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
sections 定義大綱清單,內容以 OutlineSection 包裹、id 一一對應:
import {
SyncedOutlineReader,
OutlineSection,
} from "@/components/ui/synced-outline-reader";
const sections = [
{ id: "intro", title: "簡介" },
{ id: "usage", title: "使用方式" },
{ id: "faq", title: "常見問題" },
];
<SyncedOutlineReader sections={sections}>
<OutlineSection id="intro" title="簡介">
<p>第一章內文……</p>
</OutlineSection>
<OutlineSection id="usage" title="使用方式">
<p>第二章內文……</p>
</OutlineSection>
<OutlineSection id="faq" title="常見問題">
<p>第三章內文……</p>
</OutlineSection>
</SyncedOutlineReader>滾動發生在巢狀 overflow 容器內時,把該容器的 ref 傳給 container:
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[400px] overflow-y-auto">
<SyncedOutlineReader sections={sections} container={scrollerRef}>
{/* ... */}
</SyncedOutlineReader>
</div>Props
SyncedOutlineReader
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
sections | { id: string; title: string }[] | — | 大綱欄的章節清單,順序需與內容中的 OutlineSection 一致 |
children | ReactNode | — | 直接放入 OutlineSection 子元件 |
container | RefObject<HTMLElement> | — | 滾動發生在巢狀 overflow 容器內時,傳入該容器的 ref |
outlineLabel | string | "內容大綱" | 大綱欄 <nav> 的無障礙標籤 |
className | string | — | 附加到雙欄外層容器的 class |
OutlineSection
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | string | — | 章節錨點 id,需對應 sections 陣列中的同名項目 |
title | ReactNode | — | 章節標題,渲染為 <h2> |
children | ReactNode | — | 章節內文 |
className | string | — | 附加到章節 <section> 的 class |
細節
- 指示脊椎不是傳統 scroll-spy 的跳格切換:以
IntersectionObserver(root為捲動容器)追蹤各章節的可見比例,換算成大綱項上的覆蓋範圍,再用useSpring驅動top與height,在大綱項之間連續伸縮滑動 - 當前章節(可見比例最高者)內文 opacity 為 1,其餘章節降至 0.6,閱讀焦點隨滾動同步轉移
- 大綱項是真正的
<button>,點擊平滑捲動到對應章節,並以aria-current="location"標示當前位置 - 窄螢幕大綱欄整欄隱藏,
md斷點以上才顯示雙欄;內容欄不受影響 - 使用者系統開啟「減少動態效果」時,脊椎直接跳到目標位置(不經彈簧)、聚焦切換不再過渡、點擊大綱改為即時捲動,版面完全不變