From 084d1f8b52de39393d9c1ddfebfc24f738e4ecf6 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 15:51:12 +0000 Subject: [PATCH] Make directory cards and pages easier to scan Shorter directory introduction and view descriptions, coloured schedule status badges, one time range per line with shorter twelve-hour times, larger field labels and button text, Call and Directions before the detail on resource pages, and a direct directory link in the project homepage introduction. Phone numbers show in North American format, addresses drop the country code, and dated changes no longer end in a double period. --- CHANGELOG.md | 1 + deployments/kingston/site.json | 2 +- project-site/styles.css | 4 +- scripts/build-project.ts | 2 +- src/copy/en.ts | 12 ++-- src/presentation.ts | 38 ++++++++---- src/styles.css | 104 +++++++++++++++++++------------- tests/unit/presentation.test.ts | 14 ++++- 8 files changed, 112 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f341b..ed2ca53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Notable user-visible changes to Food Help are recorded here. Community publicati ### Changed +- Directory cards are easier to scan: schedule status is a coloured badge, today’s hours show one time range per line with shorter twelve-hour times (for example “9–11 a.m.”), field labels are larger, the current view’s tag and a repeated operator name are no longer shown, and the directory introduction is shorter. Resource pages show Call and Directions before the detailed schedule and sources, phone numbers in North American format, and addresses without the country code. The project homepage links straight to the directory from its introduction when one community is available. - Configured community directories can link discreetly back to the Food Help project without changing their resource URLs or provider data. - 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. diff --git a/deployments/kingston/site.json b/deployments/kingston/site.json index 0337e17..365dacc 100644 --- a/deployments/kingston/site.json +++ b/deployments/kingston/site.json @@ -39,7 +39,7 @@ "interval_days": 30 }, "presentation": { - "introduction": "Find Emergency food or Affordable food in Kingston. Use meal, grocery and market filters to see what is offered, and check details before travelling.", + "introduction": "Free and low-cost meals and groceries in Kingston, and when to go.", "category_groups": [ { "id": "meals", "label": "Meals", "categories": ["prepared_meals"] }, { "id": "groceries", "label": "Groceries", "categories": ["groceries", "food_banks_pantries"] }, diff --git a/project-site/styles.css b/project-site/styles.css index 98dd16f..02e78b6 100644 --- a/project-site/styles.css +++ b/project-site/styles.css @@ -34,6 +34,8 @@ h1,h2,h3{color:var(--navy);line-height:1.15} .eyebrow{margin:0 0 .8rem;color:var(--brick);font-size:.875rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase} h1{max-width:14ch;margin:0;font-size:clamp(2.7rem,6.3vw,5.6rem);font-weight:650;letter-spacing:-.04em} .hero-lead{max-width:40rem;margin:1.4rem 0 0;color:var(--muted);font-size:clamp(1.08rem,1.8vw,1.3rem);line-height:1.55} +.hero-actions{margin:1.6rem 0 0} +.hero-actions .button{min-height:52px;padding-inline:1.4rem;font-size:1.05rem} .hero-note{border-left:4px solid var(--brick);padding:.25rem 0 .25rem 1.25rem;color:var(--muted)} .hero-note strong{display:block;color:var(--navy);font-size:1.15rem} .hero-note p{margin:.35rem 0 0} @@ -78,7 +80,7 @@ h1{max-width:14ch;margin:0;font-size:clamp(2.7rem,6.3vw,5.6rem);font-weight:650; .header-inner{align-items:flex-start;flex-direction:column;gap:.25rem;padding-block:.75rem} .site-nav{justify-content:flex-start;gap:.1rem 1rem} .hero,.section-heading,.split,.contact-panel,.footer-inner{grid-template-columns:1fr} - .hero{gap:2rem;padding-top:3.5rem} + .hero{gap:2rem;padding-top:2rem} .community-card{grid-template-columns:1fr} .principles{grid-template-columns:1fr} .footer-links{justify-content:flex-start} diff --git a/scripts/build-project.ts b/scripts/build-project.ts index addd291..70f5a99 100644 --- a/scripts/build-project.ts +++ b/scripts/build-project.ts @@ -61,7 +61,7 @@ function home(site: ProjectSite, communities: CommunityList, production: boolean { '@type': 'ItemList', name: 'Food Help community directories', itemListElement: communities.communities.map((community, index) => ({ '@type': 'ListItem', position: index + 1, name: `${community.name} Food Help`, url: `${community.canonical_url}/` })) } ] }; return `${head(site, '/', site.site_name, site.description, index, css, logo, jsonld)}${header(site, logo)}
-

Emergency and affordable food directories

${e(site.headline)}

${e(site.introduction)}

+

Emergency and affordable food directories

${e(site.headline)}

${e(site.introduction)}

${communities.communities.length === 1 ? `Find food in ${e(communities.communities[0]!.name)}` : 'Choose a community'}

Choose a community

Community directories are the place to find food programs. This project homepage does not duplicate their listings.

${communityCards}

Information people can check

${e(site.maintenance)}

  1. Public sources

    Published program pages and trusted public directories provide an evidence trail.

  2. Provider input

    Provider details can clarify what is offered and what people should know before travelling.

  3. Corrections

    Community feedback is reviewed before it changes a public listing.

