Skip to content

Commit d25a960

Browse files
authored
Merge pull request #4 from flexion/worktree-featured-content-design
2 parents d82bab9 + d122c7d commit d25a960

17 files changed

Lines changed: 464 additions & 17 deletions

File tree

content/work/document-extractor.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
---
22
title: Document Extractor
33
summary: Turn PDFs and images of forms into structured data — without vendor lock-in.
4+
highlights:
5+
- Scanned PDFs, photos, and faxes
6+
- Open alternative to commercial OCR
7+
- Deploy, audit, and extend in-house
48
---
59

610
## What it solves
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
---
2-
title: Messaging
2+
title: Notify
33
summary: A public-sector-grade platform for sending SMS and email notifications about benefits, deadlines, and outages.
4+
highlights:
5+
- SMS and email from one API
6+
- Self-hosted, auditable delivery
7+
- No per-message vendor pricing
48
---
59

610
## What it solves

content/work/forms-lab.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
title: Forms Lab
3+
summary: An LLM-assisted platform that turns PDF forms into structured specs and delivers them as accessible digital experiences.
4+
highlights:
5+
- PDF-to-spec extraction via LLM
6+
- Static and conversational delivery modes
7+
- Pluggable model variants per step
8+
related:
9+
- forms
10+
---
11+
12+
## What it solves
13+
14+
Government forms are trapped in PDFs. Manually converting them to digital experiences is slow, expensive, and error-prone. Forms Lab automates the pipeline: upload a PDF, extract a structured spec, and deliver a form experience — static or conversational — without hand-coding each field.
15+
16+
## Who it's for
17+
18+
Teams exploring how LLMs can accelerate form digitization. The platform separates *what to collect* from *how to present it*, so extraction and delivery can evolve independently.
19+
20+
## Status
21+
22+
Active. Deployed with branch-per-experiment architecture and a live demo catalog documenting findings on extraction accuracy, model selection, and presentation strategies.
23+
24+
## Get started
25+
26+
The repository includes a live demo, experiment catalog, and architecture documentation. See the README for deployment instructions.

content/work/forms.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
---
22
title: Forms
33
summary: Accessible, USWDS-aligned form experiences that work for every resident and every agency.
4+
highlights:
5+
- WCAG 2.1 AA conformant
6+
- Multi-step with save and resume
7+
- Agency-agnostic, works with any back-end
8+
related:
9+
- forms-lab
410
---
511

612
## What it solves

data/overrides.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,22 @@
11
# Hand-authored overrides keyed by repo name.
22
# See docs/catalog.md for supported fields.
3+
4+
forms:
5+
tier: active
6+
category: product
7+
featured: true
8+
9+
forms-lab:
10+
tier: active
11+
category: product
12+
featured: true
13+
14+
document-extractor:
15+
tier: active
16+
category: product
17+
featured: true
18+
19+
flexion-notify:
20+
tier: active
21+
category: product
22+
featured: true

