From fe7bdb61647e41bba0c186f521e7982f61b9d150 Mon Sep 17 00:00:00 2001 From: Jamie Date: Tue, 15 Sep 2026 14:26:20 -0400 Subject: [PATCH] Make category filters responsive --- CHANGELOG.md | 1 + docs/configuration.md | 2 +- scripts/lib/web.ts | 10 +++++----- scripts/verify-release.mjs | 9 +++++---- src/copy/en.ts | 2 +- src/domain.ts | 14 ++++++++++++-- src/main.ts | 18 ++++++++++-------- tests/contracts/output.test.ts | 4 ++++ tests/e2e/layout.spec.ts | 11 ++++++++--- tests/unit/presentation.test.ts | 21 ++++++++++++++++++++- 10 files changed, 67 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61f3f41..f9748e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Notable user-visible changes to Food Help are recorded here. Community publicati ### Changed +- Category controls now show only primary types represented in the active browsing view, and omit “All types” when only one type is available. - Published resources require reviewed, evidence-backed cost information. Free services appear in Emergency food, low-cost and subsidized services appear in Affordable food, and mixed-cost services appear in both without duplicate records. - Static, printable, downloaded, offline and public-data surfaces continue to preserve the complete published directory. - Kingston’s eight Lionhearts Fresh Food Market location records were approved by Jamie Whelan for publication on 2026-09-15, with their recorded uncertainties and accessibility qualifications unchanged. diff --git a/docs/configuration.md b/docs/configuration.md index 011a384..b247af3 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -37,7 +37,7 @@ Branding files must live in the selected folder's `assets/` and are copied with Jurisdiction configuration contains `coverage_through` and `warning_dates` entries with date, note, source URL and checked date. There is no automatic national holiday library. A local warning suppresses an inferred weekly status unless a provider has a confirmed exception for that date. Expired coverage yields uncertainty. Do not assume that a public holiday means a provider is closed. -The directory title derives from `community.name`. `presentation.introduction` overrides the generic introductory sentence. Optional `presentation.category_groups` entries have a unique `id`, a short `label`, and one or more existing taxonomy `categories`. For example, a “Take-home food” button can include both `groceries` and `food_banks_pantries`. Groups without published resources are hidden. Without configured groups, buttons are generated from the categories present. The built-in “All food help” option always includes all published resources, even categories outside the configured groups; do not define an `all` group yourself. Grouping changes discovery, never resource classification or evidence. +The directory title derives from `community.name`. `presentation.introduction` overrides the generic introductory sentence. Optional `presentation.category_groups` entries have a unique `id`, a short `label`, and one or more existing taxonomy `categories`. For example, a “Take-home food” button can include both `groceries` and `food_banks_pantries`. The first category on a resource is its primary configured filter type; later categories remain descriptive tags and search terms. Groups without a resource of that primary type are hidden. Without configured groups, buttons are generated from all categories present. “All types” appears when two or more groups are available, or when it is needed to keep a resource whose primary category is outside the configured groups reachable. A single represented group is shown by itself. Do not define an `all` group. Grouping changes discovery, never resource classification or evidence. The compact header and help panel use `help_contact.label` and `help_contact.description`; keep the label brief. `operator.statement` supports plain-text line breaks in the footer. These are reviewed public deployment copy, not HTML templates. diff --git a/scripts/lib/web.ts b/scripts/lib/web.ts index a861207..aea0948 100644 --- a/scripts/lib/web.ts +++ b/scripts/lib/web.ts @@ -2,7 +2,7 @@ import { createHash } from 'node:crypto'; import { copy as c } from '../../src/copy/en.ts'; import { card, escape as e, resourcePath, formatDate } from '../../src/presentation.ts'; -import { browseViewPaths, categoryGroups, inBrowseView, type BrowseView } from '../../src/domain.ts'; +import { browseViewPaths, categoryFilter, inBrowseView, type BrowseView } from '../../src/domain.ts'; import type { PublicDataset, Site, Usage } from '../../src/types.ts'; export const digest = (input: string | Uint8Array): string => createHash('sha256').update(input).digest('hex'); export type Page = { path: string; title: string; description: string; body: string; indexable: boolean; directory?: boolean; review?: boolean; jsonld?: unknown }; @@ -15,7 +15,7 @@ export function pages(site: Site, data: PublicDataset, usage?: Usage): Page[] { const directoryPage = (view: BrowseView): Page => { const path = browseViewPaths[view], label = c.browseViews[view], description = c.browseDescriptions[view]; const resources = data.resources.filter(resource => inBrowseView(resource, view)); - const groups = categoryGroups(site, resources); + const { groups, includeAll } = categoryFilter(site, resources); const listData = { '@context': 'https://schema.org', '@type': 'CollectionPage', name: view === 'emergency' ? site.site_name : `${label} | ${site.site_name}`, url: site.canonical_origin + path, description, mainEntity: { '@type': 'ItemList', itemListElement: resources.map((r, index) => ({ '@type': 'ListItem', position: index + 1, url: site.canonical_origin + resourcePath(r.id), name: r.name })) } }; const viewNavigation = ``; return { @@ -25,9 +25,9 @@ export function pages(site: Site, data: PublicDataset, usage?: Usage): Page[] {

${c.directory}

${data.data_updated_on ? `${c.listingsUpdated} · ${formatDate(data.data_updated_on, site)}` : ''}

${viewNavigation}

${e(description)}

-