Ka-Note/docs/feature-mdeditor.md

133 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Feature: Markdown-Editor Verbesserungen
## Motivation
Der Wiki-Editor in Ka-Note basiert auf **Tiptap v3** (ProseMirror). Für Nutzer die primär mit Tastatur und Maus arbeiten fehlten:
- Ein schneller Weg in den Edit-Modus (ohne Button-Klick)
- Kontextuelle Formatierungshilfe beim Schreiben (Slash-Menü)
- Schnell-Formatierung bei Textauswahl (Bubble Menu)
Referenz-UI: UpNote (Slash-Menü, mobiler Toolbar-Bereich).
---
## Umgesetzte Features
### 1. Doppelklick → Edit-Modus
**Datei:** `ka-note/client/src/routes/wiki/[id]/+page.svelte`
Im Read-Modus aktiviert ein Doppelklick auf den Inhaltsbereich oder den Seitentitel den Editor.
- Titel (`<span>`, Zeile ~118): `ondblclick={() => editing = true}`
- Content-Container (`<div>`, Zeile ~202): `ondblclick={() => editing = true}` + `cursor-text`
- Einfacher Klick auf `[[Wikilinks]]` → Navigation (unverändert)
- Doppelklick auf Linktext → öffnet Editor (kein Konflikt, da Browser-Doppelklick = Textauswahl, nicht Click-Event auf Anchor)
---
### 2. Slash-Command-Menü (`/`)
**Datei:** `ka-note/client/src/lib/editor/tiptapSlashCommand.ts`
Tippt man `/` am Zeilenanfang oder nach einem Leerzeichen, erscheint ein Kontext-Menü mit Block-Befehlen.
#### Verfügbare Befehle
| Icon | Label | Tiptap-Command |
|------|-------|----------------|
| `H1` | Heading 1 | `toggleHeading({ level: 1 })` |
| `H2` | Heading 2 | `toggleHeading({ level: 2 })` |
| `H3` | Heading 3 | `toggleHeading({ level: 3 })` |
| `•–` | Bullet List | `toggleBulletList()` |
| `1.` | Ordered List | `toggleOrderedList()` |
| `` `x` `` | Code (inline) | `toggleCode()` |
| ` ``` ` | Code Block | `toggleCodeBlock()` |
| `❝` | Blockquote | `toggleBlockquote()` |
| `⊞` | Table (3×3) | `insertTable({ rows: 3, cols: 3, withHeaderRow: true })` |
| `—` | Divider | `setHorizontalRule()` |
#### Verhalten
- Trigger: `/` nach Whitespace oder am Zeilenanfang
- Typing filtert die Liste (Label + Keywords, deutsch + englisch)
- Arrow Up/Down → navigieren, Enter → ausführen, Escape → schließen
- Mausklick auf Eintrag → ausführen
- Vor Ausführung: `/` + getippter Query-Text werden gelöscht (`deleteRange`)
- URLs wie `https://example.com` triggern das Menü **nicht** (`:` vor `/` bricht den Scan ab)
#### Architektur
Exakt das gleiche ProseMirror Plugin-Pattern wie `tiptapMention.ts` und `tiptapWikiLink.ts`:
- `Extension.create()` mit `addProseMirrorPlugins()`
- Rückwärts-Scan im `update(view)`-Hook
- DOM-Dropdown in `.ka-editor-wrapper` (renutzt `.mention-dropdown`/`.mention-item`/`.mention-item-active` aus `mention.css`)
- `pointerdown` + `preventDefault()` für Klick-Handling ohne Fokusverlust
---
### 3. Bubble Menu (Textauswahl-Toolbar)
**Extension:** `@tiptap/extension-bubble-menu` (Tiptap v3, floating-ui-basiert)
Bei Textauswahl erscheint eine Mini-Toolbar mit:
| Button | Funktion |
|--------|----------|
| **B** | Bold toggle |
| *I* | Italic toggle |
| H2 | Heading 2 toggle |
| ↗ | Link setzen/entfernen (`window.prompt`) |
- Buttons werden aktiv (blau) wenn der Cursor im entsprechenden Mark/Node sitzt
- Verschwindet automatisch wenn Auswahl aufgehoben wird
- Nicht aktiv bei Bild-Auswahl (`!e.isActive('image')`)
- `onpointerdown` + `preventDefault()` verhindert Fokusverlust im Editor
#### Tiptap v3 BubbleMenu API
v3 nutzt `@floating-ui/dom` für Positionierung (kein tippy.js mehr).
Visibility wird über `element.style.visibility` gesteuert (nicht `display`).
Der `element`-Prop erwartet einen DOM-Node — in Svelte via `bind:this={bubbleMenuEl}`.
---
## Neue Tiptap-Extensions (Table)
Für das Table-Slash-Command wurden hinzugefügt:
- `@tiptap/extension-table`
- `@tiptap/extension-table-row`
- `@tiptap/extension-table-cell`
- `@tiptap/extension-table-header`
Konfiguration: `Table.configure({ resizable: false })`
**Hinweis:** `tiptap-markdown` v0.9 serialisiert Tabellen als GFM (`| col | col |`). Beim ersten produktiven Einsatz verifizieren dass Round-Trip (Edit → Save → reOpen) korrekt funktioniert.
---
## Geänderte / neue Dateien
| Datei | Änderung |
|-------|----------|
| `client/src/routes/wiki/[id]/+page.svelte` | `ondblclick` auf Titel-Span + Content-Container |
| `client/src/lib/components/MarkdownEditor.svelte` | 7 neue Imports, `bubbleMenuEl`-Variable, 6 neue Extensions, Bubble-Menu-Template |
| `client/src/lib/editor/tiptapSlashCommand.ts` | Neu — Slash-Command Extension |
| `client/src/lib/editor/editor.css` | Neu — Slash-Icon + Bubble-Menu-Styles |
---
## Nicht umgesetzt (bewusste Entscheidung)
- **Feste Toolbar**: Passt nicht zum minimalistischen UI-Stil; Bubble Menu ist ausreichend für Desktop
- **Mobile Keyboard-Toolbar**: Separates Thema — erfordert `visualViewport`-Handling für iOS; bei Bedarf als eigenes Feature
- **Link-inline-Dialog**: `window.prompt` als MVP; langfristig ein kleines Svelte-Popover
- **Tabellen-Resize**: `resizable: false` — die Resize-Handles brauchen zusätzliches CSS-Styling
---
## Bekannte Einschränkungen
- `/code` (inline) — nach dem Löschen des Slash-Texts gibt es keine Auswahl; das Code-Mark wird als "stored mark" für den nächsten Tipp-Vorgang aktiviert (Tiptap-Standardverhalten)
- Bubble Menu Link-Button nutzt `window.prompt` — blockiert kurz den Browser