- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Auth Surface
- Avatar
- Badge
- Browse Catalog Dialog
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Command
- Connector Setup Dialog
- Cookie Banner
- Dialog
- Directory Card
- Directory Detail
- Directory Skeleton
- DrawerНовое
- Token Parts Input
- Empty
- Field
- Fieldset
- File Preview Modal
- File Preview Skeleton
- Form
- Frame
- Group
- Icon
- Input
- Input Group
- Kbd
- Label
- Legal Shell
- Menu
- Mermaid Diagram
- Mind Map Diagram
- Not Found Screen
- Onboarding Frame
- Popover
- PDF Thumbnail
- Personalization Landing
- Preview Card
- Pricing Page
- Progress
- Radio Group
- Ring Spinner
- Scroll Area
- Select
- Separator
- Settings Page
- Settings Skills
- Settings Connectors
- Settings Capabilities
- Settings Usage
- Settings Account
- Settings Billing
- Sheet
- Sidebar
- Skeleton
- Skill Create Dialog
- Slider
- Spinner
- Stat
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Tooltip
- Компоненты AI
- Chat Conversation
- Chat Message
- Chat Response
- Chat Suggestion
- Chat Prompt Input
- Slash Highlighted Textarea
- Chat Search Dialog
- Chat Skill Doc
- Chat Connector Detail
- Chat Attachments
- Chat File Card
- Chat Token Chip
- Chat Code Block
- Chat Image
- Chat Inline Citation
- Chat Sources
- Chat Web Search
- Chat Research
- Chat Source
- Chat Actions
- Chat Context
- Chat Loader
- Chat Compaction
- Chat Timeline
- Chat Snippet
- Chat Terminal
- Chat Stack Trace
- Chat Test Results
- Chat File Tree
- Chat Environment Variables
- Chat Audio Player
- Chat Transcription
- Chat Speech Input
- Chat Mic Selector
- Chat Voice Selector
- Chat Agent
- Chat Persona
- Chat Connection
- Chat Connector Suggestion
- Chat Queue
- Chat Checkpoint
- Chat Confirmation
- Chat Artifact
- Chat JSX Preview
- Chat Schema Display
- Chat Package Info
- Chat Commit
- Chat Plan
- Chat Open In Chat
- Chat Sandbox
- Chat Model Selector
- Chat Canvas
- Chat Node
- Chat Edge
Chat Timeline
Сворачиваемый таймлайн выполнения агента в стиле Claude — рельс с шагами, узлы-мысли, действия с прогрессом и терминальный шаг «Done».
Пользователю нужен самый быстрый вариант, поэтому перед ответом стоит сравнить опубликованные бенчмарки.
"use client";
import { IconBook, IconClock, IconWorld } from "@tabler/icons-react";
import {
ChatTimeline,
ChatTimelineAction,
ChatTimelineActionTitle,
ChatTimelineContent,
ChatTimelineDone,
ChatTimelineReasoning,
ChatTimelineStep,
ChatTimelineTrigger,
} from "@/components/ui/chat-timeline";
import { ChatWebSearch } from "@/components/ui/chat-web-search";
export default function Particle() {
return (
<div className="w-full max-w-2xl p-4">
<ChatTimeline defaultOpen>
<ChatTimelineTrigger>Прочитано 2 страницы</ChatTimelineTrigger>
<ChatTimelineContent>
<ChatTimelineStep icon={IconClock} status="done">
<ChatTimelineReasoning>
Пользователю нужен **самый быстрый** вариант, поэтому перед
ответом стоит сравнить опубликованные бенчмарки.
</ChatTimelineReasoning>
</ChatTimelineStep>
<ChatTimelineStep icon={IconWorld} status="done">
<ChatWebSearch
query="бенчмарк самой быстрой open-source векторной базы данных"
results={[
{
domain: "github.com",
title: "Qdrant — высокопроизводительный векторный поиск",
url: "https://github.com/qdrant/qdrant",
},
{
domain: "ann-benchmarks.com",
title: "ANN Benchmarks — полнота против запросов/сек",
url: "https://ann-benchmarks.com",
},
]}
status="complete"
variant="timeline"
/>
</ChatTimelineStep>
<ChatTimelineStep icon={IconBook} status="done">
<ChatTimelineAction>
<ChatTimelineActionTitle>
Прочитано 2 страницы
</ChatTimelineActionTitle>
</ChatTimelineAction>
</ChatTimelineStep>
<ChatTimelineDone />
</ChatTimelineContent>
</ChatTimeline>
</div>
);
}
Установка
pnpm dlx shadcn@latest add @oracul/chat-timeline
Использование
import { BookOpenIcon, ClockIcon, GlobeIcon } from "lucide-react";
import {
ChatTimeline,
ChatTimelineAction,
ChatTimelineActionTitle,
ChatTimelineContent,
ChatTimelineDone,
ChatTimelineReasoning,
ChatTimelineStep,
ChatTimelineTrigger,
} from "@/components/ui/chat-timeline";
<ChatTimeline defaultOpen>
<ChatTimelineTrigger>Read 2 pages</ChatTimelineTrigger>
<ChatTimelineContent>
<ChatTimelineStep icon={ClockIcon} status="done">
<ChatTimelineReasoning>
Comparing published benchmarks before answering.
</ChatTimelineReasoning>
</ChatTimelineStep>
<ChatTimelineStep icon={GlobeIcon} status="done">
<ChatTimelineAction>
<ChatTimelineActionTitle>Searched the web</ChatTimelineActionTitle>
</ChatTimelineAction>
</ChatTimelineStep>
<ChatTimelineStep icon={BookOpenIcon} iconSize="md" status="done">
<ChatTimelineAction>
<ChatTimelineActionTitle>Read 2 pages</ChatTimelineActionTitle>
</ChatTimelineAction>
</ChatTimelineStep>
<ChatTimelineDone />
</ChatTimelineContent>
</ChatTimeline>Открыта во время прогона, свёрнута по завершении
Таймлайн — это тонкий Collapsible: открытие и сворачивание лежат на стороне
вызывающего кода. Держите его открытым, пока прогон активен, а по завершении
сворачивайте в строку-итог (как в Claude). error — терминальный статус, но он
не должен держать таймлайн открытым.
const [open, setOpen] = useState(isRunning);
useEffect(() => {
setOpen(isRunning);
}, [isRunning]);
<ChatTimeline onOpenChange={setOpen} open={open}>
<ChatTimelineTrigger loading={isRunning}>
{isRunning ? "Indexing files" : "Read 2 pages"}
</ChatTimelineTrigger>
{/* … */}
</ChatTimeline>;Живой / потоковый шаг
Для активного шага передайте status="running" (вращающийся загрузчик), а в
заголовок — loading для shimmer-эффекта. Шаги-действия могут нести под-строку с
деталями и прогресс-бар.
import { FileTextIcon } from "lucide-react";
import {
ChatTimelineAction,
ChatTimelineActionDetail,
ChatTimelineActionTitle,
ChatTimelineProgress,
ChatTimelineStep,
} from "@/components/ui/chat-timeline";
<ChatTimelineStep icon={FileTextIcon} status="running">
<ChatTimelineAction>
<ChatTimelineActionTitle loading>Indexing files</ChatTimelineActionTitle>
<ChatTimelineActionDetail>apps/ui/registry/default/ui</ChatTimelineActionDetail>
<ChatTimelineProgress value={62} />
</ChatTimelineAction>
</ChatTimelineStep>;Слотовые карточки поиска / загрузки
Поверхности поиска и загрузки передаются как children шага (используйте вариант
timeline) — таймлайн остаётся развязанным и не несёт от них зависимости.
import { GlobeIcon } from "lucide-react";
import { ChatWebSearch } from "@/components/ui/chat-web-search";
import { ChatTimelineStep } from "@/components/ui/chat-timeline";
<ChatTimelineStep icon={GlobeIcon} status="done">
<ChatWebSearch
query="fastest open-source vector database"
results={results}
status="complete"
variant="timeline"
/>
</ChatTimelineStep>;Группы загрузок
Группировка последовательных чтений в один узел «Read N pages» лежит на стороне
вызывающего кода — отрендерьте один шаг с BookOpenIcon и iconSize="md".
<ChatTimelineStep icon={BookOpenIcon} iconSize="md" status="done">
<ChatTimelineAction>
<ChatTimelineActionTitle>Read 4 pages</ChatTimelineActionTitle>
</ChatTimelineAction>
</ChatTimelineStep>Research-fallback (цепочка только из рассуждений)
Когда событий инструментов нет, отрендерьте цепочку узлов-мыслей, соединённых
рельсом — ClockIcon с iconSize="md", а в summary подставьте краткое описание
размышлений.
<ChatTimeline defaultOpen>
<ChatTimelineTrigger>Spotted a pattern…</ChatTimelineTrigger>
<ChatTimelineContent>
{segments.map((segment, index) => (
<ChatTimelineStep
icon={ClockIcon}
iconSize="md"
key={index}
last={index === segments.length - 1}
status="done"
>
<ChatTimelineReasoning>{segment}</ChatTimelineReasoning>
</ChatTimelineStep>
))}
</ChatTimelineContent>
</ChatTimeline>Состояния
Лента с активным прогоном: trigger в режиме loading, done-узел-мысль,
текущий шаг running (спиннер + shimmer-заголовок + под-строка и прогресс-бар)
и ещё не начатый шаг pending.
Перед ответом я просканирую репозиторий и построю индекс символов.
"use client";
import { IconClock, IconFileText } from "@tabler/icons-react";
import {
ChatTimeline,
ChatTimelineAction,
ChatTimelineActionDetail,
ChatTimelineActionTitle,
ChatTimelineContent,
ChatTimelineProgress,
ChatTimelineReasoning,
ChatTimelineStep,
ChatTimelineTrigger,
} from "@/components/ui/chat-timeline";
export default function Particle() {
return (
<div className="w-full max-w-2xl p-4">
<ChatTimeline defaultOpen>
<ChatTimelineTrigger loading>Индексирование файлов</ChatTimelineTrigger>
<ChatTimelineContent>
<ChatTimelineStep icon={IconClock} status="done">
<ChatTimelineReasoning>
Перед ответом я просканирую репозиторий и построю индекс символов.
</ChatTimelineReasoning>
</ChatTimelineStep>
<ChatTimelineStep icon={IconFileText} status="running">
<ChatTimelineAction>
<ChatTimelineActionTitle loading>
Индексирование файлов
</ChatTimelineActionTitle>
<ChatTimelineActionDetail>
apps/ui/registry/default/ui
</ChatTimelineActionDetail>
<ChatTimelineProgress value={62} />
</ChatTimelineAction>
</ChatTimelineStep>
<ChatTimelineStep last status="pending">
<ChatTimelineAction>
<ChatTimelineActionTitle>
Сводка соглашений
</ChatTimelineActionTitle>
</ChatTimelineAction>
</ChatTimelineStep>
</ChatTimelineContent>
</ChatTimeline>
</div>
);
}
Терминальная лента со сбоем: глиф skill (ScrollIcon), шаг error
(text-destructive + под-строка), глиф файла (FileTextIcon) и строка-итог
«Done».
"use client";
import { IconBook, IconFileText, IconScript } from "@tabler/icons-react";
import {
ChatTimeline,
ChatTimelineAction,
ChatTimelineActionDetail,
ChatTimelineActionTitle,
ChatTimelineContent,
ChatTimelineDone,
ChatTimelineStep,
ChatTimelineTrigger,
} from "@/components/ui/chat-timeline";
export default function Particle() {
return (
<div className="w-full max-w-2xl p-4">
<ChatTimeline defaultOpen>
<ChatTimelineTrigger>Создан report.md</ChatTimelineTrigger>
<ChatTimelineContent>
<ChatTimelineStep icon={IconScript} status="done">
<ChatTimelineAction>
<ChatTimelineActionTitle>
Запущен навык: summarize-pdf
</ChatTimelineActionTitle>
</ChatTimelineAction>
</ChatTimelineStep>
<ChatTimelineStep icon={IconBook} status="error">
<ChatTimelineAction>
<ChatTimelineActionTitle>
Не удалось открыть paywalled.example.com
</ChatTimelineActionTitle>
<ChatTimelineActionDetail>HTTP 403</ChatTimelineActionDetail>
</ChatTimelineAction>
</ChatTimelineStep>
<ChatTimelineStep icon={IconFileText} status="done">
<ChatTimelineAction>
<ChatTimelineActionTitle>
Создан report.md
</ChatTimelineActionTitle>
</ChatTimelineAction>
</ChatTimelineStep>
<ChatTimelineDone />
</ChatTimelineContent>
</ChatTimeline>
</div>
);
}
| Состояние | Где | Как выглядит |
|---|---|---|
status="pending" | шаг ещё не начался | CircleIcon text-muted-foreground |
status="running" / "active" | текущий шаг | LoaderCircleIcon animate-spin; заголовок — shimmer через loading |
status="done" | завершён | CheckCircleIcon text-muted-foreground (приглушённый, НЕ ярко-зелёный) |
status="error" | сбой; терминальный | CircleIcon text-destructive; ленту открытой НЕ держит |
| открыт / раскрыт | open / defaultOpen | рельс виден, шеврон rotate-90 |
| свёрнут | по завершении | одна строка-итог, шеврон в покое |
trigger loading | строковый label | summary — текущее действие через ChatLoader (duration~1) |
| trigger idle | свёрнутая лента | последнее действие / thinking-summary / fallback |
| reasoning-узел | <ChatTimelineReasoning> | markdown через Streamdown, text-foreground/75 14px/1.4 |
| search-шаг | <ChatWebSearch variant="timeline"> в children | слот-карточка поиска внутри ряда |
| single fetch | icon={BookOpenIcon} | книга 16px |
| fetch-group ≥2 | icon={BookOpenIcon} iconSize="md" | книга 20px, «Read N pages» |
| skill / file | ScrollIcon / FileTextIcon | свиток / файл |
| detail | <ChatTimelineActionDetail> | под-строка 13px muted-foreground/80 |
| progress | <ChatTimelineProgress value> | бар max-w-44 + NN% 11px tabular-nums |
| рельс есть | ряд не последний | линия bg-foreground/15 под иконкой |
| рельс отсутствует | last / терминал | хвоста рельса нет |
| done-строка | <ChatTimelineDone> | терминальный CheckCircle + «Done», без рельса |
| research-fallback | events пусты | цепочка ClockIcon 20px, соединённая рельсом |
| focus-visible | Tab на триггере | кольцо фокуса от CollapsibleTrigger |
API
| Компонент | Описание |
|---|---|
ChatTimeline | Корень-Collapsible; open / defaultOpen / onOpenChange. Ширина max-w-[min(100%,40rem)]. |
ChatTimelineTrigger | Свёрнутая строка-итог + шеврон; loading оборачивает строковый label в ChatLoader. |
ChatTimelineContent | Раскрываемое тело — вертикальная лента шагов. |
ChatTimelineStep | Ряд-рельс: status, icon, iconSize (sm/md), last. Рендерит иконку, рельс и контент. |
ChatTimelineStepIcon | Глиф шага; icon, status, size. Статусный фоллбэк → Circle / LoaderCircle / CheckCircle. |
ChatTimelineRail | Вертикальный коннектор bg-foreground/15 (рендерится внутри Step; экспортирован для кастомных рядов). |
ChatTimelineReasoning | Узел-мысль: markdown через Streamdown, text-foreground/75. |
ChatTimelineAction | Обёртка тела действия. |
ChatTimelineActionTitle | Заголовок действия; loading — shimmer. |
ChatTimelineActionDetail | Под-строка 13px muted-foreground/80. |
ChatTimelineProgress | Прогресс-бар + проценты; value (0–100), label. |
ChatTimelineDone | Терминальный ряд «Done» (по умолчанию), без рельса. |