Skip to content

Sidebar: the foot stands on the rows' grid and the pane's bottom edge; a host draws its own plans (0.3.13) - #24

Open
zeekay wants to merge 1 commit into
mainfrom
sidebar-foot
Open

zeekay wants to merge 1 commit into
mainfrom
sidebar-foot

Conversation

@zeekay

@zeekay zeekay commented Nov 2, 2026

Copy link
Copy Markdown
Member

The sidebar's foot is now aligned with the rest of the sidebar. The Quick setup card's edges sit on the same column as the words and icons above it, 16px in on both sides. Upgrade plan and the rail's account share one line on the pane's bottom edge, beside the rail and in the phone drawer, the same way the title row and the first rail icon sit on its top edge.

This PR also adds one optional prop, upgrade, on Host. A host that draws its own plans passes it, and every upgrade press in the package then calls it and does not navigate. Version 0.3.13.

The foot

Measured on hanzo.ai's own export, signed in on the free plan with the card showing:

before after
card left..right (1440) 52..276 60..268
text column ('Recents', New chat icon) 60 60
card title fits at 224px wide fits at 208px (Setup padding $2, a row's inset)
Upgrade row centre vs account centre, 1440 862 vs 870 (hanzo.ai, patched rail) 870 vs 870
Upgrade row centre vs account centre, 390 drawer 818 vs 810 (this package) 818 vs 818
list end to card / card to foot row 8 / 8 8 / 8

Beside the rail the sidebar's foot had 8px of padding. In the drawer it had none, while the rail's foot kept its 8px. So the account and Upgrade plan were on one line in one layout and 8px apart in the other. Now both feet are 0 (Sidebar and Rail pb), and the foot row stands on the pane's bottom edge. The space above the card is Recents' own flex fill and nothing more.

The upgrade link

The press already went straight to https://hanzo.ai/pay/cart?returnUrl=..., which answers 200 with no redirect. Nothing in this package writes billing.hanzo.ai. (The billing: "https://billing.hanzo.ai" in hanzo.ai's chunks is @hanzogui/shell's links map, read only by its Billing links, none of them an upgrade press.)

payUrl is still the one writer of the checkout address. On the checkout's own origin it now writes a path (/pay/cart?...); from any other origin, and in the prerender, it writes the whole address. term follows the same rule (local).

pay chooses the plan from ?plan= itself and reads what the viewer holds from their subscriptions, so no parameter for the viewer's current plan is added.

The host's plans

Host takes upgrade?: () => void. Every upgrade press goes through useUpgrade (host.tsx):

  • the sidebar's Upgrade plan and the shell's
  • Chat's header
  • the bar's Upgrade
  • the account menu's Get Pro and its plans row
  • Dev's plans (leave)
  • the composer's usage
  • Settings' model controls

Chat's paywall (Upgrade.tsx) hands its ask to the host instead of drawing its dialog. The prop is on Host rather than App because the shell's presses are drawn outside App.

Checks

  • pnpm typecheck
  • pnpm lint:design
  • pnpm build, and the dist root loads in Node
  • vitest run: 61 files, 577 tests

New tests:

  • The foot's shared padding and the card's inset (fails on the old source).
  • A host's upgrade takes Dev's plans press and the page goes nowhere (fails when useUpgrade ignores it).
  • payUrl and term on hanzo.ai, on other origins (a lookalike included) and in the prerender.

https://claude.ai/code/session_016DKtyuzxU43Gsc6Pm9vKTF

…; a host draws its own plans (0.3.13)

The Quick setup card stood on the rows' pill edge, 8px left of every word
and mark above it (52 against 60 at 1440), and the foot row and the
rail's account sat on one line only beside the rail: in the drawer the
rail's 8px foot put the account 8px above Upgrade plan. The cards now
stand inside a row's inset (ROW.px), 16px in on both sides, with Setup's
padding that inset so its title keeps its words; the foot row and the
account stand on the pane's bottom edge (Sidebar and Rail pb 0) beside
the rail and in the drawer, as the title row and the first mark stand
on its top.

The upgrade press already went straight to https://hanzo.ai/pay/cart,
which answers 200; nothing in this package names billing.hanzo.ai.
payUrl now writes the path on the checkout's own origin and the whole
address from any other, and term keeps the same form.

Host takes `upgrade`: a host that draws its own plans passes it, and
every upgrade press (useUpgrade) calls it and leaves nothing: the
sidebar's and the shell's Upgrade plan, Chat's header, the bar's
Upgrade, the account menu's Get Pro and plans row, Dev's plans (leave),
the composer's usage and Settings' model controls. Chat's paywall hands
its ask to the host instead of drawing its dialog. On Host and not App,
because the shell's presses are drawn outside App.

Claude-Session: https://claude.ai/code/session_016DKtyuzxU43Gsc6Pm9vKTF
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