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
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -175,15 +175,15 @@ 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
it structurally: `.ldh-footer > .cols` is a `1.4fr repeat(4, 1fr)` grid, so
exactly one `.brand-col` plus FOUR `.col` children, each a `.ftitle` followed
by bare `<a>`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
Expand Down
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,18 @@ sef:
find "$$TMP_DIR/static" -name '*.xsl' -print0 | while IFS= read -r -d '' f; do xmlstarlet c14n "$$f" > "$$f.tmp" 2>/dev/null && mv "$$f.tmp" "$$f" || rm -f "$$f.tmp"; done; \
mkdir -p "$$TMP_DIR/static/files" && xmlstarlet c14n ./files/client.xsl > "$$TMP_DIR/static/files/client.xsl"; \
xmlstarlet c14n ./files/overrides.xsl > "$$TMP_DIR/static/files/overrides.xsl"; \
npx xslt3-he -t -xsl:"$$TMP_DIR/static/files/client.xsl" -export:./files/client.xsl.sef.json -nogo -ns:##html5 -relocate:on; \
npx xslt3-he -t -xsl:"$$TMP_DIR/static/files/client.xsl" -export:"$$TMP_DIR/client.xsl.sef.json" -nogo -ns:##html5 -relocate:on; \
if [ $$? -ne 0 ] || [ ! -s "$$TMP_DIR/client.xsl.sef.json" ]; then \
rm -rf "$$TMP_DIR"; \
echo "SEF compile FAILED - files/client.xsl.sef.json left unchanged" >&2; \
exit 1; \
fi; \
mv "$$TMP_DIR/client.xsl.sef.json" ./files/client.xsl.sef.json; \
rm -rf "$$TMP_DIR"; \
echo "Wrote files/client.xsl.sef.json"

up: secrets cert
mkdir -p datasets/owner datasets/secretary uploads fuseki/admin fuseki/end-user
docker compose up -d
docker compose up
@echo "LinkedDataHub starting — first boot takes ~1-2 min (self-signed cert)."
@echo "URL: https://localhost:4443/"

Expand Down
2 changes: 1 addition & 1 deletion app/ns.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion app/persons.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 13 additions & 5 deletions app/root.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

<#intro> a ldh:XHTML ;
rdf:value """<div xmlns="http://www.w3.org/1999/xhtml">
<p class="lead">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.</p>
<p class="lede">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.</p>
<p>Žemiau — keli pjūviai iš duomenų: apskritys žemėlapyje, Seimo frakcijos, partijos ir komitetų pirmininkai. Visi duomenų rinkiniai — puslapio apačioje.</p>
</div>"""^^rdf:XMLLiteral .

Expand All @@ -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 ;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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 ;
Expand Down Expand Up @@ -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 ;
Expand Down
101 changes: 72 additions & 29 deletions files/client.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@
<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<!ENTITY org "http://www.w3.org/ns/org#">
<!ENTITY time "http://www.w3.org/2006/time#">
<!ENTITY foaf "http://xmlns.com/foaf/0.1/">
]>
<xsl:stylesheet version="3.0"
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="&ac;"
xmlns:rdf="&rdf;"
xmlns:json="http://www.w3.org/2005/xpath-functions"
xmlns:foaf="&foaf;"
xmlns:org="&org;"
xmlns:time="&time;"
xmlns:bs2="http://graphity.org/xsl/bootstrap/2.3.2"
exclude-result-prefixes="#all">

<xsl:import href="../com/atomgraph/linkeddatahub/xsl/client.xsl"/>
Expand All @@ -58,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.
-->
<xsl:param name="geo-resources-string" as="xs:string">
PREFIX geo: &lt;http://www.w3.org/2003/01/geo/wgs84_pos#&gt;
PREFIX dct: &lt;http://purl.org/dc/terms/&gt;
PREFIX gsp: &lt;http://www.opengis.net/ont/geosparql#&gt;
<xsl:param name="geo-resources-string" as="xs:string"><![CDATA[
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#>

SELECT DISTINCT ?resource
WHERE
Expand All @@ -76,7 +76,22 @@ WHERE
}
}
ORDER BY ?title
</xsl:param>
]]></xsl:param>

<!--
The label predicates the facet-value-count override below filters on, in the
order LDH's own alternative path lists them - so the SAMPLE(?label) a filter
pill displays is unchanged. See that template for why the path became a FILTER.
-->
<xsl:param name="ldh:label-predicates" as="xs:string+" select="(
'http://www.w3.org/2000/01/rdf-schema#label',
'http://purl.org/dc/elements/1.1/title',
'http://purl.org/dc/terms/title',
'http://xmlns.com/foaf/0.1/name',
'http://xmlns.com/foaf/0.1/givenName',
'http://xmlns.com/foaf/0.1/familyName',
'http://rdfs.org/sioc/ns#name',
'http://www.w3.org/2004/02/skos/core#prefLabel')"/>

