diff --git a/content/commitment.md b/content/commitment.md index b835979..f3fe642 100644 --- a/content/commitment.md +++ b/content/commitment.md @@ -4,7 +4,7 @@ title: Open source commitment # Flexion's open source commitment -Flexion has always worked differently. How we work is what distinguishes us. Our commitment to open source is part of how we create value. Open source enables long-term resilience, and the Flexion approach to development prioritizes resilience. We know that our customers may need to pivot at any moment, and we want them to be able to adapt to changing conditions. +Flexion has always worked differently. How we work is what distinguishes us. Our commitment to open source is part of how we create value. Open source enables long-term resilience, and the Flexion approach to development prioritizes resilience. We know that our customers may need to pivot at any time, and we want them to be able to do so, so that they can adapt to changing conditions. 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. diff --git a/content/featured/document-extractor-lab.md b/content/featured/document-extractor-lab.md index 08a6d0c..aae2b0c 100644 --- a/content/featured/document-extractor-lab.md +++ b/content/featured/document-extractor-lab.md @@ -1,6 +1,6 @@ --- title: Document Extractor Lab -tagline: Accurately extract data from PDFs and images for faster application processing. +tagline: Accurately extract data from PDFs and images for faster application processing. Document Extractor recognizes and maps key data fields, turning them into data that can be integrated into existing systems. The Document Extractor Lab emerged from work done for GSA's Public Benefits Studio. order: 3 links: - label: flexion/document-extractor diff --git a/content/featured/forms-lab.md b/content/featured/forms-lab.md index e2e9dd1..41d8dce 100644 --- a/content/featured/forms-lab.md +++ b/content/featured/forms-lab.md @@ -1,6 +1,7 @@ --- title: Forms Lab -tagline: Digitize forms to create modern, accessible experiences for public outreach. +tagline: Digitize forms to create modern, accessible experiences for public outreach. Simple, accessible, and conformant, with powerful automation and integration options. The Forms Lab emerged from work done for the General Services Administration's (GSA) 10x program. + order: 1 links: - label: Forms Platform @@ -14,5 +15,5 @@ links: kind: demo - label: flexion/forms-lab url: https://github.com/flexion/forms-lab - kind: repo + kind: repo --- diff --git a/content/featured/messaging-lab.md b/content/featured/messaging-lab.md index 7e7e098..1f023bc 100644 --- a/content/featured/messaging-lab.md +++ b/content/featured/messaging-lab.md @@ -1,8 +1,15 @@ --- title: Messaging Lab -tagline: Text messaging services to deliver critical updates to the people you serve. +tagline: Text messaging services to deliver critical updates to the people you serve. An easy-to-use, web-based service, Messaging allows personalized text messaging, including messaging in more than 30 languages, with limited data retention. The Messaging Lab emerged from work done for GSA's Public Benefits Studio. order: 2 links: + - label: Flexion Messaging + kind: screenshot + images: + - src: /assets/images/messaging-dashboard.png + alt: Organization Dashboard showing message allowance and services overview + - src: /assets/images/messaging-get-started.png + alt: Get started guide with steps for using Flexion Messaging - label: flexion/flexion-messaging url: https://github.com/flexion/flexion-messaging kind: repo diff --git a/content/home.md b/content/home.md index d173d5f..f9fa57a 100644 --- a/content/home.md +++ b/content/home.md @@ -1,6 +1,6 @@ --- -title: Solutions for the public, in the open -subtitle: +title: Flexion Labs +subtitle: Solutions for the public, built in the open intro: | Flexion is committed to excellence in civic technology. We are also committed to transparency. As part of that commitment, Flexion Labs diff --git a/docs/views/home.md b/docs/views/home.md index 32a036f..8d82256 100644 --- a/docs/views/home.md +++ b/docs/views/home.md @@ -12,7 +12,7 @@ First impression for every visitor. Introduces Flexion Labs with a hero, showcas ## Behavior -- **When the page loads, then** the hero renders the `title` as `

`, the `subtitle` as a tagline paragraph, and the rendered `intro` HTML as the intro block. +- **When the page loads, then** the hero renders the `title` as `

`, the `subtitle` as a `

