From 3655e810f0a39c3539d493a5c0f36a02d6315c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martynas=20Jusevi=C4=8Dius?= Date: Wed, 2 Sep 2026 19:35:13 +0200 Subject: [PATCH 1/3] Show one image per foaf:depiction table cell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The design system folds every value of a property into the cell the first one opens and caps the stack (ldh-bridge.css: table.table td > .values has max-height 12em, overflow-y auto). Right for literals, wrong for portraits: a Seimas member legitimately carries more than one foaf:depiction — Wikidata P18 plus the scraped lrs.lt portrait — and the second says nothing the first does not, while costing ~180px of row height on every row. Override the cell-opening depiction (the same node the stock priority-1 xhtml:TableDataCell template matches; the stock empty template still swallows the rest) and emit the design system's own div.values > div.value markup with a single value, so cell padding, the ~ .value separator and the height cap all still apply — none of which engage at one value. Deleting the template reverts to the stacked cell. https: is preferred over http: when both forms of one image are present: http Wikimedia Commons URLs do not render in browsers, which is why the reconciler https-normalises them, so an arbitrary pick could show a knowingly-broken image. The predicate is a no-op once no http Commons URL survives in the store. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PoiMWyMGtWZos9wWoVUCwg --- files/client.xsl | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/files/client.xsl b/files/client.xsl index 367ad89..8e180d5 100644 --- a/files/client.xsl +++ b/files/client.xsl @@ -22,6 +22,7 @@ + ]> + + + + + +
+ +
+ +
+ - - + From 327fae77449206ee821a91c79bfd8dd20a844488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martynas=20Jusevi=C4=8Dius?= Date: Fri, 11 Sep 2026 19:16:44 +0200 Subject: [PATCH 3/3] Port the XSLT overrides to LinkedDataHub's new stylesheet API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LDH dropped the Bootstrap 2.3.2 stylesheet tree; the modes our overrides hook into moved into the ac: and ldh: namespaces and the imports lost the bootstrap/2.3.2/ path segment. Retarget every override accordingly: bs2:Row -> ldh:BlockRow (membership/interval/instant blocks) bs2:PropertyList -> ac:PropertyEditor (gsp:asWKT suppression) bs2:ContainerTable-> ac:ResultsTable (memberships table) xhtml:Table* -> ac:ResultsTable* (cell overrides) bs2:Footer -> ac:Footer (LTLOD footer) layout.xsl now imports ../com/atomgraph/linkeddatahub/xsl/layout.xsl and the bs2 prefix is gone from all three files. The memberships table can no longer delegate with apply-templates: the stock table emitter lives in ac:ResultsTable, the same mode this template matches in, so applying templates there would re-enter it forever. Hand the restricted column list to the stock emitter with xsl:next-match instead, which is what reaches the lower-precedence stock template. The footer markup follows the new design system: .ldh-footer without the legacy .footer class, plus role="contentinfo". Cell CSS moved from ldh-bridge.css to ldh.css under .ldh-results-table — comment-only change. While here: give the frontpage and persons-container views dct:title and ldh:showWhenEmpty false. They are document-defined views that commit 3cc5a5b deliberately skipped, but an empty store (or a load that has not finished) renders them as titleless empty blocks; the flag costs nothing when they do have results. Also fix the .lead -> .lede class on the frontpage intro and write geo-resources-string as CDATA rather than entity-escaped angle brackets, so the query reads as SPARQL. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Rpcs7VhsGAhungG9fjwR1Z --- CLAUDE.md | 6 ++-- app/ns.ttl | 2 +- app/persons.ttl | 3 +- app/root.ttl | 18 ++++++++---- files/client.xsl | 68 +++++++++++++++++++++++---------------------- files/layout.xsl | 14 +++++----- files/overrides.xsl | 13 ++++----- 7 files changed, 67 insertions(+), 57 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 9c716f1..694baac 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -144,7 +144,7 @@ since the rows differ in the image cell. Three files, all mounted over the running image's `ROOT/static` for the **end-user app only** (admin untouched): - `files/overrides.xsl` — the **shared** module: suppresses the n-ary - membership plumbing blocks (`bs2:Row`). Matching is **property-centric via + membership plumbing blocks (`ldh:BlockRow`). Matching is **property-centric via `key()`**, never bare `rdf:type`, so a block is hidden only when it is a rendered target of the `:Memberships` 1:N view *on this page* — a membership whose `org:member` is `key('resources', ac:absolute-path(ldh:request-uri()))`'s @@ -175,7 +175,7 @@ since the rows differ in the image cell. are unaffected, so settlement points stay mappable there. - `files/layout.xsl` — imports base `layout.xsl` + `overrides.xsl`; repoints the client bootstrap (`xhtml:Script` → `client-stylesheet`) at our SEF, and - **replaces the stock `bs2:Footer`** with the LTLOD one (own wordmark, dataset + **replaces the stock `ac:Footer`** with the LTLOD one (own wordmark, dataset shortcuts, source attribution, licence; the developer entry points — SPARQL, example queries, dataset downloads, `{base}ns` — live there instead of on the frontpage). The footer keeps the stock markup contract, since `app.css` styles @@ -183,7 +183,7 @@ since the rows differ in the image cell. exactly one `.brand-col` plus FOUR `.col` children, each a `.ftitle` followed by bare ``s, then `.legal` with two space-between spans. Only the wordmark `.mark` deviates — restyled inline to the Lithuanian tricolour, class-supplied - geometry kept. Footer-only because `bs2:Footer` is applied ONCE server-side + geometry kept. Footer-only because `ac:Footer` is applied ONCE server-side (LDH `layout.xsl`) and never re-rendered by client.xsl — so it belongs here, not in `overrides.xsl`, and needs no SEF rebuild. Mounted at the end-user app's `ac:stylesheet` target `static/xsl/layout.xsl`; imports `overrides.xsl` from diff --git a/app/ns.ttl b/app/ns.ttl index a211d87..8149085 100644 --- a/app/ns.ttl +++ b/app/ns.ttl @@ -13,7 +13,7 @@ # the AR-spatial *-geo.trig), so :SubUnits uses ac:MapMode — LDH plots each unit as # a map marker (RDFXML2GeoJSON keys on geo:lat+geo:long). Views that project # image-bearing persons (foaf:depiction portraits from lrs.lt) use ac:GridMode so -# LDH lays them out as a thumbnail grid (bs2:ContainerGrid → foaf:depiction per +# LDH lays them out as a thumbnail grid (ac:Grid → foaf:depiction per # card). Imageless targets (Seimas org-units) keep the default list. # # Filter/sort columns: LDH turns the BGP triples whose subject is the query's diff --git a/app/persons.ttl b/app/persons.ttl index b12b71e..0c3e8e9 100644 --- a/app/persons.ttl +++ b/app/persons.ttl @@ -31,7 +31,8 @@ <#persons-view> a ldh:View ; dct:title "Seimo nariai"@lt, "Members of the Seimas"@en ; spin:query <#persons-query> ; - ac:mode ac:GridMode . + ac:mode ac:GridMode ; + ldh:showWhenEmpty false . # dct:title (not just rdfs:label) is mandatory on sp:Select — LDH enforces # def:MissingTitle as a SPIN constraint and rejects the PUT with 422 otherwise. diff --git a/app/root.ttl b/app/root.ttl index a56a43c..639a8dc 100644 --- a/app/root.ttl +++ b/app/root.ttl @@ -26,7 +26,7 @@ <#intro> a ldh:XHTML ; rdf:value """
-