<!--
Tidy the memberships table (rendered by the :Memberships ldh:View in
Expand All @@ -85,24 +100,23 @@ ORDER BY ?title
org:member (redundant — always this person), org:memberDuring,
org:organization and org:role columns.

We delegate to the stock xhtml:Table but restrict the columns to
Pareigos (org:role) | Organizacija (org:organization) | Laikotarpis
(org:memberDuring) and drop the anchor column. This reuses all the base
table machinery; if the override does not fire, the base
bs2:ContainerTable still renders a (busier but functional) table.
Removing this one template reverts to it.
We restrict the columns to Pareigos (org:role) | Organizacija
(org:organization) | Laikotarpis (org:memberDuring) and drop the anchor
column, then hand the table back to the stock emitter with xsl:next-match.
The stock table is the SAME mode this template matches in, so next-match
is what reaches it — an apply-templates in ac:ResultsTable would re-enter
this template forever. This reuses all the base table machinery; removing
this one template reverts to the busier but functional stock table.
-->
<xsl:template match="rdf:RDF[*/rdf:type/@rdf:resource = '&org;Membership']"
mode="bs2:ContainerTable" priority="5">
<xsl:param name="select-xml" as="document-node()"/>

mode="ac:ResultsTable" priority="5">
<xsl:variable name="predicates" as="element()*"
select="(*/org:role)[1], (*/org:organization)[1], (*/org:memberDuring)[1]"/>

<xsl:apply-templates select="." mode="xhtml:Table">
<xsl:next-match>
<xsl:with-param name="predicates" select="$predicates"/>
<xsl:with-param name="anchor-column" select="false()" tunnel="yes"/>
</xsl:apply-templates>
</xsl:next-match>
</xsl:template>

<!--
Expand All @@ -113,12 +127,51 @@ ORDER BY ?title
already loads (tunnel), so this prints e.g. "2024-11-14 – dabar" as a
plain literal instead of an anchor to the interval resource.
-->
<xsl:template match="*[@rdf:about or @rdf:nodeID]/org:memberDuring" mode="xhtml:TableDataCell" priority="5">
<xsl:template match="*[@rdf:about or @rdf:nodeID]/org:memberDuring" mode="ac:ResultsTableDataCell" priority="5">
<td>
<xsl:apply-templates select="@rdf:resource" mode="ac:object-label"/>
</td>
</xsl:template>

<!--
Show ONE image per foaf:depiction table cell.

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.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
one depiction (Wikidata P18 plus the scraped lrs.lt portrait, see CLAUDE.md).

So this keeps the design system's markup exactly — `div.values > div.value`,
so the cell padding, the `~ .value` separator rule and the height cap all
still apply — and simply feeds it a single value. With one value the cap
never engages and the separator never draws.

Matched on the cell-opening depiction (the one without a preceding
foaf:depiction sibling), which is the same node the stock priority-1
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
present: Wikimedia Commons URLs served over http do not render in browsers
(which is why the reconciler https-normalises them), so picking one blindly
could show a knowingly-broken image. After a clean store rebuild no http
Commons URL survives and the predicate is a no-op.
-->
<xsl:template match="*[@rdf:about or @rdf:nodeID]/foaf:depiction[not(preceding-sibling::foaf:depiction)]"
mode="ac:ResultsTableDataCell" priority="5">
<xsl:variable name="depictions" select="../foaf:depiction" as="element()*"/>

<td>
<div class="values">
<xsl:apply-templates select="($depictions[starts-with(@rdf:resource, 'https:')], $depictions)[1]"
mode="ac:ResultsTableDataCellValue"/>
</div>
</td>
</xsl:template>

<!--
Facet value loading: replace the label lookup that LDH appends to the
facet-value-count query (ldh:bgp-value-counts in the stock
Expand Down Expand Up @@ -151,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.
-->
<xsl:param name="ldh:label-predicates" as="xs:string+" select="(
'http://www.w3.org/2000/01/rdf-schema#label',
'http://purl.org/dc/elements/1.1/title',
'http://purl.org/dc/terms/title',
'http://xmlns.com/foaf/0.1/name',
'http://xmlns.com/foaf/0.1/givenName',
'http://xmlns.com/foaf/0.1/familyName',
'http://rdfs.org/sioc/ns#name',
'http://www.w3.org/2004/02/skos/core#prefLabel')"/>

<xsl:template match="json:map[json:string[@key = 'type'] = 'bgp']/.." mode="ldh:bgp-value-counts" priority="2">
<xsl:param name="object-var-name" as="xs:string" tunnel="yes"/>
<xsl:param name="label-var-name" as="xs:string" tunnel="yes"/>
Expand Down
14 changes: 7 additions & 7 deletions files/layout.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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">

<xsl:import href="../com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/layout.xsl"/>
<xsl:import href="../com/atomgraph/linkeddatahub/xsl/layout.xsl"/>
<!-- imported last so its suppression templates take import precedence -->
<xsl:import href="overrides.xsl"/>

Expand Down Expand Up @@ -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. -->

<xsl:template match="rdf:RDF | srx:sparql" mode="bs2:Footer">
<div class="footer ldh-footer">
<xsl:template match="rdf:RDF | srx:sparql" mode="ac:Footer">
<div class="ldh-footer" role="contentinfo">
<div class="cols">
<div class="col brand-col">
<a class="ldh-wordmark" href="{$ldt:base}">
Expand Down
Loading
Loading