From 8756c9a14092d08ede0179149cdcbdf69e8fd5a1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 10 Sep 2026 12:23:31 +0200 Subject: [PATCH] style: flat menu on the tiled ground in both views; tiled page cards - The tiled ground moves from .main-content to .app-body, so the menu sits on it too and the grid keeps one origin whichever view is showing. A second tile on .main-content would have started 210px in and seamed. - Desktop: the workspace sidebar is flat (transparent, no border), the same as the assistant rail, which drops the white box it briefly had. The phone sheets stay white because they slide over the page. - Workspace page cards get the assistant chat panel's tiled-white fill. Measured in Chromium: name card 848-892 at x=8, brand, switch and 210px width identical in both views, expanded and collapsed; no page scroll. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01W4rptBNvn6RYieQw54GXNS --- public/css/assistant.css | 12 ++++++------ public/css/styles.css | 23 +++++++++++++++++------ test/assistant-workspace-layout.test.js | 23 +++++++++++++++++++---- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/public/css/assistant.css b/public/css/assistant.css index 1356c679..3cbae761 100644 --- a/public/css/assistant.css +++ b/public/css/assistant.css @@ -563,17 +563,17 @@ body.assistant-mode-workspace .assistant-rail-workspace { display:flex; } body.assistant-sources-open .assistant-sources-fab { background:var(--blue-light); border-color:var(--blue-light); } } -/* Desktop: the rail is the same white sidebar the workspace uses, flush to the - window edge. It used to sit inside the content area's 14px padding, on the - tiled ground — so the menu changed background between the two views, the - name card sat 6px lower and further in, and the page was 28px taller than - the window. The 14px now belongs to the panels beside the rail. */ +/* Desktop: the rail is laid out as the workspace sidebar is, flush to the + window edge and flat on the page's tiled ground. It used to sit inside the + content area's 14px padding, so its name card sat 6px lower and further in + and the page was 28px taller than the window. The 14px now belongs to the + panels beside the rail. */ @media (min-width:961px) { body.assistant-workspace .main-content { padding:0; } body.assistant-workspace .assistant-layout { padding-right:14px; } body.assistant-workspace .assistant-main, body.assistant-workspace .assistant-side { margin-block:14px; height:auto; } - body.assistant-workspace .assistant-history { padding:0; gap:0; background:white; border-right:1.5px solid var(--g200); } + body.assistant-workspace .assistant-history { padding:0; gap:0; } body.assistant-workspace .assistant-rail-actions { padding:0 8px; } body.assistant-workspace .assistant-history .card { padding:0 8px; } /* Workspace links: the app's .tab-btn, full-bleed with the same inset. */ diff --git a/public/css/styles.css b/public/css/styles.css index 4055ea77..15b02d97 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -66,11 +66,20 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(-- } /* APP BODY LAYOUT */ -.app-body{display:flex;min-height:100vh;} +/* The tiled ground covers the whole page — menu and content alike — from one + origin, so switching between the assistant and a workspace page never moves + the grid or changes what the menu sits on. */ +.app-body{display:flex;min-height:100vh; + background-image:linear-gradient(var(--g100) 1px, transparent 1px), linear-gradient(90deg, var(--g100) 1px, transparent 1px); + background-size:28px 28px;background-position:-1px -1px;background-color:var(--g50);} /* SIDEBAR */ .sidebar{width:210px;flex-shrink:0;background:white;border-right:1.5px solid var(--g200);display:flex;flex-direction:column;position:sticky;top:0;height:100vh;overflow:hidden;z-index:100;transition:width 0.22s ease;} .sidebar.collapsed{width:0;border:none;overflow:hidden;} +/* Desktop: the menu is flat on the tiled ground, as the assistant's rail is — + a white boxed sidebar here made every workspace page look like another app. + A phone keeps the white sheet, because there it slides over the page. */ +@media(min-width:769px){ .sidebar{ background:transparent; border-right:none; } } .sidebar-header{display:none;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--g200);} .sidebar-title{font-size:13px;font-weight:700;color:var(--g700);} /* Head pinned, list scrolls, account card pinned. */ @@ -89,12 +98,14 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(-- /* MAIN */ /* One shell for every view. Each tab used to be a plain white page while the assistant and the workspace launcher sat on a tiled card, so opening any menu - item changed the whole face of the app. The tiled ground and the card edge - belong to the shell, so only the contents differ. */ -.main-content{flex:1;min-width:0;min-height:0;padding:14px;display:flex;flex-direction:column; + item changed the whole face of the app. The card edge belongs to the shell + and the tiled ground to .app-body, so only the contents differ. */ +.main-content{flex:1;min-width:0;min-height:0;padding:14px;display:flex;flex-direction:column;} +/* The page card carries the same tiled-white fill as the assistant's chat panel + (.assistant-main.card), so entering a workspace page keeps the surface. */ +.main-content > .tab-content.active{flex:1 1 auto;min-height:0;background-color:white; background-image:linear-gradient(var(--g100) 1px, transparent 1px), linear-gradient(90deg, var(--g100) 1px, transparent 1px); - background-size:28px 28px;background-position:-1px -1px;background-color:var(--g50);} -.main-content > .tab-content.active{flex:1 1 auto;min-height:0;background:white;border:1px solid var(--g200);border-radius:14px;box-shadow:var(--shadow);padding:20px;overflow:auto;} + background-size:28px 28px;background-position:-1px -1px;border:1px solid var(--g200);border-radius:14px;box-shadow:var(--shadow);padding:20px;overflow:auto;} /* The assistant brings its own full-bleed layout, so it takes the shell's place rather than nesting a second card inside it. */ .main-content > #assistant-tab.active{padding:0;border:none;box-shadow:none;background:transparent;overflow:visible;} diff --git a/test/assistant-workspace-layout.test.js b/test/assistant-workspace-layout.test.js index 1b8360e0..517a87ee 100644 --- a/test/assistant-workspace-layout.test.js +++ b/test/assistant-workspace-layout.test.js @@ -423,10 +423,24 @@ test('every view sits in the same shell, so opening a menu item is not a new app const css = read('public/css/styles.css'); // Each tab used to be a plain white page while the assistant and the workspace // launcher sat on a tiled card, so any menu click changed the whole face. - assert.match(css, /\.main-content\{[^}]*background-image:linear-gradient/, - 'the tiled ground belongs to the shell'); + // The ground covers the whole page, menu included, from one origin: a second + // tile on .main-content would start 210px in and seam against the menu's. + assert.match(css, /\.app-body\{[^}]*background-image:linear-gradient/, + 'the tiled ground belongs to the page'); + assert.doesNotMatch(css, /\.main-content\{[^}]*background-image/, 'and only to the page'); + // Flat menu on desktop, in both views; the phone sheet stays white. + assert.match(css, /@media\(min-width:769px\)\{ \.sidebar\{ background:transparent; border-right:none; \} \}/); assert.match(css, /\.main-content > \.tab-content\.active\{[^}]*border:1px solid var\(--g200\);border-radius:14px/, 'and every tab gets the same card edge'); + // ...and the same tiled-white surface as the assistant's chat panel, so a + // workspace page does not turn plain white on entry. + const tile = 'linear-gradient(var(--g100) 1px, transparent 1px), linear-gradient(90deg, var(--g100) 1px, transparent 1px)'; + const card = css.slice(css.indexOf('.main-content > .tab-content.active{'), css.indexOf('}', css.indexOf('.main-content > .tab-content.active{'))); + assert.ok(card.includes('background-color:white') && card.includes(tile) && card.includes('background-size:28px 28px'), 'page card is tiled white'); + const panel = read('public/css/assistant.css'); + // The top-level rule, not the phone override that also names .assistant-main.card. + const chat = (panel.match(/^\.assistant-main\.card \{[^}]*\}/m) || [''])[0]; + assert.ok(chat.includes('background-color:white') && chat.includes(tile) && chat.includes('background-size:28px 28px'), 'the same fill as the chat panel'); // The assistant brings a full-bleed layout, so it replaces the shell card // rather than nesting a second one inside it. assert.match(css, /\.main-content > #assistant-tab\.active\{padding:0;border:none/); @@ -535,14 +549,15 @@ test('the menu head reads toggle, mark, search — and account tabs are not list } }); -test('desktop: the assistant rail is the app sidebar, flush and white', () => { +test('desktop: the assistant rail is the app sidebar, flush and flat', () => { const css = read('public/css/assistant.css'); const styles = read('public/css/styles.css'); // Inside the content area's 14px padding the rail sat on the tiled ground, its // name card 6px lower and further in, and the page 28px taller than the window. const desk = css.slice(css.lastIndexOf('@media (min-width:961px) {')); assert.match(desk, /body\.assistant-workspace \.main-content \{ padding:0; \}/); - assert.match(desk, /body\.assistant-workspace \.assistant-history \{ padding:0; gap:0; background:white; border-right:1\.5px solid var\(--g200\); \}/); + assert.match(desk, /body\.assistant-workspace \.assistant-history \{ padding:0; gap:0; \}/, + 'flush, and flat on the tiled ground like the workspace sidebar'); assert.match(desk, /body\.assistant-workspace \.assistant-side \{ margin-block:14px; height:auto; \}/, 'the panels carry the 14px'); // Same insets as the sidebar: .menu-head, .assistant-mode-switch, .account-card. const rail = styles.slice(styles.lastIndexOf('@media (min-width:961px) {'));