Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
9824e86
chore: initialize Bun + Hono project
danielnaab Apr 27, 2026
3890d40
docs(plan): correct @hono/ssg to hono/ssg subpath export
danielnaab Apr 27, 2026
9fb366f
docs: rewrite README with Flexion Labs orientation
danielnaab Apr 27, 2026
7890b4b
feat(catalog): define catalog entry types
danielnaab Apr 27, 2026
7d9e706
feat(catalog): apply tier and category defaults
danielnaab Apr 27, 2026
e694ce2
docs(spec): clarify archived-over-fork precedence for tier defaults
danielnaab Apr 27, 2026
3b266a8
feat(catalog): load markdown overlays with front-matter
danielnaab Apr 27, 2026
52f6b08
feat(catalog): merge snapshot with overrides and overlays
danielnaab Apr 27, 2026
c270c08
feat(catalog): load snapshot, overrides, and overlays from disk
danielnaab Apr 27, 2026
d4d0df6
docs(catalog): explain what the catalog is and how it's refreshed
danielnaab Apr 27, 2026
30bc29d
feat(standards): evaluate repos against stewardship standards
danielnaab Apr 27, 2026
7123bf1
test: shared fixture catalog for view tests
danielnaab Apr 27, 2026
06cbf00
feat(build): add renderToHtml helper
danielnaab Apr 27, 2026
37837fd
feat(build): resolve base path and build-time URL helpers
danielnaab Apr 27, 2026
dd95376
feat(views): layout shell with header, footer, and skip link
danielnaab Apr 27, 2026
efef78a
feat(views): badge, repo card, and standards list components
danielnaab Apr 27, 2026
77681f6
feat(views): home page with hero, featured labs, stats, and paths
danielnaab Apr 27, 2026
de99090
feat(views): work index with default sort and filter shell
danielnaab Apr 27, 2026
78f54ae
feat(views): work detail with overlay, fallback copy, and stewardship…
danielnaab Apr 27, 2026
80c5d02
feat(views): stewardship health report
danielnaab Apr 27, 2026
5758498
feat(views): content page renderer for commitment and about
danielnaab Apr 27, 2026
3a9a822
content: seed overlays for the three featured labs
danielnaab Apr 27, 2026
24746c5
feat(build): hero loader and route table
danielnaab Apr 27, 2026
ae2f362
feat(build): SSG entry renders every route to dist/
danielnaab Apr 27, 2026
e432fad
style: define every Flexion brand color and design token
danielnaab Apr 27, 2026
cb7bdc1
style: reset, base, layout, components, utilities layers
danielnaab Apr 27, 2026
dc15921
feat(enhancements): copy-button component
danielnaab Apr 27, 2026
5e29255
feat(enhancements): catalog-filter component (tier + category AND)
danielnaab Apr 27, 2026
c964d38
feat(enhancements): sortable-table component
danielnaab Apr 27, 2026
f69cf79
feat(build): bundle enhancements as register.js
danielnaab Apr 27, 2026
8afdf5b
test(a11y): scan rendered pages with axe-core
danielnaab Apr 27, 2026
eccb7be
feat(catalog): refresh script that queries the GitHub API
danielnaab Apr 27, 2026
1b94e09
ci: build, test, and deploy with branch previews via GitHub environments
danielnaab Apr 27, 2026
b79d63a
ci: daily catalog refresh and CNAME for custom domain
danielnaab Apr 27, 2026
d0e7075
docs: project orientation and per-area behavioral docs
danielnaab Apr 27, 2026
714503d
docs(views): per-view behavioral docs mapped to tests
danielnaab Apr 27, 2026
630c695
chore(catalog): seed initial snapshot of flexion public repos
danielnaab Apr 28, 2026
5d81caf
ci: bootstrap gh-pages branch on first deploy if missing
danielnaab Apr 28, 2026
580b3af
refactor: restructure into src/ and apply brand colors
danielnaab Apr 28, 2026
789dc13
fix: use <base> tag for URLs, remove CNAME until custom domain is con…
danielnaab Apr 28, 2026
98aedb8
fix: restore CNAME and deployment URLs for labs.flexion.us
danielnaab Apr 28, 2026
8a67946
refactor: establish src/design/ as the design system
danielnaab Apr 28, 2026
2d8d4f1
feat: design system components, showcase page, and favicon
danielnaab Apr 28, 2026
dc56e67
fix: align typography spacing with USWDS conventions
danielnaab Apr 28, 2026
a7c40e7
fix: remove placeholder favicon SVG, complete typography coverage
danielnaab Apr 28, 2026
4b4baf8
fix: remove <base> tag, restore url() helper for clean link handling
danielnaab Apr 28, 2026
6e03ba2
chore: verify signed commits
danielnaab Apr 28, 2026
76c587c
fix: add margin-block-start to headings for proper section separation
danielnaab Apr 28, 2026
56b48f6
fix: prevent list bullets in nav elements, narrow prose list scope
danielnaab Apr 28, 2026
14cbdf9
feat: add tornado logo to header, switch wordmark to ink for contrast
danielnaab Apr 28, 2026
ad00a7f
fix: pass config to header/footer examples for correct asset base paths
danielnaab Apr 28, 2026
1b72e14
feat: hide catalog filter without JS, suppress Apply button with JS
danielnaab Apr 28, 2026
0f4c505
refactor: remove Apply button and dead submit handler from catalog fi…
danielnaab Apr 28, 2026
e4180dd
fix: use raw() so inline JS script is not HTML-escaped by Hono JSX
danielnaab Apr 28, 2026
d7be977
refactor: remove method=get from catalog filter form
danielnaab Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
name: Build, test, and deploy

