Sidebar session list grows the figma 239-10458 feature set and the
workspace/session browsing region moves wholesale into ui-workspace:
- Group-by menu (WorkSpace / In one list): flat mode lists every session
top-level, strictly newest-first; the choice persists across reloads.
- Session rows get a 500ms hover detail card (title / relative time /
status line) and a ... menu (Rename / Fork session / Delete session,
visual-only for now); workspace headers get ... with Rename (wired) and
Delete workspace (visual-only).
- workspace.rename RPC: trims, rejects duplicate titles on the create
chain (workspace-name-conflict), no-op on same title; modal dialog with
client-side duplicate pre-check.
- workspace.insertSessionBefore RPC (DOM-insertBefore semantics, omitted
anchor appends): HTML5 drag reorder of root sessions inside a workspace
group; order truth stays host-side, the view refreshes from the
response/changed frame.
- Activity pinning removed: the session/event touchSession chain is gone;
workspace accounts are manually owned (new sessions prepend, explicit
reordering only). Contracts and tests updated, api catalog regenerated.
- ui-sidebar reduced to the column shell (brand, fold state machine, New
Session, Settings) exposing one sidebar.workspaces hole with a two-fact
owner share {wide, expandSidebar}; ui-workspace owns the whole region
(header, search, grouped/flat lists, dialogs, drag) plus the picker via
a shared WorkspaceCreateFlow. The old sidebar.workspace picker slot and
its deferral indirection are gone.
- ui-primitives: Menu gains label entries, danger rows, and
closeOnPointerLeave; new HoverCard (portaled, open-delay, disabled
guard). Hover card and row menu never coexist.
247 lines
5.9 KiB
CSS
247 lines
5.9 KiB
CSS
/* Sidebar column (figma 133:7629): vertical stack, padding 12/6, sidebar
|
|
fill + 1px right border painted by the layout column. Collapse is a
|
|
slide + crossfade, not a morph: the content holds its frozen expanded
|
|
layout (inline width set by the component) and fades in place (.fading)
|
|
while the sliding column (AppFrame grid tracks) clips it; the rail layout
|
|
(.collapsed) only applies after the fade settles, so nothing reflows
|
|
mid-slide. */
|
|
|
|
.root {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
padding: 6px 12px;
|
|
box-sizing: border-box;
|
|
background: var(--dsw-specific-sidebar-fill);
|
|
color: var(--dsw-alias-label-primary);
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* Rail geometry (figma rail spec): 36x36 control boxes centered in the 56px
|
|
rail (10px side padding), 12px vertical rhythm, 18px from the rail top to
|
|
the whale's box (24px to the 24-wide whale glyph itself). */
|
|
.root.collapsed {
|
|
padding: 18px 10px 6px;
|
|
}
|
|
|
|
/* Collapse phase 1: the whole frozen-width content fades out in place over
|
|
150ms; at settle the children unmount/snap to the rail layout. */
|
|
.fading > * {
|
|
opacity: 0;
|
|
transition: opacity 150ms var(--ds-ease-in-out);
|
|
}
|
|
|
|
/* Wide-only content fades back in on expand remount. */
|
|
.wide {
|
|
animation: wide-in 200ms var(--ds-ease-in-out);
|
|
}
|
|
|
|
@keyframes wide-in {
|
|
from { opacity: 0; }
|
|
}
|
|
|
|
/* Rail controls hold hidden while the column slides shut, then fade in over
|
|
the slide's tail: .railIn applies at settle (150ms into the 0.3s AppFrame
|
|
track transition), so a 100ms delay + 150ms fade starts just before the
|
|
slide ends (250ms) and finishes at 400ms; `backwards` keeps them at
|
|
opacity 0 through the delay. Only a live collapse gets .railIn — a
|
|
refresh straight into the collapsed state renders statically. */
|
|
.railIn .iconButton,
|
|
.railIn .newSession,
|
|
.railIn .foot {
|
|
animation: rail-in 150ms var(--ds-ease-in-out) 100ms backwards;
|
|
}
|
|
|
|
@keyframes rail-in {
|
|
from { opacity: 0; }
|
|
}
|
|
|
|
/* Logo row (figma pad (4,8,4,8)): brand left, panel toggle right-anchored —
|
|
the toggle is the rail's expand control and slides in with the right edge. */
|
|
.logoRow {
|
|
flex: none;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
gap: 8px;
|
|
height: 60px;
|
|
padding: 8px 0 8px 4px;
|
|
margin-bottom: 16px;
|
|
box-sizing: border-box;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.collapsed .logoRow {
|
|
height: 36px;
|
|
padding: 0;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
/* Brand group (figma I133:7632): the full wordmark rides the text ink
|
|
(figma-flows ruling: main-screen instance is black; blue is brand
|
|
emphasis only). */
|
|
.brand {
|
|
flex: 1;
|
|
min-width: 0;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.iconButton {
|
|
flex: none;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 28px;
|
|
height: 28px;
|
|
border: none;
|
|
border-radius: 50%;
|
|
padding: 0;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
color: var(--dsw-alias-label-secondary);
|
|
}
|
|
|
|
.iconButton:hover {
|
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
}
|
|
|
|
.collapsed .iconButton {
|
|
width: 36px;
|
|
height: 36px;
|
|
}
|
|
|
|
/* Rail logo swap: collapsed, the toggle rests as the whale mark (brand ink,
|
|
no hover circle) and hovering reveals the panel icon — the expand
|
|
affordance (figma sidebar-hover flow). Expanded it is a plain panel icon. */
|
|
.collapsed .toggle .panelIcon {
|
|
display: none;
|
|
}
|
|
|
|
.collapsed .toggle:hover .panelIcon {
|
|
display: inline;
|
|
}
|
|
|
|
.collapsed .toggle:hover .railFish {
|
|
display: none;
|
|
}
|
|
|
|
/* Rail icons ride the primary ink (figma rail spec); expanded keeps the
|
|
secondary icon-button ink. */
|
|
.collapsed .iconButton {
|
|
color: var(--dsw-alias-label-primary);
|
|
}
|
|
|
|
/* New Session: 38px capsule (figma 133:7634); collapsed it renders as the
|
|
rail's plain icon control. */
|
|
.newSession {
|
|
flex: none;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6px;
|
|
height: 38px;
|
|
padding: 8px 16px;
|
|
margin: 0 2px 20px; /* bottom: former headerBlock padBottom 12 + root gap 8 */
|
|
box-sizing: border-box;
|
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
border-radius: 24px;
|
|
background: var(--dsw-alias-button-elevated-fill);
|
|
color: var(--dsw-alias-label-primary);
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
line-height: 22px;
|
|
cursor: pointer;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.newSession:hover {
|
|
background: var(--dsw-alias-button-floating-hover);
|
|
}
|
|
|
|
.collapsed .newSession {
|
|
height: 36px;
|
|
padding: 0;
|
|
margin: 0 0 12px;
|
|
gap: 0;
|
|
border-color: transparent;
|
|
background: transparent;
|
|
}
|
|
|
|
.collapsed .newSession:hover {
|
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
}
|
|
|
|
.newSessionLabel {
|
|
max-width: 200px;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.collapsed .newSessionLabel {
|
|
max-width: 0;
|
|
}
|
|
|
|
/* Region seat: always mounted so the foot never moves; the browser inside
|
|
handles its own wide/rail content. */
|
|
.regionArea {
|
|
flex: 1;
|
|
min-height: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Foot: settings entry (figma 133:7668, 49 hug): the former 18/10 vertical
|
|
margins fold into the row so the hover pill spans the full 49px. */
|
|
.foot {
|
|
flex: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
height: 49px;
|
|
margin: 8px 0 0; /* + 49px row + root padBottom 6 keeps the old 57px band */
|
|
padding: 0 2px 0 6px;
|
|
border-radius: 12px;
|
|
cursor: pointer;
|
|
overflow: hidden;
|
|
color: var(--dsw-alias-label-primary);
|
|
}
|
|
|
|
.foot:hover {
|
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
}
|
|
|
|
/* Rail settings: the same 36x36 circle box as the other rail controls. */
|
|
.collapsed .foot {
|
|
width: 36px;
|
|
height: 36px;
|
|
margin: 18px 0 10px;
|
|
justify-content: center;
|
|
gap: 0;
|
|
padding: 0;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.footLabel {
|
|
max-width: 120px;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.collapsed .footLabel {
|
|
max-width: 0;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.wide,
|
|
.fading > *,
|
|
.railIn .iconButton,
|
|
.railIn .newSession,
|
|
.railIn .foot {
|
|
transition: none;
|
|
animation: none;
|
|
}
|
|
}
|