WebberUI

Interview Spread

雜誌訪談版式:問句窄欄粗體靠左、答句寬欄襯線靠右交錯落版,超大引號錨定,捲動時邊欄發言者標記沿軌道滑動、問答依序浮現。

載入預覽⋯

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

56
<InterviewSpread />

安裝

npx shadcn@latest add https://webberui.com/r/interview-spread.json

或在 components.json 設定 registries 後,改用 @webberui/interview-spread 安裝。

安裝依賴後,從 registry JSON(/r/interview-spread.jsonfiles[0].content)複製 interview-spread.tsx 原始碼到你的 components/ui/ 目錄:

npm install motion clsx tailwind-merge

使用

import {
  InterviewSpread,
  InterviewTurn,
} from "@/components/ui/interview-spread";

<InterviewSpread interviewer="編輯" interviewee="設計師">
  <InterviewTurn role="question">你如何看待動畫在介面裡的角色?</InterviewTurn>
  <InterviewTurn role="answer">動畫不是裝飾,而是敘事。</InterviewTurn>
  <InterviewTurn role="question">那節奏呢?</InterviewTurn>
  <InterviewTurn role="answer">節奏就是一切,我把每條緩動曲線都當成呼吸。</InterviewTurn>
</InterviewSpread>;

若訪談置於自訂的捲動容器內(例如彈窗、側欄),把容器 ref 傳給 container,邊欄標記與進場偵測便會以該容器為捲動基準:

const scrollRef = React.useRef<HTMLDivElement>(null);

<div ref={scrollRef} className="h-[300px] overflow-y-auto">
  <InterviewSpread container={scrollRef}>{/* … */}</InterviewSpread>
</div>;

Props

InterviewSpread

Prop型別預設值說明
childrenReactNode放入 InterviewTurn 子元件,依序落版
interviewerstring"問"訪談者稱謂(問句預設發言者)
intervieweestring"答"受訪者稱謂(答句預設發言者)
railbooleantrue是否顯示左側發言者邊欄標記
railWidthnumber56邊欄寬度(px)
containerRefObject<HTMLElement | null>巢狀 overflow 捲動容器 ref;預設以視窗為捲動容器
oncebooleantrue只在第一次進入視口時播放進場
aria-labelstring"訪談"版面的無障礙標籤

InterviewTurn

Prop型別預設值說明
role"question" | "answer""answer"問句窄欄粗體靠左、答句寬欄襯線靠右
speakerstring覆寫此段發言者稱謂;預設沿用容器設定
quoteMarkboolean答句 true是否顯示超大引號錨定版面
childrenReactNode發言內容

細節

  • 問句採無襯線粗體、答句採襯線體,兩者以窄/寬欄左右交錯,形成雜誌訪談的落版節奏。
  • 每段答句左上角以超大引號錨定版面(quoteMark,可關閉)。
  • 捲動時左側邊欄標記沿軌道滑動:位置隨捲動進度移動,並以 IntersectionObserver 偵測閱讀線帶狀區內的段落,切換標記顏色與發言者簡稱。
  • 段落以 whileInView 依序浮現,問句自左、答句自右輕移淡入。

可及性

  • 邊欄標記為純裝飾(aria-hidden),發言者資訊同時以文字標籤呈現於各段開頭。
  • 答句使用 blockquote 語意標記;閱讀順序即為問答的自然順序。
  • 版面容器帶 role="group"aria-label(預設「訪談」,可覆寫)。
  • 使用者系統開啟「減少動態效果」時,停用進場與邊欄滑動動畫,直接呈現完整靜態版面。
  • 邊欄標記位置量測與捲動監看在卸載時皆清理 ResizeObserverIntersectionObserver 與事件監聽。

On this page