Develop - #373
Draft
namedgraph wants to merge 184 commits into
Draft
Conversation
Blocks now carry the classes ui_kits/app/app.css targets, replacing the Bootstrap grid ones: row-fluid block -> block ldh-block main span7 -> main ldh-block-body well -> ldh-block-head 'block' and 'main' stay alongside the new names: 62 and 11 CSR handler patterns anchor on those tokens, so dropping them would unhook drag-drop, inline editing and the block toolbars. The header gains the two flex children app.css expects - a titles group (type list as badge, h2.ttl, description as span.sub instead of a <p>) and an .actions group holding the timestamp and actions. bs2:Left and bs2:Right emitted reserved grid columns for backlinks, related resources and parallax navigation. The design system has no columns; that content belongs to a block-scoped drawer, so they now render inside div.ldh-drawer. They stay unconditional because CSR fills them later. Two CSR call sites had to follow the markup: - view.xsl took the nav placeholders with a child step, which the drawer wrapper broke - faceted search would have lost its facets and parallax its controls, silently, since an empty for-each is not an error. - chart.xsl and query.xsl lift the header out before replacing block content via ./div/div[@Class = 'well'], declared as="element()", so the rename would have been a runtime type error rather than a silent miss. Still to port: bs2:Left/bs2:Right internals to the drawer's own structure, the drawer's open/close behaviour, bs2:Actions buttons to .tb, the YouTube header's inner markup, and dropping app.css itself in - without which this renders unstyled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
colors_and_type.css (tokens), app.css (components), retro.css (m3 skin) copied from the design system export; fonts.css @font-faces the vendored woff2s - Geist, Geist Mono, Instrument Serif (latin subsets) and the Material Symbols Rounded variable icon font - so no external font requests. The root element takes data-retro="m3" data-theme="light", which the skin keys on. Linked after the Bootstrap stylesheets so the design system wins where both target the same elements; the Bootstrap links come out at the end of the port. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bs2:NavBar becomes the ldh-header grid (wordmark | address | actions), replacing the Bootstrap fixed-top collapse structure; NavBarLeft/Main/ Right and their span columns go. The brand takes the wordmark shape, the address bar the ldh-address skin (same form, 'navbar-form' token and input#uri kept for the CSR submit handler), and the right side becomes ldh-icon-btn buttons with Material Symbols glyphs - apps grid, settings gear, notification bell (admin) - plus an initials ldh-avatar for the agent. btn-group/dropdown-toggle tokens stay: the CSR handler toggles .open on them. ldh:LeftSidebar takes the ldh-sidebar skin: sb-search field, sb-section/ sb-heading groups, sb-tree rows with Material carets. The flyout mechanics are untouched - hidden by default, edge-hover shows, mouseout hides - and document-tree/class-list/btn-expand-tree/btn-geo/btn-latest anchors stay for the CSR handlers. ldh-bridge.css is the deliberate shim between CSR state tokens and the design system: dropdown .open menus, ul.nav strips, the tab bar, tree rows and the expand/collapse carets, styled with the system's tokens. Rules leave this file as components finish porting. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The generic bs2:Row got the drawer in the shell port, but two more block templates - the ldh:XHTML content block and the edit-form row - still applied bs2:Left/bs2:Right in-flow, so their backlinks headings rendered inside the block body. The drawer markup is extracted into the ldh:BlockLinksDrawer named template (dh title + close, db holding bs2:Left/bs2:Right) and all three block shapes call it; bs2:Left/Right defaults become drawer groups (left-nav/right-nav dgroup) and the backlinks well becomes a dgroup with its nav-header kept for the CSR load-on-click handler. The header actions gain the tb-links trigger for @Rdf:about resources; CSR handlers in block.xsl open the drawer (display flex) and close it from its dh button. bs2:Actions loses the Bootstrap button faces: btn-copy-uri and btn-edit become .tb toolbar icons (content_copy, edit) with their handler tokens kept. Verified in the browser: 14 drawers on the dev root document, all hidden; clicking tb-links opens the block's drawer with hydrated facet/backlinks content, its close button hides it again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bs2:ActionBar becomes the zoned ldh-actionbar grid (add | breadcrumb+ timestamp | actions), dropping its container/row/span wrappers. The Create/Add cluster sits in ldh-add-wrap, breadcrumbs take the classic ldh-bc skin on the same CSR-built ul, and doc-controls becomes the quiet mono ldh-ab-ts stamp (History link unchanged). The right-side document actions lose their sprite-logo faces: delete, save-as, access and edit are .tb icon buttons with Material glyphs and their identity tokens (btn-delete, btn-save-as, btn-acl btn-access-form, btn-edit) plus disabled state written explicitly. Export and the layout mode switcher stay dropdowns but with .tb trigger faces; mode glyphs come from the new $ldh:mode-icons map shared by the switcher button and the bs2:ModeListItem entries. bs2:TypeList becomes the badge strip (ldh-typelist), facet headers move from nav-header btn to the drawer's dh2 look, and the bridge styles the read-mode dl/dt/dd as design-system property rows and ul.pager - whose exact-class markup the CSR paging handlers match on - as prev/next buttons. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Modals: the CSR appends div.modal.fade.in and removes it on close, so the bridge styles those tokens as the ldh-modal card - centered fixed panel, radius/shadow, mhead-style header with close, scrolling body, footer bar shared with .form-actions. No modal.xsl template changes. Forms: control-group/control-label/controls stay (they are CSR anchors for constraint violations and constructor rows) and become a two-column property grid with explicit cell placement - RDF/POST hidden inputs and <hr> separators are also direct children of .control-group and were silently taking the first grid cell, pushing every label off its row. Inputs, textareas and selects get the field skin with the focus ring; type hints (.help-inline) read quiet and turn danger only inside .error groups; submit buttons take the accent skin. Verified in the browser: the document edit modal renders the two-column statement layout with working focus states and footer actions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
static/css/bootstrap.css and bootstrap-responsive.css are no longer linked. ldh-bridge.css replaces the primitives LDH still emits - .btn faces, carets, badges, alerts, progress bars, tables, typeahead menus - at :where() zero specificity so design-system component classes always win. The two remaining bootstrap.css links are app-specific rule files (Web-Client's and LDH's own) that keep the historical name only. Bootstrap-only vocabulary dies per the census of what the CSR actually anchors on: - purged outright (no anchors): span2-span10, offset*, well/well-small, sidebar-nav, nav-list, input-*, form-search, input-append, btn-small, btn-large, inline, table-striped/bordered, progress-striped, pull-* trimmed where flex replaced floats - renamed on both sides, emission and contains-token anchors together: span12 -> row-main, row-fluid -> block-row, form-horizontal -> ldh-prop-form, alert alert-error -> ldhc-alert va-danger, container-fluid folded into content-body - kept, still meaningful as CSR anchors: block, main, control-group/ control-label/controls, progress/bar/active, dropdown/btn-group/open, modal family, navbar/navbar-form, breadcrumb, pager/previous/next, tab-pane/tab-content, nav-header, search-form/search-query - btn-danger remove buttons become ldhc-btn in-negative, keeping their remove-action/link-remove handler tokens The footer takes the design system's cols/ftitle shape, and the content body gets its stacking rhythm and max-width from the bridge now that Bootstrap's row margins are gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A dt followed by several dds dropped the extra dds into the term column under grid auto-placement; dt/dd now take explicit columns. .btn-primary picks up a link-colored text rule somewhere upstream, which vanishes on the accent fill - one real-specificity color rule pins it to --fg-on-accent. Content column takes a 1280px measure and the block cards get their stacking margins back (Bootstrap's row margins are gone). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, WYMEditor static/css/bootstrap.css and bootstrap.min.css (the 2.3.2 framework files) are deleted - nothing links them since the framework drop. The script chain loses static/js/bootstrap.js and jquery.min.js: dropdowns, modals and tabs have been IXSL-driven for years, and the only jQuery left in LDH code was the RDF/POST subject-type/value glue. js/jquery.js becomes js/functions.js with the IXSL contract intact - fetchDispatchXML, onSubjectTypeChange, onSubjectValueChange and ixslTemplateListener keep their names and behaviour (the two subject handlers rewritten from jQuery to plain DOM). The Bootstrap-layout pieces of its ready block die with the markup they served (btn-navbar collapse, $().dropdown fallback); outside-click dropdown close and the typeahead autocomplete-off live on as vanilla listeners. The WYMEditor bundle (2.2MB, jQuery-based) goes too - replaced by the RDFa editor in 5.7.0, nothing references it. Verified in the browser: no jQuery-undefined errors, Export dropdown opens via IXSL and closes on outside click, the edit modal renders. The one remaining console 404 is the dev dataset's own broken test object (?uri=https://example.org/aaa), not a regression. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
com/atomgraph/linkeddatahub/css/bootstrap.css never was the framework - it holds LDH's own application rules that accumulated under the historical name. It becomes ldh.css, minus the ten rules whose selector tokens no longer occur in any LDH or Web-Client markup (old breadcrumb logos, action-bar span layout, btn-ban/btn-context, dead sidebar list skins). Web-Client's bootstrap.css stays linked: it styles Web-Client-emitted markup and lives in that repo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two things made the page read as a wall of anonymous white cards rather than the design: - The SaxonJS bs2:Row wrapper carried the ldh-block card skin AND passed it to its next-match inner block, so every CSR-wrapped block rendered card-in-card - visible as sliver borders around alerts and empty- looking bars. The wrapper keeps only the 'block' anchor token now; the inner block is the card. - ldh:XHTML content blocks are prose, and the design renders prose as quiet blocks (no surface, part of the page flow). Their class default becomes 'block ldh-block is-quiet', which app.css already styles. The [Language: en] chip in the reported screenshot does not reproduce in a fresh Chromium or Firefox - it is the stale-SEF browser cache (/static/ is served immutable); a hard reload clears it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The legacy .action-bar rule pins it at --action-bar-top with a 51px fallback - the old Bootstrap navbar height - while the new ldh-header is 56px tall and was not sticky at all, so on scroll the header left the viewport and content showed through a 51px gap above the stuck action bar. The header is now sticky at top 0 and --action-bar-top is defined as the header height, so the two form one pinned chrome stack; #tab-bar's legacy 51px offset follows the same variable. The action bar trades the legacy gray fill for the surface color with a bottom hairline. Verified scrolled 1200px down: header spans 0-56, action bar starts at exactly 56, content scrolls beneath both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The breadcrumb items were still li > sprite-classed anchor + divider. bs2:BreadCrumbListItem now emits the design's crumb anatomy - a.crumb (is-current on the leaf) holding a Material glyph chosen by document type (folder for Root/Container, description for Item, link otherwise) plus the label, with span.sep between crumbs - inside the same ul both render paths share; the CSR-created ul takes the ldh-breadcrumb classes. The crumb builds its own <a> with the imports/default.xsl href recipe rather than overriding the generic xhtml:Anchor mode, which would have re-defaulted every anchor's href away from ldh:href(). The action-bar port had also silently reversed the document buttons: the old markup floated each one right, so DOM order delete->edit read on screen as edit->delete, and the flex container preserved DOM order instead. The DOM now matches the screen order the floats produced: edit, access, save-as, delete, then export and the mode switcher. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…alert blocks The container block's double bottom border had three contributors, found by DOM forensics rather than guesswork: - CSR hydration re-renders a row as a full ldh-block card inside the SSR wrapper card, stacking two borders 13px apart. One card layer only now: a nested .ldh-block flattens (no border/shadow/radius/surface). - The token rename swept the XSLT but not ldh.css, orphaning its row-fluid/span12/form-horizontal/input-append selectors - drag-handle hiding, block clipping, drag-over and diff borders, the progress-bar sizing that kept the loading skeleton invisible after errors, and the search-field flex. All follow the rename (block/block-row/row-main/ ldh-prop-form); the dead action-bar span rule is deleted. - A block whose content collapsed to a single error alert kept its card chrome, framing the alert with white lips. Such blocks go quiet via :has() - the alert brings its own surface - and alerts lose their stray margins inside blocks. The m3 skin's resting M3-elevation shadow, which reads as a hard line under every card, rests flat per the design's card preview (border instead; hover unchanged), and the bridge table rule no longer draws a separator under the last row. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bar's controls were still Bootstrap skeletons (btn-group + ul.dropdown-menu) under bridge CSS. They now emit the design system's own structures, as divs per house style: - Create: ldh-add-wrap > ldh-btn (add glyph + label + caret) + ldh-add-menu with .it entries; bs2:ConstructorListItem renders the design item shape (ico/body/lbl, folder for Container, description for Item) while keeping the add-constructor/data-for-class/ data-create-graph contract. Both end-user and admin variants. - Add: ldh-of-wrap > ghost ldh-btn + ldh-of-menu, generate-containers / import-ontology tokens kept. - Document actions collapse into the design's single Actions menu (bolt + label + caret): Edit / Access / Save as, a divider, the three RDF export links (target=_blank keeps them outside CSR interception), a divider, and a danger-styled Delete - handler tokens and disabled states preserved. bs2:MediaTypeList dies with its dead export-rdf interception exemption; its links live in the menu now. - Mode switcher: ldh-mode > label-row trigger (glyph + active-mode label + caret) + modes-pop with .mi entries as anchors, mode-class and active tokens kept alongside is-active. - Breadcrumbs switch to the pills variant: bc-pill chips with chevron separators in a div container on both render paths. - The timestamp gains the schedule glyph; the address bar shows the document URI on SSR and always mirrors it on navigation (previously blanked for local documents - the design's Header shows the URL). All design menus open through the existing CSR btn-group 'open' toggle; the bridge maps that state onto ldh-add-menu/ldh-of-menu/modes-pop visibility and exempts the address field from the form-field skin. Verified in the browser before the stack was stopped externally: Create pill, Actions menu with dividers and danger Delete, pill breadcrumb, labeled Content switcher all render and open; the address-bar change compiles but its browser check is pending the stack's return. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The XHTML/Object create-block buttons were the last old-school controls: Bootstrap primary pills with sprite faces. They are ghost ldh-btns now, with Material glyphs (notes / data_object) and their create-action / add-constructor / data-for-class contract intact. The sprite system itself goes: all 73 background-image rules pointing at the icons/ directory are deleted from ldh.css and the directory itself is removed - every ported control renders Material Symbols instead. The ldh:logo templates stay purely as class-token carriers for the CSR handlers that anchor on them; with the sprite CSS gone they paint nothing. The one non-CSS consumer, the signup-complete <img>, becomes a check_circle glyph. Verified in the browser: the create-block buttons render as quiet design pills, and the address bar now shows the document URI (the CSR change from the previous commit, unverifiable then while the stack was down). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bridge's Bootstrap-replacement .caret was a 0x0 border triangle, which collided with the ported markup's <span class="msi caret"> expand_more</span>: the triangle painted inside the button while the glyph text overflowed the zero-size box as a stray chevron below it. .caret is now a Material glyph in both generations - ported spans render their own expand_more, and legacy empty <span class="caret"/> spans (login dropdown, sort toggle, the drawer's backlinks heading) get the same glyph via ::before, with caret-reversed flipping to expand_less. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…les only Of the empty <span class="caret"/> leftovers, five were static dropdown carets - they now ship the expand_more glyph directly, like the rest of the ported markup. The two caret-reversed collapse indicators stay empty by design: the CSR handlers flip the caret-reversed class on them, and only ::before content can follow a class change on a ligature-font glyph. The bridge comment records that distinction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sticky action bar (z-index 999 from the legacy rules) painted over modal dialogs, hiding their header - the bridge had given modals z-index 110. Modals sit at 1050 now, above the whole chrome stack, with a non-interactive dim behind them via body:has(); typeahead suggestion menus move above the modal plane so in-form typeaheads keep working. Design menus (Create/Actions/modes) also stayed open after picking an item. The outside-click closer now also closes on menu-item picks, deferred a tick so it settles after the IXSL btn-group toggle that handles the same click - otherwise the two could race and re-open the menu. Verified in the browser: Create > Container opens the modal above the chrome with the page dimmed behind it, and the Create menu is closed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The m3 skin paints every .ldh-header descendant with the inverse near- white text color for the dark bar - correct for the bar itself, but the light dropdown panels inside it (Applications, Settings, agent) rendered white-on-white and read as empty. Panel content takes the regular ink back at higher specificity, section headers keep the hint color, and the avatar's initials stay dark in its hover/open state where the fill goes light. Settings had no pull-right token, so its menu left-aligned and clipped off the viewport; header menus now hug the right edge regardless. Menu picks also close these header menus via the same deferred closer as the action-bar menus. Verified in the browser: all three menus open readable and right- aligned - System apps list, Application/Administration/Namespace ontology, and the agent entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Census: zero CSR anchors on pull-*, and floats are inert inside flex containers and on absolutely positioned elements - so every pull token whose parent already became flex chrome (header action strips, block head actions, alerts, dropdown toggles) or that rode an absolute menu was doing nothing. Those 14 are gone; the Actions wrapper layout keys on its position in .actions instead of the token. What stays, deliberately: pull-right on ul.dropdown-menu as the alignment signal for the not-yet-ported menus, and the still-active floats in interior form markup (btn-remove-property/btn-add rows, typeahead metadata, the hover-overlay edit buttons) - those go when their components get ported, and the bridge documents exactly that. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The legacy modal markup puts button.close FIRST and titles the dialog with a <legend>; the bridge's flex header laid children out in DOM order - close at the left, the title squeezed into a wrapping column, the description eating the rest. The header is a two-column grid now: the title column (legend/h2/h3 styled as the design's mhead title, any <p> as a muted subtitle under it) and the close button pinned top-right, regardless of source order. Verified on the Request access modal: title left, description under it, close at the right - matching the design's mhead anatomy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both bs2:Chart forms (the RDF and SPARQL-results variants, which the CSR re-render also compiles in) swap their fieldset block-row for the design system's chart-controls three-column grid with .field cells - mono uppercase overline labels, full-width selects, the series multi-select as a listbox. Select classes/ids (chart-type / chart-category / chart-series, name=ou|ol) are untouched, so the onchange handlers and the RDF/POST encoding are unaffected. Fieldsets and legends lose their Bootstrap-era box look globally: borderless sections with overline legends, which also fixes the old-school group boxes in the access modal. Multi-selects inside the controls grid keep their natural height. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Full-DOM audit (Playwright crawl of every menu, modal, form and mode against the design-system contracts) surfaced the components that lost their faces when the sprite CSS died, plus one real regression risk: - The constructor modal had an empty <legend> - it is titled with the class label now (ac:object-label in xsl:try; the bare call throws and killed the whole modal render, which the first fix attempt proved the hard way. The catch falls back to the URI local name.) - Remove-statement and remove-resource buttons were empty invisible boxes in every editing form: .tb buttons with the close glyph now, in all three emitters (constructor.xsl - with the xsl:attribute reordered before the glyph span, imports/default.xsl, resource.xsl), handler tokens kept - The search modal's submit button was invisible: search glyph - Add-statement button swaps the HTML entity cross for the add glyph - Graph HUD buttons gain fit_screen / fullscreen glyphs per OtherModes - Dead tokens purged: wymupdate, dl-horizontal, the sprite-era class injection on block-title anchors Verified in the browser: Create > Container opens titled with glyphed remove buttons (4/4); the per-block edit button opens the inline editing form with glyphed controls and footer actions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A faceless-button DOM sweep (every button with no text, glyph or image, across edit mode, the create modal and the inline block edit form) caught the emitters whose only face was a sprite class injected via the ldh:logo mode: the subject-edit toggle in form legends (edit glyph), the add-value button on property controls (add glyph) and the rdf:type control group's remove button in imports/rdf.xsl, which now matches the canonical tb btn-remove-property + close-glyph shape. Dead sprite background-position rules and the border-triangle caret-reversed rule (the double-arrow bug's last holdout) leave ldh.css. Re-swept after deploying: no faceless buttons remain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…glish go with it The facets answer to 'where did the filters go': out of the links drawer, into a ldh-view-toolbar at the top of every view block, per the ViewBlocks contract. Left zone: filter_alt lead + one dropdown pill per facetable property - the pill is the old nav-header (button-shaped, same hidden subject/predicate/object inputs), so the lazy value-load onclick and the checkbox filter onchange run unchanged; the hydrated ul.nav now doubles as the facet-pop popover card. Right zone: the inline-create button, Total results, the order-by select + direction button, and the mode dropdown (with a visible active-mode glyph from ldh:mode-icons). The drawer group the facets vacated hides when empty; parallax stays in the drawer. Verified in the browser: pill opens, values load with counts, checking a value filters the results. The last pull-left/pull-right tokens are purged along the way - header menus right-align via a header-scoped rule, the form legend is restructured (label first, subject controls in a right-hugging .actions cluster, remove button last), remove/add groups trail their form rows via flex order, the language badge follows its value, and the typeahead metadata span is .meta. The bridge float shims are deleted. Branch-introduced English strings move to translations.rdf (add-stmt, remove-resource, remove-link, get-started, learn-more, footer titles and links, export format names); the facet lead reuses filter-title. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The three serialization links (RDF/XML, Turtle, JSON-LD) move out of the Actions menu into a new bs2:ExportList mode that bs2:ActionBarRight renders after the mode switcher: an icon-only ghost button (download glyph, titled from the existing export translation entry) opening the same target=_blank links. Same signed-in guard and HTTP-error suppression as before, same ldh-of-wrap anatomy, so the open-toggle and close-on-pick wiring covers it unchanged. The Actions menu keeps edit / access / save-as / delete, minus the now-stray second divider. Verified in the browser: the button renders right of Content, its menu lists the three formats with the correct accept hrefs, and the Actions menu no longer carries them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The edge-hover flyout stopped appearing: the port stamped the sidebar with the design's ldh-sidebar class, whose resting state is translateX(-100%) waiting for an is-open toggle - but the CSR handlers carry show/hide as inline display (mouse at x=0 sets block, mouseout sets none). The handler fired, display flipped, and the panel stayed 288px off-screen. The bridge now neutralizes the slide transform so display alone controls visibility, and starts the panel below the sticky header instead of the design's full-height top:0. Verified in the browser: mouse at the left edge slides out the panel (search, document tree, class pills, other views) at x:0 under the header; mousing out hides it again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ith it Every form footer (modal and inline) now follows the design's footer anatomy: secondaries (Cancel/Reset/Close) are ghost ldh-btns, the primary (Save/Compare/Allow/Annotate) is a filled ldh-btn with a glyph, and it sits last so the ghost buttons lead into it. Handler tokens (btn-save, btn-cancel, btn-reset, btn-close, btn-save-chart, spo-action, cancel-action) ride along unchanged, as do the two $button-class param defaults that feed the ldh:logo class injection. The Bootstrap-era form-actions class itself is gone: the design system has no such band (its ldh-form-actions-* names mean the per-form actions dropdown), so the footers take the design's ldh-block-foot token - all emitters, the one CSR matcher that anchored on it, and the bridge rules renamed together. modal-footer stays as the sticky-scroll token, its hardcoded white swapped for the surface token. Also fixed en route: a stray quote in ldh:Form's save button class, and the access form's hardcoded Allow label now comes from a new translations entry. Verified in the browser: the create modal footer renders ghost Reset + filled glyphed Save on the ldh-block-foot band. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…column The rdf:RDF form shell gains a show-close-button param (default false, so the SSR EditMode page keeps its plain footer) emitting a ghost Close button ahead of Reset; the generic modal.xsl close handler already matches any button.btn-close inside a modal, so no new wiring. All six modal flows through the shell opt in: document create, document edit, add-instance, app settings, and both constraint-violation re-render paths. The three modal footers that already had a Close (import ontology, generate containers, request access) join the new convention: ghost Close and Reset leading into the ldh-btn primary. Also swept up: form-actions-class param values that still said 'form-actions' (the class-literal rename missed them), and modal.xsl's button-class defaults move off btn btn-primary. Modals now span the content column - width matches .content-body's inner width (max 1280px minus side padding) instead of the 880px cap. Verified in the browser: create modal footer reads Close / Reset / Save, inline form reads Cancel / Reset / Save, and the modal box is pixel-identical in x and width to the content blocks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t describes. Two versioning tests failed in CI run 33626306733 while the platform did exactly what they were asserting: the commits landed in ~1.3s, and 664d147d carried the agent's WebID as its author. What failed was how the tests read GitHub back. Each polled the Contents API until the file appeared, then threw that result away and re-derived it from a fresh read. PUT-creates-commit read commits?path= once, and got an empty listing: GitHub indexes a path's commit history asynchronously, so a file that is already readable can still have no history. DELETE-removes-file re-issued the identical contents request 150ms after it had succeeded and got a 404 back. Both tests finished in under 5s, so neither loop ran to its timeout. The poll is now the assertion. PUT-creates-commit waits for the author it wants to compare, GET-timemap - which passed this run, on the same pattern and the same luck - waits for the listing its TimeMap is built from, and DELETE-removes-file keeps what its loop found rather than asking again. This is what GET-version and GET-timegate already do, and why they pass: they spent 10-12s waiting out the same lag the other three refused to. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WK1ssk2A67MYseeH3hWnhf
…s already are. Web-Client now folds every value of a property into the one cell its header allots, each value a block of its own inside a container the cell holds. Give that container the treatment the property list's dd's already have: a divider between consecutive values, and a cap on the stack. The cap belongs on the container rather than the cell because a td cannot bound its own height. Past it the surplus scrolls, so an order with fifty line items stays whole and reachable instead of setting the row height for the whole table. The language pill moves behind the ac:lang-tag mode Web-Client applies from wherever values are laid out. It was written inline in the dd and would have had to be written again for the cell; now the property list and the table cell read the same pill from one place, and the mode is what a skin answers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
Versioning has served all three RFC 7089 roles from the document URI since 5.9.0, but the CLI could reach only two of them, and only by concatenating the query string itself. ?timegate it could not reach at all: negotiation is carried by an Accept-Datetime request header, and no command could send one. So the suite that covers the contract asserted two thirds of it through ldh and dropped to curl for the rest, converting datetimes with a `date -u -j -f ... || date -u -d ...` pair to paper over BSD and GNU disagreeing about how to parse a flag. get now takes --version, --timemap and --timegate as an exclusive group, each still one request, plus a --datetime that reads RFC 1123 or ISO 8601 and writes the zero-padded RFC 1123 the grammar asks for. The ISO half is what removes the date(1) dance: a prov:generatedAtTime lifted out of a TimeMap, or a commit datetime out of the GitHub API, goes straight back in. --timegate prints the Location as the only line on stdout, which is the same contract create-item has and what lets the negotiated version pipe into another get. It is also the one request that needs no --accept, a 302 having no representation to negotiate, so the option moves from picocli's required to a check in call(). Through --proxy the printed URI is rewritten back to the logical origin, as everywhere else the CLI prints one. The enablers were already in place and unused: Core's get() has taken a header map since 4.0.14, and the client has never followed redirects, on the grounds that the scripts called curl without -L. That decision was about matching the scripts; it is what makes reading Location possible. Nothing here has run against a live instance. The suite is gated on a GitHub token and skips without one, so CI is where these paths first execute. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
Seventy-seven echoes across eighteen scripts printed DEBUG lines, most of them on every passing run. They accumulated the way CLAUDE.md prescribes - when a test fails, add output showing expected against actual, then diagnose - but the step after that, taking the scaffolding back out once the cause is found, was never taken. What was left restated in a string what the line under it already asserts in code, and buried the runs that mattered under the ones that didn't. Three kinds went beyond the echo itself. A label ending in a colon introduced a bare dump on the next line, so removing only the label would have left the body printing. Failure branches carried `gh api ... || true` calls, and one carried a five-line curl piped into sed, that no assertion reads and no exit code depends on. PUT-creates-commit had an if whose entire body was diagnostic and which never exited; the equality test after it already fails on an empty author. import_triple_count() had no callers left once its two call sites went. Every assertion stands, and the comments were already saying what the strings were repeating. What is lost is expected-against-actual at the moment of failure: a failing run now names the script and not the values. That is the first thing to add back when one fails, which is where CLAUDE.md starts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
The pill was written for the property list and scoped to it: .ldh-block dl > div > dd .chip-inline. But ac:lang-tag emits the badge from wherever values are laid out, and since a table cell started holding every value a property has, it emits it there too - where no rule matched it and it fell back to bare inline text glued to the value it annotates, so a Lithuanian label read "Seimaslt". The graph3d node details had the same gap. So the pill belongs to .chip-inline itself rather than to a position inside one container, the way .btn-type already belongs to the type and not to the header list it first appeared in. A property renders every language it carries, ordered by the reader's preference, so the tag is what tells the values apart: it has to survive being laid out somewhere new. Its tag stays on one line - sr-Latn-RS must not break the way the prose beside it does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
…ent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
These blocks are never stored. ldh:RenderRow queries /ns for the views attached to a resource's types, fetches each one and appends it to the host wrapper, so the block is rebuilt on every load. ac:uuid() gave each rebuild a fresh subject, which left the block's Copy URI value true for exactly as long as the page stayed open. What identifies such a block is the resource it hangs off and the view it renders, and both are already in hand at the insertion point. Deriving the fragment from that pair reproduces the same URI the next time the block is derived. Both halves are needed: ldh:RenderRow visits every wrapper, so a container listing injects the same view under each of its children, and the view URI alone would hand them all one @about - enough to make element-by-about ambiguous and to give ldh:ScrollToFragment more than one element to land on. Combining them means hashing. No digest is reachable from XSLT in either product, and crypto.subtle.digest returns a promise, so it cannot stand where ac:uuid() stands. djb2 over the codepoints needs only multiplication and addition, which XPath 3.1 has, so one definition serves Saxon-HE and Saxon-JS alike. Random UUIDs stay right wherever a block's subject is written down, so ldh:CreateBlock and the form flows keep theirs. The line is whether the URI is stored or re-derived. A stable fragment is still not one you can follow, because the scroll ran too early. ldh:RenderTab defers a fragment scroll until the page's block factories settle, but the view chain fired its per-view promises as detached instructions and returned, so it settled as the /ns query came back and the countdown reached zero while the document held none of the injected blocks. The chains are returned and joined with ixsl:all now, down to the injected block's own hydration: the block's results are what give it its height, and a scroll that lands before they arrive lands on a block that then grows out from under it. The per-view context merge kept the first 'request' it saw, which was the /ns query rather than the view fetch. Nothing read it while the fetch took the request directly, but the fan-out reads it from the map, and ldh:retry-request re-fires whatever it holds when a 429 comes back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
A <pre> in an ldh:XHTML block had no skin left once Bootstrap 2 went, so a Turtle listing ran on the bare page background. It now takes the recessed well the inline .ldh-code chip and the error-detail listing already share, which tints with the theme rather than fixing a white that inverts wrong in dark mode. Colour and size come from the inline chip instead of the error listing, whose --fg-muted at --fs-xs demotes text that here is the content; and a long IRI scrolls the block instead of wrapping, so a listing keeps the line structure it was written with. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
… dls to their own layout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1UnYpbW5aYLj7LbwtyUo1
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
Installing a package is one ldh:import triple in the application settings, and the CLI's answer to that had been "use ldh patch". But add-ontology-import is the same shape -- one owl:imports triple, PATCHed -- and it has a command, because sparing the caller the RDF is what the CLI is for. Here the caller was being asked for rather more: the /settings path, the unabbreviated ldh:import IRI, SPARQL update syntax, and the subject to hang the triple off. That last one is not guessable at all. The application is identified by an opaque urn:linkeddatahub:apps/end-user, not by its origin, so the updates match it by type instead of naming it and the caller never has to learn the URN exists. list-packages is the affordance ldh patch cannot substitute for. The registry is not the application's own URI and is not live yet, resolving from a bundled copy through the Linked Data proxy, so the listing is read the same way the settings modal reads it -- through ?uri= -- and cross-referenced against the ldh:import triples already in the settings. One tab-separated line per package keeps it greppable. The names stay on the declaration rather than reviving install/uninstall, which were deleted along with their endpoints when packages became declarative: those verbs mutated webapp files, and nothing here does. Removing an import that is not there succeeds and changes nothing, as a DELETE should. StubServer grew per-path responses because list-packages is the first command to read two documents with different media types in one run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
… landed. Bootstrap 2 is gone, and an override emitting its class vocabulary still compiles and still runs -- it just renders unstyled, with no diagnostic. A failure that gives no signal of its own is what the major version is for, so 5.11.0 becomes 6.0.0 and the section leads with a migration list naming each replacement. The Fixed entries are for work already committed but never written down, and the Web-Client 5.0.4 bump landed with the Content-Language change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
… key for. SaxonJS backs distinct-values() and xsl:for-each-group with a hash trie whose insert recurses once per character of the key. A key longer than the JS stack allows -- around 6-7K frames -- takes the whole transform down with "too much recursion", and the keys that get there are real content: an XHTML content block's serialized literal is the object of a triple, so it lands in merge-rdfxml's group-by and in ldh:triple-key verbatim. ldh:bounded-key() passes anything under 1000 characters through unchanged and folds the rest into a prefix, a length and a rolling hash. Distinctness is what these keys are for, and prefix plus length plus djb2-style hash keeps it for content that differs anywhere -- while the bounded result stays inside the recursion the trie can afford. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
The canonicalization treated class, id, aria-*, data-*, role and hidden as editor bookkeeping and dropped them all, and stripped button outright as an active element. That is right for what the editor injects and wrong for what an author wrote: a tab strip is buttons carrying role, aria-selected and aria-controls over panels carrying id and hidden, and none of it came back from storage. C2 now strips only what the editor itself mints -- contenteditable, draggable, tabindex="-1" -- plus @Style, which no editing gesture can author but browsers mint freely during editing and paste. @Class is subtracted token by token, the editor's own rdfa-editor-* and transient gesture markers going and authored tokens staying, and an attribute left empty drops. button is exempt from S1 because S2 has already stripped its handlers, leaving inert markup. A host that wants stricter storage layers its own stripping at higher import precedence. C6 and C7 asked whether an element carried RDFa before unwrapping it as browser junk; they now ask whether it carries any attribute that survives canonicalization, so an authored class or id is meaning too. An empty a[@id] is an anchor target rather than the empty inline C8 discards. The tab strip then needs to work in both directions. In read mode the click handler moves is-on and aria-selected to the clicked tab and unhides the panel it aria-controls, guarded on panels existing so the query block's paneless mode tabs keep their own handlers. While a region is edited every panel is shown stacked -- an editor that hides content cannot edit it -- and hidden reasserts itself on restore. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
…ing. The XMLLiteral autosave fired on every focusout that left the region, so opening a block and clicking away rewrote the stored literal with a value identical to the one already there -- and minted a version recording it. A no-op save is still a save. The region now stashes its canonical form when it is activated, and the focusout compares against that baseline. Unchanged content takes the path Cancel takes: the pre-editing snapshot is restored and editing ends, so leaving the editor always leaves it. Changed content saves and moves the baseline forward, so continued editing only ever saves what came after; a rejected save leaves the form re-rendered with its violations, which re-dirties as soon as the author fixes them. Comparing needs one canonical form, not two implementations of it, so the serialization the ol input already did becomes ldh:canonical-content() and the baseline and the dirty check call it. Restoring needs one implementation too: Cancel's body becomes ldh:CancelEditing on the block. It also had to start replacing the snapshot element rather than its children -- the edit-mode render replaces the block wrapper itself, and an XHTML block is quiet prose in read mode but carded while editing, so restoring only the children left the card around them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
… DOM workarounds they emulate. ixsl:replace-element replaces the attribute-copy emulations in ldh:replace-block-element and the inline row-form success handler (the follow-up listener re-inits now re-resolve the inserted node by the rendered element's id, since the replacement detaches the host), and the add-typeahead button swaps itself for the lookup markup instead of rebuilding all of its parent's children. ixsl:insert-before retires the remove/re-append dances: the constructor fieldset lands above the still-live Add constructor button, and new property control groups land above the property picker, which also deletes the positional [last()] / control-group-count re-lookups. In the rdfa-editor, the rendering island and the invalid-region fix write nodes directly instead of a serialize + innerHTML round-trip (closing the self-closing-tag fragment-parser hazard), and the block-paste path threads pasted blocks in with a single ixsl:insert-after instead of a staging div and an xsl:iterate. Live-node moves (drag-drop, toolbar adoption, caret machinery) stay imperative - result-document copies content, it cannot relocate DOM nodes. The unused ldh:replace-content helper is removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1UnYpbW5aYLj7LbwtyUo1
…s one shared pipeline. signup.xsl moves from client/admin/ down to admin/ and is included by layout.xsl alongside client.xsl: since the SSR shell became the default for local pages, its client-only bs2:ContentBody/bs2:Row overrides never fired on direct loads and the form only appeared after in-app navigation. The rendering overrides are product-neutral; the browser-only submit handling is use-when-guarded to SaxonJS, restoring the guard idiom the file had before it went client-side in #294. The placeholder div, the constructed-doc promise chain and ldh:render-signup-form are deleted - one synchronous bs2:Row serves both the server render and client-side re-renders. That works because ldh:construct-instance, ldh:instance-term, ldh:marker-types and ldh:triples-to-descriptions move to the shared imports/default.xsl, with parsing behind the new dual ldh:parse-query: the browser keeps the SPARQL.js 2.x Parser, the server gets the new ParseQuery extension function (Jena QueryFactory) which emits the same parse-tree JSON subset in the same term serialization - the lockstep contract between the two parsers and the consuming stylesheets is documented on all three sides. The ldh:construct-forClass wrapper is deleted; its two call sites (signup and the $constructor tunnel default in resource.xsl, which now also instantiates constructors server-side instead of hitting the removed SSR stub) inline the constructor-query/fetch/construct-instance primitives. The unused ldh:parse-html and the commented-out ldh:new are removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1UnYpbW5aYLj7LbwtyUo1
… the editor. Only leaf text hosts are contenteditable, so the surface between them - sibling margins, the drag-handle gutter, a structural container's own box, chrome on a structural block - had no focusable ancestor. A press there dropped focus off the canvas, and the autosave's focusout guard reads a null relatedTarget as leaving the editor, so an incidental click saved and exited. The region now carries tabindex, absorbing that focus, and a press outside every editable host places the caret at the point itself: the nearest host takes focus and the caret lands where the pointer is. Its sweep anchor is host-less, since the preventDefault leaves no native drag session for the mousemove takeover to ride. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YxhcqMPK1kZR1pxxJqoge
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1UnYpbW5aYLj7LbwtyUo1
…g generic alerts, with the type set read from the block's @typeof. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WK1ssk2A67MYseeH3hWnhf
…tton mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1UnYpbW5aYLj7LbwtyUo1
…lls with required markers and description toggletips, capped controls with inline annotations in read-height rows, compact textarea defaults, and the vendored controls/overlays stylesheets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WK1ssk2A67MYseeH3hWnhf
…icky bars drop below the overlay scale so dialog heads no longer hide under the navbar. The RDFa annotation overlay sheds the bare modal token (Esc and ldh:CloseModal no longer destroy it) and carries its own card chrome; .modal-header/.modal-body survive only rescoped to it and the map info window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DfCWF1dExp6zyLrdfrAsZ4
…description is an association list, so the grid projection rides the elements specified for it, with the RDFa attributes on the dd rows and the dl's UA margin bridged until the design system carries the reset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WK1ssk2A67MYseeH3hWnhf
…gle request they name, import carries the composite workflows, and the packages family and the admin scope replace the bin/ directory mirror. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1UnYpbW5aYLj7LbwtyUo1
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.