feat(desktop): compact sidebar and topbar chrome

This commit is contained in:
DragonnZhang 2026-04-26 11:40:01 +08:00
parent 6c59e2bc96
commit 4e64dae91c
4 changed files with 382 additions and 79 deletions

View file

@ -0,0 +1,61 @@
# Electron Desktop E2E: Sidebar and Topbar Density
- Slice: Sidebar and Topbar Chrome Density Pass
- Date: 2026-04-26
- Executable harness: `packages/desktop/scripts/e2e-cdp-smoke.mjs`
- Command:
`cd packages/desktop && npm run e2e:cdp`
- Result: passed
- Passing artifact directory:
`.qwen/e2e-tests/electron-desktop/artifacts/2026-04-26T03-36-28-286Z/`
- Earlier failed artifact directory:
`.qwen/e2e-tests/electron-desktop/artifacts/2026-04-26T03-35-53-527Z/`
## Scenario Steps
1. Launch the real Electron app with isolated HOME, runtime, user-data, and a
temporary fake Git workspace.
2. Open the fake project through the desktop project picker flow.
3. Send a prompt from the composer, approve the deterministic command request,
and wait for the fake ACP assistant result.
4. Assert sidebar and topbar geometry, typography, containment, and overflow at
the default `1240x820` Electron window.
5. Continue the existing branch creation/switching, review drawer, compact
review, settings, terminal, discard safety, and commit smoke workflows.
## Assertions
- Sidebar width is `252` px, below the previous `272` px baseline.
- Sidebar app/footer action rows are `28` px tall, below the previous `32` px
baseline.
- Project row height is `32.6328125` px and thread row height is `32` px, below
the previous `39.75`/`36` px baselines.
- Sidebar action/project/thread text is `12` px; section headings are `10` px;
project/thread meta text is `9.5` px.
- Topbar height is `50` px, below the previous `54` px baseline.
- Topbar action buttons are `28x28`; runtime status is `65.6328125x28`.
- Long branch and Git status text remain present, clipped, and contained.
- No sidebar/topbar horizontal overflow, console errors, or failed local
requests are recorded.
## Failure and Fix
The first run failed because project/thread button parents still inherited the
root `14` px font even though their visible child labels had been compacted.
The stylesheet now sets the project and thread row parent font size explicitly,
and the harness records both row parent and child text metrics.
## Artifacts
- `sidebar-app-rail.json`
- `topbar-context-fidelity.json`
- `topbar-context-fidelity.png`
- `initial-workspace.png`
- `electron.log`
- `summary.json`
## Known Uncovered Risk
This pass is a density/fidelity slice, not a navigation redesign. The harness
still covers one project/thread pair; a future visual regression path should add
several recent projects and longer localized thread titles at compact width.

View file

