WebberUI

Agenda Tracks Grid

時間 × 軌道的會議議程網格:時間軸欄凍結於左側,切換軌道或講者篩選時場次卡以 FLIP 重排補位,點擊場次原位展開講者與摘要。

載入預覽⋯

Playground

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

240
68
152
<AgendaTracksGrid />

安裝

npx shadcn@latest add https://webberui.com/r/agenda-tracks-grid.json

或在 components.json 設定 registries 後,改用 @webberui/agenda-tracks-grid 安裝。

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

npm install motion lucide-react clsx tailwind-merge

使用

軌道以 tracks 傳入(決定欄),場次以 sessions 傳入。每個 trackIdstart 的交會至多對應一場。工具列的軌道開關與講者篩選由元件內建管理,也可透過受控 props 由外部主導。

import {
  AgendaTracksGrid,
  type AgendaTrack,
  type AgendaSession,
} from "@/components/ui/agenda-tracks-grid";

const tracks: AgendaTrack[] = [
  { id: "keynote", label: "主舞台" },
  { id: "workshop", label: "工作坊" },
];

const sessions: AgendaSession[] = [
  {
    id: "s1",
    trackId: "keynote",
    start: "09:00",
    title: "開場:動畫優先的介面",
    speaker: "林安琪",
    summary: "從第一性原理談動效如何承載資訊層級。",
  },
  {
    id: "s2",
    trackId: "workshop",
    start: "09:00",
    title: "手把手:FLIP 補位實作",
    speaker: "周子軒",
    summary: "以 layout 動畫做出切換即補位的網格重排。",
  },
];

<AgendaTracksGrid tracks={tracks} sessions={sessions} defaultExpandedId="s1" />

Props

Prop型別預設值說明
tracksAgendaTrack[]軌道清單,決定欄的內容與由左至右順序
sessionsAgendaSession[]場次清單,每個 track + time 交會至多一場
timesstring[]時間列順序;省略時自動由場次彙整並字典序排序
activeTracksstring[]受控:目前顯示的軌道 id 陣列
defaultActiveTracksstring[]全部非受控初始顯示的軌道
onActiveTracksChange(ids: string[]) => void顯示軌道變更時觸發
speakerstring | null受控:講者篩選(null 代表全部)
defaultSpeakerstring | nullnull非受控初始講者篩選
onSpeakerChange(speaker: string | null) => void講者篩選變更時觸發
expandedIdstring | null受控:目前展開的場次 id
defaultExpandedIdstring | nullnull非受控初始展開的場次
onExpandedChange(id: string | null) => void展開場次變更時觸發
showControlsbooleantrue是否顯示內建的軌道/講者篩選工具列
maxHeightnumber360捲動容器最大高度(px)
timeColumnWidthnumber68時間軸欄寬度(px)
trackMinWidthnumber152每條軌道的最小欄寬(px),欄過多時觸發水平捲動
classNamestring附加到最外層容器的 class

AgendaTrack

欄位型別說明
idstring軌道唯一 id,對應 AgendaSession.trackId
labelstring軌道顯示名稱(欄首)

AgendaSession

欄位型別說明
idstring場次唯一 id
trackIdstring所屬軌道 id
startstring起始時間標籤,需對應某個時間列
titlestring場次標題
speakerstring講者姓名(供篩選與展開顯示)
summaryReact.ReactNode展開後顯示的摘要內容

動畫細節

  • 凍結表頭:時間軸欄以 sticky left 固定於左側,軌道欄首以 sticky top 固定於頂部,左上角落交會處疊在最上層;欄數超出容器寬度時水平捲動,時間軸欄始終可見。
  • FLIP 重排補位:切換軌道會移除整欄,或以講者篩選時自動收合沒有對應場次的軌道;離場的場次卡以 popLayout 凍結原位淡出,其餘卡片以 layout="position" 平滑補位,避免文字縮放變形。
  • 原位展開:點擊場次卡就地展開講者與摘要,該時間列高度隨之增長,下方列以相同 spring 推移補位;再次點擊或點其他卡片收合(單一展開)。
  • 講者篩選:非符合的場次卡淡出為停用狀態,仍保留時間對齊的脈絡。

可及性

  • 使用者系統開啟「減少動態效果」時,停用 FLIP、進退場與展開動畫,切換即定位;DOM 結構不變,掛載後才切換避免 hydration 落差
  • 網格採 role="grid" 搭配 aria-rowcount / aria-colcount,列與格分別標記 columnheaderrowheadergridcell 與對應索引
  • 軌道開關為 aria-pressed 切換鈕;講者篩選為 role="radiogroup" 單選;場次卡為帶 aria-expanded / aria-controls 的按鈕,展開內容以 role="region" 標記
  • 所有裝飾性圖示與佔位符皆標記 aria-hidden,可鍵盤聚焦並具 focus-visible 外框

On this page