Activity Feed
自動插入項目的動態列表,新事件由上而下推入、既有列以 FLIP 平滑重排,支援時間軸與相對時間。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
5
1200
<ActivityFeed />
安裝
npx shadcn@latest add https://webberui.com/r/activity-feed.json或在 components.json 設定 registries 後,改用 @webberui/activity-feed 安裝。
安裝依賴後,從 registry JSON(/r/activity-feed.json 的 files[0].content)複製 activity-feed.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
items 以時間先後(舊 → 新)排列,持續往陣列尾端 push 新事件即可;元件依 id 做動畫配對,新項目進場、既有項目自動重排。
import { ActivityFeed, type ActivityFeedItem } from "@/components/ui/activity-feed";
const items: ActivityFeedItem[] = [
{ id: "1", title: "系統啟動", timestamp: Date.now(), accent: "green" },
{ id: "2", title: "使用者登入", description: "來自 台北", timestamp: Date.now() },
];
<ActivityFeed items={items} max={8} />款式
透過 variant 切換三款版面:default(卡片列)、timeline(左側時間軸連接線)、compact(精簡單行)。
<ActivityFeed items={items} variant="timeline" />Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
items | ActivityFeedItem[] | — | 依時間先後(舊 → 新)排列的事件 |
variant | "default" | "timeline" | "compact" | "default" | 版面款式 |
insertAt | "top" | "bottom" | "top" | 新事件插入的視覺位置 |
max | number | — | 最多顯示筆數;超過時保留最新者,較舊者淡出移除 |
relativeTime | boolean | true | 以相對時間顯示(如「3 分鐘前」),關閉時顯示 HH:MM |
locale | string | — | 時間格式化的地區設定(BCP 47) |
highlightDuration | number | 1200 | 新進項目背景閃動時長(毫秒),0 停用 |
emptyState | React.ReactNode | — | 清單為空時顯示的內容 |
label | string | "動態消息" | 清單的無障礙標籤 |
className | string | — | 附加到 <ol> 容器的 class |
ActivityFeedItem
| 欄位 | 型別 | 說明 |
|---|---|---|
id | string | 穩定唯一識別碼,動畫據此配對前後狀態 |
title | React.ReactNode | 主要內容(一行標題) |
description | React.ReactNode | 次要說明(compact 款式省略) |
icon | React.ReactNode | 左側圖示;未提供時顯示強調色小圓點 |
meta | React.ReactNode | 附掛內容,顯示於說明下方(compact 款式省略) |
timestamp | Date | number | string | 事件時間;提供時顯示於右上角 |
accent | "neutral" | "blue" | "green" | "amber" | "red" | "violet" | 強調色 |
細節
- 資料驅動:清單完全由
items控制(受控模式)。元件不持有內部項目狀態,你只需維護一份陣列並往尾端 push,插入、移除、重排都會自動產生動畫。 - 進場與重排:新項目以透明度 + 位移 + 微縮放進場,既有列透過 Motion 的
layout(FLIP)以 spring 平滑讓位;超過max的最舊項目淡出退場。 - 相對時間:開啟
relativeTime時,時間每 30 秒自動刷新;計時器在無時間戳或元件卸載時清理。時間戳依Date.now()計算,故時間節點以suppressHydrationWarning容許 SSR 與客戶端差異。
可及性
- 容器帶
role="log"與aria-live="polite"aria-relevant="additions",新插入的項目會被螢幕閱讀器朗讀,初始批次則不會重複播報。 - 純裝飾的圖示、閃動與連接線皆標記
aria-hidden;時間以語意化<time dateTime>呈現,並帶完整時間的title。 - 使用者系統開啟「減少動態效果」時,停用 FLIP 重排與位移縮放,僅保留最低限度的透明度淡入,退場與插入不再位移。