KQ-1708 · WORKSPACE/LOBBY

Workspace Lobby

The screen after sign-in: your workspaces as tiles with role, people and last visit, invitations in their own row, and a way to create one. Choosing a tile grows its real box from the tile's measured place to fill the panel on springs.glide while every other tile steps back on the same spring, the workspace's spaces cascade in under a loading line, and the answer resolves to a check drawn on springs.flick — or folds the tile back with the reason; a single accent plate travels between tiles on springs.snap. The tiles are a listbox: arrows walk them by their rendered rows, letters jump by name, Enter opens and Escape folds back.

KQ-1708 · WORKSPACE/LOBBY
Signed in as Mara Okaformara@fieldline.io

Choose a workspace

3 workspaces · 2 invitations

Arrow keys move between workspaces, letters jump by name, Enter opens.

OwnerColdbrookcoldbrook2 h ago4 new
AdminBasinworksbasinworks-opsYesterday
MemberFernworksfernworks6 days ago

Invitations

  • Gaugeworks Field OpsAna Ferreira invited you · Member38 members · sent 3 h ago
  • Waylight StudioKofi Mensah invited you · Guest14 members · sent 2 days ago

3 workspaces · Coldbrook selected

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/workspace-lobby

Props

workspaces
LobbyWorkspace[]
default defaultLobbyWorkspaces
The workspaces you belong to: { id, name, handle?, members, people?, role, lastVisit?, unread?, tint?, spaces? }.
invitations
LobbyInvitation[]
default defaultLobbyInvitations
Invitations waiting for an answer: { id, name, handle?, invitedBy, role, members, tint?, sentAt? }.
account
{ name, email }
default defaultLobbyAccount
Who is signed in, shown in the header.
now
number
default defaultLobbyNow
The clock (epoch ms) every last visit and invitation age is measured from.
value / defaultValue
string | null
default — / first workspace
The active tile — the option the arrows are on — controlled or initial.
onValueChange
(id) => void
default —
Fires from the arrow, type-ahead or press that moved the active tile.
onSelect
(workspace) => void | Promise<void>
default —
A workspace was chosen. A promise holds the expanded tile while it loads; a rejection folds it back and shows the message on the tile.
onCancel
(workspace) => void
default —
Cancel, Switch or Escape folded the open workspace back into its tile.
onCreate
() => void
default —
Create a workspace was pressed (the dashed row, or the empty state's button).
onJoin
(invitation) => void | Promise<void>
default —
Join was pressed. While a promise runs the card reads Joining…; when the host moves it into workspaces the tile lands from the card's place.
onDecline
(invitation) => void
default —
Decline was pressed on an invitation.
onSwitchAccount
() => void
default —
Switch account was pressed in the header.
status
"ready" | "loading" | "error"
default "ready"
Skeleton tiles while loading; a message and Try again on error.
onRetry
() => void
default —
Try again was pressed after loading failed.
tileStyle
"card" | "row" | "poster"
default "card"
A card, a compact row, or a poster with a seeded contour band.
columns
number
default 3
Tile columns at wide widths, 1 to 4; two at most below 44rem and one below 30rem of container.
accent
string
default "var(--accent-bright)"
The selection plate, the loading line, unread dots and Join, any CSS colour.
title
string
default "Choose a workspace"
The heading that names the listbox.
maxHeight
number
default 560
Tallest the panel grows, in px, before its body scrolls.
disabled
boolean
default false
Nothing can be opened, joined or created; the tiles stay readable and reachable.
className
string
default —
Classes for the wrapper.