Seiten-Einbettung ![[Seite]] (Transklusion) im Lesemodus #135

Closed
opened 2026-07-19 00:18:35 +02:00 by fable-5 · 1 comment
Collaborator

Ziel

Obsidian-Syntax ![[Seite]] (Wikilink mit vorangestelltem !) als Seiten-Einbettung / Transklusion. Im Lese- und öffentlichen Modus wird der Inhalt der Zielseite an dieser Stelle gerendert. Im Editor erscheint eine Platzhalter-Karte mit Titel + Öffnen-Link (kein Volltext).

Vorbild

Das bestehende plugin_block ist das End-to-End-Muster (Block-Atom mit Daten, Placeholder in docToHtml, serverseitige Expansion) und wird nachgebaut.

Umsetzung (Reihenfolge = Pipeline)

  1. Schema: Block-Atom-NodeSpec transclusion in packages/shared/src/editor-schema/schema.ts (Vorbild plugin_block ~L96-130 und wikilink ~L226-256), Attr targetSlug (+ optional displayText). Reservierten Node-Namen ergänzen (Kommentar ~L11-12).
  2. Markdown: Regel für ![[…]] in packages/shared/src/editor-schema/markdown.ts, vor wikilink/image registriert (sonst frisst image das !); Token→Node-Eintrag + Serializer (![[slug]] / ![[slug|display]]). Innere Regeln wie beim Wikilink (kein \n/[/]).
  3. Placeholder-HTML: renderBlock-Fall in packages/shared/src/editor-schema/html.ts, der einen Platzhalter ausgibt (<div data-transclusion="{slug}">…), analog zum dt-plugin-block-Placeholder (~L121-134). docToHtml hat keinen DB-Zugriff und kann nicht selbst inlinen.
  4. Serverseitige Expansion: Post-Processor analog apps/api/src/plugins/plugin-fallback-renderer.ts, aufgerufen in apps/api/src/public/public.service.ts (content(), ~L62-76, neben fallbacks.applyToHtml/resolveMediaUrls) sowie in export.service.ts / pdf-html.ts: ersetzt jeden Platzhalter durch die gecachte HTML der Zielseite (page_content_cache), pond-scoped und permission-gefiltert (Zielseite muss lesbar sein, sonst neutraler Hinweis/Link). Rekursion begrenzen (Tiefe max. 1–2, Zyklen erkennen).
  5. Editor-NodeView: TipTap-Node + React-NodeView unter apps/web/src/editor/nodes/ (Vorbild wikilink.tsx / plugin-block.tsx), in document-extensions.ts (~L28-56) eintragen. NodeView = Platzhalter-Karte („⧉ Eingebettet: " + Öffnen-Link /p/{pond}/{slug}), Titel live über apps/web/src/editor/wikilink-context.tsx (makeWikilinkResolver); Phantom-Zustand kennzeichnen.
  6. Link-Ableitung: Einbettung zählt als Link (semantische Referenz). Choke-Point packages/shared/src/editor-schema/wikilinks.ts extractWikilinkSlugs (~L13) so erweitern, dass auch transclusion-Nodes ihren targetSlug beitragen. Beide Persistenz-Schreiber (collab persistence.ts, api pages.service.ts) indizieren dann automatisch → Backlinks & Graph erfassen Einbettungen.
  7. Autocomplete: ![[ analog zu [[ auslösen (apps/web/src/editor/WikilinkAutocomplete.tsx).
  8. Tests: Unit für Parser/Serializer (Round-Trip Markdown↔Doc), DB/e2e für serverseitige Expansion inkl. Permission-Slicing & Rekursionsgrenze, Public-View-Rendering.

Akzeptanzkriterien

  • ![[Seite]] rendert im Lese- und öffentlichen Modus den Inhalt der Zielseite inline.
  • Nur wenn Zielseite lesbar; pond-intern; Rekursion begrenzt (kein Endlos-/Tiefen-Loop).
  • Im Editor erscheint die Platzhalter-Karte mit Titel + Öffnen-Link.
  • Einbettung erzeugt Backlink / Graph-Kante zur Zielseite.
  • Round-Trip Markdown↔Doc stabil.
  • pnpm lint + Unit/DB/e2e grün.
## Ziel Obsidian-Syntax **`![[Seite]]`** (Wikilink mit vorangestelltem `!`) als **Seiten-Einbettung / Transklusion**. Im **Lese- und öffentlichen Modus** wird der Inhalt der Zielseite an dieser Stelle gerendert. Im **Editor** erscheint eine **Platzhalter-Karte** mit Titel + Öffnen-Link (kein Volltext). ## Vorbild Das bestehende `plugin_block` ist das End-to-End-Muster (Block-Atom mit Daten, Placeholder in `docToHtml`, serverseitige Expansion) und wird nachgebaut. ## Umsetzung (Reihenfolge = Pipeline) 1. **Schema:** Block-Atom-NodeSpec `transclusion` in `packages/shared/src/editor-schema/schema.ts` (Vorbild `plugin_block` ~L96-130 und `wikilink` ~L226-256), Attr `targetSlug` (+ optional `displayText`). Reservierten Node-Namen ergänzen (Kommentar ~L11-12). 2. **Markdown:** Regel für `![[…]]` in `packages/shared/src/editor-schema/markdown.ts`, **vor** `wikilink`/`image` registriert (sonst frisst `image` das `!`); Token→Node-Eintrag + Serializer (`![[slug]]` / `![[slug|display]]`). Innere Regeln wie beim Wikilink (kein `\n`/`[`/`]`). 3. **Placeholder-HTML:** `renderBlock`-Fall in `packages/shared/src/editor-schema/html.ts`, der einen Platzhalter ausgibt (`<div data-transclusion="{slug}">…`), analog zum `dt-plugin-block`-Placeholder (~L121-134). `docToHtml` hat keinen DB-Zugriff und kann nicht selbst inlinen. 4. **Serverseitige Expansion:** Post-Processor analog `apps/api/src/plugins/plugin-fallback-renderer.ts`, aufgerufen in `apps/api/src/public/public.service.ts` (`content()`, ~L62-76, neben `fallbacks.applyToHtml`/`resolveMediaUrls`) sowie in `export.service.ts` / `pdf-html.ts`: ersetzt jeden Platzhalter durch die **gecachte HTML der Zielseite** (`page_content_cache`), **pond-scoped** und **permission-gefiltert** (Zielseite muss lesbar sein, sonst neutraler Hinweis/Link). **Rekursion begrenzen** (Tiefe max. 1–2, Zyklen erkennen). 5. **Editor-NodeView:** TipTap-Node + React-NodeView unter `apps/web/src/editor/nodes/` (Vorbild `wikilink.tsx` / `plugin-block.tsx`), in `document-extensions.ts` (~L28-56) eintragen. NodeView = **Platzhalter-Karte** („⧉ Eingebettet: <Titel>" + Öffnen-Link `/p/{pond}/{slug}`), Titel live über `apps/web/src/editor/wikilink-context.tsx` (`makeWikilinkResolver`); Phantom-Zustand kennzeichnen. 6. **Link-Ableitung:** Einbettung **zählt als Link** (semantische Referenz). Choke-Point `packages/shared/src/editor-schema/wikilinks.ts` `extractWikilinkSlugs` (~L13) so erweitern, dass auch `transclusion`-Nodes ihren `targetSlug` beitragen. Beide Persistenz-Schreiber (collab `persistence.ts`, api `pages.service.ts`) indizieren dann automatisch → Backlinks & Graph erfassen Einbettungen. 7. **Autocomplete:** `![[` analog zu `[[` auslösen (`apps/web/src/editor/WikilinkAutocomplete.tsx`). 8. **Tests:** Unit für Parser/Serializer (Round-Trip Markdown↔Doc), DB/e2e für serverseitige Expansion inkl. Permission-Slicing & Rekursionsgrenze, Public-View-Rendering. ## Akzeptanzkriterien - [ ] `![[Seite]]` rendert im Lese- **und** öffentlichen Modus den Inhalt der Zielseite inline. - [ ] Nur wenn Zielseite lesbar; pond-intern; Rekursion begrenzt (kein Endlos-/Tiefen-Loop). - [ ] Im Editor erscheint die Platzhalter-Karte mit Titel + Öffnen-Link. - [ ] Einbettung erzeugt Backlink / Graph-Kante zur Zielseite. - [ ] Round-Trip Markdown↔Doc stabil. - [ ] `pnpm lint` + Unit/DB/e2e grün.
fable-5 added this to the M17 — Lesemodus-Ausbau milestone 2026-07-19 00:18:35 +02:00
Author
Collaborator

Umgesetzt in 15376d4 (+ d5b895a @AuthenticatedOnly auf /read, Route-Coverage #52): Obsidian-Syntax ![[slug]] / ![[slug|Anzeige]] als Block-Node transclusion (Schema, Markdown-Regel vor paragraph, Serializer, HTML-Placeholder). extractWikilinkSlugs erfasst Embeds → Backlinks/Graph. Serverseitige Expansion in PublicService (Tiefe ≤2, Zyklen-Guard, pond-scoped, permission-geprüft, Fehlend→Wikilink); neuer auth-Endpoint GET /read/:pond/:slug für die NodeView. Editor: Platzhalter-Karte im Bearbeiten-Modus, gerenderter Zielinhalt im Lesemodus; ![[-Autocomplete.

Verifiziert: 5 Round-Trip-Unit-Tests + Embed-DB-Test (zyklus-sicher) grün; live auf Test/Int in öffentlicher UND angemeldeter Ansicht. Deployt bis 60be198, von Stefan abgenommen.

Umgesetzt in `15376d4` (+ `d5b895a` @AuthenticatedOnly auf /read, Route-Coverage #52): Obsidian-Syntax `![[slug]]` / `![[slug|Anzeige]]` als Block-Node `transclusion` (Schema, Markdown-Regel vor `paragraph`, Serializer, HTML-Placeholder). `extractWikilinkSlugs` erfasst Embeds → Backlinks/Graph. Serverseitige Expansion in `PublicService` (Tiefe ≤2, Zyklen-Guard, pond-scoped, permission-geprüft, Fehlend→Wikilink); neuer auth-Endpoint `GET /read/:pond/:slug` für die NodeView. Editor: Platzhalter-Karte im Bearbeiten-Modus, gerenderter Zielinhalt im Lesemodus; `![[`-Autocomplete. Verifiziert: 5 Round-Trip-Unit-Tests + Embed-DB-Test (zyklus-sicher) grün; live auf Test/Int in öffentlicher UND angemeldeter Ansicht. Deployt bis `60be198`, von Stefan abgenommen.
Sign in to join this conversation.
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: stwaidele/dorfteich#135
No description provided.