frontend
Technical notes on web development, DevOps, and AI integration.
37 articles
- 11:22frontend
Mirroring the Status Transition Map in the Frontend
A tiny frontend mirror of the backend transition map: one union type, one map, and impossible options disabled before the click.
TL;DR: I refactored the tangled status logic into a clean switch that maps six statuses to four display stages. A lean NEXT_STATUSES map only decides which options light up, leaving the backend as the true authority that returns 409s. I added type guards, fallback labels for unknown statuses, and real disabling beyond just aria-disabled.
#frontend#typescript#state-machine - 13:59frontend
One Design Language for Every Page
The homepage redesign left five subpages looking like a different website. The fix was not restyling each page by hand but extracting shared components.
TL;DR: Shipping a polished homepage exposed inconsistent spacing, heroes and buttons across other pages. Instead of patching each page, the fix extended two components, page-hero.tsx and page-cta.tsx, plus a borderless card pattern using layered gradients, CSS variable tokens and consistent pill buttons. Pages now share the same visual language through props while keeping unique content, so updates happen in one place.
#css#design#frontend - 00:44frontend
[Placeholder] Was the Feature: Typed Content Cards
Company cards changed shape three times in a week, but the typed content contract held: optional fields plus truthiness guards make empty data hide itself.
TL;DR: Building a bilingual Next.js company profile, I kept adding card fields and filling gaps with placeholder strings. Turns out optional TypeScript properties plus truthiness guards meant absent data simply never rendered, no helper logic needed. Typed content files beat a headless CMS at this scale, surviving three redesigns with zero component changes.
#typescript#react#nextjs - 18:35frontend
Why I Put 92% Alpha in My Header Token Instead of Using bg-white/60
Dark navy header felt heavy in light mode. The fix: bake 92% alpha into the --color-header token so backdrop-blur works everywhere without per-component overrides.
TL;DR: Slapping bg-white/60 on a navbar breaks fast, since child elements inherit transparency and fixes scatter across files. The fix is baking alpha into a --color-header token (about 92 percent opacity), which cascades to every consumer and pairs cleanly with backdrop-blur-md. Trade-off: the header decouples from the global background token, but one line brings it back if needed.
#css#tailwind#design - 02:26devops
The Sidebar Said 30, the Ring Said 92
Two numbers for one server: risk score and health score point in opposite directions, and my sidebar was still reading the old one.
TL;DR: A dashboard showed conflicting scores for the same server because the sidebar still read the old risk-based fields (100 means critical) while everything else used the new health-based ones (100 means healthy). The lesson: invert metric direction once at the API boundary, never per component. Treat opposite-direction metric renames as data contract migrations, not simple renames.
#monitoring#frontend#observability - 14:17frontend
Fullscreen Mobile Chat Under a Fixed 66px Header
Fullscreen mobile wrapper under a 66px fixed header using mt-66px plus calc 100dvh-66px, uncapped transcript, and a compact messaging header.
#css#tailwind#frontend - 12:43frontend
A Separate Mobile Chat Component With One Answer Logic
My mobile chat needed its own messaging-app-style frame, but the answer logic stays single-sourced by reusing the exported TurnBody.
TL;DR: A desktop three-column chat layout doesn't survive shrinking to phones, so the author built a separate mobile thread component using the familiar messaging-app pattern. Sticky header, chat bubbles, composer, all done with CSS sticky and backdrop-filter. Only the frame is duplicated; shared TurnBody logic keeps desktop and mobile in sync.
#react#frontend#ux - 16:57frontend
Badge [2] in the Sidebar Isn't the Second Card You See
Citation badges in the sidebar list are computed with indexOf from the original array, not the filtered iteration position, so numbers stay truthful.
TL;DR: While refactoring a chat sources sidebar, badge numbers were computed over a filtered array, so dropping knowledge entries shifted every web source's number and broke reference links. The fix: compute numbers with indexOf on the original turn.sources, so badges always match answer references. Lesson: reference numbers must come from original data, not filtered display order.
#react#frontend#ux - 16:41frontend
It's Never Just a Re-Render
Knowledge cards now render inline below the chat answer; reusing the card component takes a named export, unique per-panel ids, and its own expand state.
TL;DR: Moving knowledge cards inline into the chat answer panel sounded trivial but broke two hidden contracts. SourceCard became a named export, and card ids got a prefix to avoid duplicate ids across the document. Expanded state now lives locally per panel, keyed by turn and slug, so opening a card in one panel doesn't leak into the other.
#react#frontend#ux