diff --git a/docs/assets/app.css b/docs/assets/app.css index 80674d1d..a3c2ce84 100644 --- a/docs/assets/app.css +++ b/docs/assets/app.css @@ -7191,3 +7191,24 @@ mark.ck ins { color: var(--status-good, #2f6b3a); text-decoration: none; font-st border: 1px solid var(--rule, #ddd); border-radius: 999px; font-size: 11.5px; color: var(--ink-3); cursor: help; } .data-asof::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .55; } + +/* Update log (About › Methodology) and its footer chip (paintUpdateLog) */ +.foot-updated { + display: inline-flex; align-items: center; gap: 6px; padding: 2px 9px; border: 1px solid var(--rule); + border-radius: 999px; color: var(--ink-2); text-decoration: none; font-size: 11px; white-space: nowrap; +} +.foot-updated::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--garnet); opacity: .7; } +.foot-updated:hover, .foot-updated:focus-visible { border-color: var(--garnet); color: var(--ink); } +.update-log { + list-style: none; margin: 8px 0 16px; padding: 0; max-height: 320px; overflow-y: auto; + border: 1px solid var(--rule); border-radius: 4px; font-size: 13px; +} +.update-log-row { display: grid; grid-template-columns: 92px 78px 1fr; gap: 10px; padding: 7px 10px; border-bottom: 1px solid var(--rule); } +.update-log-row:last-child { border-bottom: 0; } +.update-log-row time { color: var(--ink-3); font-variant-numeric: tabular-nums; white-space: nowrap; } +.update-log-status { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--garnet); } +.update-log-row.is-not-added .update-log-status { color: var(--ink-3); } +.update-log-note { display: block; color: var(--ink-3); font-size: 12px; margin-top: 2px; } +@media (max-width: 640px) { + .update-log-row { grid-template-columns: 1fr; gap: 2px; } +} diff --git a/docs/assets/app.js b/docs/assets/app.js index cd1849c5..a2533ee8 100644 --- a/docs/assets/app.js +++ b/docs/assets/app.js @@ -275,6 +275,7 @@ async function pingApi() { state.apiStats = r; paintApiBadge(true, ms); paintDataAsOf(); + paintUpdateLog(); return; } catch (e) { console.warn(`[unhrdb-api] unreachable (${timeoutMs} ms budget):`, e.message); @@ -1495,6 +1496,55 @@ function mergeJurFacets(base) { }; } +// ─────────── Update log (About › Methodology) and the footer chip ─────────── +// docs/updates/log.json is written by the pipeline (build_feeds.py): every document added since the log +// started, and the ones reviewed and left out, with the reason. The footer chip says when the data last +// changed and how many documents arrived in the last 30 days; it opens the log. +const _logDay = d => new Date(d + (d.length === 10 ? 'T00:00:00Z' : '')).toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric', timeZone: 'UTC' }); +let _updateLog = null; +async function paintUpdateLog() { + try { + if (!_updateLog) { + const r = await fetch('updates/log.json', { cache: 'no-cache' }); + if (!r.ok) return; + _updateLog = await r.json(); + } + } catch (e) { return; } + const log = _updateLog, entries = log.entries || []; + const since = $('#update-log-since'); + if (since && log.since) since.textContent = _logDay(log.since); + const list = $('#update-log-list'); + if (list) { + list.innerHTML = entries.length ? entries.map(e => { + const added = e.status === 'added'; + const sym = added && e.docId + ? `${escape(e.symbol || e.docId)}` + : `${escape(e.symbol)}`; + return `