Oficialių Lietuvos registrų duomenys vienoje vietoje: administraciniai vienetai, Seimo nariai, partijos, juridiniai asmenys ir klasifikatoriai. Duomenys susieti tarpusavyje, tad nuo vieno objekto galite pereiti prie visų su juo susijusių — nuo apskrities prie savivaldybių, nuo Seimo nario prie jo komitetų ir partijos.

+

Oficialių Lietuvos registrų duomenys vienoje vietoje: administraciniai vienetai, Seimo nariai, partijos, juridiniai asmenys ir klasifikatoriai. Duomenys susieti tarpusavyje, tad nuo vieno objekto galite pereiti prie visų su juo susijusių — nuo apskrities prie savivaldybių, nuo Seimo nario prie jo komitetų ir partijos.

Žemiau — keli pjūviai iš duomenų: apskritys žemėlapyje, Seimo frakcijos, partijos ir komitetų pirmininkai. Visi duomenų rinkiniai — puslapio apačioje.

"""^^rdf:XMLLiteral . @@ -42,8 +42,10 @@ rdf:value <#counties-view> . <#counties-view> a ldh:View ; + dct:title "Apskritys"@lt, "Counties"@en ; spin:query <#counties-query> ; - ac:mode ac:GridMode . + ac:mode ac:GridMode ; + ldh:showWhenEmpty false . <#counties-query> a sp:Select ; dct:title "Apskritys"@lt ; @@ -76,8 +78,10 @@ ORDER BY ?label""" . rdf:value <#counties-map-view> . <#counties-map-view> a ldh:View ; + dct:title "Apskritys žemėlapyje"@lt, "Counties on the map"@en ; spin:query <#counties-query> ; - ac:mode ac:MapMode . + ac:mode ac:MapMode ; + ldh:showWhenEmpty false . # rdf:_5 / rdf:_6 — faction sizes bar chart @@ -133,8 +137,10 @@ ORDER BY DESC(?members)""" . rdf:value <#parties-view> . <#parties-view> a ldh:View ; + dct:title "Seimo narius iškėlusios partijos"@lt, "Parties that nominated members of the Seimas"@en ; spin:query <#parties-query> ; - ac:mode ac:TableMode . + ac:mode ac:TableMode ; + ldh:showWhenEmpty false . <#parties-query> a sp:Select ; dct:title "Seimo narius iškėlusios partijos"@lt ; @@ -166,8 +172,10 @@ ORDER BY ?label""" . rdf:value <#table-chairs-view> . <#table-chairs-view> a ldh:View ; + dct:title "Komitetų ir komisijų pirmininkai"@lt, "Committee and commission chairs"@en ; spin:query <#table-chairs-query> ; - ac:mode ac:TableMode . + ac:mode ac:TableMode ; + ldh:showWhenEmpty false . <#table-chairs-query> a sp:Select ; dct:title "Komitetų ir komisijų pirmininkai"@lt ; diff --git a/files/client.xsl b/files/client.xsl index 8e180d5..d6ce7ff 100644 --- a/files/client.xsl +++ b/files/client.xsl @@ -28,7 +28,6 @@ xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" - xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ldh="&ldh;" xmlns:ac="∾" xmlns:rdf="&rdf;" @@ -36,7 +35,6 @@ xmlns:foaf="&foaf;" xmlns:org="&org;" xmlns:time="&time;" - xmlns:bs2="http://graphity.org/xsl/bootstrap/2.3.2" exclude-result-prefixes="#all"> @@ -60,10 +58,10 @@ it wins. Scoped map views (:SubUnits, the frontpage counties map) use their own spin:query and are unaffected — settlement points remain mappable there. --> - -PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> -PREFIX dct: <http://purl.org/dc/terms/> -PREFIX gsp: <http://www.opengis.net/ont/geosparql#> + +PREFIX dct: +PREFIX gsp: SELECT DISTINCT ?resource WHERE @@ -78,7 +76,22 @@ WHERE } } ORDER BY ?title - +]]> + + + - - + mode="ac:ResultsTable" priority="5"> - + - + - + @@ -126,7 +138,7 @@ ORDER BY ?title The design system's cell rule is that every value of a property shares the one cell the first value opens, stacked in a `div.values` that caps its own - height (ldh-bridge.css: `table.table td > .values { max-height: 12em; + height (ldh.css: `.ldh-results-table td > .values { max-height: 12em; overflow-y: auto }`). That is right for literals, but a stack of portraits turns every row into a ~180px scroll box, and the second portrait carries no information the first does not — Seimas members legitimately have more than @@ -139,7 +151,7 @@ ORDER BY ?title Matched on the cell-opening depiction (the one without a preceding foaf:depiction sibling), which is the same node the stock priority-1 - xhtml:TableDataCell template matches; the stock empty template still + ac:ResultsTableDataCell template matches; the stock empty template still swallows the rest. Removing this template reverts to the stacked cell. https: is preferred over http: when both forms of the same image are @@ -149,13 +161,13 @@ ORDER BY ?title Commons URL survives and the predicate is a no-op. --> + mode="ac:ResultsTableDataCell" priority="5">
+ mode="ac:ResultsTableDataCellValue"/>
@@ -192,16 +204,6 @@ ORDER BY ?title Structure mirrors the stock template: it is matched on the parent of a bgp and only fires for the group that binds the facet's object variable. --> - - diff --git a/files/layout.xsl b/files/layout.xsl index 02b494d..bf94e9e 100644 --- a/files/layout.xsl +++ b/files/layout.xsl @@ -10,9 +10,9 @@ 2. import the shared files/overrides.xsl so the membership plumbing blocks are suppressed in the SERVER render too — otherwise the server emits them and the client removes them during CSR, causing a visible flash; - 3. replace the stock LinkedDataHub footer (bs2:Footer) with the LTLOD one — + 3. replace the stock LinkedDataHub footer (ac:Footer) with the LTLOD one — our own wordmark, dataset shortcuts, source attribution and licence. - The footer is server-rendered ONLY (layout.xsl applies bs2:Footer once, + The footer is server-rendered ONLY (layout.xsl applies ac:Footer once, client.xsl never re-renders it), so it lives here and not in overrides.xsl — no SEF rebuild needed after editing it. @@ -37,12 +37,12 @@ xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:rdf="&rdf;" xmlns:ldt="&ldt;" + xmlns:ac="https://w3id.org/atomgraph/client#" xmlns:lapp="https://w3id.org/atomgraph/linkeddatahub/apps#" xmlns:srx="http://www.w3.org/2005/sparql-results#" - xmlns:bs2="http://graphity.org/xsl/bootstrap/2.3.2" exclude-result-prefixes="#all"> - + @@ -77,11 +77,11 @@ above), so they land in the XHTML namespace like the surrounding markup — without it the serialiser emits a stray xmlns="" reset on the footer. Footer links are excluded from the client-side click interceptor - (client.xsl's ixsl:onclick match skips ancestor .footer), so internal + (client.xsl's ixsl:onclick match skips ancestor .ldh-footer), so internal ones do a normal page load rather than CSR. --> - -