Date: 2026-03-23
Status: Approved
Scope: Topic detail pages (/malefni/{slug}/)
Two improvements to the topic detail pages:
label_date_short()-style hierarchical labelsclaims.jsonThe site is receiving significant media attention (Spursmál, Bylgjan, Rás 2). Málefni is the natural entry point for "I want to understand topic X" — upgrading it improves both first impressions and return-visit value.
_includes/topic-detail.njk (lines 82–100)assets/css/topic-detail.css (lines 83–128)display: flex with equal flex: 1 sizing — each bar gets equal width regardless of time gap"22. apríl 2024") on every bar, positioned absolutely at bottom: -1.4remFilter to 2026 only. The EU debate is heating up this year; earlier data is sparse and not relevant to the current picture. The Nunjucks template filters topic.timeline to entries where w.week >= "2026-01-01".
Proportional time positioning. Bars are positioned on a real calendar axis. The container switches from display: flex to position: relative. Each bar gets:
left: X% — computed as (date - yearStart) / (yearEnd - yearStart) * 100max(1.5%, 6px) — ensures visibility even for sparse timelinesHierarchical labels in stacked rows below the bar area:
2026 shown once at the left edge (since all data is 2026)Label thinning when bars are dense:
Tooltips: full date on hover (e.g. "9. mars 2026: 174 tilvísanir, 127 nýjar fullyrðingar") — uses existing isDate filter, same format as before.
| File | Change |
|---|---|
_includes/topic-detail.njk |
Rewrite timeline section: filter to 2026, compute proportional positions, render three label rows |
assets/css/topic-detail.css |
Rewrite .td-timeline-* styles: relative positioning, absolute bars, label row layout |
eleventy.config.js |
Add isMonthShort filter for 3-char Icelandic month abbreviations (used by hierarchical label row 2) |
<details> list in _includes/topic-detail.njk (lines 102–135)_data/topic-details/*.json which has a minimal claim subset (no confidence, explanation, sightings, evidence)The td-claims section is replaced with a tracker mount point:
<section class="td-claims" id="topic-claim-tracker"
data-category="fisheries"
data-base="/assets/data">
<noscript>...</noscript>
</section>
A new script (topic-claim-tracker.js) creates a TrackerController instance that:
claims.json + reports.json when the section enters the viewport (IntersectionObserver)category === topicCategory (derived from data-category)Category mapping: Topic slugs use hyphens (eea-eu-law), claim categories use underscores (eea_eu_law). The script converts with .replace(/-/g, '_').
/fullyrdingar/ tracker| Aspect | /fullyrdingar/ |
Topic embedded |
|---|---|---|
| Category filter | Dropdown (all categories) | Pre-filtered, no dropdown |
| URL query sync | Yes (pushes to ?q=&verdict=) |
No (embedded section, don't pollute topic URL) |
| Data loading | Eager (on page load) | Lazy (IntersectionObserver on mount point) |
| Stats row | Full site-wide stats | Topic-scoped stats (count, sightings, verdict breakdown) |
The renderClaimCard() function (~110 lines) is currently inline in claim-tracker.js. To avoid duplication, extract it into a new shared module:
New file: assets/js/tracker-claim-card.js
renderClaimCard(claim, options) — the card HTML generatortoggleClaimCard(header) and toggleSightings(toggle) — interaction handlersclaim-tracker.js and topic-claim-tracker.js consume itThe base.njk template currently supports a single extra_css and extra_js string. The topic detail page needs:
topic-detail.css + claim-tracker.csstopic-claim-tracker.jsChange extra_css to support arrays. In base.njk, update the CSS block:
Then topic-detail.njk frontmatter becomes:
extra_css:
- /assets/css/topic-detail.css
- /assets/css/claim-tracker.css
extra_js: /assets/js/topic-claim-tracker.js
Loading tracker-claim-card.js in base.njk: The new shared module must load after the existing shared infrastructure scripts (tracker-renderer.js, tracker-controller.js) but before the page-specific script. Add it to the auto-loaded chain in base.njk, gated on extra_js (same condition as the other shared scripts):
This ensures tracker-claim-card.js is available on both /fullyrdingar/ (which uses claim-tracker.js) and topic detail pages (which use topic-claim-tracker.js). The module attaches to globalThis.ESBvaktinClaimCard following the same IIFE + globalThis pattern used by all other shared modules in this codebase (not ES module exports).
assets/js/topic-claim-tracker.js (~150 lines)Glue script that:
data-category and data-base from the mount elementcontroller.start() on viewport entryload(): fetches claims.json + reports.json, filters to categoryrenderShell(): search input, verdict filter, sort dropdown (no category dropdown)renderStats(): topic-scoped verdict breakdownrenderResults(): delegates to shared renderClaimCard()| File | Change |
|---|---|
_includes/topic-detail.njk |
Replace td-claims section with tracker mount point; update frontmatter for array extra_css |
_includes/base.njk |
Support array extra_css; add tracker-claim-card.js to shared script loading chain |
assets/js/tracker-claim-card.js |
New — extracted shared card rendering + interaction handlers |
assets/js/claim-tracker.js |
Refactor to import from tracker-claim-card.js |
assets/js/topic-claim-tracker.js |
New — topic-scoped claim tracker glue |
Current data: 1,319 claims, 2.5 MB raw / ~608 KB gzipped. Client-side approach is sound up to ~3,000–5,000 claims. If growth exceeds that, consider virtual scrolling or per-category JSON splits. Not needed now.
/malefni/) — no changes