feat(ui): migrate to HeroUI v3 and rebuild the marketing landing - #7
Draft
sardorml wants to merge 14 commits into
Draft
feat(ui): migrate to HeroUI v3 and rebuild the marketing landing#7sardorml wants to merge 14 commits into
sardorml wants to merge 14 commits into
Conversation
Replaces two overlapping UI stacks — shadcn/Radix in the dashboard and antd v6 on the marketing pages — with HeroUI v3 everywhere. Both are gone from apps/web, along with @base-ui/react, class-variance-authority and tw-animate-css. @captureflow/ui shrinks to what HeroUI has no equivalent for: the theme tokens, ThemeToggle and cookie helpers, cn(), AvatarGroup, GridLoader and VisibilityPicker. Its per-primitive subpath exports are dropped. The marketing tree kept an antd-shaped API in a lot of places, so components/marketing gains local Row/Col/Flex, typography and small-UI shims rather than rewriting every section's layout call sites at once. Landing work on top of the migration: - pricing rebuilt as two subgrid-aligned cards with a gradient panel; the managed card's storage tiers are a segmented switch that drives the headline price, the CTA target and the storage highlight - hero CTAs are platform install buttons plus a signup line, icon strip and a link to the download page - footer wordmark is a dashed SVG outline; nav loses the theme switch and marketing is dark-only via MarketingShell - the collaboration block splits into one titled section per capability Theme fixes that were masking content app-wide: - HeroUI's dark --field-background equals --surface with a 0px transparent border, so any Input inside a Card was invisible; fields now recess to the canvas with a real border - the light theme inverts --color-neutral-*, and nothing restored it for a dark subtree inside a light root, so text-neutral-900 painted white on white in MarketingShell - MarketingShell now sets the baseline text color; nothing sets one on <body>, so anything inheriting (a HeroUI Accordion trigger) fell back to the UA default and rendered near-black - Col resolved one order for every breakpoint, so flipped sections put the feature list above the mockup on mobile Dashboard fixes: dead Upgrade and Invite triggers (React Aria's usePress stops click propagation, so the trigger is cloned with a handler instead of wrapped), the upgrade modal rebuilt around the same storage switch, share-dialog selection made visible via Radio.Content, plus card padding, alignment and type-scale corrections.
Brings the popup onto the same component vocabulary as the web app — Button, Select, Switch, Meter, Alert and Card from @heroui/react in place of the hand-rolled Tailwind elements — and adds the Tailwind v4 Vite plugin so wxt compiles the stylesheet. Net removal: the panels lose ~360 lines of bespoke markup.
Section 7 described antd v6 and the shadcn kit. Rewrites it around HeroUI: the React Aria prop vocabulary (onPress, isDisabled, isSelected), compound parts as statics, buttonVariants for anchors, and which semantic color names belong to HeroUI's theme rather than ours.
The modal portals to <body>, so it lands outside MarketingShell and resolved its theme off <html> — a white dialog with dark text over the dark landing whenever the app cookie said light. Re-declare the theme on the backdrop, which is the outermost portalled node.
Windows, Chrome and Firefox were disabled lg buttons with a Soon chip inside — three filled pills reading as CTAs competing with the one real download, for things nobody can click. They're status, so they render as a muted icon + label line under the requirements note instead.
HeroUI's Typography emits text-align:start by default, which beats the centered ancestor — the heading and subtitle sat left of the logo. Pass align explicitly, as the marketing sections already do. Chrome moves out of the "coming soon" line into a live secondary button beside the macOS download. It points at "#" until CHROME_WEBSTORE_URL is set; setting that constant swaps in the store link and the new tab.
"Download for Apple Silicon Macs (Beta)" dwarfed the Chrome button beside it. The requirements line under the pair already says "Requires macOS 14 or later on Apple Silicon", so the qualifiers were duplicated anyway.
HeroUI's secondary variant paints its label with --accent-soft-foreground over the same grey fill tertiary uses, and blue on grey reads as a disabled control rather than an alternative action — the hero's "Add to Chrome" looked dead beside the primary download. Switches the hero install button, the download page's Chrome CTA, the mobile nav's Log in, and the marketing Button shim's `default` type (which covers "Suggest a feature") to tertiary, which leaves the label at currentColor.
"Download for macOS" and "Add to Chrome" are different lengths, so shrink-to-fit buttons came out visibly lopsided. Lays them out as equal grid columns capped at max-w-md, stacking full width below sm.
Grey on a dark page recedes next to the blue primary. Both Chrome CTAs — hero and download page — now render as a white pill with dark text, the same treatment the plan cards' CTA uses. Overrides .button's own --button-* colour vars rather than passing bg-* utilities: HeroUI's component styles land after Tailwind's, so its background-color rule wins over a bg-* class at equal specificity.
Drops the split layout — the desktop-only carousel panel took half the viewport and forced the form into the right pane. The shell is now one centered column with the wordmark at the top, and AuthCarousel goes with it since nothing else rendered it. Reorders the form email-first to match: an email field with a leading mail icon and a Continue button, an OR rule, then Google and GitHub. The password (and name, on signup) moves to a second step that shows the captured address with a way back to change it. Buttons are pills. No terms/privacy line — those pages don't exist yet.
The input and the buttons were three different heights: InputGroup is a fixed min-h-9 (36px) with no size variant, and HeroUI's .button--lg drops from 44px to 40px at md and up. Pins every control to h-11 so the column reads as one stack, and opens the vertical rhythm to 20px gaps with a 32px divider. Also corrects the comment added with the white Chrome pill: it claimed a Tailwind bg-* utility loses to .button's background-color rule. The bundle has it the other way round — utilities land after HeroUI's component styles and win at equal specificity. Overriding the --button-* vars is still the right call, but because hover and pressed follow from the same place, not because bg-* wouldn't apply.
Column 440 -> 360px, controls 44 -> 38px, heading 30 -> 22px, body text 13px, and the gaps tighten to match. Sizes are px rather than HeroUI's rem-based ones so the column keeps its proportions regardless of the browser's root font size, and so .button--lg's 4px drop at md doesn't desync the buttons from the input.
Header becomes an identity block — avatar beside the name and address, not the name alone above it. Nav items gain an optional trailing slot, used for the Billing row's Free/Pro chip. A theme row with an inline segmented control sits above Sign out, which retires the standalone toggle from the top bar. The dashboard's list fills out to match: Billing, Profile, Connected devices, Settings, Feedback, Contact support, Sign out. Billing has no page of its own — it opens the upgrade modal via ?upgrade=1. The segmented control is two-way (light/dark), not the reference's three: Theme is typed "light" | "dark" and resolved from a cookie server-side, so a "system" option needs OS-preference detection before first paint to avoid a flash. Out of scope here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces two overlapping UI stacks — shadcn/Radix in the dashboard and antd v6 on the marketing pages — with HeroUI v3 across
apps/weband the extension popup, then rebuilds the landing on top of it.Based on
feat/extension-complete(#6), so the diff here is the UI work only.What's in it
The migration.
antd,@ant-design/*, all@radix-ui/*,@base-ui/react,class-variance-authority,shadcnandtw-animate-cssare gone fromapps/web.@captureflow/uishrinks to what HeroUI has no equivalent for — theme tokens,ThemeToggle+ cookie helpers,cn(),AvatarGroup,GridLoader,VisibilityPicker— and drops its per-primitive subpath exports. The marketing tree kept an antd-shaped API in a lot of call sites, socomponents/marketinggains localRow/Col/Flex, typography and small-UI shims instead of rewriting every section's layout at once.Landing. Pricing is two subgrid-aligned cards with a gradient panel; the managed card's storage tiers became a segmented switch that drives the headline price, the CTA target and the storage highlight. Hero CTAs are platform install buttons plus a signup line, icon strip and download link. Footer wordmark is a dashed SVG outline. Nav loses the theme switch — marketing is dark-only via
MarketingShell. The collaboration block splits into one titled section per capability.Theme bugs that were masking content app-wide. Each of these hid real UI rather than just looking off:
--field-backgroundis the same value as--surfacewith a 0px transparent border, so anyInputinside aCardwas invisible. Fields now recess to the canvas with a real border.--color-neutral-*for ~900 legacy utilities, and nothing restored the upright scale for a dark subtree inside a light root —text-neutral-900painted white on white insideMarketingShell.<body>, so anything that inherits rather than picking a token (a HeroUIAccordiontrigger) fell back to the UA default and rendered near-black.MarketingShellnow sets the baseline.Colfolded every breakpoint'sorderinto one value, so thelgorder applied on mobile too and flipped sections put the feature list above the mockup.Dashboard. Dead Upgrade and Invite triggers — React Aria's
usePresscallsstopPropagation()on click, so an ancestoronClicknever fires; the trigger is cloned with a handler instead of wrapped (it has to stay an element, not a render prop, because server components render it). The upgrade modal is rebuilt around the same storage switch as the plan card. Share-dialog selection is visible again viaRadio.Content— plain children skip it and render no selected state. Plus card padding, alignment and type-scale corrections.Testing
pnpm typecheck— clean across all 7 projectspnpm --filter @captureflow/web test— 26/26Not run: the production build. A
next buildwhilenext devis servingapps/webcorrupts.next, and the dev server was up throughout. Needspnpm --filter @captureflow/web buildon a quiet tree before this leaves draft.Also unverified by machine: the visual result. Every fix above was checked against the running dev server's rendered HTML and compiled CSS, not screenshotted.