Skip to content

refactor(ui): migrate to Fluid Functionalism, and ask for tax residency - #32

Merged
suiramdev merged 7 commits into
devfrom
refactor/fluid-functionalism-ui
Sep 18, 2026
Merged

suiramdev merged 7 commits into
devfrom
refactor/fluid-functionalism-ui

Conversation

@suiramdev

Copy link
Copy Markdown
Owner

Summary

Migrates the interface to the Fluid Functionalism registry and lands four product changes on it: settings category rows carry a fixed chip so the icon stops overflowing, the budget and recurring charts sit on Elevated again, onboarding asks for tax residency as a multi-select rather than one country, and the bank list fades its scrolling edge. The tax-residency change reaches the schema: user.country String? becomes user.taxCountries String[], and listInstitutions fans out across them. Start with packages/ui/src/styles/globals.css and packages/api/src/routers/bank-connection.ts.

Motivation

  • The settings category icon overflowed its row, and the chart cards had gone flat against the page.
  • One country cannot express a person taxed in several jurisdictions, which decides both the banks they can link and the categorisation rules applied.
  • The registry gives the app one surface ladder, one size system and one motion vocabulary.
  • A failed bank-provider call was indistinguishable from a country with no banks, so a user whose call failed concluded their bank was unsupported.

Drawbacks

  • packages/ui/src/components is vendored source that has been hand-patched. A re-pull overwrites the patches silently; packages/ui/AGENTS.md records an inventory and the baseline commit, but nothing enforces it.
  • The diff is large because the registry arrives wholesale. The product changes are a small part of it.
  • BankingProvider.listInstitutions returns an Effect now, so a future adapter must model its own failure.
  • The seven .tsx subpath exports are listed one by one: Node does not fall back across an exports entry whose file is absent.

Prior art

  • The previous shadcn/ui primitives, which this replaces; the UiLabels seam is extended rather than rebuilt.
  • Rejected shadcn add --overwrite for items already installed: it reverts lib/utils.ts and every local patch.
  • Rejected a country join table as more schema than a string array earns here.
  • Rejected marking the bank list from isError alone: it cannot say which country failed.

Notes

  • No visual change beyond the four described; screenshots in the first comment.
  • Docs updated: guides/first-steps, guides/bank-connections, concepts, contributing/data-model, contributing/bank-provider, integrations/api, integrations/procedures, self-hosting/bank-providers, self-hosting/troubleshooting.
  • Migration 20260918120000_user_tax_countries rewrites user.country into user.taxCountries, preserving values.
  • Breaking for adapters: listInstitutions returns Effect<ProviderInstitution[], BankInstitutionsUnavailable>; the procedure returns { banks, unavailableCountries }.
  • Tests: bank-rows.test.ts covers the country:id institution key; utils.test.ts pins the ease-fluid merge.
  • packages/api/src/categorisation/merchant-key.test.ts fails identically on origin/dev — not introduced here.
  • Removes four unused dependencies and a duplicate framer-motion; THIRD-PARTY-NOTICES.md carries the Fluid Functionalism MIT notice.
  • Review: five reviewers over disjoint slices raised 18 findings; all fixed and re-reviewed.

Install the Fluid Functionalism registry components (button, badge, card,
dialog, dropdown, select, sidebar, table, tabs, tooltip, input-group,
checkbox-group, command-menu, scroll-area) into packages/ui via the shadcn
CLI, and migrate every call site in apps/web to their APIs.

- Root SizeProvider (compact) keeps the app's control density; IconProvider
  maps the shared icon slots to Remix icons.
- Dropdown call sites move to the flat-index MenuItem API; the account
  menu's Language/Theme submenus flatten to labeled sections (no submenu
  in Fluid Functionalism), and the docs page follows.
- The assistant model picker rebuilds on CommandMenuDialog; the old
  dropdown-menu/command modules are deleted, and the addon-style input
  group survives as input-addons.tsx for the prompt box.
- Button/Badge/Tabs/Select/Tooltip variants remap onto the new APIs.

Signed-off-by: suiramdev <me@suiram.dev>
Continue the Fluid Functionalism migration and land four product
changes on top of it:

- Settings category rows carry a fixed 28px chip so the icon stops
  overflowing its row.
