Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/assets/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}
52 changes: 52 additions & 0 deletions docs/assets/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
? `<a class="about-link" href="#documents/${encodeURIComponent(e.docId)}">${escape(e.symbol || e.docId)}</a>`
: `<span>${escape(e.symbol)}</span>`;
return `<li class="update-log-row${added ? '' : ' is-not-added'}"><time datetime="${escape(e.date)}">${escape(_logDay(e.date))}</time>`
+ `<span class="update-log-status">${added ? 'Added' : 'Not added'}</span>`
+ `<span class="update-log-doc">${sym} · ${escape(e.title)}${e.body ? ` <span class="dim">— ${escape(e.body)}</span>` : ''}`
+ `${e.note ? `<span class="update-log-note">${escape(e.note)}</span>` : ''}</span></li>`;
}).join('') : '<li class="dim">No changes since the log started.</li>';
}
const chip = $('#foot-updated');
if (chip) {
const built = state.apiStats?.manifest?.builtAt || state.manifest?.builtAt || '';
const latest = [built.slice(0, 10), entries[0]?.date || ''].sort().pop();
const cutoff = new Date(Date.now() - 30 * 864e5).toISOString().slice(0, 10);
const recent = entries.filter(e => e.status === 'added' && e.date >= cutoff).length;
if (latest) {
chip.textContent = `Data updated ${_logDay(latest)}` + (recent ? ` · +${recent} new` : '');
chip.title = (recent ? `${recent} ${recent === 1 ? 'document' : 'documents'} added in the last 30 days. ` : '') + 'Open the update log.';
chip.hidden = false;
}
}
}
function openUpdateLog(ev) {
ev.preventDefault();
window.location.hash = 'about';
setTimeout(() => $('#update-log')?.scrollIntoView({ block: 'start', behavior: 'smooth' }), 60);
}

// ─────────── "Data as of" chip under the Source list ───────────
// When the corpus behind the selected source last changed. UNHRDB: the live API's build date (the static
// manifest when the API is offline). Recommendations: the newest UHRI recommendation and the last check of
Expand Down Expand Up @@ -1561,6 +1611,8 @@ function paintMastFolio(m) {
if (q) q.placeholder = `Search ${totParas} paragraphs across ${totDocs} UN documents…`;
paintFreshnessCard(m);
paintDataAsOf();
paintUpdateLog();
$('#foot-updated')?.addEventListener('click', openUpdateLog);
}

