Develop - #93
Draft
namedgraph wants to merge 42 commits into
Draft
Develop#93namedgraph wants to merge 42 commits into
namedgraph wants to merge 42 commits into
Conversation
… the design system's component vocabulary in the ac: namespace (bs2:Header→ac:BlockHeader, bs2:PropertyList→ac:PropertyEditor, bs2:Form→ac:ResourceForm, bs2:FormControlTypeLabel→ac:ValueAnnotations, bs2:NavBar→ac:Header, bs2:QueryForm→ac:SPARQLPane, ...), the bootstrap/2.3.2 skin directory flattens into the xsl root with its imports merged into the base vocabulary files (the ac:lang-tag base/skin dual collapses into one definition), the dead bs2:EditForm dispatch repoints at the edit form, and the form-control system adopts the design system's core-kit anatomy: field shells (ldhc-field/ldhc-field-box) around bare inputs, ldhc-tag term annotations, ldhc-iconbtn statement actions, with UI strings served from Web-Client's own translations.rdf catalog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…shell (header with URI field, action bar zones, details-based mode/export menus, footer), resource blocks, ul/li collections (the grid drops its span-chunked rows for a CSS grid), the results table (native table layout with a visually-hidden caption and th scope), forms and the SPARQL pane all compose core-kit primitives (ldhc-btn, ldhc-iconbtn, ldhc-field/-box, ldhc-tag, ldhc-alert, ldhc-card) under Web-Client's own client.css chrome. The output is XHTML5, the vendored Bootstrap CSS/JS, jQuery, UUID.js and glyphicons retire in favour of a dependency-free client.js (crypto.randomUUID, delegated statement add/remove, data-confirm'd deletes), the design system's tokens and core kit are vendored beside client.css, hardcoded English moves into translations.rdf, and the version becomes 6.0.0-SNAPSHOT. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…standalone browser's crash on every page: at SSR time document() goes through the graph repository, which returns an empty document for uncached HTTP URIs, so context-relative catalog fetches yielded nothing and ac:label() blew up on the empty lookup (XPTY0004 in button/@data-confirm). The catalog now has a canonical URI location-mapped in prefix-mapping.n3 to a bundled classpath copy, the overridable ac:translations() function is the single accessor (importing layers re-resolve it their own way), the entries become URI resources under xml:base because blank-node ids do not survive the repository's parse/serialize round-trip, every lookup keys on the absolute URI via the &translations; entity, and the delete buttons' data-confirm moves out of attribute value templates so a missing label degrades to an empty attribute instead of an error page. Verified end-to-end against a live browse of atomgraph.com: labels, icons and the confirm prompt all render. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…edDataHub and app stylesheets: every resource fieldset names itself with an ac:label legend (the computed $legend param finally gets used), the value row stops wrapping so a type tag and the statement actions stay on their field's line (the row wraps only to give an inlined blank-node resource its full-width recessed sub-form panel), and the ghost statement-action buttons take a resting hairline so the remove control reads as a control rather than a stray minus. Verified against a live EditMode render: five legends, tags beside their boxes, nested fieldsets recessed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…ELETE addresses, so the action bar's ac:HeaderActions is their only home and the per-resource pair that stamped every block header, list row and grid card retires. ac:BlockActions stays as the empty per-block extension point importing layers fill with their own actions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…ependency goes entirely, hardcoded API key included: ol.js and ol.css are vendored beside the other client assets, ol.css rides an xhtml:Style override that fires only in MapMode (living beside the base template in layout.xsl, since an imported override loses on import precedence however high its priority), and instead of marking only the current document's resource the map renders every resource in the graph carrying WGS84 coordinates as a marker and fits the view to them, falling back to a world view on a graph with none. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…can be followed by a run of dds (the grouping pass suppresses repeated terms, per the dl content model), and two-column grid auto-placement cannot keep such a run in the value column without per-group wrappers the flat dl deliberately lacks - the second value wrapped into the term column and shifted every row after it (Northwind's areaServed with seven values). The dl drops the grid for float/clear column layout, which handles any dt/dd sequence by construction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…ap-view through the base template's new class param (a next-match one-liner beside the base, at include-level precedence), and client.css turns that page into a viewport-high column where the map takes every pixel below the header and action bar - content cap, padding and radius drop, the footer yields. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
… columns flex-start, which sizes .main to content - and a map canvas has no intrinsic height, so the whole chain collapsed to 0 and OpenLayers refused to render. Map view re-aligns the content row to stretch, gives .main min-height 0, and hides the empty aside that was reserving its 320px next to the canvas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…, and it now emits the design system's Tag (ldhc-tag em-quiet co-primary sz-sm) instead of the Bootstrap-era span.btn.btn-type that the clean break missed - every surface that shows a type (the header's ul.types, property values, table cells, and LinkedDataHub's overriding chip surfaces) applies templates into this rule or its mode-level siblings rather than building its own pill. The five anchor params keep forwarding, so a caller-computed href (LinkedDataHub's ?uri= proxying rule sits above this one) passes through untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…apper every text control rides in (the $control slot takes the pre-built input or textarea, $adorn a leading adornment, hidden inputs bypass the chrome), ac:SelectShell the caret-adorned dropdown wrapper (multiple selects mark the shell and drop the caret by rule rather than per site), and ac:AnnotationTag the one value-kind chip beside edit-mode controls, with $class/$title/$label slots so a downstream layer re-skins every chip by overriding the single rule. The five field-shell copies in imports/default.xsl, the vocab-import textareas (rdfs:comment, dct:description, sp:text, foaf:mbox/phone), the uri-form and endpoint sz-md shells in layout.xsl and sparql.xsl, and the four byte-identical annotation tags all route through them instead of retyping the two-div anatomy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…d title/text slots plus a $body tail for links, technical detail or actions, deriving the glyph from the variant. The http:Response block header and the constraint-violation renderer route through it; the response header's h2 rides the $body slot to keep the document outline and adopts the canonical ldhc-alert-title styling instead of the drifted -text class. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…e instead of the retired framework, mirroring the design-system source. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…lers sit inside an anchor of their own (a document-list row is one link), where a nested a is invalid, so the Tag renders its ac:object-label text instead of the anchor while everything else about the pill stays the one emitter's business. Tunneled because the proxying @Rdf:resource rule above it does not know the parameter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…ces - raw Saxon rejects the undeclared prefix at compile time even though the SEF toolchain let it through. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
… childless element primitives whose mode name IS the emitted element's QName (Input, Anchor, Option, Title, Meta, Script) - one element, attributes as parameters, content at most a text label. Every mode with element structure inside is a component and moves to the component namespace under the design system's name for its surface: xhtml:Body becomes ac:AppShell, xhtml:Head ac:Head, xhtml:Style ac:Stylesheets (which also retires the one name that never matched its output - it emits link elements), the table family becomes ac:ResultsTable/-HeaderCell/-DataCell/-DataCellValue (ResultsTable, not DataTable: the fixed-column core table already owns that name downstream), and the property-list pair dt/dd becomes ac:PropertyListLabel/ac:PropertyListValue. The caller-less xhtml:ListItem template goes outright. CLAUDE.md states the rule: element identity in xhtml:, structure in component namespaces, the unnamed mode as the value leaf. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbug2gnhHvbcCzzDXpSoZU
…toring the invariant the Bootstrap stack lived by: generic emitters in imports/default.xsl, vocabulary specifics in the vocab modules imported after it, specific beating generic by import order within one layer rather than by downstream precedence games. The combobox lookup family moves down from LinkedDataHub as ac:Lookup, ac:Typeahead and ac:class-label - the @Rdf:resource and blank-node ac:FormControl/ac:ValueAnnotations emitters with their object-metadata and constructor plumbing (the resources-by-type key comes along) - replacing the shelled plain-input pair and the priority-1 recursion pair, whose inline bnode expansion survives behind the $inline tunnel; the xsd-typed bnode literal template widens to @Rdf:about subjects and takes the synthesized-datatype annotation tail, honoring its own old move-to-Web-Client marker. foaf:mbox broadens to every term type (a constructed node degrades to an empty value) and gains the Literal annotation tag, so the mailbox stays an email field without any importer having to out-rank the generic for it, and ac:FieldShell gains optional class/style params so a hidden field can ride the shell. The vocab link and image emitters adopt the href/class contract the type pill already honored: a proxying importer's rewritten href and external class are used, not undone by hardcoding the raw URI - mailto: and tel: links stay raw by design, and image bytes load from the raw URI while only the anchor navigates through the proxy. schema.xsl gains the image/logo/thumbnailUrl ac:image ladder rules beside foaf's and dbpedia-owl's, with the no-image fallback placed in imports/default.xsl below every vocab rule - the one spot where a match-all cannot shadow the ladder (a first attempt in resource.xsl sat above it and blanked every thumbnail; a SaxonJS scratch test caught it). sh.xsl arrives imported first among the vocabulary modules, where sh:name and sh:description lose to every language-negotiated data label, and dbpedia-owl.xsl declares the xs prefix its new params need - invisible to the SEF toolchain because that module compiles server-side only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016eTC7vovaXXzkuuAcCMrgR
…est generic Linked Data client, with the namespace prefix reasserted as the ownership marker it always was. The typeahead cluster the move-down commits had laundered into ac: names goes home: the owl:NamedIndividual and non-XSD bnode specials, the combobox lookup and committed-chip emitters and the class-label function leave imports/default.xsl, and the object-position @Rdf:resource/@Rdf:nodeID controls return to the pre-move shelled plain pair plus the historic hidden-input + inline sub-form recursion pair - markup that is inert without LDH's client-side handlers is LDH UI whatever its QNames say, and bare Web-Client was rendering dead comboboxes to prove it. Constructor logic follows outright: the $ac:forClass global and its EditMode-dispatch arm, the fieldset's ac:construct constructor/template plumbing and its "Template is not defined" message, the forClass Legend, both ac:construct stubs, the ConstructForClass extension function with its registration, the Constructor SPIN-instantiation engine, the SPIN vocabulary class, the writer's forClass stylesheet param and the AC forClass/ConstructMode constants and ns.ttl keyword all delete - LDH's constructor machinery never used any of it. The proxy stops pretending to be a resource. ProxiedGraph (with its DirectGraphStore costume) gives way to a @PreMatching ProxyRequestFilter in the image of LDH's: the target comes from ?uri=, the entity stream forwards verbatim with its original Content-Type (an RDF/POST form reaches the origin for the origin to parse - no local Model round-trip, no 415), conditional headers ride through so preconditions evaluate at the origin, and responses dispatch on the live RIOT registry into Model/ResultSet re-served through content negotiation including (X)HTML - this client's whole purpose, so no HTML bypass - while HEAD, errors and non-RDF bodies relay verbatim with buffered entities so a rejected write surfaces as the origin's own status instead of a dead connection (the raw client Response the old put() returned died on the wire as a 0-byte 403). A minimal Root resource keeps the endpoint+query redirect and the no-target 404. The RDFPostMediaTypeInterceptor moves down from LDH - the layer that emits RDF/POST forms can read them back - and stays registered for LDH to import. Correct Link forwarding (split into per-value headers the writer's Link.valueOf can actually parse) unmasked the latent ontology-without-base construct() crash, which the constructor removal then deleted whole; the duplicate no-image ac:image fallback that spammed XTDE0540 goes with it. The edit form's action carries the browsed URI - a bare relative ?_method=PUT replaced the whole query string and dropped the ?uri= the proxy routes on - and the Delete form moves _method into the ac:build-uri map instead of concatenating a second ?. The datatype input defaults to hidden (the value-side xsd: tag is its visible face, as LDH has had it since 2022), and XMLLiteral objects gain a markup-source fallback: one textarea carrying serialize() of the whole fragment with a hidden rdf:XMLLiteral lt, instead of the built-in descent exploding every text node into its own control and shredding the markup on round-trip. translations.rdf returns to the master convention: rdf:nodeID entries, bare-id keys, ac:translations() reading the static file beside the stylesheets - the invented w3id.org catalog URI, its DOCTYPE entities, the prefix-mapping.n3 line and the classpath duplicate all delete, because a URL that does not and should not resolve is not a namespace. ProxyRequestFilterTest covers target resolution, the Link splitting, header forwarding and pass-through; RootTest covers the redirect and the 404. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EEXsDAWWcutTN5sDpih57k
…ent negotiation instead of relaying them verbatim: the verbatim relay was faithful but useless to this client's actual consumer - the outbound Accept offers every readable RDF flavor, the origin answered a rejected form PUT with a 403 typed application/rdf+thrift, and Firefox's response to binary bytes on an error status is its own network-error page, not the origin's diagnostic. The entity buffers first, and when the upstream Content-Type maps to an RDF lang in the live RIOT registry the body parses into a Model and re-serves with the origin's status kept - a browser gets the rendered error page (the diagnostic is typed http:Response, which the layout has dedicated templates for), an API client gets the RDF format it asked for - while a body that is not the RDF its type claims falls back to the buffered verbatim relay rather than masking the origin's status as 502, the trap the buffering exists to avoid. LDH's ProxyRequestFilter deliberately keeps the verbatim relay: its proxy consumer is SaxonJS reading status and RDF programmatically; this one's is a person. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EEXsDAWWcutTN5sDpih57k
…dy had: ac:Alert becomes ac:InlineAlert - the emitter builds ldhc-alert anatomy, and InlineAlert is that component's export name, Toast being the other alert-classed surface - and ac:ModeList/ac:ModeListItem become ac:ModeSwitcher/ac:ModeSwitcherItem, ModeSwitcher being the design system's name for the control the details menu of ac:Mode instances renders. The NAVBAR ACTIONS and MODE LIST section comments take the same vocabulary (HEADER ACTIONS, MODE SWITCHER). LinkedDataHub renames its shadows and dispatch sites in lockstep. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EEXsDAWWcutTN5sDpih57k
…ac:FieldShell takes the design's remaining slots as parameters - a label (with its size axis and optional for-target) above the box, a validation state (st-valid/st-invalid) on the box, help text in the new field foot - and drops the $style passthrough, which existed only to hide a shell inline where a state class belongs; ac:SelectShell takes the same state axis. The Tag family stops relying on colors it never had: the language tag, both @Rdf:datatype leaves and the ac:AnnotationTag default gain the co-accent axis (violet, the system's semantic-annotation hue) and wrap their text in .ldhc-tag-lbl, the one carrier of the truncation treatment. ac:InlineAlert announces by variant - role=alert only for va-negative, polite status for the rest. xhtml:Anchor gains a $role parameter (a menu item needs menuitem; the primitive's contract is every attribute a parameter). The standalone delete button takes in-negative - in-destructive is the IconButton axis, and .ldhc-btn.ap-outline resolved its border and ink against a variable that was never set, so the danger treatment silently vanished. sparql.xsl's list mode applies to the graph node rather than its descriptions, so the rows get their <ul> back. The <details> disclosure menus stay: these standalone pages run without a CSR menu handler, and details is the no-script dropdown - now said in a comment. The standalone statement-row and property-list templates keep their pre-grid shape for now; LinkedDataHub overrides both, and their alignment is a standalone-page pass of its own. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EEXsDAWWcutTN5sDpih57k
…hing below the page layout - group-sort, functions, the value/property dispatch, the vocabulary modules in their commented precedence order (sh's modeling-layer fallbacks still first among them), resource, document, container - and internal-layout collapses to the SVG converter plus common plus the layout include, external-layout to the same with imports/external.xsl imported above the whole common layer (its proxy anchor and value-leaf overrides must win over every renderer below, and nothing above common defines the same matches - a deliberate precedence raise from its old mid-list seat, with no overlapping definitions to raise over). Import order IS the precedence ladder (XSLT 3.0 §3.10.3), so the ladder now exists in one file instead of two parallel enumerations, downstream masters (LinkedDataHub's client.xsl among them) can import one module instead of a hand-picked subset, and a module entering a closure twice - two precedences for one stylesheet, the condition behind Saxon's SXWN9019 - becomes structurally impossible rather than list-discipline. Converters stay standalone by design: never aggregated, imported only by the layout aggregators that use them. Both aggregators compile under Saxon-HE 12.9 with zero duplicate-module warnings and zero static errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EEXsDAWWcutTN5sDpih57k
…eb-Client's own vocabulary: .brand becomes .logo (the anchor wraps a foaf:logo image, so the name is the data's), the header's <ul class="nav"> of links becomes a <div class="actions"> - .actions is already this layer's name for an action cluster in four other places, and the design system's header cluster takes direct children rather than an intermediate list - and .breadcrumb becomes .crumbs. .header and .footer stay exactly as they were: neither is a Bootstrap 2 class (that framework had .navbar and .page-header), and both sit in the same bare descriptive register as .action-bar, .block-header and .resource-list, so renaming them would have been churn dressed as a purge. The two shells gain role=banner and role=contentinfo, which is landmark correctness independent of naming. No ldh- prefix enters this layer: the app kit's CSS is not vendored here, so an ldh-header rule would have been an app-kit name invented locally, while the ldhc- primitives stay because their kit IS vendored (core, controls, overlays, surfaces). README and CLAUDE.md stop claiming the UI is built with Twitter Bootstrap 2.3.2 and stop pointing at xsl/bootstrap/2.3.2/layout.xsl, a path deleted from this repo and from LinkedDataHub. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
…71 class names move from ldhc-* to ac-*, and the vendored kit and the markup that consumes it move in lockstep, since a renamed stylesheet under unrenamed markup is not a partial port but an unstyled page. The four vendored core stylesheets (core, controls, overlays, surfaces) carry the substitution, client.css follows for the primitives its own app layer styles, and the seven XSL modules that emit them - container, document, layout, resource, sparql, imports/default and imports/rdf - rename their class attributes in the same pass; 339 emission sites across the two repos had to agree at once, so nothing here is staged. The prefix is the ownership marker and this is the layer that owns the kit: ldhc- named the primitives after LinkedDataHub, which vendors them, rather than after the client layer that defines and emits them, and the same rename lands in the design system's own source and in LinkedDataHub's vendored copies. CLAUDE.md and README.md stop describing a vocabulary the repo no longer emits. Verified mechanical rather than assumed: normalising both prefixes to a common placeholder and diffing every changed file against HEAD yields zero differing lines in all fourteen, so no rule, anatomy or token changed - the 704 insertions and 704 deletions are the same lines with one token substituted - and no ldhc- string survives anywhere in the repo. Separately and left alone here: the vendored copies still trail the kit by one rule, .ac-tag.sz-xs, which is inert because every tag this layer emits takes sz-sm, and controls.css carries two comment blocks describing an earlier revision's ring and icon-button sizes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
… out two revisions. This layer vendored core, controls, overlays and surfaces once, in the Bootstrap 2 port (b491d8a, 7 September), and never again: the kit moved on 8 September and again on 9 September, LinkedDataHub re-vendored both times, and this copy stayed at the port's revision - so .ac-tag.sz-xs, the inline extra-small Tag size the design system added for a tag that sits after a value rather than in a row of its own, has been absent here since it was written, along with reworded controls.css comments for the focus ring and the icon button's size axis. Nothing overwrote the rule; this copy was simply never refreshed, which is the other half of the same problem the two recorded clobbers are: two independent vendored copies of one kit, with nothing on the path comparing either to its source, so divergence is only ever found by hand or by symptom. Nothing renders differently here as a result. The rule is inert in this layer - every ac-tag it emits takes sz-sm, sz-xs appears only on two icon buttons whose rule was already present, and client.css defines no tag sizing to collide with it - so this closes a divergence rather than fixing a visible defect; LinkedDataHub is the consumer that puts the language tag at the xs size. Verified byte-equality rather than a line count: all four stylesheets are now identical both to the kit and to LinkedDataHub's vendored copies, braces balance in each, and no ldhc- string is reintroduced. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
…rfaces.css re-vendors from the design system, where .ac-table stopped switching the table algorithm off: the display: block on the table and thead/tbody, the display: grid on every tr and the --ac-cols track variable are gone, density moves from row padding to cell padding (a tr under table layout is not a box that takes padding), and the header row's first and last cells round themselves because border-radius does not clip the corner cells of a border-collapse table. The change also removes a real accessibility defect: .ac-table > thead.ac-vh { display: none } had been overriding the kit's own clip-based visually-hidden utility, so a hideHead table's column headers were absent from the accessibility tree entirely rather than present but unseen. Nothing in this layer emits .ac-table - the standalone pages' tables are Web-Client's own - so this is a vendoring catch-up with no markup change here; the consumer that does emit it is LinkedDataHub, whose ldh:DataTable now emits a colgroup and drops the role attributes that only existed because grid on a tr dropped the implicit ones. All four core stylesheets remain byte-identical to the kit and to LinkedDataHub's vendored copies.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
…the half it was missing: overflow: hidden is not the fix for a border-collapse table's unclipped corner cells, and it would cost, because it makes the table its own scrollport and leaves a position: sticky header inert. It also stops pointing at .ldh-results-table in LinkedDataHub's ldh.css, a block that no longer exists now that the SPARQL results table rides .ac-table directly. Comment only; no rule changes, and the four core stylesheets stay byte-identical to the kit and to LinkedDataHub's vendored copies. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
…versal API goes with it. functions.xsl held eleven functions nobody calls: rdfs:domain, rdfs:range and ac:inDomainOf with no call site at all, and rdfs:subClassOf, ac:superClassOf, skos:broader and skos:narrower as #1/#2 pairs where each #1 only ever calls its own #2 and nothing reaches #1. ac:visit-elements is the same shape, recursing into itself and called from nowhere. The four keys only those functions used - resources-by-domain, resources-by-range, resources-by-broader, resources-by-narrower - go with them; resources-by-subclass stays, because LinkedDataHub uses it. Once the dead code was out, every vocabulary prefix the module declared was unused: skos, sp, foaf, dct, dc, ldt, xsd and sparql, with their entities. The generic function module now names no vocabulary at all, which is the point - the prefix in a match pattern is the marker of which layer owns the rule, and these had outlived the rules that justified them. imports/dbpedia-owl.xsl goes entirely. wikiPageExternalLink, thumbnail and abstract are one dataset's conventions, not a vocabulary's, and a generic RDF browser has no business knowing them. Browsing a DBpedia URI through the proxy still renders; it loses the thumbnail, the abstract as description, and the shortened external link. A vocabulary module that only maps a labelling property into the ac:label ladder is a different thing and stays - skos:prefLabel and dc:title are entries in the label-predicate chain, not "SKOS support". Nine of those modules repeated the same shape: a priority="1" language-preferring template and a plain fallback, per property, differing only in the property name. The pair was also internally inconsistent - the match required a lang-matching value with text, while the body then selected the first lang-matching value whether or not that one had text. ac:preferred-lang() states the rule once, picking the first value that has text at each tier, and each pair collapses to a single template; schema.xsl collapses further, since its http: and https: spellings are the same property and belong in one candidate set. Because this is a behaviour normalisation rather than a rename, it was measured: a ten-case fixture table run through the old templates first to capture the baseline, then through the new function. Exactly one cell moves - a preferred-language value that is present but empty alongside a tagged sibling now yields that sibling's text instead of nothing. foaf.xsl is deliberately untouched: its priorities are load-bearing, a name in the reader's language outranking foaf:nick which outranks a name in a foreign one, and collapsing the pair would force one priority and change that ordering. The rest is placement. imports/external.xsl had three verbatim copies of the proxied-href builder, now ac:proxied-href(). sparql.xsl was included by layout.xsl, welding the query editor into the chrome; the entry points that offer the mode include it instead. violations-by-root moves to resource.xsl, beside its only caller, and violations-by-path goes - nothing uses it. The Java writer stops supplying ac:httpHeaders, ac:method and ldt:ontology, none of which any stylesheet has read for some time. Two Web-Client templates are worth recording rather than changing: LinkedDataHub redeclares *[@Rdf:about] in mode ac:BreadcrumbItem and rdf:RDF in mode ac:Map with the identical match at higher import precedence, so the versions here never execute in an LDH build - they are live only standalone. The breadcrumb pair also disagrees on the $leaf contract, tunnel="yes" here and not there.
… produce. The ac:Violation mode is Bootstrap 2 machinery that outlived its call site. b130f266f renamed it from bs2:Violation during the clean break, dropping the spin:ConstraintViolation template on the LinkedDataHub side and keeping the other two, and the apply-templates that drives it stayed here - inside the ac:FormControl that LinkedDataHub shadows with an identical match at higher precedence. So in an LDH build nothing applied the mode at all, on either side of the repo boundary, and what actually ships is the per-field path: $row-violations and $error decorating ldh-prop-group with is-violation. Web-Client has no validator. Nothing here ever produces a spin:ConstraintViolation; the vocabulary was only ever read, to mark a field invalid and to render one alert per violation. That is LinkedDataHub's concern - it owns the SPIN and SHACL constraint machinery, the three violation keys, and its own violation rendering - so the prefix on the mode was misattributing it, and a generic RDF browser had a vendor constraint vocabulary wired through its form controls. The violations-by-root key goes too. Key declarations are global to the package and same-named ones are additive rather than overriding, so this one was not scoped to Web-Client in any sense - it merged with LinkedDataHub's byte-identical declaration and contributed the same entries twice, while putting a SPIN-specific name into the global key namespace of every package that imports this one. Nothing is moved anywhere: LinkedDataHub already declares it. Standalone Web-Client loses the invalid-field decoration and the per-violation alerts. That is the intended trade - they were rendering a vocabulary this layer cannot generate, and a viewer that wants them can define the mode in its own namespace.
Three templates in layout.xsl - ac:Main, ac:ModeSwitcher and ac:Aside for an http:Response - carried
a [not(key('resources-by-type', '&spin;ConstraintViolation'))] guard, so that a validation-error
response kept its chrome where a plain error response lost it. The guard could never do any work
here: Web-Client has no validator, so a spin:ConstraintViolation never appears in a response it
renders, and the predicate is always true in this product. It only ever mattered in LinkedDataHub,
which carries its own guarded copies at document.xsl:393, :570 and :655 at higher import precedence.
So the composite match splits along the layer boundary that was already there - the generic
http:Response template stays here, the constraint-aware refinement is LinkedDataHub's - and the
spin prefix and entity go from layout.xsl, document.xsl and imports/default.xsl with it.
imports/sh.xsl moves to LinkedDataHub. It is a labelling rule rather than a constraint one -
sh:name and sh:description into the ac:label and ac:description ladders - but SHACL is a constraint
vocabulary and the validator belongs to that layer, along with the shape-driven form machinery that
is the only thing generating shapes to label. The move is not free and the cost is recorded there:
this module was imported first among the vocabulary modules, deliberately, so a shape's sh:name
lost to every data-layer label, and nothing in LinkedDataHub's tree can reproduce that ordering.
What remains from spinrdf.org is sp: and spl:, which describe SPARQL queries as RDF rather than
constraints, and imports/sp.xsl renders query text - a different concern that a browser displaying
a query resource has a claim to.
rdf: and foaf: were declared and never used; the ontology label read "Atomgraph".
The breadcrumb walked sioc:has_container and sioc:has_parent up the ancestor chain, fetching each parent with document() when it was not already in the graph. That is a document hierarchy, which is LinkedDataHub's model: it is the layer that creates dh:Container and dh:Item documents and knows what nests inside what. Web-Client renders the graph it is handed and creates nothing, so it had a navigation aid for a structure it never builds. LinkedDataHub is unaffected and always was. It calls its own ldh:Breadcrumb mode from its own shell, renders crumbs with its own template, and does the ancestor walk client-side in ldh:breadcrumb-resource-response - the same sioc:has_container/has_parent traversal, re-expressed as a promise chain so it does not block the render the way a synchronous document() per ancestor does. Nothing here was reachable from there. imports/dh.xsl goes with it rather than moving: dh:slug's only rendering rule made the datatype control hidden on a creation form, and Web-Client has no creation forms. Standalone Web-Client loses its breadcrumb trail. The sioc prefix goes from resource.xsl with the last use of it.
Three things held the last of it. The writer derived $ldt:base from the Link rel=ldt#base response header; the param fed one reader, a logo block in ac:Header that fetched the base document and rendered its foaf:logo; and imports/ldt.xsl wrapped ldt:match and ldt:path literals in <pre>. The chain went together, because removing the write alone would have left the param permanently unset and the logo block permanently false. What it means for this product: standalone Web-Client no longer renders a site logo, and LDT sitemap templates render their match and path strings like any other literal. The address bar that is the rest of ac:Header - the ?uri= form that makes this a browser for arbitrary Linked Data - is untouched, and so is the LDT vocabulary class, which is public API here. LinkedDataHub was already independent: it stopped reading $ldt:base when lapp:base() began deriving the dataspace base from lapp:origin(), and its own writer no longer sets it. Neither product now mentions ldt: in a stylesheet.
Removing the breadcrumb pulled the mode switcher and the action buttons hard left, because the breadcrumb was what held them right - .ab-main .crumbs carried flex: 1 1 auto, making it the only growing child in a flex row, so it absorbed the free space and everything after it was pushed against the right edge. That was a side effect of a list that happened to be first, not a stated intention, and it left with the list. justify-content: flex-end on .ab-main says it directly and does not depend on what the bar contains. Measured in the browser at 1400px: .ab-main runs to 1376, and its three children - the mode menu, the actions group and the export menu - occupy 982 to 1376, flush with that edge. The .crumbs rules go too: neither product emits the markup any more, LinkedDataHub's own breadcrumb being built from bc-pill anchors in its own stylesheet.
A blank-node range marker typed rdf:langString had no form control. The literal control matched only markers typed in the xsd: namespace, so a constructor declaring [ a rdf:langString ] fell through to the resource control and offered a URI picker for a property that takes text - and on save an empty combobox still submits its generated id URI as the object, so the form wrote resource references where literals belong. The new rule is separate rather than a widening of the xsd:* predicate, because the two differ in what they emit and not merely in a label: RDF 1.1 requires an rdf:langString literal to carry a language tag and forbids it carrying a datatype, so emitting lt=rdf:langString would encode an ill-formed literal. This control emits the value input and a language field, and no lt at all. The language field, its ll input and the annotation are reached by synthesising the value node the control will produce and applying the same templates the data path already uses for an existing @xml:lang value, so a constructor-driven field and one rendered from stored data are one implementation rather than two that can drift. It is prefilled from ac:langs(), which is the single source of language preference and already floors at 'en'. The tag takes the same treatment as any other datatype tag, because that is what rdf:langString is.
…omes the client kit's ExceptionMapperBase turns every mapped exception into an http:Response resource - statusCodeValue, reasonPhrase, an http:sc link, dct:title - and ac:Main rendered it as a block like any other. The block header was already an alert (va-negative), but it carried only what the server called the response: "Not Found", "Bad Gateway". A reason phrase is the protocol's words, not the reader's, and it is the one part of that model a reader needs least - the status code beside it already says as much. The header now carries a sentence keyed off the status: 401 says you need to sign in, 403 that you do not have access, 502/503/504 that the endpoint could not be reached. The response's own metadata stays in the block body, where it was. The three functions that build this arrive from LinkedDataHub, where they were ldh:http-error-key, ldh:error-alert and ldh:error-detail in client/functions.xsl - a client-only module. Neither the status-to-sentence mapping nor the markup is an app concern: InlineAlert is this layer's component, the disclosure is the core kit's, and this layer renders error documents too, so both consumers were about to need the same two builders. They land in imports/default.xsl beside the ac:InlineAlert template they compose, not in functions.xsl, which is version 2.0 and declares no XHTML default namespace - literal result elements there would land in no namespace at all. ac:error-alert takes a resolved title and text rather than catalog keys. The catalog a headline comes from is the caller's: LinkedDataHub resolves 'block-query-failed' in its own translations.rdf and hands the result down, while this layer resolves its own. ac:http-error-key stays a key rather than a label for the same reason - it is the mapping that is shared, and each catalog carries its own wording for it, which is how the sixteen labels these two catalogs already duplicate work. The alert builder dispatches on a synthesized element, and that is not decoration. ac:InlineAlert matches node() | @*, and in Saxon HE that pattern does not match a DOCUMENT node: handing it ac:translations() let the built-in rule descend instead, firing the mode once per child - twice over a catalog that opens with a licence comment - and the function's as="element()" rejected the pair with "a sequence of more than one item". SaxonJS matches the document node directly, so the same construction had worked in the browser and failed only here. One element in, one alert out, on both engines. core.css is re-vendored for .ac-disclosure, the collapsed technical-detail disclosure the error builders emit, and .ac-alert-uri, the alert's link slot. Both were pushed to the design system project first. The disclosure previously lived in ui_kits/app/app.css, which this layer does not link - only LinkedDataHub does - so it moved to core, the one kit both vendor byte-identically, and was renamed from .ldh-block-detail on the way: core is ac- throughout since 77ae481e0, and "block" was app vocabulary in a kit that has no blocks. .ac-alert-uri replaces a .ldh-code borrowed off the brand type scale, which is how an ldh- class reached this layer's markup in the first place; every other slot of this alert states its own type directly, and now so does this one. client.css and this layer's stylesheets are back to zero ldh- class references. Verified by rendering internal-layout.xsl over a 404 model with Saxon HE: one alert, the headline the mapper supplied, the sentence under it, and the reasonPhrase / sc / statusCodeValue / title rows intact below. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
This layer declared no mime mappings at all, so every static file took Tomcat's default: .css and .js came back with no charset parameter, and .xsl with application/xml rather than the text/xsl;charset=UTF-8 LinkedDataHub declares for the same files. A response that names no charset is decoded with the client's fallback encoding - windows-1252 in a browser tab - and every multi-byte character breaks apart: "—" arrives as "â€"", "·" as "·". Six of the eight stylesheets here carry one or both, and all twenty-five stylesheets do. The app did not show it, which is why it went unnoticed. A stylesheet or script loaded FROM a page inherits the referencing document's encoding when the response names none, and the pages declare UTF-8, so everything rendered correctly while the files themselves were unreadable the moment anyone opened one directly. The failure surfaces at the edges instead - a consumer that fetches a sheet with no environment encoding to inherit, and any content: value carrying a non-ASCII glyph. The mappings cover css, js, txt and xsl. .rdf is deliberately left alone: an XML document declares its own encoding, and a charset parameter beside it is a second source of truth that can disagree (RFC 7303). Fonts are binary and take no charset. These matter only for a standalone deploy. LinkedDataHub overlays this WAR and supplies its own web.xml, which wins outright - which is how one lone xsl entry there covered for both layers and hid the gap here. The same block is committed on that side. Verified against the running standalone instance: text/css and text/xsl now arrive with charset=UTF-8 where they previously arrived bare and as application/xml. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
…an be asserted without being shown. ac:RDFaAttributes is the single mapping from an RDF/XML term to the attributes that assert it, at the object/literal level and matching ac:PropertyListValue's own match set, so any emitter that lays a statement out asks for the set instead of retyping it. The property list here routes through it, the carriers below share it, and a downstream layer's own anatomy can too - which is the point, because the same mapping was previously being spelled out at each site and drifting between them. Literals always carry @content. The rendered text is a display decision - a date is formatted, a number grouped, a language pill placed beside the value - while the literal is the lexical form, and @content is the only attribute that lets the two differ. Emitting it unconditionally costs a few bytes and buys the property that no later rendering change can silently alter the extracted graph; emitting it only where the two happen to differ would put that guarantee in the hands of every caller computing its display string correctly. @content never appears beside @resource, where RDFa gives it precedence and would orphan the resource. Both language spellings are written, because the text/html and application/xhtml+xml representations of one URL have to agree and each host language reads a different one. A datatype suppresses language inheritance outright, which is what keeps the document's language off a number. An XML literal takes its lexical form from the source rather than the rendering, which strips the markup to text. The copy drops namespaces first, or serializing would stamp every prefix the surrounding RDF/XML document happens to declare onto the literal's outermost element, and indent is pinned off because the stylesheet's own xsl:output has it on and it reaches serialize() from there. ac:RDFaCarrier serializes a description to link and meta elements, which assert and render nothing - what a graph the page cannot show visibly still needs in order to be in the page's graph at all. Both are display:none in every UA stylesheet, so there is no rule to load and nothing to hide, and neither takes part in layout, so no positional selector or flex gap shifts around them. @Property throughout and never @rel, since the platform's own extractor has @rel out of scope. An empty literal is a childless predicate element, so RDF/XML leaves the level mapping "literal is */text()" with a hole in it: nothing was dispatched and the statement lost its value cell, which also left the dl with a term and no description. The predicate element now stands in for its own object. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPLdcTh9VikFVpAN3iTXf4
colors_and_type.css gains a long-form layer — h1-h6 bound to the .ldh-h* role of the same name, code/samp/kbd, pre, dl/dt/dd, dfn, mark, blockquote and hr — and surfaces.css moves the DataTable base from .ac-table onto `table`. The kit covered app surfaces comprehensively and prose not at all, so anything authored as plain semantic XHTML arrived undressed and every fix so far had been a class hung on the content. A <code> already says it is code and a <table> already says it is a table; a class restating that is one more thing an author can forget, and one more way the same markup renders differently in two places. A class earns its place only where the author is choosing something the markup cannot express, which is why .ldh-body-lg stays and .ac-table survives as the hook for density, ap-plain, is-hoverable and the platform's sortable/sticky behaviour. Cell decorations stay scoped under table: .num and .mono are far too generic to own globally. The elements were cleared against the markup that already exists. The property lists are the case that looks dangerous and is not: read mode and the edit form emit dl.ldh-prop-form > dt.label + dd.ldh-prop-row, .ldh-prop-form already sets margin: 0 to cancel the UA block margin, and .ldh-prop-row is display: contents so it generates no box for a margin to land on. ul/ol/li and p are deliberately left out - one bare <ul> control list has no class to outrank a prose rule, and giving p a margin would hand every alert and card body one to undo. This also picks up the tbody th / th[colspan] / tbody + tbody group-heading rules that had reached the platform but never this copy, so a Web-Client-served table stops rendering its row groups flat. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019EptZ6w7rd883q8N4CMorR
.ac-alert-body is a flex column with its own gap, so a child's block margin was a second spacing mechanism fighting the first: two paragraphs of alert text came out further apart than the gap says, and the first and last pushed their text off the component's padding. Consumers had been resetting it per surface — the documentation site zeroed :first-child and :last-child and still double-spaced everything between them, and the product had no reset at all, so the same alert read differently in each. The component owns it now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019EptZ6w7rd883q8N4CMorR
Web-Client vendors the design system's kit, so it takes the responsive axis with it: the breakpoint scale and the fluid display steps in colors_and_type.css, and the query containers on .ac-card and .ac-modal-body. Its own layer had the bug the axis was built for. .properties gives the label a fixed 200px float, and .statement asks for minmax(140px, 220px) 1fr — which resolves to its MAXIMUM beside a 1fr sibling, because the flexible track is sized last, so the label takes 220px and the value takes what is left. Measured at a 1440px viewport, a 300px container left them 100px and 64px respectively, narrower than the label sitting above. Both now collapse to one column on the kit's 520px container stop. The float is released along with the indent: dropping only the dd margin wraps the value around the label instead of starting it beneath. fieldset and .properties are the containers, since a statement row cannot query itself and a fieldset is the one box always between it and whatever surface holds the form. Nested fieldsets — an inlined blank node sits in a value column — then give their own rows a narrower container than the outer form's, which is right. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.