**Alias-Einträge (`params.alias: true`):** Seiten, die in `stili-json` in mehreren `childs`-Listen auftauchen, werden vom Import-Skript an mehreren Stellen im Content-Tree abgelegt. Die primäre Datei (kanonischer Ort, mit Body + Routing) folgt den `crumbs`/`path`-Feldern. Zusätzliche **Stub-Dateien** (leer, kein Routing) entstehen an den weiteren Positionen und erhalten `params.alias: true`.
-In `BlogNav.astro` werden Alias-Nodes mit der CSS-Klasse `alias` versehen. In der `off`-Berechnung überspringen Alias-Nodes `isCurrent` und `isAncestor` — dadurch sind sie im Classic-Layout versteckt, wenn die Seite aktiv ist (der kanonische Eintrag übernimmt die Darstellung). Sichtbar sind sie als Geschwister (normale `isSibling`-Logik). Im Layout „None" (kein CSS) erscheinen alle Einträge, kanonischer und Alias-Eintrag beide fett.
+In `BlogNav.astro` werden Alias-Nodes mit der CSS-Klasse `alias` versehen. In der `off`-Berechnung überspringen Alias-Nodes `isCurrent` und `isAncestor` — dadurch sind sie im Classic-Layout versteckt, wenn die Seite aktiv ist (der kanonische Eintrag übernimmt die Darstellung). Sichtbar sind sie als Geschwister (normale `isSibling`-Logik).
+
+Alias-Nodes erhalten zusätzlich einen Barrierefreiheits-Hinweis im Markup: `<span class="alias-hint"> (Schnellzugriff)</span>` direkt nach dem Titel-Element (`<strong>` oder `<a>`). Der Hinweis steht **außerhalb** von `<strong>` und ist damit nie fett — auch nicht wenn die Seite aktiv ist. Im Layout „None" (kein CSS) erscheint der Hinweis, damit Nutzende von Text-Browsern und Screen-Readern erkennen, dass dieser Eintrag ein Zusatzzugang zu einer auch anderswo gelisteten Seite ist. Im CSS (`base/navigation.scss`: `#submenu .alias-hint { display: none }`) wird er in allen Screen-Layouts ausgeblendet. Der kanonische Eintrag erhält keinen Hinweis.
**Generierte Inhalte (apidocs, xref etc.):** Maven-Site-Outputs liegen fertig generiert in `public/projects/PROJEKT_NAME/VERSION/` und werden als statische Dateien ausgeliefert — ohne Astro-Layout, ohne HTML-Anpassungen, ohne Routing-Dateien in `src/pages/`. `src/lib/projects.ts` (`generatedDocNodes()`) erkennt diese Verzeichnisse zur Build-Zeit automatisch und fügt sie als Nav-Blatteinträge hinzu:
// A nav item is visible (not off) when it is: current, ancestor of current,
// sibling of current (only when current is not a section-index node), or child of current.
// `inPath` = inSubtree(node, currentUrl), pre-computed by the caller to avoid double traversal.
+// `isAlias` = true for nav-only stub entries: isCurrent and isAncestor are suppressed so the
+// alias is hidden in Classic layout when its page is active (the canonical entry handles that).
function nodeOff(
nodeUrl: string,
parentUrl: string,
inPath: boolean,
currentParentUrl: string,
currentIsNode: boolean,
+ isAlias = false,
): boolean {
- const isCurrent = nodeUrl === currentUrl;
- const isAncestor = inPath && !isCurrent;
+ const isCurrent = !isAlias && nodeUrl === currentUrl;
+ const isAncestor = !isAlias && inPath && !isCurrent;
const isSibling = parentUrl === currentParentUrl && !currentIsNode;
const isChild = parentUrl === currentUrl;
return !(isCurrent || isAncestor || isSibling || isChild);
// Partial application of nodeOff bound to the Projects subtree's current-page context
const _projCurrentParentUrl = activeProjectCurrentParent?.url ?? '';
-const projNodeOff = (nodeUrl: string, parentUrl: string, inPath: boolean) =>
- nodeOff(nodeUrl, parentUrl, inPath, _projCurrentParentUrl, activeProjectCurrentIsNode);
+const projNodeOff = (nodeUrl: string, parentUrl: string, inPath: boolean, isAlias = false) =>
+ nodeOff(nodeUrl, parentUrl, inPath, _projCurrentParentUrl, activeProjectCurrentIsNode, isAlias);
// ── Blog URL classification ────────────────────────────────────────────────────
const mainSections = [
<ul class={`s${rootInPath ? ' active' : ''}`}>
{root.children.map(child => {
const childInPath = inSubtree(child, currentUrl);
- const childOff = projNodeOff(child.url, root.url, childInPath);
+ const childOff = projNodeOff(child.url, root.url, childInPath, child.isAlias);
const childIsNode = child.isNode;
return (
- <li class={`s${childIsNode ? ' sub' : ''}${childOff ? ' off' : ''}`}>
+ <li class={`s${childIsNode ? ' sub' : ''}${child.isAlias ? ' alias' : ''}${childOff ? ' off' : ''}`}>
{child.url === currentUrl
? <strong class="s">{child.title}</strong>
: <a href={child.url} class={childInPath ? 's selected' : 's'}>
<ul class={`s${childInPath ? ' active' : ''}`}>
{child.children.map(grand => {
const grandInPath = inSubtree(grand, currentUrl);
- const grandOff = projNodeOff(grand.url, child.url, grandInPath);
+ const grandOff = projNodeOff(grand.url, child.url, grandInPath, grand.isAlias);
const grandIsNode = grand.isNode;
return (
- <li class={`s${grandIsNode ? ' sub' : ''}${grandOff ? ' off' : ''}`}>
+ <li class={`s${grandIsNode ? ' sub' : ''}${grand.isAlias ? ' alias' : ''}${grandOff ? ' off' : ''}`}>
{grand.url === currentUrl
? <strong class="s">{grand.title}</strong>
: <a href={grand.url} class={grandInPath ? 's selected' : 's'}>
<ul class={`s${grandInPath ? ' active' : ''}`}>
{grand.children.map(ggrand => {
const ggInPath = ggrand.url === currentUrl;
- const ggOff = projNodeOff(ggrand.url, grand.url, ggInPath);
+ const ggOff = projNodeOff(ggrand.url, grand.url, ggInPath, ggrand.isAlias);
return (
- <li class={`s${ggOff ? ' off' : ''}`}>
+ <li class={`s${ggrand.isAlias ? ' alias' : ''}${ggOff ? ' off' : ''}`}>
{ggInPath
? <strong class="s">{ggrand.title}</strong>
: <a href={ggrand.url} class="s">{ggrand.title}</a>