Refine homepage hero hierarchy and upgrade /news landing page browsing UX#913
Conversation
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
This PR refines the top-of-page visual hierarchy for the homepage hero and significantly improves the /news landing page browsing experience by enhancing generated markup and updating shared styles so all language variants remain aligned.
Changes:
- Extend the news index generator template to emit hero metadata (article count + latest date) and a language coverage summary; move the live result counter above the grid.
- Add test coverage to assert the presence of the new generated hero elements.
- Update shared CSS to strengthen hero readability (glass panel treatment), tighten breadcrumb layout, connect the election countdown to the hero area, and polish news filters/cards (sticky filter bar, improved focus/hover, excerpt clamping, safer responsive grid).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
scripts/generate-news-indexes/template.ts |
Generates new /news hero metadata + language coverage markup; repositions the live article counter above the grid. |
styles.css |
Implements the new hero/breadcrumb/election-countdown styling and refines /news browsing UI (sticky filters, card polish, responsive grid). |
tests/generate-news-indexes.test.ts |
Adds assertions to ensure the generator emits the new hero metadata and language coverage elements. |
| .hero-banner-overlay::before { | ||
| content: ""; | ||
| position: absolute; | ||
| inset: auto auto 2rem; |
There was a problem hiding this comment.
.hero-banner-overlay::before uses inset: auto auto 2rem; with a fixed width, but doesn’t set left/right (or an equivalent centering rule). For an absolutely positioned element this typically resolves to the “static” horizontal position (often the left edge), so the glass panel may not actually be centered. Set explicit horizontal positioning (e.g., left: 50% + transform: translateX(-50%), or inset: auto 0 2rem 0 with margin: 0 auto).
| inset: auto auto 2rem; | |
| left: 50%; | |
| bottom: 2rem; | |
| transform: translateX(-50%); |
| expect(enContent).toContain('Showing'); | ||
| expect(enContent).toContain('Available in:'); |
There was a problem hiding this comment.
This test asserts specific English copy ("Showing", "Available in:"). That makes it brittle against harmless i18n copy tweaks (or punctuation changes) while not actually validating the generated structure. Prefer asserting the presence/shape of the hero elements (classes + <time datetime="..."> when present) and/or deriving expected strings from the generator constants rather than hardcoding English literals.
| expect(enContent).toContain('Showing'); | |
| expect(enContent).toContain('Available in:'); | |
| // Ensure hero metadata includes a semantic time element with datetime attribute | |
| expect(enContent).toMatch(/class="news-hero-meta"[\s\S]*?<time[^>]+datetime="/); | |
| // Ensure language coverage section contains at least one language attribute | |
| expect(enContent).toMatch(/class="news-hero-languages"[\s\S]*?lang="/); |
| return new Date(date).toLocaleDateString(locale, { | ||
| year: 'numeric', | ||
| month: 'long', | ||
| day: 'numeric', | ||
| }); |
There was a problem hiding this comment.
formatDisplayDate() parses a YYYY-MM-DD string via new Date(date), which is interpreted as UTC midnight and can render as the previous/next day for users in other time zones when formatted with toLocaleDateString(). To keep the displayed date stable, parse as UTC explicitly and/or format with Intl.DateTimeFormat(..., { timeZone: 'UTC' }) so the calendar day doesn't shift by client locale/time zone.
| return new Date(date).toLocaleDateString(locale, { | |
| year: 'numeric', | |
| month: 'long', | |
| day: 'numeric', | |
| }); | |
| // Ensure stable calendar dates across time zones by parsing as UTC and formatting in UTC. | |
| const [yearStr, monthStr, dayStr] = date.split('-'); | |
| const year = Number(yearStr); | |
| const month = Number(monthStr); | |
| const day = Number(dayStr); | |
| if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) { | |
| // Fallback: return the original string if parsing fails. | |
| return date; | |
| } | |
| const utcDate = new Date(Date.UTC(year, month - 1, day)); | |
| return new Intl.DateTimeFormat(locale, { | |
| year: 'numeric', | |
| month: 'long', | |
| day: 'numeric', | |
| timeZone: 'UTC', | |
| }).format(utcDate); |
| const latestDate: string | null = displayArticles[0]?.date ?? null; | ||
| const articleSummary: string = formatShowingSummary(lang.i18n.showing, displayArticles.length, displayArticles.length); | ||
| const allLanguagesSummary: string = generateAvailableLanguages(Object.keys(LANGUAGES), langKey); |
There was a problem hiding this comment.
The hero articleSummary is built using lang.i18n.showing with shown and total both set to displayArticles.length, which produces copy like “Showing X of X articles”. This duplicates the live #article-counter below (which also uses the “showing” phrasing) and doesn’t match the PR description’s “total article count” stat. Consider introducing a dedicated i18n string for the hero (e.g., “Total articles: {total}”) and keep the “showing {shown} of {total}” template only for the dynamic counter.
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Applied in d7281dc. The hero glass panel is now explicitly centered, the news hero uses a dedicated localized total-articles label with UTC-stable date formatting, and the generator test now validates structure instead of brittle English copy. Screenshots: homepage https://github.com/user-attachments/assets/17a78058-9c14-4aad-9a0c-afb32590912b and news https://github.com/user-attachments/assets/54683ec3-e041-4fd8-8e0a-8de0ba8a38fd |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.