KQ-1657 · OPEN/DAY
Open Day
An empty calendar day: the working hours as a calm column, suggested blocks floating beside it, and an empty message that sits in the largest free stretch and shrinks as the day fills. A suggestion follows the finger 1:1, tucked to a compact chip while a dashed slot shows where it would land; released over the day it drops onto the slot on springs.snap with the throw's velocity and then stretches to its default length on springs.glide a beat later, and released anywhere else it flies home. Keyboard users pick a suggestion and press Enter to place it at the next free hour with the same drop and stretch, Delete dismisses it, and placed blocks move a quarter hour with Up and Down.
Thursday 15 October
09:00–17:00
nothing booked · 8 h open
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/open-day
Props
- hourHeight
- number
- default 40
- Pixels per hour of the column; the drag maps to it.
- cardStyle
- "soft" | "outline" | "solid"
- default "soft"
- How blocks and suggestions are drawn: a tinted fill, a dashed outline, or solid pigment.
- tone
- "calm" | "warm" | "mono"
- default "calm"
- The block colours: token hues at a fixed lightness, so they read in both themes.
- date
- number
- default defaultOpenDayDate
- Any time on the day shown, in ms (read in UTC).
- workingHours
- [number, number]
- default [9, 17]
- Working hours as whole hours; the column covers them.
- suggestions
- DaySuggestion[]
- default defaultDaySuggestions
- Blocks offered beside the day: { id, label, kind: "focus" | "lunch" | "review" | "inbox" | "prep", minutes }.
- value / defaultValue
- DayBlock[]
- default — / []
- The placed blocks, controlled or initial: { id, suggestion, label, kind, start, end } in ms.
- onValueChange
- (blocks: DayBlock[]) => void
- default —
- Fires from the drop, key or press that changed the day, with every block.
- onPlace
- (block: DayBlock) => void | Promise<unknown>
- default —
- A block landed or moved. Return a promise to save it; a rejection keeps it, marked unsaved.
- onDismiss
- (suggestion: DaySuggestion) => void
- default —
- A suggestion was dismissed (its × or Delete).
- onRemove
- (block: DayBlock) => void
- default —
- A placed block was removed; its suggestion goes back beside the day.
- now
- number
- default defaultOpenDayNow
- The current time in ms; "next free hour" counts from it on its own day. Never read from the clock.
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the day has loaded. Loading shows a skeleton column and cards; error marks every placed block unsaved under a Retry banner.
- onRetry
- () => void
- default —
- Retry was pressed on the sync banner; unsaved blocks are placed again through onPlace.
- step
- number
- default 15
- The minutes the column snaps to, and one Up or Down press.
- height
- number
- default 540
- Height of the day in px; its body scrolls inside it.
- disabled
- boolean
- default false
- Nothing can be placed, moved or dismissed.
- className
- string
- default —
- Classes for the outer surface.
| Prop | Type | Default | Description |
|---|---|---|---|
| hourHeight | number | 40 | Pixels per hour of the column; the drag maps to it. |
| cardStyle | "soft" | "outline" | "solid" | "soft" | How blocks and suggestions are drawn: a tinted fill, a dashed outline, or solid pigment. |
| tone | "calm" | "warm" | "mono" | "calm" | The block colours: token hues at a fixed lightness, so they read in both themes. |
| date | number | defaultOpenDayDate | Any time on the day shown, in ms (read in UTC). |
| workingHours | [number, number] | [9, 17] | Working hours as whole hours; the column covers them. |
| suggestions | DaySuggestion[] | defaultDaySuggestions | Blocks offered beside the day: { id, label, kind: "focus" | "lunch" | "review" | "inbox" | "prep", minutes }. |
| value / defaultValue | DayBlock[] | — / [] | The placed blocks, controlled or initial: { id, suggestion, label, kind, start, end } in ms. |
| onValueChange | (blocks: DayBlock[]) => void | — | Fires from the drop, key or press that changed the day, with every block. |
| onPlace | (block: DayBlock) => void | Promise<unknown> | — | A block landed or moved. Return a promise to save it; a rejection keeps it, marked unsaved. |
| onDismiss | (suggestion: DaySuggestion) => void | — | A suggestion was dismissed (its × or Delete). |
| onRemove | (block: DayBlock) => void | — | A placed block was removed; its suggestion goes back beside the day. |
| now | number | defaultOpenDayNow | The current time in ms; "next free hour" counts from it on its own day. Never read from the clock. |
| status | "ready" | "loading" | "error" | "ready" | Whether the day has loaded. Loading shows a skeleton column and cards; error marks every placed block unsaved under a Retry banner. |
| onRetry | () => void | — | Retry was pressed on the sync banner; unsaved blocks are placed again through onPlace. |
| step | number | 15 | The minutes the column snaps to, and one Up or Down press. |
| height | number | 540 | Height of the day in px; its body scrolls inside it. |
| disabled | boolean | false | Nothing can be placed, moved or dismissed. |
| className | string | — | Classes for the outer surface. |