// Freshness card — green/amber/red traffic light on the About tab.
Expand Down
2 changes: 1 addition & 1 deletion docs/feeds/index.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"builtAt": "2026-10-13T21:25:20+00:00",
"builtAt": "2026-10-13T21:48:29+00:00",
"feeds": [
{
"id": "all",
Expand Down
14 changes: 12 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@
</script>

<link rel="stylesheet" href="assets/tokens.css?v=20261013-f5d20f0" />
<link rel="stylesheet" href="assets/app.css?v=20261013-asof" />
<link rel="stylesheet" href="assets/app.css?v=20261013-log" />

<!-- Google Analytics 4 is loaded LAZILY, only after the visitor opts in
via the consent banner — see initConsent()/loadAnalytics() in app.js.
Expand Down Expand Up @@ -1543,6 +1543,14 @@ <h3 class="folio">Open data — Hugging Face</h3>
additions by day; returning visitors see a “new” chip on documents added
since their last visit.
</p>
<div class="update-log-block" id="update-log">
<p class="serif">
<strong>Update log.</strong> Every document added since <span id="update-log-since">13 October 2026</span>,
and every document that was checked and left out, with the reason. New UN documents are found by a
daily check of the UN Documents system; each is reviewed (paragraphs, notes, headings) before it is added.
</p>
<ol class="update-log" id="update-log-list" aria-label="Update log, newest first"><li class="dim">Loading…</li></ol>
</div>
<p class="serif">
<strong>Related paragraphs.</strong> For every General Comment paragraph the
reader and the dossier list the five most similar paragraphs of other General
Expand Down Expand Up @@ -1676,6 +1684,8 @@ <h3 class="folio">Contact</h3>
<footer class="foot">
<div class="foot-inner">
<span class="folio" id="foot-version">Build —</span>
<!-- When the data last changed and how many documents arrived lately; opens the update log (paintUpdateLog). -->
<a class="foot-updated" id="foot-updated" href="#about" hidden></a>
<span class="dim">·</span>
<span class="serif" style="font-style: italic;">App by <a href="https://lszoszk.github.io" class="foot-link" target="_blank" rel="noopener">Łukasz Szoszkiewicz</a> &amp; Zuzanna Kowalska.</span>
<span class="dim">·</span>
Expand Down Expand Up @@ -1753,7 +1763,7 @@ <h3 id="report-modal-title" class="report-modal-title">What did you spot?</h3>
<div class="diff-tray" id="diff-tray" hidden></div>
<div class="diff-modal" id="diff-modal" hidden></div>

<script type="module" src="assets/app.js?v=20261013-asof"></script>
<script type="module" src="assets/app.js?v=20261013-log"></script>
<script src="assets/who.js?v=20261013" data-tool="unhrdb" data-endpoint="https://lszoszk.goatcounter.com/count" defer></script>
</body>
</html>
89 changes: 89 additions & 0 deletions docs/updates/log.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"since": "2026-10-13",
"builtAt": "2026-10-13T21:48:29+00:00",
"added": 8,
"entries": [
{
"date": "2026-10-13",
"status": "added",
"type": "gc",
"docId": "cerd-c-gc-40",
"symbol": "CERD/C/GC/40",
"title": "General Recommendation No. 40 (2026) on reparatory justice for the harms and continuing consequences of colonialism, the trafficking in enslaved Africans across the Atlantic and other routes, and racialized chattel slavery",
"body": "Committee on the Elimination of Racial Discrimination"
},
{
"date": "2026-10-13",
"status": "added",
"type": "sp",
"docId": "a-hrc-62-48",
"symbol": "A/HRC/62/48",
"title": "Women's and girls' rights and artificial intelligence and related digital technologies",
"body": "WG Discrimination against Women and Girls"
},
{
"date": "2026-10-13",
"status": "added",
"type": "sp",
"docId": "a-81-133",
"symbol": "A/81/133",
"title": "Violence against older women",
"body": "SR Violence against Women"
},
{
"date": "2026-10-13",
"status": "added",
"type": "sp",
"docId": "a-81-132",
"symbol": "A/81/132",
"title": "Strategic vision, thematic priorities and methods of work of the Special Rapporteur",
"body": "SR Sale of Children"
},
{
"date": "2026-10-13",
"status": "added",
"type": "sp",
"docId": "a-81-130",
"symbol": "A/81/130",
"title": "Emerging technologies and transitional justice",
"body": "SR Truth Justice and Reparation"
},
{
"date": "2026-10-13",
"status": "added",
"type": "sp",
"docId": "a-81-128",
"symbol": "A/81/128",
"title": "The psychosocial impact of colour-based discrimination on the enjoyment of human rights by persons with albinism",
"body": "IE Albinism"
},
{
"date": "2026-10-13",
"status": "added",
"type": "sp",
"docId": "a-80-341",
"symbol": "A/80/341",
"title": "Threats to freedom of expression online in turbulent times",
"body": "SR Freedom of Expression"
},
{
"date": "2026-10-13",
"status": "added",
"type": "sp",
"docId": "a-80-139",
"symbol": "A/80/139",
"title": "Access delayed, rights denied: bottlenecks in the leprosy drug supply chain and their daily impact on affected persons",
"body": "SR Leprosy"
},
{
"date": "2026-10-13",
"status": "not-added",
"type": "sp",
"docId": null,
"symbol": "A/80/115",
"title": "Reports of the Working Group on discrimination against women and girls — note by the Secretariat",
"body": "WG Discrimination against Women and Girls",
"note": "A note of the Secretariat that points to the Working Group's reports to the Human Rights Council; the reports themselves are in the database."
}
]
}
Loading