`, and the rendered `intro` HTML as the intro block. - **When there are featured labs, then** one `LabCard` is rendered per lab in `order` ascending. - **When the page loads, then** a "Learn more" section renders two side-by-side teasers — one linking to `/commitment/`, one linking to `https://flexion.us/`. The grid collapses to a single column below 48rem. - **The stats strip is not rendered.** The catalog directory is disabled in this pass. diff --git a/notes/plans/2026-05-06-screenshot-link-kind.md b/notes/plans/2026-05-06-screenshot-link-kind.md new file mode 100644 index 0000000..c060a93 --- /dev/null +++ b/notes/plans/2026-05-06-screenshot-link-kind.md @@ -0,0 +1,600 @@ +# Screenshot Link Kind Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add a `screenshot` link kind to featured labs that opens a native `` modal with product screenshots, starting with Flexion Messaging. + +**Architecture:** Extend the `FeaturedLink` union type to include a `screenshot` variant carrying `images[]` instead of `url`. The LabCard component renders screenshot links as ` + ) + } + return ( + + + {link.label} + + ) + })} + + ))} + + {screenshotLinks.map(({ link, id }) => ( + + + +
+ {link.images.map((img) => ( + {img.alt} + ))} +
+
+
+ ))} + + ) +} +``` + +Add `ScreenshotIcon` to the `LinkIcon` switch and define it: + +```typescript +function LinkIcon({ kind }: { kind: FeaturedLinkKind }) { + switch (kind) { + case 'demo': + return + case 'screenshot': + return + case 'repo': + return + case 'case-study': + return + } +} + +function ScreenshotIcon() { + // Image / picture frame — signals "view screenshots" + return ( + + ) +} +``` + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `bun test tests/views/components.test.tsx` +Expected: ALL PASS + +- [ ] **Step 5: Commit** + +```bash +git add src/design/components/lab-card/index.tsx tests/views/components.test.tsx +git commit -m "Render screenshot links as buttons with dialog in LabCard" +``` + +--- + +### Task 4: Add dialog styles + +**Files:** +- Modify: `src/design/components/lab-card/styles.css` + +- [ ] **Step 1: Add styles for the screenshot button, dialog, and its contents** + +Append to `src/design/components/lab-card/styles.css`, inside the existing `@layer components { ... }` block, before the closing `}`: + +```css + /* Screenshot button — match anchor styling */ + .lab-card__column-link--button { + background: none; + border: none; + padding: 0; + cursor: pointer; + font: inherit; + } + + /* Screenshot dialog */ + .screenshot-dialog { + max-inline-size: min(900px, 90vw); + max-block-size: 90vh; + border: none; + border-radius: var(--radius-sm); + padding: var(--space-6); + overflow-y: auto; + position: relative; + } + + .screenshot-dialog::backdrop { + background: rgb(0 0 0 / 0.6); + } + + .screenshot-dialog__close { + position: absolute; + inset-block-start: var(--space-3); + inset-inline-end: var(--space-3); + background: none; + border: none; + font-size: var(--step-3); + line-height: 1; + cursor: pointer; + color: var(--color-ink-subtle); + padding: var(--space-1) var(--space-2); + border-radius: var(--radius-sm); + } + + .screenshot-dialog__close:hover, + .screenshot-dialog__close:focus-visible { + color: var(--color-ink); + background: var(--color-surface-alt); + } + + .screenshot-dialog__images { + display: flex; + flex-direction: column; + gap: var(--space-4); + } + + .screenshot-dialog__img { + max-inline-size: 100%; + block-size: auto; + border-radius: var(--radius-sm); + box-shadow: var(--shadow-card); + } +``` + +- [ ] **Step 2: Build the site and visually verify** + +Run: `bun run build` +Expected: Build succeeds with no errors. + +- [ ] **Step 3: Commit** + +```bash +git add src/design/components/lab-card/styles.css +git commit -m "Add dialog styles for screenshot modal" +``` + +--- + +### Task 5: Add client-side dialog behavior + +**Files:** +- Create: `src/design/components/screenshot-dialog/client.ts` +- Modify: `src/design/register.ts` + +- [ ] **Step 1: Create the custom element at `src/design/components/screenshot-dialog/client.ts`** + +```typescript +class ScreenshotDialogElement extends HTMLElement { + private dialog: HTMLDialogElement | null = null + + connectedCallback() { + this.dialog = this.querySelector('dialog') + if (!this.dialog) return + + this.addEventListener('click', this.handleClick) + this.dialog.addEventListener('click', this.handleBackdropClick) + } + + disconnectedCallback() { + this.removeEventListener('click', this.handleClick) + this.dialog?.removeEventListener('click', this.handleBackdropClick) + } + + handleClick = (e: Event) => { + const target = (e.target as Element).closest('[data-open-dialog]') as HTMLElement | null + if (target) { + this.dialog?.showModal() + } + const close = (e.target as Element).closest('[data-close-dialog]') + if (close) { + this.dialog?.close() + } + } + + handleBackdropClick = (e: Event) => { + // Clicks on the element itself (not its children) are backdrop clicks + if (e.target === this.dialog) { + this.dialog.close() + } + } +} + +if (!customElements.get('screenshot-dialog')) { + customElements.define('screenshot-dialog', ScreenshotDialogElement) +} +``` + +- [ ] **Step 2: Register it in `src/design/register.ts`** + +Add the import: + +```typescript +import './components/screenshot-dialog/client' +``` + +- [ ] **Step 3: Build and test manually** + +Run: `bun run build` +Expected: Build succeeds. The `dist/enhancements/register.js` bundle now includes the screenshot-dialog custom element. + +- [ ] **Step 4: Commit** + +```bash +git add src/design/components/screenshot-dialog/client.ts src/design/register.ts +git commit -m "Add screenshot-dialog custom element for modal behavior" +``` + +--- + +### Task 6: Visual verification + +- [ ] **Step 1: Start the dev server and verify the feature** + +Run: `bun run dev` + +Open the site in a browser. On the home page, find the Messaging Lab card. Verify: + +1. A "Screenshots" column appears with a "Flexion Messaging" button +2. Clicking the button opens a modal dialog with both screenshots stacked vertically +3. The close button (X) closes the dialog +4. Pressing Escape closes the dialog +5. Clicking the dark backdrop closes the dialog +6. The repo link still works normally +7. Other lab cards (Forms Lab, Document Extractor Lab) are unaffected + +- [ ] **Step 2: Run the full test suite** + +Run: `bun test` +Expected: ALL PASS + +- [ ] **Step 3: Final commit if any touch-ups were needed** + +Only if adjustments were made during visual verification. diff --git a/notes/specs/2026-05-06-screenshot-link-kind-design.md b/notes/specs/2026-05-06-screenshot-link-kind-design.md new file mode 100644 index 0000000..ed25644 --- /dev/null +++ b/notes/specs/2026-05-06-screenshot-link-kind-design.md @@ -0,0 +1,121 @@ +# Screenshot Link Kind for Featured Labs + +Add a `screenshot` link kind to featured labs that opens a modal dialog +with product screenshots instead of navigating to an external URL. + +## Motivation + +Flexion Messaging doesn't have a public demo URL. Two screenshots of the +product interface (Organization Dashboard and Get Started guide) should be +viewable directly from the lab card via a modal popup. + +## Data model + +### New frontmatter shape + +Screenshot links carry `images[]` instead of `url`: + +```yaml +links: + - label: Flexion Messaging + kind: screenshot + images: + - src: /assets/images/messaging-dashboard.png + alt: Organization Dashboard showing message allowance and services overview + - src: /assets/images/messaging-get-started.png + alt: Get started guide with steps for using Flexion Messaging +``` + +### Updated types (`src/build/featured.ts`) + +```typescript +type FeaturedLinkKind = 'demo' | 'repo' | 'case-study' | 'screenshot' + +type FeaturedUrlLink = { + label: string + url: string + kind: 'demo' | 'repo' | 'case-study' +} + +type ScreenshotImage = { src: string; alt: string } + +type FeaturedScreenshotLink = { + label: string + kind: 'screenshot' + images: ScreenshotImage[] +} + +type FeaturedLink = FeaturedUrlLink | FeaturedScreenshotLink +``` + +Parsing in `parseLinks` validates: if `kind === 'screenshot'`, require +`images` array with `src` and `alt` strings; otherwise require `url` string. + +## Column ordering + +`KIND_ORDER`: `['demo', 'screenshot', 'repo', 'case-study']` + +Column heading: **"Screenshots"** + +## Icon + +An image/picture icon (frame with mountain and sun) to distinguish from +the globe (demo) and GitHub mark (repo). + +## LabCard rendering changes + +- For url-based links: render as `` (no change). +- For screenshot links: render as `