- The budget and recurring charts sit on `Elevated` again, so the
  cards read as surfaces rather than flat panels.
- Onboarding asks for tax residency rather than a single country:
  `user.country` becomes `user.taxCountries`, and the bank list fans
  `listInstitutions` out across them and dedups on `country:id`.
- The bank list fades its scrolling edge, like every other list.

Signed-off-by: suiramdev <me@suiram.dev>
- The tax residency step threads the whole selection through
  `onCountriesChange`, so the combobox clear button empties every chip
  instead of removing one.
- The chips field carries an accessible name once a chip hides the
  placeholder.
- The companion chart selectors set `size` on the `Select` root, so the
  popup rows match the trigger they open from.
- Filter chips paint their focus ring on the badge; a `display: contents`
  button generates no box to paint one on.
- `ffIcons` maps every registry name the interface reaches, so no slot
  falls through to a lucide glyph beside a Remix one.
- `AppSidebar` drops the branch the offcanvas switch made unreachable.

Signed-off-by: suiramdev <me@suiram.dev>
- Hoist every `@keyframes` out of `@theme inline`. Tailwind emits a
  theme keyframe only when a scanned file names it, and the button
  spinner names its animation from a JS inline style, so the spinner
  never moved at any of the 26 `loading` call sites.
- Move the component CSS into `@layer components`, so the
  `[--scroll-fade-size:32px]` utility can beat the 48px default the
  popup viewports were silently getting.
- Drop nineteen `@theme inline` entries that back no utility.
- List the seven `.tsx` subpaths in `exports`. Node does not fall back
  across an array entry whose file is absent, so the wildcards alone
  left them unresolvable outside Vite and Bun.
- Read every remaining primitive string from the `UiLabels` seam, so a
  French reader stops getting English on the sidebar, the card dismiss,
  the command menu and the file thumbnail.
- Standardise on `motion`: one animation runtime instead of two copies
  that could not share React context.
- Drop four unused dependencies, and restore the `ease-fluid` merge
  extension that kept a caller's easing from losing to the base class.
- Validate the `countries` input and bound the provider fan-out.
- Report the countries whose provider call failed, so a failure stops
  looking like a bank that is not supported.
- Record the Fluid Functionalism MIT notice, and correct the census.

Signed-off-by: suiramdev <me@suiram.dev>
… records

Wrapping the vendored CSS in `@layer components` let shadcn's own
`scroll-fade` utility win, so the vertical fade ran shadcn's engine at a
96px reveal while the horizontal one ran the registry's at 48px, and the
`[--scroll-fade-size:32px]` override reached the gradient but not the
reveal. Keep the rules unlayered so they outrank the utility, and move
the 48px default into each `var()` fallback so no declaration of ours
competes with the override.

Also replace five `cn` fixtures whose class strings this branch's own
rewrites had already changed, and record five vendored API patches the
inventory had missed.

Signed-off-by: suiramdev <me@suiram.dev>
The engineering bullets named a svg rule that is on `SidebarMenuAction`
rather than `SidebarMenuButton`, inverted `MenuRowLabel`'s child order,
cited a composer this branch deletes, described a diff the tax-residency
step does not perform, and claimed the merchant label carries its total.

The pages told an operator that a wrong Powens client id fails the bank
list, which it cannot: that call sends no token and reads only the
domain. The bank guide promised a row for every jurisdiction and a
sub-line on every row, and documented neither the unavailable-countries
notice nor the two cases that drop a jurisdiction. The quickstart still
asked for one country, and the recurring filters listed one badge where
the strip carries one per pick.

Signed-off-by: suiramdev <me@suiram.dev>
…ards

The sub-line carries the country only when the list spans more than one
jurisdiction, and the identifier code only when the provider supplies
one, so a default Powens install with one residency shows no sub-line at
all. There are four guarded handlers, not five: the fifth match was the
helper's own definition.

Signed-off-by: suiramdev <me@suiram.dev>
@coderabbitai

coderabbitai Bot commented Sep 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 42a9f3b2-5c2b-49a3-870f-0e39aba17664

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@suiramdev
suiramdev merged commit 1303541 into dev Sep 18, 2026
3 checks passed
@suiramdev
suiramdev deleted the refactor/fluid-functionalism-ui branch September 18, 2026 21:48
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