diff --git a/src/copy/en.ts b/src/copy/en.ts index a55a675..7f70a44 100644 --- a/src/copy/en.ts +++ b/src/copy/en.ts @@ -8,14 +8,14 @@ export const copy = { directory: 'What would help?', browseBy: 'Choose the kind of food access you need', all: 'All types', search: 'Search the directory', searchPlaceholder: 'Name, street or neighbourhood', category: 'Type of food help', browseViews: { emergency: 'Emergency food', affordable: 'Affordable food' }, browseDescriptions: { - emergency: 'Free food support, including services with both free and lower-cost options. You do not need to prove a crisis to browse or ask for help; each listing explains any eligibility or access requirements.', - affordable: 'Lower-cost or subsidized food sold through community programs, including services with both paid and free options. These are food purchases unless a listing says otherwise.', + emergency: 'Free food, including places with some low-cost options. You do not need to prove a crisis. Each listing says who can use it.', + affordable: 'Lower-cost food sold through community programs, including places with some free options. Each listing says what it costs.', }, scheduledFilter: 'Open now or later today', location: 'Use my location', clearLocation: 'Forget my location', - locationOptional: 'Location is optional. Browse all listings without it.', - scheduleDisclaimer: 'Times are based on published schedules,', notLive: 'not live availability.', callBefore: 'Call before travelling when you can.', + locationOptional: 'Location is optional.', + scheduleDisclaimer: 'Times come from published schedules,', notLive: 'not live availability.', callBefore: 'Call before travelling when you can.', locationNotice: 'Location stays in memory on this device. Distance is straight-line, not a travel route.', locationFailed: 'Location was unavailable. You can still browse every resource.', - nearest: 'Approximate distance', resourceCount: (n: number, view: 'emergency' | 'affordable', review = false) => review ? `${n} ${n === 1 ? 'option' : 'options'} shown for review in ${view === 'emergency' ? 'Emergency food' : 'Affordable food'}.` : `${n} reviewed ${n === 1 ? 'option' : 'options'} shown in ${view === 'emergency' ? 'Emergency food' : 'Affordable food'}.`, noResults: (view: 'emergency' | 'affordable', includeAll = true) => `No ${view === 'emergency' ? 'Emergency food' : 'Affordable food'} options match. Clear the search${includeAll ? ', choose All types, or' : ' or'} turn off the schedule filter.`, noListings: (view: 'emergency' | 'affordable') => view === 'emergency' ? 'No Emergency food listings have completed review for publication yet. Affordable food listings may still be available.' : 'No Affordable food listings have completed review for publication yet. Emergency food listings are still available.', + nearest: 'Approximate distance', resourceCount: (n: number, view: 'emergency' | 'affordable', review = false) => review ? `${n} ${n === 1 ? 'option' : 'options'} shown for review in ${view === 'emergency' ? 'Emergency food' : 'Affordable food'}.` : `${n} ${n === 1 ? 'place' : 'places'} in ${view === 'emergency' ? 'Emergency food' : 'Affordable food'}.`, noResults: (view: 'emergency' | 'affordable', includeAll = true) => `No ${view === 'emergency' ? 'Emergency food' : 'Affordable food'} options match. Clear the search${includeAll ? ', choose All types, or' : ' or'} turn off the schedule filter.`, noListings: (view: 'emergency' | 'affordable') => view === 'emergency' ? 'No Emergency food listings have completed review for publication yet. Affordable food listings may still be available.' : 'No Affordable food listings have completed review for publication yet. Emergency food listings are still available.', provider: 'Operated by', address: 'Where', today: 'Today', quickAccess: 'Access', area: 'Service area', phone: 'Phone', eligibility: 'Who can use this', limitations: 'Limitations', before: 'Before you go', access: 'Access requirements', details: 'Before you go & weekly hours', schedule: 'Published schedule', timezone: 'Local timezone', cost: 'Cost', languages: 'Service languages', foodPurpose: 'Food support provided', staticHours: 'See published hours below; confirm before travelling.', accessUnknown: 'Check access arrangements before travelling.', dropIn: 'Drop-in access', appointmentNeeded: 'Appointment required', registrationNeeded: 'Registration required', @@ -27,7 +27,7 @@ export const copy = { weekdays: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], closed: 'No service by published schedule', nextDay: '(next day)', scheduled: { scheduled_now: 'Open by published schedule', not_scheduled_now: 'Outside published hours or currently unavailable', unknown: 'Check hours with the provider' }, scheduleLabels: { now: 'Open by schedule', later: 'Later today', ended: 'No more hours today', none: 'No published hours today', unknown: 'Check hours before going', unavailable: 'Service temporarily unavailable' }, - appointmentHours: 'Appointment hours', appointmentLater: 'Appointments later today', bookingRequired: 'Booking required', until: 'Until', publishedOpening: 'Published opening', seeWeekly: 'See the weekly hours below.', + appointmentHours: 'Appointment hours', appointmentLater: 'Appointments later today', bookingRequired: 'Booking required', until: 'Until', publishedOpening: 'Scheduled to open', seeWeekly: 'See the weekly hours below.', scheduleKinds: { weekly: 'Weekly schedule', dated: 'Dated schedule', by_arrangement: 'Contact provider to arrange', unknown: 'Hours not confirmed' }, validity: 'Schedule date range', exceptions: 'Date-specific changes', unconfirmed: 'Unconfirmed', reviewed: 'Last reviewed', updated: 'Information updated', overdue: 'Review overdue — confirm details before travelling.', source: 'Official details', scheduleSource: 'Schedule and updates', sources: 'Evidence and provenance', checked: 'Source checked', sourcesChecked: 'Sources checked', supports: 'Reviewed information', call: 'Call', directions: 'Directions', resourcePage: 'Resource page', diff --git a/src/presentation.ts b/src/presentation.ts index c313b8a..b0fbc52 100644 --- a/src/presentation.ts +++ b/src/presentation.ts @@ -8,19 +8,33 @@ export const list = (items: readonly string[]): string => items.length ? `