docs/featured-content.md

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# Featured content: design and requirements
2+
3+
This document thinks through how to present Flexion's featured projects — Forms, Messaging (Notify), Document Extractor, and Forms Lab — within the existing site structure.
4+
5+
## Goals
6+
7+
1. **Signal intentionality.** Visitors should immediately understand that these four repos represent Flexion's deliberate, invested product work — not just code that happens to be public.
8+
2. **Stay part of the collection.** Featured projects are *members* of the broader catalog, not a separate silo. They should feel like the "front shelf" of the same library.
9+
3. **Invite exploration.** A visitor drawn in by a featured project should naturally discover the rest of the work index, and vice versa.
10+
4. **Scale gracefully.** The design should work today with 4 featured projects and still work with 6–8 later, without requiring a layout overhaul.
11+
12+
## Current state
13+
14+
- The home page has a "Featured labs" section with a 3-column grid, but no repos are marked `featured: true` in `overrides.yml` yet — so it renders empty.
15+
- The work index already sorts featured repos first.
16+
- `document-extractor` exists in `repos.json`. The others are in various stages of going public:
17+
- `forms-lab` — now public (will appear in next refresh)
18+
- `forms` — public access requested, pending
19+
- `flexion-notify` — will be made public soon
20+
- Rich content overlays exist for `forms`, `messaging`, and `document-extractor` in `content/work/`.
21+
- **Naming mismatch:** The Notify repo is `flexion-notify` on GitHub, but the overlay is `content/work/messaging.md`. It needs to be renamed to `content/work/flexion-notify.md` for the merge logic to attach it.
22+
23+
## Data model gap
24+
25+
The merge logic (`src/catalog/merge.ts`) only produces entries for repos present in `repos.json`. Overlay content for repos not yet in the snapshot is orphaned until they appear.
26+
27+
### Resolution: Approach A (wait for public repos)
28+
29+
All four repos are going public:
30+
31+
| Repo | Status | Action needed |
32+
|------|--------|---------------|
33+
| `document-extractor` | Already in snapshot | None |
34+
| `forms-lab` | Now public | Next daily refresh (or manual dispatch) picks it up |
35+
| `forms` | Public access requested | Wait for approval, then refresh picks it up |
36+
| `flexion-notify` | Will be made public soon | Wait, then refresh picks it up |
37+
38+
No code changes needed for the data pipeline. Once a repo is public, the 09:00 UTC refresh workflow adds it to `repos.json` automatically.
39+
40+
### Content file rename needed
41+
42+
The overlay at `content/work/messaging.md` must be renamed to `content/work/flexion-notify.md` to match the actual GitHub repo name. The merge logic joins on filename slug → repo name.
43+
44+
---
45+
46+
## Layout and presentation
47+
48+
### Home page: featured section
49+
50+
The current `home-featured__grid` (3-column at 48rem+) is appropriate for 3–4 cards. But the standard `RepoCard` — name, one-line summary, tier/category badges — is designed for browsing, not for *selling* a product. Featured projects deserve more presence.
51+
52+
#### Option 1: Enhanced card (recommended)
53+
54+
Keep the grid layout but introduce a `FeaturedCard` variant that provides:
55+
56+
- **Title** (from overlay, e.g. "Forms" not "forms")
57+
- **Tagline/summary** (the overlay's `summary` field, already written to be compelling)
58+
- **2–3 bullet "value props"** — a new optional field in the overlay front-matter, e.g. `highlights: [...]`
59+
- **CTA link** to the detail page
60+
61+
Why: The featured section lives on the home page, which is a marketing surface. The current RepoCard is neutral/informational; a featured card should persuade.
62+
63+
#### Option 2: Hero spotlight + carousel
64+
65+
One project dominates above the fold; others are secondary. More dramatic, but:
66+
- Introduces ordering politics (which one is "first"?)
67+
- Doesn't scale to 6+ without pagination
68+
- Adds JS complexity for carousel behavior
69+
70+
#### Option 3: Keep current RepoCard, just mark them featured
71+
72+
Simplest change (just set `featured: true`), but doesn't visually distinguish featured work from the catalog list below. Misses the goal of signaling intentionality.
73+
74+
**Recommendation:** Option 1 — an enhanced card in the existing grid. It's the minimum change that achieves the "front shelf" feeling without adding interaction complexity.
75+
76+
### Work index: integration between featured and full catalog
77+
78+
The work index currently sorts featured repos to the top, which is good. But there's no visual break between them and the rest. Options:
79+
80+
#### A. Visual separator with section heading (recommended)
81+
82+
Add a lightweight heading ("Featured" or "Highlighted work") above the featured cluster, with a subtle divider before the rest. Featured repos still live *in* the list (same filter/sort controls apply), but they're visually grouped.
83+
84+
- Preserves "part of the same collection" feeling
85+
- Featured repos still respond to tier/category filters (if a user filters to "Tool" and a featured repo is a Tool, it stays; if not, it correctly disappears)
86+
- Low implementation cost
87+
88+
#### B. Separate "pinned" section outside the filter
89+
90+
Featured repos get a fixed section above the filterable list, unaffected by filters.
91+
92+
- Guarantees visibility regardless of filter state
93+
- But breaks the "same collection" mental model — they become a separate thing
94+
95+
#### C. Visual emphasis only (border/background)
96+
97+
Featured repos get a subtle highlight (accent border, background tint) but stay in normal sort flow with no heading.
98+
99+
- Lightest touch
100+
- May be too subtle; visitors won't understand *why* some cards look different
101+
102+
**Recommendation:** Option A — section heading within the list. Featured repos are still part of the filterable collection, but the heading signals "start here." If filtered out by tier/category, the heading hides too, which is correct behavior.
103+
104+
### Detail pages: connecting back
105+
106+
Each featured repo already gets a full detail page from the existing `WorkDetail` template. No structural change needed there. But consider:
107+
108+
- **Cross-linking between related projects.** Forms and Forms Lab should cross-link on their detail pages via a "Related projects" section. Driven by a `related: [forms-lab]` field in overlay front-matter. This is low-cost and makes the relationship explicit without conflating the two.
109+
- **"Back to featured" breadcrumb vs. "Back to all work."** Since featured repos are *part of* the catalog, the breadcrumb should go to `/work/` (the full index), not to a separate featured page. This reinforces the "same collection" principle.
110+
111+
---
112+
113+
## Content requirements per featured project
114+
115+
Each featured overlay should communicate:
116+
117+
| Field | Purpose | Example |
118+
|-------|---------|---------|
119+
| `title` | Human-friendly name | "Forms" |
120+
| `summary` | One-sentence value prop (used on cards) | "Accessible, USWDS-aligned form experiences..." |
121+
| `highlights` (new) | 2–3 bullet differentiators for the featured card | ["WCAG 2.1 AA conformant", "Multi-step with save-and-resume", "Agency-agnostic"] |
122+
| Body `## What it solves` | Problem framing | (already written for 3 of 4) |
123+
| Body `## Who it's for` | Audience | (already written for 3 of 4) |
124+
| Body `## Status` | Maturity signal | (already written for 3 of 4) |
125+
| Body `## Get started` | Entry point for developers | (already written for 3 of 4) |
126+
127+
**Forms Lab** still needs its overlay (`content/work/forms-lab.md`).
128+
129+
---
130+
131+
## Forms and Forms Lab: linked but separate
132+
133+
Forms and Forms Lab are **separate featured items** — each gets its own card, detail page, and overlay. But they should be visibly linked so visitors understand the relationship.
134+
135+
### How to surface the link
136+
137+
| Mechanism | Where it appears | Effort |
138+
|-----------|-----------------|--------|
139+
| **`related` field in overlay front-matter** | Detail page — "Related projects" section at bottom | New field + render logic |
140+
| **Explicit mention in body copy** | Detail page body (e.g. "See also [Forms Lab](/work/forms-lab/)") | Zero code, just content |
141+
| **Shared "family" tag or badge** | Cards and detail pages | New taxonomy concept — probably overkill |
142+
| **Adjacent placement in featured grid** | Home page | Just ordering, no code |
143+
144+
**Recommendation:** Use the `related` front-matter field (planned for stretch anyway) to cross-link them on detail pages, and place them adjacent in the featured grid on the home page. The body copy can also reference the sibling naturally. This gives multiple touchpoints without introducing new taxonomy.
145+
146+
---
147+
148+
## Navigation and discovery flow
149+
150+
```
151+
Home page
152+
├── Featured labs (4 enhanced cards) ──→ /work/{name}/ (detail)
153+
├── "Explore our work" CTA ──────────→ /work/ (full index)
154+
└── Stats section (public projects count, etc.)
155+
156+
Work index (/work/)
157+
├── [Featured heading]
158+
│ ├── Featured repo card ──────────→ /work/{name}/
159+
│ ├── Featured repo card ──────────→ /work/{name}/
160+
│ └── ...
161+
├── [All work heading]
162+
│ ├── Repo card ───────────────────→ /work/{name}/
163+
│ └── ...
164+
└── Filter controls (tier, category)
165+
166+
Detail page (/work/{name}/)
167+
├── Full content (overlay body)
168+
├── Stewardship sidebar
169+
├── "View on GitHub" link
170+
└── Related projects (optional, future)
171+
```
172+
173+
This means:
174+
- Home → featured detail: 1 click
175+
- Home → full catalog: 1 click
176+
- Featured detail → full catalog: 1 click (breadcrumb / header nav)
177+
- Full catalog → featured detail: 0 extra clicks (they're in the list)
178+
179+
No dead ends. Featured content is always reachable from the catalog, and the catalog is always reachable from featured content.
180+
181+
---
182+
183+
## Implementation sequence
184+
185+
1. **Rename:** `content/work/messaging.md``content/work/flexion-notify.md` (update title/summary to reflect repo name if needed).
186+
2. **Content:** Write `content/work/forms-lab.md`. Add `highlights` field to all four overlays. Add `related` field to Forms and Forms Lab overlays.
187+
3. **Overrides:** Mark all four repos as `featured: true`, `tier: active`, `category: product` in `overrides.yml`.
188+
4. **Refresh:** Trigger manual catalog refresh (or wait for daily run) once repos are public, to populate `repos.json`.
189+
5. **Component:** Build `FeaturedCard` component (or extend `RepoCard` with a `variant` prop).
190+
6. **Home page:** Wire `FeaturedCard` into the existing `home-featured__grid`. Place Forms and Forms Lab adjacent.
191+
7. **Work index:** Add section heading logic for featured cluster.
192+
8. **Related projects:** Add `related` field support to overlay front-matter and render cross-links on detail pages (needed for Forms ↔ Forms Lab link).
193+
194+
---
195+
196+
## Open questions
197+
198+
1. ~~Are the repos going to be public?~~ **Resolved** — yes, all going public. Approach A confirmed.
199+
2. ~~Forms Lab's relationship to Forms?~~ **Resolved** — separate featured items, but linked visibly (cross-links on detail pages, adjacent in grid).
200+
3. Should the featured section on the home page have its own heading/intro copy, or just the grid?
201+
4. Do we want a cap on featured projects (e.g., max 6) to protect the home page layout?
202+
5. For the `highlights` field — should these be auto-derived from the overlay body, or always hand-authored?

src/build/entry.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ async function render(
109109
return renderToHtml(<DesignSystem config={config} />)
110110
case 'work-detail': {
111111
const entry = catalog.find((e) => e.name === route.slug)!
112-
return renderToHtml(<WorkDetail entry={entry} now={now} config={config} />)
112+
return renderToHtml(<WorkDetail entry={entry} catalog={catalog} now={now} config={config} />)
113113
}
114114
}
115115
}

src/catalog/overlays.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { parse as parseYaml } from 'yaml'
2+
import { marked } from 'marked'
23
import type { Overlay } from './types'
34

45
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/
@@ -18,10 +19,18 @@ export async function loadOverlay(path: string): Promise<Overlay | null> {
1819
return {
1920
title: stringOrUndefined(frontMatter.title),
2021
summary: stringOrUndefined(frontMatter.summary),
21-
body: body || undefined,
22+
highlights: stringArrayOrUndefined(frontMatter.highlights),
23+
related: stringArrayOrUndefined(frontMatter.related),
24+
body: body ? (marked.parse(body, { async: false }) as string) : undefined,
2225
}
2326
}
2427

2528
function stringOrUndefined(value: unknown): string | undefined {
2629
return typeof value === 'string' ? value : undefined
2730
}
31+
32+
function stringArrayOrUndefined(value: unknown): string[] | undefined {
33+
if (!Array.isArray(value)) return undefined
34+
const strings = value.filter((v): v is string => typeof v === 'string')
35+
return strings.length > 0 ? strings : undefined
36+
}

src/catalog/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export type OverrideEntry = {
3434
export type Overlay = {
3535
title?: string
3636
summary?: string
37+
highlights?: string[]
38+
related?: string[]
3739
body?: string
3840
}
3941

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { CatalogEntry } from '../../../catalog/types'
2+
import { url } from '../../../build/config'
3+
4+
export function FeaturedCard({ entry, basePath }: { entry: CatalogEntry; basePath: string }) {
5+
const href = url(`/work/${entry.name}/`, basePath)
6+
const title = entry.overlay?.title ?? entry.name
7+
const summary = entry.overlay?.summary ?? entry.description ?? ''
8+
const highlights = entry.overlay?.highlights
9+
10+
return (
11+
<article class="featured-card">
12+
<h3 class="featured-card__title">
13+
<a href={href}>{title}</a>
14+
</h3>
15+
{summary ? <p class="featured-card__summary">{summary}</p> : null}
16+
{highlights ? (
17+
<ul class="featured-card__highlights">
18+
{highlights.map((h) => <li>{h}</li>)}
19+
</ul>
20+
) : null}
21+
<p class="featured-card__cta">
22+
<a href={href}>Learn more &rarr;</a>
23+
</p>
24+
</article>
25+
)
26+
}

0 commit comments

Comments
 (0)