@timebraid/vue
@timebraid/vue
Vue 3 components for Timebraid, built only on @timebraid/tokens variables.
pnpm add @timebraid/vue @timebraid/tokens vue
<script setup lang="ts">
import { TBtn, TPill, TIcon } from '@timebraid/vue'
</script>
<template>
<TBtn size="xl" icon="download">Download for macOS</TBtn>
<TPill :running="[{ id: '1', task: 'Logo exploration', project: 'Acme rebrand', projectId: 'acme', color: 'var(--chart-1)', since: '9:12', seconds: 8047 }]" />
<TIcon name="play" :size="16" />
</template>
Import @timebraid/tokens/styles.css once in main.ts (or @timebraid/vue/style.css, which bundles the same tokens). Light is :root, dark is [data-theme="dark"], set by watchTheme. watchTheme(() => pref.value, root) returns { refresh, stop }; call refresh() whenever the preference changes and stop() on teardown.
Components
| Purpose | |
|---|---|
TGroup |
Grouped inset section: uppercase header, optional footer, card background |
TRow |
Inset list row: icon, title, subtitle, value, chevron; a leading slot for a swatch or a still before the title |
TConfirmRow |
A row that confirms a destructive action inside itself: the first tap turns the label into a question with Cancel and a filled verb; disarms after 6 s; compact is the 36px size, a control-height box whose armed state is the strip TTriage swaps in |
TConfirmButton |
A gray sm button that splits into Cancel and a filled red verb when tapped |
TSeg |
Segmented control with an animated thumb; an option's icon sits 14px before its label, iconOnly names each tab by its label instead of showing it, and height and radius take explicit pixels (the arm card's 44 and 13) |
TTriage |
A 36px segmented control for sorting an item (Stronghold's Keep · Archive · Discard) whose value can be null (no thumb), where clicking the selected option clears it and a confirm option (one or several, each with its question, verb and red or accent tone) first swaps the control in place for a compact TConfirmRow (Cancel, Escape, an outside change or 6 s restore it; only the verb emits) |
TBtn |
Button: primary, tinted, gray, plain, danger, destructive, white; four sizes; loading puts a spinner in the icon's place (or the label's) without changing the width, sets aria-busy and ignores clicks |
TIconBtn |
Round icon-only button; loading swaps the glyph for a spinner; the favourite toggle is this with star / star-filled and aria-pressed |
TToggle |
Switch control |
TField |
Filled text field |
TSelect |
Trailing-value select with chevrons-up-down, used inside TRow; name the control with label (rendered visually hidden) or ariaLabel |
TBadge |
Status pill: neutral, running, green, red, soon |
TKbd |
A keycap: "⌘K", "↵" or "esc" in mono on --fill inside a --sep-strong ring, 20px (md 24px); the palette's rows and foot use it |
TBanner |
Full-width bar for a standing notice such as "Signed in as Mia Okafor" while an admin acts as another person: an optional icon, a bold title with the text (or the default slot) under it, and a pill action on the right; inverse (the tooltip's --label and --bg pairing) by default or accent, compact for the phone sizes, card for a group's corners and shadow (--r-cell, --sh-card) when it sits inside the page |
TBar |
Animated value bar |
TBudgetBar |
A budget bar for Reports: used fills the track, the gap up to where the budget stands by now is tinted and marked, time past the budget runs red |
TGoalBar |
Today's goal bar: done fills a --fill track in green and the catch-up share of the target is hatched in orange at the right end until the goal is met |
TGoalStatus |
Today's goal status pill: "+19m catch-up" ("+19m" when short), Ahead or Done; nothing for none |
TAvatar |
Initials avatar; pass src for a photo instead |
TAvatarStack |
Overlapping TAvatars with a +N overflow count |
TLargeTitle |
Large collapsing page title; sticky pins it above its scrolling content |
TSheet |
Centred sheet on desktop, bottom sheet on phones, capped at the window height minus 48px (54px on phones) with the header and desktop footer pinned and the body scrolling; the phone header is a 1fr auto 1fr grid whose left spot is Cancel, the left slot, or nothing with cancelLabel null; a title slot renders in the header in place of the title text (the title prop stays the accessible name); on phones drag the grabber, the header or, at the top of its scroll, the content to dismiss - it follows the finger and closes or springs back by release direction |
TDot |
Status dot with a pulsing ring when running |
TDur |
Duration readout, mono and tabular |
TWaterfall |
Parallel-time waterfall timeline for reports, one lane per task grouped under its project; showWs adds a workspace tag per project |
TPill |
The floating always-visible timer pill: count first, the longest timer leads; the popover slot (scoped with running) replaces the popover body, grouped by workspace then project, and open is consumer-owned through update:open; with several timers its stop control opens the popover, where Stop all sits top right |
TWsIcon |
Workspace glyph: a coloured initial square, or the app mark when all |
TWsTag |
Small workspace label, the square plus its name; appears only in the All-workspaces scope |
TWorkspaceSwitcher |
Scope selector: All workspaces or one; actions adds rows such as Admin portal under the list, each closing the menu and emitting action with its id |
TWorkspaceMenu |
The workspace list shared by the switcher's popover and the drawer; embedded drops its shadow for inline use; actions sit between two hairlines above New workspace |
TWorkspaceDrawer |
Full-height phone workspace list; drag the panel to dismiss; actions pin above Add a workspace and emit action with the id, then close |
TTimerBar |
Phone bottom timer bar: takes the full timers array, count first with the longest leading; with several timers its stop control emits open for the running sheet instead of stopping them all |
TAuthBackdrop |
The sign-in stage from the app icon: brand field, oversized stopwatch dial, sweeping orange hand; the motif slot (scoped with size and delay) draws another product's picture in the dial's place on the same field |
TStrokes |
Oversized faded tally strokes behind sign-in and empty states |
TStartHero |
The pill-shaped start field that opens Today: "Start a timer" with "Quick start" chips on desktop when nothing runs, "Start another timer" with a "Runs in parallel" hint (chips kept) when hasRunning, the bare pill when mobile |
TIOSNav |
iOS nav bar under the status-bar inset (--inset-top); the leading control, the large title and the right actions share one line and the title collapses in place on scroll |
TIOSTabBar |
iOS tab bar |
TAndroidTop |
Android top app bar under the status-bar inset (--inset-top); sub for a subtitle, scrolled for its elevated state, title slot to replace the text |
TAndroidNavBar |
Android bottom navigation bar |
TIcon |
Bundled inline Lucide glyph, follows currentColor |
TLogo |
The stopwatch mark, correct artwork per size; mono paints it in currentColor |
TCodeInput |
6-digit code entry |
TAuthCard |
Sign-in layout card; brand and the mark slot (scoped with size) put another product's name and logo where Timebraid's sit |
TCheckbox |
Checkbox control |
TTooltip |
Hover tooltip |
TDaysTimeline |
Several days as bands on one shared am/pm hour axis (minutes from midnight), the day in a left gutter: parallel timers stack into lanes per day, each task in its taskSwatches colour (striped past seven), names inside wide bars, running bars run to the now line, hiddenIds leave the chart, hover syncs with the rows, and highlightIds fades non-matching bars in place |
TEyeToggle |
The eye that hides an entry from the chart (crossed out when hidden), with a tooltip that says so |
TOrderButton |
The sort icon beside Filters, newest or oldest first, with a tooltip that explains the order |
TPeriodStepper |
‹ This week › at the top of a chart card: the arrows step one day, week or month, the label opens a TMenu of Day, Week, Month and Custom range…, and a text link returns to the current period |
TMenu |
A small choice menu: a 230px popover under its anchor on the desktop, a bottom sheet of rows on the phone, the chosen item in accent with a check |
TSearchField |
Page search field with a / keycap that focuses it from anywhere, a clear button once there is text, and Escape to clear and blur; size="sm" for lists in sheets, busy for a spinner |
TFilterBar |
The sticky filter bar at the top of a list page: controls in one row keep their widths and a TSearchField takes the rest, the secondary slot is a second row (the period stepper on phones), --bg painted behind so content scrolls away under it; mobile lets the row wrap; margins and top are the page's |
TPageTitle |
The page's large title, sub and right actions, held at the top while the page scrolls. Alone it pins itself in its scroller (position: sticky, top: var(--space-6), z-index 10) and paints --bg above and behind itself, so it wants at least --space-6 of top padding on a wrapper inside the scroller (Timebraid's .content), not on the scroller itself, which would push it down by that much again. When the shell calls providePageTitleHost() and binds the ref to an element above its scroller, the title moves there and never scrolls, as in Timebraid; the host's padding and column are the shell's. A TFilterBar in the bar slot pins with the title and gives up its own sticky and --bg; under a hosted title a TFilterBar in the page pins at the top of the scroller instead. Never put a TFilterBar after an unhosted title outside bar: both pin at the top and the bar covers the title. Phones hand title and sub to TIOSNav or TAndroidTop instead |
TSeparator |
The 1px --sep rule between a sidebar's pinned Settings link and the account under it, with --space-3 above and below and --space-2 in from the sides |
TCommandPalette |
The ⌘K search: a centred dialog on a scrim with a combobox head, grouped option rows led by an avatar, a colour dot or an icon tile with the query marked in every title, hints and keycaps on the right, arrow keys, Enter and Escape, an empty state and a foot of keycap hints; mobile fills the screen with Cancel; paletteIds and stepActive walk the groups |
TParallelMark |
Two short running bars, titled "Ran alongside {names}"; replaces the "in parallel" chip on rows |
TAutoStopMark |
An orange timer-off, titled "Stopped automatically. Check the end time"; replaces that chip on rows |
TFilterButton |
The Filters button beside search; accent with a count badge when filters are on, icon-only with a corner badge when compact |
TChipRow |
Add entry's chip row: section label, 30px pills with a colour dot or an icon, single or multiple |
TFilterSheet |
The Filters sheet of Entries and Reports: an accordion of Workspace, Project, Task and Person (each a TPickList fed by fetchOptions), Show only (switch rows) and Notes (a check list), with each value on the right; picks cascade through parentOf, it keeps a draft and emits apply |
TFilterPanel |
The Filters sheet for any app, built from sections of static options: a row per section with its icon plate, label and value on the right (Any, the picked label or "{n} picked"), one open at a time; a single section is a check list led by Any, a multiple one check boxes and a searchable one gets a search field; modelValue maps each key to a string or a list, '' or [] meaning Any; it keeps a draft, Apply emits update:modelValue and apply, Clear all resets the draft and closing drops it; filterPanelCount gives TFilterButton its count |
TPickList |
A long multi-pick list that stays five rows tall: debounced server search with a spinner and dimmed old rows, picked rows first and frozen while open, 20 more rows per page as you scroll, and a fade at the bottom until the end |
THighlight |
Text with every word of a query marked in --accent-soft-2 |
TPager |
The strip under a paged list: a flat, right-aligned stepper ‹ 10 per page ▾ › under a hairline (a menu of 10, 25 and 50, arrows through the pages) with the range ("1–10 of 34") small on the left; pageSlice and pageable do the paging |
TSkeleton |
A shimmering placeholder block (text line, block, circle or pill) for a page that has not drawn yet; .t-skeleton in the tokens paints the shimmer |
TSkeletonList |
The skeleton of a list card: rows of a leading mark, two lines of differing length and a short right block |
TMediaCard |
A picture-first card for grids of camera events or clips: media at ratio (4 / 3), a badge on the picture, title, meta and a foot; a plain block to wrap in a link, which lifts it on hover and focus; it rests on --sh-raised, so its edge reads inside a TGroup as well as on the page, light and dark |
TRing |
A progress ring: a --fill-2 track and an arc in color from 12 o'clock with round caps, progress 0 to 1, transition linear (1s, while a countdown ticks) or ease (420ms --ease-out), pulse for an alarm; whatever goes inside is the default slot |
TSyncLine |
The 2px sweep along a card's top (or bottom) edge while something works: a 40% segment in color crossing every 1.3s on the tokens' t-shimmer, fading with on, resting at 30% under reduced motion |
TStatusChip |
The status chip: 26px, a 6px dot, the label and the status word at 70%, coloured by tone (ok, accent, warn, danger, off); never colour alone. Deprecated as the zone chip: zones use TZoneTile |
TArmCard |
The arming hero: the state ring, the title and sub for each phase, the mode control (or Arm now, the in-place disarm confirm, Disarm and Silence sirens), the sync line while arming, the state-colour ring and the alarm tint, the armed disc's 2.4s heartbeat ping, and a zones block (ZONES, "All 7 closed" / "2 of 7 open" / "5 of 7 secured", a grid of TZoneTiles); compact stacks it, mobile turns the grid into a strip that scrolls sideways, readonlyZones makes the tiles read-only; drive it with useArm or straight from an API |
TZoneTile |
A 48px zone tile: an 8px status dot (pulsing for Open and Opened), the name over the state word, and the sensor glyph for its type (door, window, gate, garage, motion); a button, or read-only |
TLiveTile |
A camera tracking something right now: the stream as the default slot under LIVE and "{Object} · tracking" chips, the name, room and start, the tracking timer, and Fullscreen, Snapshot and Talk on hover; once tracking.endedAt is set it lingers dimmed with "Tracked m:ss" |
TCamThumb |
A camera wall thumbnail: the still as the default slot, name and room under it, the live timer and an object capsule while tracking, the offline state |
TWallTile |
A tile of the full-screen camera wall: LIVE on every online camera, the object and timer while tracking, the offline state; small under 260px |
TCamWall |
The full-screen camera wall in the dark theme: tiles sized to fit the stage for 2×2, 3×3 or 4×4 (phone 1, 2 or 4), the tile slot for each stream, pages by arrows, dots, ← → keys and swipe, Cycle every cycleMs, Escape or × emits close |
TZoneCanvas |
A camera feed (default slot) with its zones drawn over it in 0–100 frame coordinates and labelled at their centres; with a draft it becomes the zone editor's canvas: the rest dimmed, corner handles to drag, clicks adding corners for a custom shape, Backspace removing the last, Escape emitting cancel |
TShapeChip |
A 34px zone shape chip with its 20×14 pictogram, pressed when chosen |
TZoneTray |
The shape tray under the zone canvas: six shape chips, the corner count, Undo corner and Clear for a custom shape, and a hint for the state |
TZoneEditor |
The zone editor card: Name, Detects and Colour rows, then Delete zone (two steps, existing zones), Cancel and Add zone or Save zone, disabled under 3 corners |
Also exported: formatDuration(seconds, 'clock' | 'short' | 'compact' | 'friendly'), the timeline helpers (timelineSpan, isRunningEntry, parallelMinutes, parallelPartners), the task colours (taskSwatches, swatchFill, swatchInk, SWATCH_COLORS, STRIPES, RUNNING_SHEEN), hourLabel, minutesToAmPm, toggleId, the filter helpers (emptyFilters, copyFilters, filterCount, entriesText, ENTRY_FLAGS, NOTE_FILTERS, DIMENSION_KEYS, FLAG_LABELS, FLAG_HINTS, NOTE_LABELS) and their types, filterPanelCount and the panel types FilterPanelSection, FilterPanelOption and FilterPanelValue, PickItem and PickPage, highlightSegments, the palette helpers (paletteIds, stepActive) and their types PaletteItem and PaletteGroup, the dashboard kit's useArm, ARM_MODES, ZONE_STATUS, STATUS_TONES, the camera helpers (cameraObject, trackingFor, liveColumns, wallLayout, WALL_GRIDS, LIVE_TILE_ACTIONS) and the zone helpers (ZONE_SHAPES, ZONE_COLOURS, ZONE_OBJECTS, newZoneDraft, zoneDraft, draftName, zoneSummary, withShape, withPoints) with their types, formatCountdown, formatClockTime, useMediaQuery, PROJECT_COLORS, TIMEBRAID_ICON_BASE, DEFAULT_ICON_BASE, resolveTheme, applyTheme, watchTheme, THEME_PREFERENCES.
TIcon ships its glyphs: scripts/glyphs.mjs writes the Lucide paths for every name the products use into packages/vue/src/icons/glyphs.ts, and the component renders them inline in currentColor. Nothing is fetched at runtime. To add a glyph, add its name to NAMES in the script and run pnpm glyphs. FILLS draws a solid glyph of its own (square, play); SOLIDS paints an outline solid in the same silhouette (star-filled from star), so a toggle between the two never shifts. ICON_NAMES and hasIcon() are exported so an app can assert every name it uses is bundled. A name missing from the table still masks from TIMEBRAID_ICON_BASE (or the base prop) with a dev warning, so nothing breaks while the table catches up.
Rules
TBadge tone="soon"with the words "Coming soon" on every roadmap item.- Indigo (
--accent) is the accent and the running colour. Amber lives in the app icon only. - Project colours come from
PROJECT_COLORS(Okabe-Ito). Nothing else. - No chips on list rows; marks with tooltips instead (
TParallelMark,TAutoStopMark, and the workspace once as aTWsIconbeside the project). - Long option lists use
TPickList(server search, 5 rows, paged by 20). On/off filters are switch rows, single choices are check lists. No pills or tabs in sheets.
Develop
pnpm dev opens the playground with every component and state, and a dark/light switch.
Version History
| Version | Released | License |
|---|---|---|
| 1.32.0 | MIT | |
| 1.31.1 | MIT | |
| 1.31.0 | MIT | |
| 1.30.0 | MIT | |
| 1.29.0 | MIT | |
| 1.28.0 | MIT | |
| 1.27.0 | MIT | |
| 1.26.1 | MIT | |
| 1.26.0 | MIT | |
| 1.25.0 | MIT | |
| 1.24.0 | MIT | |
| 1.23.0 | MIT | |
| 1.22.0 | MIT | |
| 1.21.0 | MIT | |
| 1.20.0 | MIT | |
| 1.19.0 | MIT | |
| 1.18.0 | MIT | |
| 1.17.0 | MIT | |
| 1.16.0 | MIT | |
| 1.15.0 | MIT | |
| 1.14.0 | MIT | |
| 1.13.0 | MIT | |
| 1.12.0 | MIT | |
| 1.11.0 | MIT | |
| 1.10.0 | MIT | |
| 1.9.0 | MIT | |
| 1.8.0 | MIT | |
| 1.7.0 | MIT | |
| 1.6.0 | MIT | |
| 1.5.0 | MIT |
Showing the latest 30 of 32. See every release on npm