on:
push:
branches: ['**']
delete:
workflow_dispatch:

permissions:
contents: write
deployments: write

concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-test:
if: github.event_name != 'delete'
runs-on: ubuntu-latest
outputs:
branch: ${{ steps.meta.outputs.branch }}
base_path: ${{ steps.meta.outputs.base_path }}
is_production: ${{ steps.meta.outputs.is_production }}
steps:
- uses: actions/checkout@v4

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: bun install --frozen-lockfile || bun install

- name: Determine deploy metadata
id: meta
run: |
BRANCH="${GITHUB_REF_NAME}"
SANITIZED="$(echo "$BRANCH" | tr '/' '-' | tr -cd 'a-zA-Z0-9._-')"
if [ "$BRANCH" = "main" ]; then
echo "base_path=/" >> "$GITHUB_OUTPUT"
echo "branch=main" >> "$GITHUB_OUTPUT"
echo "is_production=true" >> "$GITHUB_OUTPUT"
else
echo "base_path=/preview/$SANITIZED/" >> "$GITHUB_OUTPUT"
echo "branch=$SANITIZED" >> "$GITHUB_OUTPUT"
echo "is_production=false" >> "$GITHUB_OUTPUT"
fi

- name: Run unit and component tests
run: bun test tests/catalog tests/standards tests/views tests/enhancements tests/build

- name: Build site
env:
SITE_BASE_URL: ${{ steps.meta.outputs.base_path }}
run: bun run build

- name: Run a11y tests against built site
run: bun test tests/a11y

- name: Upload dist artifact
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 3

publish:
if: github.event_name == 'push'
needs: build-and-test
runs-on: ubuntu-latest
environment:
name: ${{ needs.build-and-test.outputs.is_production == 'true' && 'production' || 'preview' }}
url: ${{ needs.build-and-test.outputs.is_production == 'true' && 'https://labs.flexion.us/' || format('https://labs.flexion.us/preview/{0}/', needs.build-and-test.outputs.branch) }}
steps:
- name: Check out or bootstrap gh-pages
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
git init gh-pages-work
cd gh-pages-work
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
git remote add origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
if git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then
git fetch --depth=1 origin gh-pages
git checkout -B gh-pages FETCH_HEAD
else
echo 'gh-pages branch missing — creating orphan.'
git checkout --orphan gh-pages
git reset --hard
fi

