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
7 changes: 7 additions & 0 deletions docs/assets/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -7184,3 +7184,10 @@ mark.ck ins { color: var(--status-good, #2f6b3a); text-decoration: none; font-st
.check-shell { padding: 18px 14px 48px; }
.check-toggle { margin-left: 0; }
}

/* "Data as of" chip under the Source list (paintDataAsOf) */
.data-asof {
display: inline-flex; align-items: center; gap: 6px; margin: 10px 0 0; padding: 3px 9px;
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; }
43 changes: 43 additions & 0 deletions docs/assets/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ async function pingApi() {
state.apiOnline = true;
state.apiStats = r;
paintApiBadge(true, ms);
paintDataAsOf();
return;
} catch (e) {
console.warn(`[unhrdb-api] unreachable (${timeoutMs} ms budget):`, e.message);
Expand Down Expand Up @@ -1494,6 +1495,46 @@ function mergeJurFacets(base) {
};
}

// ─────────── "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
// OHCHR for new ones, from the UHRI mirror's refresh status.
const _asofDay = d => new Date(d).toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric', timeZone: 'UTC' });
let _uhriFresh = null;
async function loadUhriFreshness() {
if (_uhriFresh) return _uhriFresh;
try {
const [st, h] = await Promise.all([
fetch(UHRI_API_BASE + '/refresh_status.json', { cache: 'no-store' }).then(r => (r.ok ? r.json() : {})),
uhriFetch('/api/data/health'),
]);
_uhriFresh = { latest: st.latest_publication || null, changed: h.modified_at || null,
checked: st.last_checked_at || st.finished_at || null };
} catch (e) { _uhriFresh = null; }
return _uhriFresh;
}
async function paintDataAsOf() {
const el = $('#data-asof');
if (!el) return;
if (state.scope === 'rec') {
el.hidden = true;
const f = await loadUhriFreshness();
if (!f || state.scope !== 'rec') return;
const main = f.latest ? `Recommendations to ${_asofDay(f.latest)}` : f.changed ? `Updated ${_asofDay(f.changed)}` : '';
if (!main) return;
el.textContent = main + (f.checked ? ` · checked ${_asofDay(f.checked)}` : '');
el.title = 'UHRI recommendations reach the index some weeks after the documents are published. '
+ (f.checked ? `OHCHR was last checked for new ones on ${_asofDay(f.checked)}` : '')
+ (f.changed ? `; the data last changed on ${_asofDay(f.changed)}.` : '.');
} else {
const built = state.apiStats?.manifest?.builtAt || state.manifest?.builtAt;
if (!built) { el.hidden = true; return; }
el.textContent = `Data updated ${_asofDay(built)}`;
el.title = `General Comments, jurisprudence and Special Procedures reports, as built on ${_asofDay(built)}. New documents are added after review, not automatically.`;
}
el.hidden = false;
}

// ─────────── Masthead folio ───────────
function paintMastFolio(m) {
const today = new Date().toLocaleDateString('en-GB', { day: '2-digit', month: 'long', year: 'numeric' }).toUpperCase();
Expand All @@ -1519,6 +1560,7 @@ function paintMastFolio(m) {
const q = $('#q');
if (q) q.placeholder = `Search ${totParas} paragraphs across ${totDocs} UN documents…`;
paintFreshnessCard(m);
paintDataAsOf();
}

// Freshness card — green/amber/red traffic light on the About tab.
Expand Down Expand Up @@ -6246,6 +6288,7 @@ function bindUI() {
syncRecFiltersVisibility();
paintCountryFilter();
if (state.scope === 'rec') { loadRecVocab(); paintRecFilters(); }
paintDataAsOf();

// Jurisprudence has 3,100+ documents and 111k paragraphs, so
// the default "Paragraphs" view dumps a wall of weakly-related rows on
Expand Down
6 changes: 4 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-f5d20f0" />
<link rel="stylesheet" href="assets/app.css?v=20261013-asof" />

<!-- 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 @@ -419,6 +419,8 @@ <h1 class="serif mast-title" title="A paragraph-level companion to UN Treaty Bod
<span class="scope-count" id="count-rec">UHRI · live</span>
</button>
</div>
<!-- How current the selected source is: paintDataAsOf() in app.js. -->
<p class="data-asof" id="data-asof" hidden></p>
<!-- Populated by paintScopeBanner() — currently only the Jurisprudence
scope shows a banner; Special Procedures no longer does. -->
<div class="scope-banner" id="scope-banner" hidden></div>
Expand Down Expand Up @@ -1751,7 +1753,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-f5d20f0"></script>
<script type="module" src="assets/app.js?v=20261013-asof"></script>
<script src="assets/who.js?v=20261013" data-tool="unhrdb" data-endpoint="https://lszoszk.goatcounter.com/count" defer></script>
</body>
</html>
Loading