Page Timeline
retab-ui/page-timelineFreeComponent
A colored page strip that ties a Segment[] to the document; hover/select syncing and click-to-jump.
Install it
npx shadcn@latest add https://ui.retab.com/r/page-timeline.jsonSource
1"use client";23import * as React from "react";45import {6 getSegmentInteractionState,7 getSegmentSurfaceProps,8 scopeSegmentInteraction,9 type SegmentInteraction,10} from "@/lib/segment-interaction";11import {12 normalizePageCount,13 segmentDisplayLabel,14 segmentsPageCount,15 type Segment,16} from "@/lib/segments";17import { cn } from "@/lib/utils";1819export interface PageTimelineProps {20 segments: Segment[];21 /** Total pages; defaults to the max page across segments. */22 pageCount?: number;23 /** Shared preview state. */24 interaction?: SegmentInteraction;25 /** 1-based current page to mark (e.g. synced to a PDF scroll position). */26 currentPage?: number | null;27 /** Fired when a page cell is clicked. */28 onSelectPage?: (page: number) => void;29 /** Fired when a segment-owned page cell is clicked. */30 onSelect?: (segment: Segment) => void;31 className?: string;32}3334interface TimelinePageSegment {35 segmentIndexes: number[];36 primarySegment?: Segment;37 label: string;38}3940/**41 * A horizontal strip of page cells colored by the segment mapped to each page.42 * It ties the legend and sidebar to the document: hovering a cell previews its43 * segment, previewing a segment elsewhere dims unrelated pages, and clicking44 * a cell jumps the document. If multiple segments map to a page, the first45 * segment in document order owns the preview state and the page label calls out46 * the overlap.47 */48export function PageTimeline({49 segments,50 pageCount,51 interaction,52 currentPage,53 onSelectPage,54 onSelect,55 className,56}: PageTimelineProps) {57 const total = normalizePageCount(pageCount ?? segmentsPageCount(segments));58 const segmentIndexesByPage = React.useMemo(59 () => buildPageSegmentIndexes(segments),60 [segments],61 );62 const segmentByIndex = React.useMemo(63 () => buildSegmentByIndex(segments),64 [segments],65 );66 const segmentIndexById = React.useMemo(67 () => buildSegmentIndexById(segments),68 [segments],69 );70 const visibleSegments = React.useMemo(71 () =>72 segments.filter((segment) =>73 segment.pages.some(74 (page) => Number.isInteger(page) && page >= 1 && page <= total,75 ),76 ),77 [segments, total],78 );79 const scopedInteraction = React.useMemo(80 () =>81 scopeSegmentInteraction(82 interaction,83 visibleSegments.map((segment) => segment.id),84 ),85 [interaction, visibleSegments],86 );87 const interactionState = React.useMemo(88 () =>89 getSegmentInteractionState({90// … truncated
What it pulls in
Other registry items
Files it writes
More from retab-ui
All 130 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Alertalert | retab-ui | Components | Free | 1 dep | |
| Alert Dialogalert-dialog | retab-ui | Components | Free | 1 dep | |
| Aspect Ratioaspect-ratio | retab-ui | Components | Free | no deps | |
| Attachment Sidebarattachment-sidebar | retab-ui | Components | Free | 1 dep | |
| Autocompleteautocomplete | retab-ui | Components | Free | 2 deps | |
| Calendarcalendar | retab-ui | Components | Free | 2 deps | |
| Code Viewercode-viewer | retab-ui | Components | Free | 2 deps · 32 files | |
| Commandcommand | retab-ui | Components | Free | 2 deps |
