diff --git a/content/work/forms.md b/content/work/forms.md index 676f8ad..359be62 100644 --- a/content/work/forms.md +++ b/content/work/forms.md @@ -5,6 +5,8 @@ highlights: - WCAG 2.1 AA conformant - Multi-step with save and resume - Agency-agnostic, works with any back-end +image: /assets/forms-phone.png +imageAlt: A mobile phone displaying an accessible government form built with Flexion Forms related: - forms-lab --- diff --git a/src/catalog/overlays.ts b/src/catalog/overlays.ts index ecf6b55..e087229 100644 --- a/src/catalog/overlays.ts +++ b/src/catalog/overlays.ts @@ -21,6 +21,8 @@ export async function loadOverlay(path: string): Promise { summary: stringOrUndefined(frontMatter.summary), highlights: stringArrayOrUndefined(frontMatter.highlights), related: stringArrayOrUndefined(frontMatter.related), + image: stringOrUndefined(frontMatter.image), + imageAlt: stringOrUndefined(frontMatter.imageAlt), body: body ? (marked.parse(body, { async: false }) as string) : undefined, } } diff --git a/src/catalog/types.ts b/src/catalog/types.ts index 9bfac90..cfe9fbe 100644 --- a/src/catalog/types.ts +++ b/src/catalog/types.ts @@ -36,6 +36,8 @@ export type Overlay = { summary?: string highlights?: string[] related?: string[] + image?: string + imageAlt?: string body?: string } diff --git a/src/design/assets/forms-phone.png b/src/design/assets/forms-phone.png new file mode 100644 index 0000000..d787c86 Binary files /dev/null and b/src/design/assets/forms-phone.png differ diff --git a/src/design/components/featured-card/index.tsx b/src/design/components/featured-card/index.tsx index de833b0..bb223ba 100644 --- a/src/design/components/featured-card/index.tsx +++ b/src/design/components/featured-card/index.tsx @@ -1,25 +1,43 @@ import type { CatalogEntry } from '../../../catalog/types' import { url } from '../../../build/config' +import { raw } from 'hono/html' + +/** Extract first

from rendered HTML body */ +function firstParagraph(html: string): string | null { + const match = html.match(/

([\s\S]*?)<\/p>/) + return match ? match[1] : null +} export function FeaturedCard({ entry, basePath }: { entry: CatalogEntry; basePath: string }) { const href = url(`/work/${entry.name}/`, basePath) const title = entry.overlay?.title ?? entry.name const summary = entry.overlay?.summary ?? entry.description ?? '' const highlights = entry.overlay?.highlights + const excerpt = entry.overlay?.body ? firstParagraph(entry.overlay.body) : null + const image = entry.overlay?.image + ? url(entry.overlay.image, basePath) + : null + const imageAlt = entry.overlay?.imageAlt ?? '' return (

) diff --git a/src/design/components/featured-card/styles.css b/src/design/components/featured-card/styles.css index 5a40a39..90f37e5 100644 --- a/src/design/components/featured-card/styles.css +++ b/src/design/components/featured-card/styles.css @@ -1,18 +1,15 @@ .featured-card { - padding: var(--space-5); - border: 1px solid var(--color-surface-alt); - border-block-start: 3px solid var(--color-accent); - border-radius: var(--radius-md); + padding: var(--space-6); + border-inline-start: 3px solid var(--color-accent); + border-radius: var(--radius-sm); background: var(--color-surface); box-shadow: var(--shadow-card); - display: grid; - gap: var(--space-3); - align-content: start; } .featured-card__title { - font-size: var(--step-1); + font-size: var(--step-2); line-height: 1.2; + margin-block-end: var(--space-3); } .featured-card__title a { @@ -24,28 +21,54 @@ color: var(--color-link-hover); } +.featured-card__image { + float: inline-end; + margin-inline-start: var(--space-5); + margin-block-end: var(--space-3); +} + +.featured-card__image img { + display: block; + max-block-size: 16rem; + inline-size: auto; + border-radius: var(--radius-sm); +} + .featured-card__summary { + font-size: var(--step-0); color: var(--color-ink-subtle); + font-weight: 500; + max-inline-size: var(--measure-prose); + margin-block-end: var(--space-3); +} + +.featured-card__excerpt { font-size: var(--step--1); + color: var(--color-ink-subtle); + line-height: 1.6; + max-inline-size: var(--measure-prose); + margin-block-end: var(--space-3); } -.featured-card__highlights { +.featured-card__tags { + display: flex; + flex-wrap: wrap; + gap: var(--space-2); list-style: none; padding: 0; - display: flex; - flex-direction: column; - gap: var(--space-1); - font-size: var(--step--1); + margin: 0 0 var(--space-3); } -.featured-card__highlights li::before { - content: "\2713\0020"; - color: var(--color-tier-active); - font-weight: 700; +.featured-card__tags li { + font-size: var(--step--1); + color: var(--color-ink-subtle); + padding: var(--space-1) var(--space-3); + background: var(--color-surface-highlight); + border-radius: var(--radius-sm); + white-space: nowrap; } .featured-card__cta { - margin-block-start: auto; font-size: var(--step--1); } diff --git a/src/design/layout.css b/src/design/layout.css index e6e4105..362014f 100644 --- a/src/design/layout.css +++ b/src/design/layout.css @@ -66,7 +66,20 @@ margin-inline: calc(-1 * var(--space-5)); border-radius: var(--radius-md); } - .home-featured__grid, + .home-featured__header { + display: grid; + gap: var(--space-2); + } + .home-featured__intro { + font-size: var(--step-0); + color: var(--color-ink-subtle); + } + .home-featured__list { + display: flex; + flex-direction: column; + gap: var(--space-5); + margin-block-start: var(--space-4); + } .home-stats__grid, .work-index__featured-grid { display: grid; @@ -74,12 +87,11 @@ container-type: inline-size; } @container (min-width: 48rem) { - .home-featured__grid { grid-template-columns: repeat(2, 1fr); } .home-stats__grid { grid-template-columns: repeat(3, 1fr); } .work-index__featured-grid { grid-template-columns: repeat(2, 1fr); } } @container (min-width: 72rem) { - .home-featured__grid { grid-template-columns: repeat(4, 1fr); } + .work-index__list { grid-template-columns: repeat(3, 1fr); } } .work-list { list-style: none; diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 0ac3753..4d02b8a 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -36,8 +36,13 @@ export function Home({