- uses: actions/download-artifact@v4
with:
name: dist
path: dist

- name: Sync dist into gh-pages
run: |
set -euo pipefail
BASE_PATH="${{ needs.build-and-test.outputs.base_path }}"
cd gh-pages-work
if [ "$BASE_PATH" = "/" ]; then
find . -mindepth 1 -maxdepth 1 ! -name '.git' ! -name 'preview' -exec rm -rf {} +
cp -r ../dist/. ./
else
rel="${BASE_PATH#/}"
rel="${rel%/}"
rm -rf "$rel"
mkdir -p "$(dirname "$rel")"
cp -r ../dist "$rel"
fi
if [ ! -f CNAME ]; then
cp ../CNAME . 2>/dev/null || true
fi

- name: Commit and push gh-pages
working-directory: gh-pages-work
run: |
set -euo pipefail
git add -A
if git diff --cached --quiet; then
echo 'No changes to publish.'
exit 0
fi
git commit -m "Deploy ${GITHUB_SHA::7} to ${{ needs.build-and-test.outputs.base_path }}"
git push origin gh-pages

cleanup-preview:
if: github.event_name == 'delete' && github.event.ref_type == 'branch'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Check out gh-pages (skip if absent)
id: checkout
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
git init .
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
git remote add origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
if git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then
git fetch --depth=1 origin gh-pages
git checkout -B gh-pages FETCH_HEAD
echo 'exists=true' >> "$GITHUB_OUTPUT"
else
echo 'gh-pages branch does not exist — nothing to clean up.'
echo 'exists=false' >> "$GITHUB_OUTPUT"
fi

- name: Remove preview directory
if: steps.checkout.outputs.exists == 'true'
run: |
set -euo pipefail
SANITIZED="$(echo "${{ github.event.ref }}" | tr '/' '-' | tr -cd 'a-zA-Z0-9._-')"
DIR="preview/$SANITIZED"
if [ -d "$DIR" ]; then
rm -rf "$DIR"
git add -A
git commit -m "Remove preview for deleted branch $SANITIZED"
git push origin gh-pages
fi
51 changes: 51 additions & 0 deletions .github/workflows/refresh-catalog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Refresh catalog

on:
schedule:
- cron: '0 9 * * *'
workflow_dispatch:

permissions:
contents: write
pull-requests: write

jobs:
refresh:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- run: bun install --frozen-lockfile || bun install

- name: Run refresh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bun run refresh:catalog

- name: Open PR if snapshot changed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if git diff --quiet data/repos.json; then
echo 'No changes; nothing to do.'
exit 0
fi
DATE="$(date -u +%F)"
BRANCH="catalog/refresh-$DATE"
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
git checkout -B "$BRANCH"
git add data/repos.json
git commit -m "chore(catalog): refresh snapshot $DATE"
git push --force-with-lease origin "$BRANCH"
if ! gh pr view "$BRANCH" >/dev/null 2>&1; then
gh pr create --base main --head "$BRANCH" \
--title "Refresh catalog snapshot — $DATE" \
--body "Automated snapshot refresh from the GitHub API."
fi
gh pr merge "$BRANCH" --auto --squash
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ dist/
.direnv/
.DS_Store
*.log
bun.lock
1 change: 1 addition & 0 deletions CNAME
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
labs.flexion.us
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,28 @@
# flexion.github.io
flexion organization github pages
# Flexion Labs

