KQ-1659 · OFFLINE/SHELF
Offline Shelf
A list that failed to load, shown honestly: a banner says the server cannot be reached and why, a countdown runs to the next automatic attempt, and under it sits what the device kept, each row wearing a Cached mark. The wait is one motion value running down at the rate of time; a failed attempt refills it to the next, longer delay on springs.glide. Back online, the marks lift off down the list on cascade() — a stamp rises, grows and turns as it fades on the exit ease — while the fresh rows slide in above on springs.glide, and losing the connection again presses the stamps back on with springs.recoil. R retries now from anywhere inside; the rows are one tab stop where the arrows move and Enter opens.
Inspections
Fieldline · 6 items saved on this device
We can't reach Fieldline.
The request timed out after 30 seconds. Showing what this device saved 2 h ago. ETIMEDOUT
Next try in 4 s
Up and Down move between rows, Enter opens one. R retries now.
offline · 6 saved on this device
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/offline-shelf
Props
- cachedItems
- OfflineShelfItem[]
- default defaultOfflineShelfCached
- What the device kept from the last load: { id, title, place?, kind?, updatedAt }.
- freshItems
- OfflineShelfItem[]
- default the cached items, re-verified
- What the server sent once it answered. New ids slide in above the cached rows; known ids take the fresh copy with a brief wash.
- status
- "offline" | "online"
- default "offline"
- Whether the server can be reached. Online lifts the marks and folds the banner away.
- error
- string | { message: string; code?: string }
- default a 30-second timeout, ETIMEDOUT
- Why the list did not load, shown as it is with its code in mono.
- cachedAt
- number
- default two hours before now
- When the cache was written, in ms; drives the stamps' age and the banner copy.
- now
- number
- default defaultOfflineShelfNow
- The moment ages count from, in ms; never read from the clock during render.
- retryDelays
- number[]
- default [5, 10, 20, 40, 60]
- Seconds to wait before each automatic attempt; the last one repeats.
- onRetry
- (cause: "auto" | "manual", attempt: number) => void | Promise<unknown>
- default —
- An attempt starts. Resolve once the server answered and set status to "online"; reject, or return nothing, and the next wait is longer.
- onOpenCached
- (item: OfflineShelfItem) => void
- default —
- A cached row was opened (Enter or a press) while offline.
- onOpen
- (item: OfflineShelfItem) => void
- default —
- A row was opened while online.
- paused
- boolean
- default false
- Hold the countdown where it is.
- retryStyle
- "ring" | "bar" | "ticks"
- default "ring"
- How the wait is drawn: a ring that drains round the seconds, a hairline bar along the banner, or ten ticks going out.
- stampStyle
- "stamp" | "tag" | "dim"
- default "stamp"
- How a cached row is marked: a rotated rubber stamp with a double rule, a quiet tag, or a dimmed row with a clock.
- tone
- "quiet" | "amber" | "cobalt"
- default "quiet"
- The banner's rule, icon, wash and wait colour.
- title
- string
- default "Inspections"
- The list's name; also the surface's accessible name.
- source
- string
- default "Fieldline"
- What cannot be reached, used in the copy and the announcements.
- maxHeight
- number
- default 540
- Tallest the surface grows before its list scrolls inside, px.
- disabled
- boolean
- default false
- Nothing can be retried or opened and the countdown holds; the surface dims.
- className
- string
- default —
- Classes for the outer surface.
| Prop | Type | Default | Description |
|---|---|---|---|
| cachedItems | OfflineShelfItem[] | defaultOfflineShelfCached | What the device kept from the last load: { id, title, place?, kind?, updatedAt }. |
| freshItems | OfflineShelfItem[] | the cached items, re-verified | What the server sent once it answered. New ids slide in above the cached rows; known ids take the fresh copy with a brief wash. |
| status | "offline" | "online" | "offline" | Whether the server can be reached. Online lifts the marks and folds the banner away. |
| error | string | { message: string; code?: string } | a 30-second timeout, ETIMEDOUT | Why the list did not load, shown as it is with its code in mono. |
| cachedAt | number | two hours before now | When the cache was written, in ms; drives the stamps' age and the banner copy. |
| now | number | defaultOfflineShelfNow | The moment ages count from, in ms; never read from the clock during render. |
| retryDelays | number[] | [5, 10, 20, 40, 60] | Seconds to wait before each automatic attempt; the last one repeats. |
| onRetry | (cause: "auto" | "manual", attempt: number) => void | Promise<unknown> | — | An attempt starts. Resolve once the server answered and set status to "online"; reject, or return nothing, and the next wait is longer. |
| onOpenCached | (item: OfflineShelfItem) => void | — | A cached row was opened (Enter or a press) while offline. |
| onOpen | (item: OfflineShelfItem) => void | — | A row was opened while online. |
| paused | boolean | false | Hold the countdown where it is. |
| retryStyle | "ring" | "bar" | "ticks" | "ring" | How the wait is drawn: a ring that drains round the seconds, a hairline bar along the banner, or ten ticks going out. |
| stampStyle | "stamp" | "tag" | "dim" | "stamp" | How a cached row is marked: a rotated rubber stamp with a double rule, a quiet tag, or a dimmed row with a clock. |
| tone | "quiet" | "amber" | "cobalt" | "quiet" | The banner's rule, icon, wash and wait colour. |
| title | string | "Inspections" | The list's name; also the surface's accessible name. |
| source | string | "Fieldline" | What cannot be reached, used in the copy and the announcements. |
| maxHeight | number | 540 | Tallest the surface grows before its list scrolls inside, px. |
| disabled | boolean | false | Nothing can be retried or opened and the countdown holds; the surface dims. |
| className | string | — | Classes for the outer surface. |