@ -22,6 +22,116 @@ execution order, verification, decisions, and remaining work.
## Codex Alignment Progress ## Codex Alignment Progress
### Completed Slice: Sidebar and Topbar Chrome Density Pass
Status: completed in iteration 26.
Goal: tighten the remaining oversized sidebar and topbar chrome so the first
viewport reads closer to the compact `home.jpg` workbench instead of a heavy
dashboard shell.
User-visible value: users get more room for the conversation and task surfaces,
while project, thread, branch, model, review, refresh, and settings controls
remain visible, readable, and safely contained.
Expected files:
- `packages/desktop/src/renderer/styles.css`
- `packages/desktop/scripts/e2e-cdp-smoke.mjs`
- `.qwen/e2e-tests/electron-desktop/sidebar-topbar-density.md`
- `design/qwen-code-electron-desktop-implementation-plan.md`
Acceptance criteria:
- The desktop sidebar is narrower and uses shorter app action, project, and
thread rows without horizontal overflow.
- Sidebar app action, project, thread, section, and footer typography moves to a
restrained workbench scale while preserving readable labels and accessible
button names.
- The topbar height, action buttons, runtime pill, and status text are slimmer
and remain contained with a deliberately long branch name.
- The topbar no longer increases body scroll width or hides conversation,
review, settings, terminal, branch, or Git status actions.
- No raw project paths, ACP/session IDs, or debug state are introduced into the
main sidebar or topbar text.
Verification:
- Unit/component test command:
`cd packages/desktop && SHELL=/bin/bash npx vitest run src/renderer/components/layout/WorkspacePage.test.tsx`
- Syntax command: `node --check packages/desktop/scripts/e2e-cdp-smoke.mjs`
- Build/typecheck/lint commands:
`cd packages/desktop && npm run typecheck && npm run lint && npm run build`
- Real Electron harness:
`cd packages/desktop && npm run e2e:cdp`
- Harness path: `packages/desktop/scripts/e2e-cdp-smoke.mjs`
- E2E scenario steps: launch real Electron with isolated HOME/runtime/user-data
and fake ACP, open the fake Git project, send a prompt, approve the command,
wait for the assistant result, then assert sidebar and topbar chrome geometry
at the default viewport before continuing the existing branch, review,
settings, terminal, discard safety, and commit workflows.
- E2E assertions: sidebar width is below the previous 272 px baseline, top app
action rows are below the previous 32 px baseline, project/thread rows are
below the previous 39.75/36 px baselines, section headings and row text use a
smaller font scale, topbar height is below the previous 54 px baseline,
action buttons are below the previous 30 px baseline, runtime status is below
the previous 30 px height, long branch/status text remains contained, and no
console errors or failed local requests are recorded.
- Diagnostic artifacts: `sidebar-app-rail.json`,
`topbar-context-fidelity.json`, `topbar-context-fidelity.png`, Electron log,
and summary JSON under `.qwen/e2e-tests/electron-desktop/artifacts/`.
- Required skills applied: `brainstorming` for choosing the narrow prototype
fidelity slice without asking for routine product decisions,
`frontend-design` for prototype-constrained density and hierarchy, and
`electron-desktop-dev` for real Electron CDP verification.
Notes and decisions:
- The prototype remains the constraint: this pass should refine density and
hierarchy, not introduce a new navigation model, new routes, or new branding.
- This slice deliberately avoids workflow logic so model configuration can
resume after the first-viewport chrome is less visually dominant.
- The sidebar grid now uses a 252 px rail, 28 px app/footer actions, and
roughly 32 px project/thread rows. Project/thread button parents now carry
the same 12 px font scale as the visible row titles so inherited styles do
not regress unnoticed.
- The topbar now uses a 50 px workbench row, 28 px icon buttons, a 28 px runtime
status pill, and 10.5 px context text. Long branch and Git status text remain
in the DOM for accessibility but are visually contained.
- The CDP harness now records sidebar/topbar font metrics as well as geometry,
so future fidelity work cannot accidentally reintroduce the heavier 272 px
sidebar, 54 px topbar, 32 px action rows, or 30 px topbar buttons.
Verification results:
- `node --check packages/desktop/scripts/e2e-cdp-smoke.mjs` passed.
- `git diff --check` passed.
- `cd packages/desktop && SHELL=/bin/bash npx vitest run src/renderer/components/layout/WorkspacePage.test.tsx`
passed with 15 tests.
- `cd packages/desktop && npm run typecheck` passed.
- `cd packages/desktop && npm run lint` passed.
- `cd packages/desktop && npm run build` passed after the final CSS fix.
- `cd packages/desktop && npm run e2e:cdp` first failed at
`.qwen/e2e-tests/electron-desktop/artifacts/2026-04-26T03-35-53-527Z/`
because project/thread row button parents still inherited the root 14 px font
even though the visible labels were compact. The CSS now sets the row parent
font size explicitly.
- `cd packages/desktop && npm run e2e:cdp` then passed through real Electron at
`.qwen/e2e-tests/electron-desktop/artifacts/2026-04-26T03-36-28-286Z/`.
- Key recorded metrics from the passing run: sidebar width `252` px, app/footer
action rows `28` px tall, project row `32.6328125` px tall, thread row `32`
px tall, sidebar row font `12` px, sidebar heading font `10` px, topbar height
`50` px, topbar action buttons `28x28`, runtime status
`65.6328125x28`, topbar context font `10.5` px, no document overflow, no
console errors, and no failed local requests.
Next work:
- Resume the model configuration workflow from the composer model picker and
settings entry now that the first-viewport chrome is less visually dominant.
- Continue prototype fidelity by reducing remaining message/file chip button
weight only where screenshots show it crowding the conversation.
### Completed Slice: Conversation Message Typography Density Pass ### Completed Slice: Conversation Message Typography Density Pass
Status: completed in iteration 25. Status: completed in iteration 25.

