Skip to content

fix(ui): titlebar tabs connect into the page + unify desk tint#117

Merged
eliotlim merged 3 commits into
mainfrom
fix/titletabs-ui-design
Jul 10, 2026
Merged

fix(ui): titlebar tabs connect into the page + unify desk tint#117
eliotlim merged 3 commits into
mainfrom
fix/titletabs-ui-design

Conversation

@eliotlim

@eliotlim eliotlim commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Problem

On the desktop, the in-window titlebar tabs (Chrome/Arc style) read as small, shadowed floating cards that sat above the page, disconnected from the content below. The active tab looked no more anchored to its page than the inactive ones. At the same time the "desk" the page sheets sit on used a distinct neutral tint (--desk), so the warm chrome tint of the sidebar/titlebar broke at the sheet's corners instead of running continuously around the window.

An earlier revision of this PR tried to connect the tab by squaring the sheet's top corners and dropping its whole top border on desktop — that flattened the sheet into a slab, so the tab still read as detached (review feedback). For the "tab extruded from the page" metaphor to work, the sheet needs to keep both its rounded corners and its full top border, with the border opening only where the active tab connects.

Solution

The sheet stays a fully rounded, bordered card on both platforms; the desktop connects the active tab into it with a 1px overlap:

  • index.css — the desk (.ob-desk) carries the same tint as the sidebar/titlebar (--sheet-1 instead of neutral --desk), so the chrome tint runs continuously and the sheets read as floating on one book cover. When the in-window titlebar is present, the cover row (.ob-desk-row[data-titlebar='true'], the desk's overflow-hidden wrapper) is pulled up 1px (margin-top: -1px), riding the sheet's top border into the titlebar's lower edge. The pull-up must sit on the row, not the desk: the row clips its children, so a desk-level negative margin pushes the border strip outside the clip box and erases the whole top border (a bug an intermediate revision had — the border must stay visible everywhere except under the tab). Moving the row moves its clip box with it. The sheet itself is untouched: rounded corners, full border, shadow — everywhere.
  • TitlebarTabs.tsx — the active tab drops the floating gap + shadow, grows to h-8, takes the page's fill with a hairline top+side border open at the bottom (border-b-0, rounded-t-md), and gets relative z-[1] so its fill paints over the sheet's top border in that 1px overlap. The sheet's border is thus interrupted only under the active tab — the page extrudes up into its tab. Inactive tabs float above the connection line (mb-1, h-7, fully rounded, muted).
  • DefaultLayout.tsx — names the cover row (ob-desk-row) and wires inWindowTabs from useNavigation() onto it as data-titlebar, gating the pull-up to the desktop shell.
  • web/src/pages/index.tsx — the ?shell=desktop preview seam now also sets --ob-inset-top: 0px, mirroring the real Tauri shell (App.tsx). Without it the preview kept the web's 6px top inset, so the tab floated a gap above the page — the source of the detached look in the earlier captures.

Target design, per platform:

  • Web: rounded sheet corners (page + side pane), border all around, sidebar-colour desk behind the sheet.
  • Desktop: the same, except the border opens where the active tab connects to the page sheet.

Purely presentational: no data, API, routing, or behavioural change.

Before / After

Live captures from the running app (next dev, fresh workspace + sample document, two tabs: sample inactive, Home active). Desktop rendered via the ?shell=desktop preview seam; web is the plain app.

Desktop — titlebar ↔ page junction

Theme Before After
Light
Dark

Before: the active tab is a floating rounded pill with a gap and seam line below it. After: the active tab merges flush into the page sheet; the sheet keeps its rounded top corners and its top border everywhere else. Pixel-probed on the captures: the 1px border row is present at both flanks of the active tab (light rgb(232,230,227), dark rgb(56,56,56)) and absent directly beneath it (continuous tab→page fill).

Desktop — full window

Theme Before After
Light
Dark

Web — no in-window tabs

Theme Before After
Light
Dark

On the web only the desk tint changes (--desk--sheet-1); the sheet was and remains a fully rounded, bordered card.

Test procedure

  1. pnpm verify — green (see counts below).
  2. Desktop shell preview: pnpm --filter @book.dev/web dev, open /?shell=desktop, insert the sample document, add a second tab with "+", switch tabs. Confirm the active tab merges into the page (border open only under it), inactive tabs float, sheet corners stay rounded, and the desk tint matches the sidebar/titlebar.
  3. Web (no ?shell=desktop): confirm the page sheets remain fully rounded bordered cards and only the desk background tint changed.
  4. The captures above were produced by a throwaway Playwright script driving both states live (main on one port for Before, this branch on another for After), light + dark via colorScheme emulation; the script is not committed.

Operational notes

  • UI-only, four files (packages/ui/src/components/TitlebarTabs.tsx, packages/ui/src/index.css, packages/ui/src/layouts/DefaultLayout.tsx, packages/web/src/pages/index.tsx). No migration, no config, no server change.
  • The web/src/pages/index.tsx change only touches the ?shell=desktop preview seam (Chromatic/e2e); production web never enters that code path.
  • Dark theme handled: --sheet-1, --background and --border are defined per-theme, so the merge renders correctly in both (see captures).
  • Present mode keeps its own neutral --desk backdrop.

pnpm verify: green (exit 0) — build:libs + typecheck + lint clean; unit sdk 171 / ui 948 / server 645 passed; server e2e 251 checks + MCP e2e 40 checks passed. (Web Playwright suite runs separately in CI.) · gate: design (Devon) — visual change, full before/after matrix embedded above.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app.book.pub Ready Ready Preview, Comment Jul 10, 2026 12:09am

Request Review

… into it

The earlier approach squared the sheet's top corners and dropped its whole
top border under the desktop titlebar, which flattened the sheet and left
the active tab reading as detached. Instead: the desk pulls up 1px under
the titlebar (margin-top: -1px) and the active tab takes relative z-[1],
so its fill paints over the sheet's top border only in the 1px strip where
they meet — the border opens under the connecting tab and nowhere else,
and the sheet stays a fully rounded, bordered card on both platforms.

Also aligns the ?shell=desktop preview seam with the real Tauri shell
(--ob-inset-top: 0px); the preview's leftover 6px web inset was the gap
that made the tab float in the earlier captures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w
…r survives

The 1px titlebar-merge pull-up lived on `.ob-desk`, which clips its
children (`overflow-hidden`): the negative margin pushed the sheet's
top-border strip outside that clip box and erased the top border, so the
active tab still read as a detached pill (the "still-detached" look flagged
in review). Move the pull-up onto the desk's `overflow-hidden` row wrapper
(`.ob-desk-row[data-titlebar]`) and carry `data-titlebar` there in
DefaultLayout: the row's clip box travels with the border, so the border
stays visible and is interrupted only under the active tab — the page
extrudes up into its tab as intended, on both light and dark themes.

Purely presentational; ui typecheck + lint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w
@eliotlim eliotlim merged commit 6d28839 into main Jul 10, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant