From e420f4f2bc8275f6cb04c8037f2cf988d8cb5a39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:40:55 +0000 Subject: [PATCH 1/3] Add nearby year navigation generator --- scripts/flashback-examples.mjs | 133 ++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/scripts/flashback-examples.mjs b/scripts/flashback-examples.mjs index 6fafc56..a0c9823 100644 --- a/scripts/flashback-examples.mjs +++ b/scripts/flashback-examples.mjs @@ -448,7 +448,7 @@ function syncExamples(entries) { for (const entry of entries) { const yearDir = join(EXAMPLES_DIR, String(entry.year)); mkdirSync(yearDir, { recursive: true }); - writeFileSync(join(yearDir, 'index.html'), generateExampleHtml(entry)); + writeFileSync(join(yearDir, 'index.html'), generateExampleHtml(entry, entries)); } writeFileSync(INDEX_PATH, generateIndexHtml(entries)); @@ -477,7 +477,7 @@ function checkExamples(entries) { for (const entry of entries) { const examplePath = join(EXAMPLES_DIR, String(entry.year), 'index.html'); const relativeExamplePath = relative(ROOT, examplePath); - const expectedHtml = generateExampleHtml(entry); + const expectedHtml = generateExampleHtml(entry, entries); if (!existsSync(examplePath)) { errors.push(`${relativeExamplePath} is missing. Run npm run sync:examples.`); @@ -630,12 +630,13 @@ function cleanupObsoleteExamples(entries) { } } -function generateExampleHtml(entry) { +function generateExampleHtml(entry, entries = [entry]) { const theme = getTheme(entry); const art = theme.art; const recipeNames = entry.recipes.map((recipe) => recipe.name).join(', '); const timelineItems = entry.timeline.slice(0, 6); const emergingItems = entry.designClimate.emerging.slice(0, 6); + const yearNavigator = renderExampleYearNavigator(entry, entries); return ` @@ -839,6 +840,84 @@ ${ornamentCss(art.ornament)} background: var(--accent-c); } + .year-rail { + display: grid; + gap: 12px; + margin-top: 22px; + } + + .year-rail-title { + margin: 0; + color: var(--muted); + font-family: var(--mono); + font-size: 0.78rem; + letter-spacing: 0.16em; + text-transform: uppercase; + } + + .year-rail-track { + display: flex; + flex-wrap: wrap; + gap: 10px; + } + + .year-chip { + --chip-a: var(--accent-a); + --chip-b: var(--accent-b); + --chip-c: var(--accent-c); + display: inline-flex; + align-items: baseline; + gap: 10px; + padding: 8px 12px; + color: var(--paper); + text-decoration: none; + border: 1px solid color-mix(in srgb, var(--chip-b) 55%, var(--line)); + border-top: 3px solid var(--chip-a); + background: color-mix(in srgb, var(--chip-a) 12%, rgba(0, 0, 0, 0.42)); + box-shadow: 5px 5px 0 rgba(0, 0, 0, 0.34); + transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease, background 0.18s ease; + } + + .year-chip:hover, + .year-chip:focus-visible { + color: var(--ink); + border-color: var(--chip-c); + background: var(--chip-c); + box-shadow: 7px 7px 0 rgba(0, 0, 0, 0.4); + transform: translate(-2px, -2px); + } + + .year-chip-num { + font-family: var(--display); + font-size: clamp(1.05rem, 2.6vw, 1.5rem); + line-height: 1; + letter-spacing: -0.08em; + text-transform: uppercase; + } + + .year-chip-stamp { + font-family: var(--mono); + font-size: 0.62rem; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--ink); + background: var(--chip-c); + padding: 4px 7px; + white-space: nowrap; + } + + .year-chip[aria-current="page"] { + color: var(--ink); + border-color: var(--chip-c); + background: color-mix(in srgb, var(--chip-c) 74%, var(--paper)); + box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.42); + pointer-events: none; + } + + .year-chip[aria-current="page"] .year-chip-stamp { + background: color-mix(in srgb, var(--chip-a) 16%, var(--paper)); + } + .backlink { display: inline-flex; align-items: center; @@ -1225,6 +1304,7 @@ ${layoutCss(art.layout)}
  • Full corpus
  • +${yearNavigator}
    @@ -1294,6 +1374,8 @@ ${entry.antiCliches.map((item) => `
  • ${escapeHtml(item)}
  • `).join('

    ${escapeHtml(entry.feeling ? `${entry.year} rule: ${entry.feeling}.` : entry.frontmatter.subtitle)}

    +${yearNavigator} +