Consolidate hand-rolled UI into a catalog + shared primitives

Consolidate hand-rolled UI into a catalog + shared primitives

#20 in tonybierman/dx-blog — merged 2026-05-31

Consolidates UI components that were hand-rolled across pages into reusable, consistently-styled primitives — reducing duplication and standardizing the app's look and feel. Built up over the commits below.

Commits on this branch

  1. Adopt Dioxus catalog components across reader UI — first pass swapping hand-rolled reader widgets for the catalog.
  2. Use catalog Input for the search box.
  3. Widen single-sidebar layouts; match facet dropdowns to navbar chrome — layout/chrome consistency.
  4. Convert UI buttons to the catalog ButtonButtonVariant (Primary/Secondary/Destructive/Outline/Ghost/Link) × ButtonSize.
  5. Adopt catalog Input/Textarea/Select for form fields — across the admin forms.
  6. Theme catalog components via tokens, not hard-coded colors — brand-map in dx-components-theme.css, no hex/rgb literals.
  7. Add surface/text primitives and adopt them across pages (final commit) — see below.

New project-local primitives (final commit)

  • components/surfacePanel (Filled / Outlined / Bleed × None/Sm/Md/Lg padding), Alert (Warning/Info/Success/Danger), Badge (Brand/Amber/Emerald/Red/Neutral × Tinted/Outlined, optional pulsing dot), StatusDot.
  • components/textPageTitle, SectionTitle (Default / Sidebar), Eyebrow (size/tone/as), ErrorText (block + inline).

Each conceptual element is now one component with named variant/tone/size enums, adopted across the reader, home, embeds, and all admin pages.

Notable fixes

  • Spacing/size are props, not appended classes. A conflicting mb-1/text-sm appended after a base mb-3/text-xs loses to Tailwind source order, so the override silently failed. The Mb/EyebrowSize props emit exactly one utility — restoring the intended appearance on the appearance section headings and the post editor's Markdown/Preview labels.
  • ErrorText inline variant absorbs the last inline <span> error sites (admin shell, taxonomy, settings, post editor).

Intended visual convergences (worth an eyeball in review)

  • Badges that were rounded px-1.5 (dashboard activity feed, reader "awaiting approval", comment status) are now the canonical rounded-full px-2 py-0.5 pill.
  • PageTitle's mb-6 now applies to home BentoGrid and reader TagFeed (previously no bottom margin) and SearchResults (was mb-4).
  • Post editor: category/status selects gained visible field labels; the empty option was renamed to "Uncategorized".

Deliberately left alone

  • The "New post" link is a router Link styled as a primary button; it's a single occurrence and the catalog Button renders a <button>, so it has no clean target.
  • <input type="file"> / range inputs have no catalog equivalent.

Verification

  • cargo check clean on both targets (server --no-default-features --features server,sqlite; wasm --no-default-features --features web --target wasm32-unknown-unknown).
  • cargo fmt --check passes.

🤖 Generated with Claude Code

Last updated 2026-05-31