View file

@ -667,6 +667,17 @@ async function assertSidebarAppRail(fileName) {
}; };
const overflows = (element) => const overflows = (element) =>
Boolean(element && element.scrollWidth > element.clientWidth + 4); Boolean(element && element.scrollWidth > element.clientWidth + 4);
const styleFor = (element) => {
if (!element) {
return null;
}
const style = window.getComputedStyle(element);
return {
fontSize: Number.parseFloat(style.fontSize),
fontWeight: Number.parseFloat(style.fontWeight),
lineHeight: Number.parseFloat(style.lineHeight)
};
};
const sidebar = document.querySelector('[data-testid="project-sidebar"]'); const sidebar = document.querySelector('[data-testid="project-sidebar"]');
const appActions = document.querySelector('[data-testid="sidebar-app-actions"]'); const appActions = document.querySelector('[data-testid="sidebar-app-actions"]');
const footerSettings = document.querySelector( const footerSettings = document.querySelector(
@ -684,12 +695,29 @@ async function assertSidebarAppRail(fileName) {
return { return {
label, label,
text: row.textContent.trim(), text: row.textContent.trim(),
className: row.className,
rect: rectFor(row), rect: rectFor(row),
style: styleFor(row),
scrollWidth: row.scrollWidth, scrollWidth: row.scrollWidth,
clientWidth: row.clientWidth, clientWidth: row.clientWidth,
overflows: overflows(row) overflows: overflows(row)
}; };
}); });
const headingStyles = [
...document.querySelectorAll('.sidebar-section-heading h2')
].map((heading) => styleFor(heading));
const projectTitleStyles = [
...document.querySelectorAll('.project-row-copy span')
].map((title) => styleFor(title));
const projectMetaStyles = [
...document.querySelectorAll('.project-row-copy small')
].map((meta) => styleFor(meta));
const threadTitleStyles = [
...document.querySelectorAll('.session-row-title')
].map((title) => styleFor(title));
const threadMetaStyles = [
...document.querySelectorAll('.session-row-meta')
].map((meta) => styleFor(meta));
return { return {
viewport: { viewport: {
@ -712,6 +740,11 @@ async function assertSidebarAppRail(fileName) {
footerSettings?.textContent.trim() || footerSettings?.textContent.trim() ||
'', '',
rows, rows,
headingStyles,
projectTitleStyles,
projectMetaStyles,
threadTitleStyles,
threadMetaStyles,
sidebarText: sidebar?.innerText ?? '', sidebarText: sidebar?.innerText ?? '',
overflows: { overflows: {
sidebar: overflows(sidebar), sidebar: overflows(sidebar),
@ -760,7 +793,7 @@ async function assertSidebarAppRail(fileName) {
); );
} }
if (metrics.sidebar.width < 236 || metrics.sidebar.width > 320) { if (metrics.sidebar.width < 236 || metrics.sidebar.width > 260) {
throw new Error( throw new Error(
`Sidebar width is no longer compact: ${metrics.sidebar.width}`, `Sidebar width is no longer compact: ${metrics.sidebar.width}`,
); );
@ -780,7 +813,18 @@ async function assertSidebarAppRail(fileName) {
); );
} }
const tallRows = metrics.rows.filter((row) => row.rect.height > 44); const tallRows = metrics.rows.filter((row) => {
if (row.className.includes('sidebar-action-row')) {
return row.rect.height > 30;
}
if (row.className.includes('session-row')) {
return row.rect.height > 34;
}
if (row.className.includes('project-row')) {
return row.rect.height > 38;
}
return row.rect.height > 38;
});
if (tallRows.length > 0) { if (tallRows.length > 0) {
throw new Error( throw new Error(
`Sidebar rows are too tall for the compact rail: ${JSON.stringify( `Sidebar rows are too tall for the compact rail: ${JSON.stringify(
@ -804,6 +848,54 @@ async function assertSidebarAppRail(fileName) {
); );
} }
const oversizedRowText = metrics.rows.filter(
(row) => row.style && row.style.fontSize > 12.5,
);
if (oversizedRowText.length > 0) {
throw new Error(
`Sidebar row typography regressed: ${JSON.stringify(oversizedRowText)}`,
);
}
const oversizedHeadings = metrics.headingStyles.filter(
(style) => style && style.fontSize > 10.5,
);
if (oversizedHeadings.length > 0) {
throw new Error(
`Sidebar heading typography regressed: ${JSON.stringify(
oversizedHeadings,
)}`,
);
}
const oversizedProjectTitles = metrics.projectTitleStyles.filter(
(style) => style && style.fontSize > 12.5,
);
const oversizedProjectMeta = metrics.projectMetaStyles.filter(
(style) => style && style.fontSize > 10,
);
const oversizedThreadTitles = metrics.threadTitleStyles.filter(
(style) => style && style.fontSize > 12.5,
);
const oversizedThreadMeta = metrics.threadMetaStyles.filter(
(style) => style && style.fontSize > 10,
);
if (
oversizedProjectTitles.length > 0 ||
oversizedProjectMeta.length > 0 ||
oversizedThreadTitles.length > 0 ||
oversizedThreadMeta.length > 0
) {
throw new Error(
`Sidebar project/thread text scale regressed: ${JSON.stringify({
oversizedProjectTitles,
oversizedProjectMeta,
oversizedThreadTitles,
oversizedThreadMeta,
})}`,
);
}
if ( if (
metrics.sidebarText.includes('session-e2e') || metrics.sidebarText.includes('session-e2e') ||
metrics.sidebarText.includes('/tmp/') || metrics.sidebarText.includes('/tmp/') ||
@ -857,7 +949,10 @@ async function assertTopbarContextFidelity(fileName) {
borderRightWidth: Number.parseFloat(style.borderRightWidth), borderRightWidth: Number.parseFloat(style.borderRightWidth),
borderBottomWidth: Number.parseFloat(style.borderBottomWidth), borderBottomWidth: Number.parseFloat(style.borderBottomWidth),
borderLeftWidth: Number.parseFloat(style.borderLeftWidth), borderLeftWidth: Number.parseFloat(style.borderLeftWidth),
borderTopAlpha: alphaFromColor(style.borderTopColor) borderTopAlpha: alphaFromColor(style.borderTopColor),
fontSize: Number.parseFloat(style.fontSize),
fontWeight: Number.parseFloat(style.fontWeight),
lineHeight: Number.parseFloat(style.lineHeight)
}; };
}; };
const escapes = (inner, outer) => const escapes = (inner, outer) =>
@ -909,6 +1004,8 @@ async function assertTopbarContextFidelity(fileName) {
topbar: topbarRect, topbar: topbarRect,
titleStack: rectFor(titleStack), titleStack: rectFor(titleStack),
title: rectFor(title), title: rectFor(title),
titleHeadingStyle: styleFor(title?.querySelector('h2')),
titleProjectStyle: styleFor(title?.querySelector('span')),
context: contextRect, context: contextRect,
runtimeStatus: rectFor(runtimeStatus), runtimeStatus: rectFor(runtimeStatus),
runtimeStatusText: runtimeStatus?.textContent.trim() ?? '', runtimeStatusText: runtimeStatus?.textContent.trim() ?? '',
@ -952,7 +1049,7 @@ async function assertTopbarContextFidelity(fileName) {
throw new Error('Topbar should not render legacy meta pills or tabs.'); throw new Error('Topbar should not render legacy meta pills or tabs.');
} }
if (metrics.topbar.height < 48 || metrics.topbar.height > 58) { if (metrics.topbar.height < 46 || metrics.topbar.height > 52) {
throw new Error(`Topbar is no longer slim: ${metrics.topbar.height}`); throw new Error(`Topbar is no longer slim: ${metrics.topbar.height}`);
} }
@ -998,16 +1095,50 @@ async function assertTopbarContextFidelity(fileName) {
); );
} }
if (metrics.runtimeStatus.height > 32 || metrics.runtimeStatus.width > 76) { if (metrics.titleHeadingStyle?.fontSize > 13.5) {
throw new Error(
`Topbar title typography regressed: ${JSON.stringify(
metrics.titleHeadingStyle,
)}`,
);
}
if (metrics.titleProjectStyle?.fontSize > 11) {
throw new Error(
`Topbar project typography regressed: ${JSON.stringify(
metrics.titleProjectStyle,
)}`,
);
}
const oversizedContextText = metrics.contextItems.filter(
(item) => item.style.fontSize > 10.75,
);
if (oversizedContextText.length > 0) {
throw new Error(
`Topbar context typography regressed: ${JSON.stringify(
oversizedContextText,
)}`,
);
}
if (
metrics.runtimeStatus.height > 29 ||
metrics.runtimeStatus.width > 72 ||
metrics.runtimeStatusStyle.fontSize > 10.75
) {
throw new Error( throw new Error(
`Runtime status should stay compact: ${JSON.stringify( `Runtime status should stay compact: ${JSON.stringify(
metrics.runtimeStatus, {
rect: metrics.runtimeStatus,
style: metrics.runtimeStatusStyle,
},
)}`, )}`,
); );
} }
const oversizedActions = metrics.actionRects.filter( const oversizedActions = metrics.actionRects.filter(
(action) => action.rect.width > 34 || action.rect.height > 34, (action) => action.rect.width > 29 || action.rect.height > 29,
); );
if (oversizedActions.length > 0) { if (oversizedActions.length > 0) {
throw new Error( throw new Error(

View file

@ -82,7 +82,7 @@ summary:focus-visible {
.desktop-shell { .desktop-shell {
display: grid; display: grid;
grid-template-columns: 272px minmax(0, 1fr); grid-template-columns: 252px minmax(0, 1fr);
width: 100%; width: 100%;
height: 100vh; height: 100vh;
overflow: hidden; overflow: hidden;
@ -96,9 +96,9 @@ summary:focus-visible {
height: 100vh; height: 100vh;
min-height: 0; min-height: 0;
flex-direction: column; flex-direction: column;
gap: 9px; gap: 7px;
overflow: hidden; overflow: hidden;
padding: 12px 10px; padding: 10px 8px;
border-right: 1px solid var(--line); border-right: 1px solid var(--line);
background: background:
linear-gradient(180deg, rgba(20, 26, 51, 0.98), rgba(13, 17, 32, 0.98)), linear-gradient(180deg, rgba(20, 26, 51, 0.98), rgba(13, 17, 32, 0.98)),
@ -123,21 +123,21 @@ summary:focus-visible {
.sidebar-app-actions { .sidebar-app-actions {
display: grid; display: grid;
gap: 2px; gap: 2px;
padding-bottom: 4px; padding-bottom: 3px;
} }
.sidebar-action-row { .sidebar-action-row {
display: grid; display: grid;
grid-template-columns: 22px minmax(0, 1fr); grid-template-columns: 20px minmax(0, 1fr);
align-items: center; align-items: center;
min-height: 32px; min-height: 28px;
gap: 8px; gap: 7px;
padding: 0 8px; padding: 0 7px;
border-radius: 6px; border-radius: 6px;
background: transparent; background: transparent;
color: rgba(225, 232, 242, 0.72); color: rgba(225, 232, 242, 0.72);
font-size: 13px; font-size: 12px;
font-weight: 680; font-weight: 660;
letter-spacing: 0; letter-spacing: 0;
text-align: left; text-align: left;
transition: transition:
@ -152,8 +152,8 @@ summary:focus-visible {
.sidebar-action-row svg { .sidebar-action-row svg {
display: block; display: block;
width: 16px; width: 14px;
height: 16px; height: 14px;
justify-self: center; justify-self: center;
} }
@ -193,7 +193,7 @@ summary:focus-visible {
.sidebar-section-heading span { .sidebar-section-heading span {
margin: 0; margin: 0;
color: var(--text-soft); color: var(--text-soft);
font-size: 11px; font-size: 10px;
font-weight: 800; font-weight: 800;
letter-spacing: 0; letter-spacing: 0;
text-transform: uppercase; text-transform: uppercase;
@ -203,8 +203,8 @@ summary:focus-visible {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
min-height: 22px; min-height: 20px;
padding: 4px 8px 0; padding: 3px 7px 0;
} }
.sidebar-section-heading span { .sidebar-section-heading span {
@ -213,11 +213,11 @@ summary:focus-visible {
.empty-row, .empty-row,
.workspace-path { .workspace-path {
min-height: 34px; min-height: 30px;
padding: 8px 2px; padding: 7px 2px;
color: rgba(225, 232, 228, 0.52); color: rgba(225, 232, 228, 0.52);
font-size: 13px; font-size: 12px;
font-weight: 680; font-weight: 650;
} }
.workspace-path { .workspace-path {
@ -289,11 +289,12 @@ summary:focus-visible {
display: grid; display: grid;
align-items: center; align-items: center;
width: 100%; width: 100%;
min-height: 36px; min-height: 32px;
border: 0; border: 0;
border-radius: 6px; border-radius: 6px;
background: transparent; background: transparent;
color: rgba(233, 238, 235, 0.86); color: rgba(233, 238, 235, 0.86);
font-size: 12px;
text-align: left; text-align: left;
transition: transition:
background 140ms ease, background 140ms ease,
@ -301,14 +302,14 @@ summary:focus-visible {
} }
.project-row { .project-row {
grid-template-columns: 24px minmax(0, 1fr); grid-template-columns: 21px minmax(0, 1fr);
padding: 5px 8px 5px 6px; padding: 3px 7px 3px 5px;
} }
.session-row { .session-row {
grid-template-columns: minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr) auto;
column-gap: 7px; column-gap: 6px;
padding: 5px 8px 5px 28px; padding: 4px 7px 4px 24px;
} }
.project-row-active, .project-row-active,
@ -320,8 +321,8 @@ summary:focus-visible {
.project-row-active::before, .project-row-active::before,
.session-row-active::before { .session-row-active::before {
position: absolute; position: absolute;
top: 7px; top: 6px;
bottom: 7px; bottom: 6px;
left: 0; left: 0;
width: 2px; width: 2px;
border-radius: 999px; border-radius: 999px;
@ -337,8 +338,8 @@ summary:focus-visible {
.project-row-icon { .project-row-icon {
justify-self: start; justify-self: start;
width: 16px; width: 14px;
height: 16px; height: 14px;
margin-left: 0; margin-left: 0;
color: rgba(225, 232, 228, 0.82); color: rgba(225, 232, 228, 0.82);
} }
@ -351,7 +352,7 @@ summary:focus-visible {
.project-row-copy { .project-row-copy {
display: grid; display: grid;
gap: 2px; gap: 1px;
} }
.project-row-copy span, .project-row-copy span,
@ -366,14 +367,14 @@ summary:focus-visible {
.project-row-copy span, .project-row-copy span,
.session-row-title { .session-row-title {
font-size: 13px; font-size: 12px;
font-weight: 660; font-weight: 660;
line-height: 1.25; line-height: 1.22;
} }
.project-row-copy small { .project-row-copy small {
color: rgba(225, 232, 228, 0.48); color: rgba(225, 232, 228, 0.48);
font-size: 10px; font-size: 9.5px;
font-weight: 680; font-weight: 680;
letter-spacing: 0; letter-spacing: 0;
} }
@ -382,15 +383,15 @@ summary:focus-visible {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
min-width: 32px; min-width: 28px;
gap: 6px; gap: 5px;
color: rgba(225, 232, 228, 0.52); color: rgba(225, 232, 228, 0.52);
font-weight: 760; font-weight: 760;
} }
.session-open-icon { .session-open-icon {
width: 15px; width: 13px;
height: 15px; height: 13px;
color: rgba(225, 232, 228, 0.48); color: rgba(225, 232, 228, 0.48);
} }
@ -399,17 +400,17 @@ summary:focus-visible {
} }
.session-ring { .session-ring {
width: 13px; width: 12px;
height: 13px; height: 12px;
border: 2px solid rgba(225, 232, 228, 0.2); border: 2px solid rgba(225, 232, 228, 0.2);
border-top-color: rgba(225, 232, 228, 0.5); border-top-color: rgba(225, 232, 228, 0.5);
border-radius: 999px; border-radius: 999px;
} }
.session-row-meta { .session-row-meta {
max-width: 48px; max-width: 44px;
color: rgba(225, 232, 228, 0.54); color: rgba(225, 232, 228, 0.54);
font-size: 10px; font-size: 9.5px;
font-weight: 720; font-weight: 720;
line-height: 1; line-height: 1;
} }
@ -417,7 +418,7 @@ summary:focus-visible {
.sidebar-footer { .sidebar-footer {
flex: 0 0 auto; flex: 0 0 auto;
margin-top: auto; margin-top: auto;
padding-top: 6px; padding-top: 5px;
border-top: 1px solid rgba(213, 224, 255, 0.08); border-top: 1px solid rgba(213, 224, 255, 0.08);
} }
@ -431,7 +432,7 @@ summary:focus-visible {
.workbench { .workbench {
display: grid; display: grid;
grid-template-rows: 54px minmax(0, 1fr) auto; grid-template-rows: 50px minmax(0, 1fr) auto;
min-width: 0; min-width: 0;
height: 100vh; height: 100vh;
min-height: 0; min-height: 0;
@ -439,16 +440,16 @@ summary:focus-visible {
} }
.workbench-settings-open { .workbench-settings-open {
grid-template-rows: 54px minmax(0, 1fr); grid-template-rows: 50px minmax(0, 1fr);
} }
.topbar { .topbar {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr) auto;
align-items: center; align-items: center;
gap: 12px; gap: 10px;
min-height: 0; min-height: 0;
padding: 0 16px 0 20px; padding: 0 14px 0 18px;
border-bottom: 1px solid var(--line); border-bottom: 1px solid var(--line);
background: rgba(13, 16, 17, 0.74); background: rgba(13, 16, 17, 0.74);
} }
@ -456,22 +457,22 @@ summary:focus-visible {
.topbar-title-stack { .topbar-title-stack {
display: grid; display: grid;
min-width: 0; min-width: 0;
gap: 3px; gap: 2px;
} }
.topbar-title { .topbar-title {
display: flex; display: flex;
align-items: baseline; align-items: baseline;
min-width: 0; min-width: 0;
gap: 10px; gap: 8px;
} }
.topbar-title h2 { .topbar-title h2 {
min-width: 0; min-width: 0;
overflow: hidden; overflow: hidden;
font-size: 14px; font-size: 13px;
font-weight: 780; font-weight: 780;
line-height: 1.15; line-height: 1.12;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
@ -480,8 +481,8 @@ summary:focus-visible {
min-width: 0; min-width: 0;
overflow: hidden; overflow: hidden;
color: var(--muted); color: var(--muted);
font-size: 11.5px; font-size: 10.5px;
font-weight: 700; font-weight: 680;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
@ -490,7 +491,7 @@ summary:focus-visible {
.topbar-actions { .topbar-actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 7px; gap: 6px;
} }
.topbar-context { .topbar-context {
@ -522,12 +523,12 @@ summary:focus-visible {
align-items: center; align-items: center;
min-width: 0; min-width: 0;
max-width: 168px; max-width: 168px;
gap: 5px; gap: 4px;
overflow: hidden; overflow: hidden;
color: rgba(215, 225, 218, 0.58); color: rgba(215, 225, 218, 0.58);
font-size: 11px; font-size: 10.5px;
font-weight: 720; font-weight: 700;
line-height: 16px; line-height: 15px;
white-space: nowrap; white-space: nowrap;
} }
@ -545,8 +546,8 @@ summary:focus-visible {
.topbar-branch-trigger svg { .topbar-branch-trigger svg {
flex: 0 0 auto; flex: 0 0 auto;
width: 13px; width: 12px;
height: 13px; height: 12px;
opacity: 0.72; opacity: 0.72;
} }
@ -572,8 +573,8 @@ summary:focus-visible {
.topbar-context-dot { .topbar-context-dot {
flex: 0 0 auto; flex: 0 0 auto;
width: 6px; width: 5px;
height: 6px; height: 5px;
border-radius: 999px; border-radius: 999px;
background: rgba(117, 217, 156, 0.88); background: rgba(117, 217, 156, 0.88);
box-shadow: 0 0 0 3px rgba(117, 217, 156, 0.08); box-shadow: 0 0 0 3px rgba(117, 217, 156, 0.08);
@ -598,7 +599,7 @@ summary:focus-visible {
.topbar-branch-menu { .topbar-branch-menu {
position: absolute; position: absolute;
top: 26px; top: 24px;
left: 7px; left: 7px;
z-index: 30; z-index: 30;
display: grid; display: grid;
@ -778,8 +779,8 @@ summary:focus-visible {
.topbar-icon-button { .topbar-icon-button {
position: relative; position: relative;
display: grid; display: grid;
width: 30px; width: 28px;
height: 30px; height: 28px;
place-items: center; place-items: center;
border: 1px solid rgba(213, 224, 255, 0.12); border: 1px solid rgba(213, 224, 255, 0.12);
border-radius: 7px; border-radius: 7px;
@ -799,8 +800,8 @@ summary:focus-visible {
} }
.topbar-icon-button svg { .topbar-icon-button svg {
width: 16px; width: 14px;
height: 16px; height: 14px;
} }
.topbar-action-badge { .topbar-action-badge {
@ -828,22 +829,22 @@ summary:focus-visible {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-width: 62px; min-width: 58px;
min-height: 30px; min-height: 28px;
gap: 6px; gap: 5px;
padding: 0 9px; padding: 0 8px;
border: 1px solid rgba(213, 224, 255, 0.14); border: 1px solid rgba(213, 224, 255, 0.14);
border-radius: 999px; border-radius: 999px;
color: var(--text-soft); color: var(--text-soft);
font-size: 11px; font-size: 10.5px;
font-weight: 820; font-weight: 820;
text-transform: uppercase; text-transform: uppercase;
} }
.status-pill-dot { .status-pill-dot {
flex: 0 0 auto; flex: 0 0 auto;
width: 6px; width: 5px;
height: 6px; height: 5px;
border-radius: 999px; border-radius: 999px;
background: currentColor; background: currentColor;
opacity: 0.92; opacity: 0.92;