Skip to content

Flexion Labs initial build: catalog, views, styles, CI#2

Merged
danielnaab merged 55 commits intomainfrom
feat/initial-build
Apr 28, 2026
Merged

Flexion Labs initial build: catalog, views, styles, CI#2
danielnaab merged 55 commits intomainfrom
feat/initial-build

Conversation

@danielnaab
Copy link
Copy Markdown
Member

@danielnaab danielnaab commented Apr 28, 2026

Summary

Initial implementation of the Flexion Labs website per notes/specs/2026-04-27-flexion-labs-website-design.md and notes/plans/2026-04-27-flexion-labs-website.md. Bun + Hono SSG, TypeScript, hand-rolled CSS with cascade layers and Flexion brand tokens, HTML Web Components for progressive enhancement, GitHub Pages deployment with per-branch previews via GitHub environments, daily catalog refresh with auto-merge.

37 TDD-ordered commits; 70 tests passing across catalog logic, standards evaluation, views, enhancements, build smoke, and a11y scan.

What's included

  • Catalog pipeline (catalog/): types, defaulting rules, YAML overrides, markdown overlays, merge, loader, GitHub API refresh script.
  • Standards (standards/): README/license/contributing/activity/tier checks feeding the health report.
  • Views (views/): home, work index, work detail (one per repo), health, commitment, about — all server-rendered via Hono JSX.
  • Styles (styles/): cascade layers (reset, tokens, base, layout, components, utilities) with every Flexion brand color tokenized, container queries for reflow, AAA-minimum contrast.
  • Enhancements (enhancements/): <catalog-filter>, <sortable-table>, <copy-button> HTML Web Components; bundled to register.js at build time.
  • Build driver (build/): renders every route to dist/ with a configurable base path for preview deploys.
  • CI/CD (.github/workflows/): deploy.yml builds, tests, scans a11y, publishes to gh-pages production (/) or preview (/preview/<branch>/) with GitHub Deployment environments; refresh-catalog.yml runs daily, opens an auto-merging PR when the snapshot changes.
  • Docs (docs/): per-area behavioral docs + per-view "when/then" specs that map 1:1 to tests.
  • Catalog snapshot: 73 public repos seeded from the live GitHub API.

Known follow-ups

  • content/work/messaging.md and content/work/forms.md reference slugs that don't match any public repo in the current snapshot. They won't render a detail page until the corresponding repos exist (or the overlays are renamed to match real repos). document-extractor does match and renders.
  • All 73 repos currently tier=unreviewed. Override entries in catalog/overrides.yml need to be authored before launch to promote the featured and actively-maintained repos.
  • Custom domain (labs.flexion.us) needs to be configured in GitHub Pages settings after this merges. CNAME file is in place.
  • preview and production GitHub environments need to be created in the repo settings to surface deployment URLs on PRs.

Test plan

  • bun test — 70 tests passing
  • bun run build — 78 HTML pages generated (home, work index, work detail ×73, health, commitment, about) in under 1 second
  • bun test tests/a11y — zero axe-core violations on all 5 static pages
  • Verify preview deployment at labs.flexion.us/preview/feat-initial-build/ after merging infrastructure
  • Visual inspection of rendered pages
  • Author initial catalog/overrides.yml entries for featured and actively-maintained repos

Implements three reusable components for displaying repository information:
- Badge: variant-based labeling for tiers, categories, and check results
- RepoCard: summary card with name, description, and metadata badges
- StandardsList: evaluation results display for repository standards

All components include comprehensive test coverage.
Dissolve src/web/ — the design system is now a first-class concern:
- src/design/ owns all stateless UI: CSS, components, templates, assets
- src/pages/ owns route entrypoints that pass data into design components
- src/ now has 4 top-level dirs: build/, catalog/, design/, pages/

Each component gets its own subdirectory (forms-lab pattern):
- Per-component styles.css split from the monolithic components.css
- Tag, button, link, select, card, side-nav stubs ready for implementation