Source for [labs.flexion.us](https://labs.flexion.us/) — a public-facing site that showcases Flexion's open source portfolio, indexes our public repositories, and publishes our open source commitment.

## Layout

- `src/` — all source code:
- `src/build/` — the Bun + Hono SSG build driver.
- `src/catalog/` — catalog domain logic: types, loading, merging, stewardship evaluation, refresh script.
- `src/design/` — the design system: all stateless UI components, CSS, assets.
- `src/design/components/` — per-component directories (forms-lab pattern): `tag/`, `button/`, `link/`, `select/`, `card/`, `header/`, `footer/`, `repo-card/`, etc.
- Each component has `index.tsx` (JSX), `styles.css` (CSS), `examples.tsx` (design system showcase).
- CSS layers: `reset, tokens, base, compositions, layout, components, utilities`.
- `src/pages/` — route entrypoints that pass data into design components.
- `data/` — catalog data: generated snapshot (`repos.json`) and hand-authored overrides (`overrides.yml`).
- `content/` — the words we publish, as markdown.
- `docs/` — durable behavioral documentation for contributors and agents.
- `notes/` — ephemeral planning and specs.

## Getting started

```bash
bun install
bun run build # writes static site to dist/
bun test # runs the full test suite
```

See `docs/README.md` for the project orientation.
2 changes: 2 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[test]
preload = ["./tests/setup.ts"]
15 changes: 15 additions & 0 deletions content/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: About
---

# About Flexion Labs

Flexion Labs is where we publish our open source work. It's curated by Flexion — a firm that helps government agencies and nonprofits modernize software that matters.

## Engage

- **Adopt** a project. Read the README, try it, open an issue if something is unclear.
- **Contribute** a fix or an improvement. Every repo lists its contribution process.
- **Partner** with us on new public infrastructure. Reach out through the main Flexion site.

[flexion.us](https://flexion.us/) is the home for Flexion the company. This site is the home for Flexion's open source work.
52 changes: 52 additions & 0 deletions content/commitment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: Open source commitment
---

# Flexion Labs open source commitment

*Status: Working draft. Pending delivery leadership and ownership group review.*

## Why we value openness

Open source solves practical problems. For the government agencies we serve, it eliminates vendor lock-in, reduces sustainability risk, and lowers total cost of ownership. For Flexion, it creates options — the freedom to build on proven foundations, to redirect resources from infrastructure to the problems that matter, and to demonstrate technical capability in ways closed projects never can.

Transparency improves quality. When code is open, more eyes find more bugs. Agencies and oversight bodies can audit how public systems work. The discipline of building in the open — knowing anyone can read the code — raises the bar for the work itself.

Openness compounds value across jurisdictions. Investment in one agency's solution becomes infrastructure that others can adopt. This commons-building isn't overhead — it's how we create defensible competitive advantage while empowering agencies to control their technology. Open source attracts talent who value transparency and civic impact, and contributors can become hires.

Openness also makes sense for the public. Publicly funded work should create reusable public infrastructure. Citizens benefit from transparency into the systems that serve them. And when agencies embrace open source, the result is higher public satisfaction with government technology. We don't ask anyone to take our word for it — the code is there to inspect, use, and build on.

## What we commit to

We are open by default. Code, architecture, and interfaces are open unless there's a specific reason otherwise — security concerns, client requirements, or competitive considerations. We will never take an open source project to a closed model. Once we release something as open source, it remains available under that license.

We use licensing appropriate to each project's context. Government-funded work uses public domain (CC0) to maximize reuse and avoid contractual friction. Commercial client work follows client preferences, typically proposing public domain. For projects where Flexion makes significant independent investment and maintains long-term stewardship, we use permissive open source licenses (Apache 2.0) with contributor agreements that preserve flexibility for the project's future. Small enhancements to existing open source projects follow those projects' conventions.

We commit to clear, professional repository standards: proper documentation, contributor guidance, legal terms, and getting-started materials. Code alone isn't enough — a project that's hard to understand or adopt isn't truly open.

Our competitive advantage comes from delivery expertise and proven capabilities, not from hiding code. We compete by being better at building, deploying, and supporting solutions — not by locking them down.

## How we operate

We develop in the open for projects intended to be open source. Public by default means the work is visible from the start, not just after delivery. We are mindful of security considerations and maintain clear vulnerability disclosure processes.

We govern our projects incrementally, starting with Flexion authority and evolving toward broader community governance as projects mature and attract use. For client work, the governance model depends on context — for traditional client engagements, operational decisions belong to the empowered client; for Flexion Solutions, Flexion governs directly.

Contribution processes are documented and all work is done through pull requests. We welcome contributions with clear guidance. We build our stewardship practices by dogfooding them on internal projects first, so we learn what works before applying it externally.

We recognize that governance stagnation — projects going dormant because no one takes ownership — is a primary risk of open source. We address this through honest communication about support levels, explicit project tiers, and a commitment to never let projects silently decay. If a project is no longer actively maintained, we say so clearly.

## What we steward

We recognize that resources are finite and not all projects warrant the same level of investment. We support a tiered approach to stewardship, with honest communication about what we will and won't provide for each project.

For actively maintained projects, we commit to security patch management and defined response commitments. For projects available as-is, we say so clearly. We don't over-promise maintenance. Abandoned repositories damage credibility and create a security risk — if we can't maintain something, we explicitly archive it rather than letting it decay silently.

Open source work is funded primarily through consulting engagements with clients who value openness. We also make strategic investments in projects where the business case warrants it — where open source creates market opportunities, builds community, or strengthens civic infrastructure. Different projects use different funding models: traditional hourly billing, retainers, maintenance within team structures, grants, and partnerships.

## Maintenance tiers

- **Active** — Flexion commits to security patch management and defined response commitments. Bug reports are triaged. Pull requests are reviewed on a predictable cadence.
- **As-is** — Available without active maintenance. The code works (or worked at one point); future updates are not promised.
- **Archived** — No longer maintained. The GitHub archive flag is set. The repo is read-only. Listed for transparency.
- **Unreviewed** — A human has not yet classified this repo. Defaults to this state; visible on the site so gaps are honest.
4 changes: 4 additions & 0 deletions content/home.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
hero: Public infrastructure, in the open.
intro: Flexion Labs gathers our open source work in one place — products we steward, tools we share, and the commitment behind them.
---
20 changes: 20 additions & 0 deletions content/work/document-extractor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Document Extractor
summary: Turn PDFs and images of forms into structured data — without vendor lock-in.
---

## What it solves

Agencies receive millions of scanned forms every year and pay commercial vendors to turn them into structured data. Document Extractor provides an open alternative that agencies can deploy, audit, and extend.

## Who it's for

Teams modernizing paper-based intake workflows. Works on scanned PDFs, phone-camera photos, and faxes.

## Status

Active. Deployed with agency partners.

## Get started

The repository documents supported document types, extraction models, and how to extend the pipeline.
20 changes: 20 additions & 0 deletions content/work/forms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Forms
summary: Accessible, USWDS-aligned form experiences that work for every resident and every agency.
---

## What it solves

Public forms are the front door to government services — and often the worst-performing part of the experience. Forms focuses on WCAG-conformant, plain-language, multi-step forms that reduce drop-off and produce clean data on submit.

## Who it's for

Agency teams building new forms or rehabilitating legacy ones. Works with the agency's existing back-end and identity stack.

## Status

Active. In use across multiple deployments.

## Get started

The repository includes component documentation, examples, and deployment guidance.
20 changes: 20 additions & 0 deletions content/work/messaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Messaging
summary: A public-sector-grade platform for sending SMS and email notifications about benefits, deadlines, and outages.
---

## What it solves

Public agencies need to reach residents quickly when something changes — a benefit status, an appointment, a service outage. Existing commercial messaging platforms are expensive, opaque about deliverability, and often lock agencies into per-message pricing that grows with the population they serve.

## Who it's for

State and local agencies that want self-hosted, auditable messaging infrastructure with clear deliverability reporting.

## Status

Active. Used in production with multiple agency partners.

## Get started

Read the README on GitHub for the deployment guide and API reference.
Loading
Loading