Add compositions layer (l-stack, l-cluster, l-sidebar) for layout utilities.
CSS layers: reset, tokens, base, compositions, layout, components, utilities.
Build copies only .css files to dist/design/ via new copyCssTree helper.
Add per-component design system with forms-lab-style organization:
each component gets index.tsx + styles.css + examples.tsx in its
own directory under src/design/components/.

New components:
- Tag (replaces Badge, uses data-variant attributes)
- Button (primary/secondary/text, renders <a> or <button>)
- Link (external variant with icon via CSS mask-image)
- Select (label + styled select with custom chevron)
- Card (generic container with tango top-border)
- Side nav (CSS-only sticky vertical nav)

Add compositions layer (l-stack, l-cluster, l-sidebar) for layout.
Add /design-system/ showcase page with all components and tokens.
Apply components: filter uses Button+Select, external links use Link,
Badge migrated to Tag throughout.

Match flexion.us favicon: 4 PNG sizes (32, 180, 192, 270) plus SVG.
- Headings get margin-block-end: 0.5em (connects heading to content)
- h1 keeps tighter line-height (1.15), h2-h4 use 1.2
- Paragraphs get margin-block-end: 1em for proper prose flow
- Lists in prose contexts restore disc/decimal markers and indentation
  (scoped via :where() to avoid affecting nav/UI lists)
- Definition list terms get font-weight: 600
- Content-page headings use larger top margins (--space-7 for h2,
  --space-6 for h3) to create clear section breaks
- Remove content-page grid gap — element margins handle prose flow
Remove the "FL" placeholder SVG favicon — use only the real Flexion
brand mark PNGs from flexion.us. Drop the SVG icon link from <head>.

Add missing prose typography for markdown content:
- blockquote: left border accent, subtle text, padding
- code/pre: monospace font stack via --font-mono token, background
  tint, proper sizing (0.9em inline, --step--1 for blocks)
- hr: clean single-line rule with vertical margin
- small: maps to --step--1
- Last-child margin prevention to avoid double-spacing in containers

Extract font stacks into tokens (--font-sans, --font-mono) so
base.css and components reference a single definition.
The <base> tag broke fragment links (#anchor resolved to root page
instead of current page) and required workarounds. Revert to the
url() helper which prefixes paths with basePath at render time.

Fragment links (#tokens, #main) now work correctly on all pages.
Skip link works on every page without JavaScript hacks.

Add side-nav web component with IntersectionObserver to highlight
the current section in the design system page as the user scrolls.
Headings had margin-block-end (connecting to content below) but no
margin-block-start (separating from content above). This caused h3
elements like "Status variants" on the design system page to sit
flush against the preceding section.

Add margin-block-start: 1.5em to h2-h4 — space scales proportionally
with heading size for natural typographic rhythm. h1 is exempted
(typically the first element on a page). Add :first-child rule to
prevent leading margin when a heading opens its container.
The list restoration selector matched too broadly — .l-stack and
section:not([class]) caused nav <ul> elements inside Header/Footer
design system examples to show disc bullets.

Two fixes:
- Narrow prose list restoration to only article and .content-page
  (the actual markdown prose containers)
- Add explicit nav ul/ol override with real specificity (0,0,2)
  that ensures navigation lists never show bullets regardless of
  their container context
Filter form is hidden by default and shown only when JS is active via a
synchronous inline script that adds `class="js"` to <html> before paint,
preventing any flash. Apply button is hidden by the custom element once JS
is available since change-event filtering makes it redundant.
…lter

The button is never visible — hidden by JS when active, and the whole filter
is hidden without JS. Remove it along with the now-unreachable submit listener.
@danielnaab danielnaab merged commit 902fceb into main Apr 28, 2026
3 checks passed
@danielnaab danielnaab deleted the feat/initial-build branch April 28, 2026 19:26
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