|
@@ -9,8 +9,7 @@ This is a **block-based markdown editor** built with Vue 3, TypeScript, and Pros
|
|
|
> [!NOTE] Every paragraph is its own Block component.
|
|
> [!NOTE] Every paragraph is its own Block component.
|
|
|
> Blocks are independent editors with their own state.
|
|
> Blocks are independent editors with their own state.
|
|
|
|
|
|
|
|
-Try editing any of the examples on the left.
|
|
|
|
|
-`)
|
|
|
|
|
|
|
+Try the examples under each component page.`)
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
<template>
|
|
@@ -23,12 +22,7 @@ Try editing any of the examples on the left.
|
|
|
<UPageBody>
|
|
<UPageBody>
|
|
|
<div class="space-y-8">
|
|
<div class="space-y-8">
|
|
|
<section class="space-y-4">
|
|
<section class="space-y-4">
|
|
|
- <h2 class="text-lg font-semibold text-highlighted">What is this?</h2>
|
|
|
|
|
- <p class="text-sm text-muted leading-relaxed">
|
|
|
|
|
- The editor is a headless engine — each <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">Block</code> component manages a single paragraph with its own ProseMirror instance.
|
|
|
|
|
- Markdown syntax is rendered as rich decorations in live-preview mode: delimiters fade when blurred, syntax elements get contextual styling.
|
|
|
|
|
- </p>
|
|
|
|
|
- <div class="rounded-lg border border-default dark:bg-neutral-950/50 p-4">
|
|
|
|
|
|
|
+ <div class="rounded-lg border border-default dark:bg-neutral-950/50 p-4 sm:p-8 rounded-t-md">
|
|
|
<EditorBlock
|
|
<EditorBlock
|
|
|
v-model:content="example"
|
|
v-model:content="example"
|
|
|
:focused="true"
|
|
:focused="true"
|
|
@@ -39,95 +33,77 @@ Try editing any of the examples on the left.
|
|
|
</section>
|
|
</section>
|
|
|
|
|
|
|
|
<section class="space-y-4">
|
|
<section class="space-y-4">
|
|
|
- <h2 class="text-lg font-semibold text-highlighted">Key Concepts</h2>
|
|
|
|
|
|
|
+ <h2 class="text-lg font-semibold text-highlighted">Components</h2>
|
|
|
|
|
+ <p class="text-sm text-muted leading-relaxed">
|
|
|
|
|
+ The editor is organised as four main components:
|
|
|
|
|
+ </p>
|
|
|
<div class="grid gap-4 sm:grid-cols-2">
|
|
<div class="grid gap-4 sm:grid-cols-2">
|
|
|
<div class="rounded-lg border border-default p-4 space-y-2">
|
|
<div class="rounded-lg border border-default p-4 space-y-2">
|
|
|
<div class="flex items-center gap-2">
|
|
<div class="flex items-center gap-2">
|
|
|
<span class="i-lucide-layers size-4 text-primary shrink-0" />
|
|
<span class="i-lucide-layers size-4 text-primary shrink-0" />
|
|
|
- <h3 class="text-sm font-medium text-highlighted">Blocks</h3>
|
|
|
|
|
|
|
+ <h3 class="text-sm font-medium text-highlighted">
|
|
|
|
|
+ <RouterLink to="/editor" class="hover:underline">Editor</RouterLink>
|
|
|
|
|
+ </h3>
|
|
|
</div>
|
|
</div>
|
|
|
<p class="text-xs text-muted leading-relaxed">
|
|
<p class="text-xs text-muted leading-relaxed">
|
|
|
- Documents are split into distinct Block components — each one is an independent editor.
|
|
|
|
|
- Blocks communicate through a shared document model.
|
|
|
|
|
|
|
+ Multi-block shell with insertion zones, shared toolbar, drag-to-reorder, and unified undo/redo.
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="rounded-lg border border-default p-4 space-y-2">
|
|
<div class="rounded-lg border border-default p-4 space-y-2">
|
|
|
<div class="flex items-center gap-2">
|
|
<div class="flex items-center gap-2">
|
|
|
- <span class="i-lucide-palette size-4 text-primary shrink-0" />
|
|
|
|
|
- <h3 class="text-sm font-medium text-highlighted">Decorations</h3>
|
|
|
|
|
|
|
+ <span class="i-lucide-file-text size-4 text-primary shrink-0" />
|
|
|
|
|
+ <h3 class="text-sm font-medium text-highlighted">
|
|
|
|
|
+ <RouterLink to="/editor-block" class="hover:underline">EditorBlock</RouterLink>
|
|
|
|
|
+ </h3>
|
|
|
</div>
|
|
</div>
|
|
|
<p class="text-xs text-muted leading-relaxed">
|
|
<p class="text-xs text-muted leading-relaxed">
|
|
|
- Markdown syntax is rendered as ProseMirror decorations — styled spans overlaid on the source text.
|
|
|
|
|
- Delimiters animate in and out based on focus.
|
|
|
|
|
|
|
+ Single-block ProseMirror editor with all markdown syntax — props, events, and exposed methods.
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="rounded-lg border border-default p-4 space-y-2">
|
|
<div class="rounded-lg border border-default p-4 space-y-2">
|
|
|
<div class="flex items-center gap-2">
|
|
<div class="flex items-center gap-2">
|
|
|
- <span class="i-lucide-parse size-4 text-primary shrink-0" />
|
|
|
|
|
- <h3 class="text-sm font-medium text-highlighted">Parsing Pipeline</h3>
|
|
|
|
|
|
|
+ <span class="i-lucide-rows-3 size-4 text-primary shrink-0" />
|
|
|
|
|
+ <h3 class="text-sm font-medium text-highlighted">
|
|
|
|
|
+ <RouterLink to="/toolbar" class="hover:underline">EditorToolbar</RouterLink>
|
|
|
|
|
+ </h3>
|
|
|
</div>
|
|
</div>
|
|
|
<p class="text-xs text-muted leading-relaxed">
|
|
<p class="text-xs text-muted leading-relaxed">
|
|
|
- A 3-stage pipeline classifies blocks, builds a Lezer AST, then extracts decorations.
|
|
|
|
|
- Everything runs in under 16ms per keystroke.
|
|
|
|
|
|
|
+ Formatting toolbar with active state tracking, undo/redo buttons, and handler integration.
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="rounded-lg border border-default p-4 space-y-2">
|
|
<div class="rounded-lg border border-default p-4 space-y-2">
|
|
|
<div class="flex items-center gap-2">
|
|
<div class="flex items-center gap-2">
|
|
|
- <span class="i-lucide-plug size-4 text-primary shrink-0" />
|
|
|
|
|
- <h3 class="text-sm font-medium text-highlighted">Extensible</h3>
|
|
|
|
|
|
|
+ <span class="i-lucide-list-ordered size-4 text-primary shrink-0" />
|
|
|
|
|
+ <h3 class="text-sm font-medium text-highlighted">
|
|
|
|
|
+ <RouterLink to="/suggestion-menu" class="hover:underline">Suggestion Menu</RouterLink>
|
|
|
|
|
+ </h3>
|
|
|
</div>
|
|
</div>
|
|
|
<p class="text-xs text-muted leading-relaxed">
|
|
<p class="text-xs text-muted leading-relaxed">
|
|
|
- Inline and block rules are registered as factories. Add new syntax by creating a rule, registering it, and writing a test.
|
|
|
|
|
|
|
+ Slash commands, page references, block references, and tag completions.
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</section>
|
|
</section>
|
|
|
|
|
|
|
|
<section class="space-y-4">
|
|
<section class="space-y-4">
|
|
|
- <h2 class="text-lg font-semibold text-highlighted">Block API</h2>
|
|
|
|
|
-
|
|
|
|
|
- <div class="rounded-lg border border-default overflow-hidden">
|
|
|
|
|
- <table class="w-full text-sm">
|
|
|
|
|
- <thead>
|
|
|
|
|
- <tr class="border-b border-default bg-elevated">
|
|
|
|
|
- <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Prop</th>
|
|
|
|
|
- <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Type</th>
|
|
|
|
|
- <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Default</th>
|
|
|
|
|
- <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Description</th>
|
|
|
|
|
- </tr>
|
|
|
|
|
- </thead>
|
|
|
|
|
- <tbody>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">content</td><td class="px-4 py-2 text-xs">string</td><td class="px-4 py-2 text-xs">—</td><td class="px-4 py-2 text-xs text-muted">Markdown content (v-model)</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">focused</td><td class="px-4 py-2 text-xs">boolean</td><td class="px-4 py-2 text-xs">false</td><td class="px-4 py-2 text-xs text-muted">Automatically focus the editor</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">cursorPosition</td><td class="px-4 py-2 text-xs">'start' | 'end'</td><td class="px-4 py-2 text-xs">—</td><td class="px-4 py-2 text-xs text-muted">Where to place cursor on focus</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">markerMode</td><td class="px-4 py-2 text-xs">'live-preview' | 'always-visible'</td><td class="px-4 py-2 text-xs">'always-visible'</td><td class="px-4 py-2 text-xs text-muted">How decorator markers behave</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">debug</td><td class="px-4 py-2 text-xs">string</td><td class="px-4 py-2 text-xs">—</td><td class="px-4 py-2 text-xs text-muted">Debug namespace filter</td></tr>
|
|
|
|
|
- </tbody>
|
|
|
|
|
- </table>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <h2 class="text-lg font-semibold text-highlighted">Link</h2>
|
|
|
|
|
+ <p class="text-sm text-muted leading-relaxed">
|
|
|
|
|
+ <RouterLink to="/themes" class="text-primary hover:underline">Theme system</RouterLink> — CSS-variable presets and custom colour overrides.
|
|
|
|
|
+ </p>
|
|
|
</section>
|
|
</section>
|
|
|
|
|
|
|
|
<section class="space-y-4">
|
|
<section class="space-y-4">
|
|
|
- <h2 class="text-lg font-semibold text-highlighted">Events</h2>
|
|
|
|
|
- <div class="rounded-lg border border-default overflow-hidden">
|
|
|
|
|
- <table class="w-full text-sm">
|
|
|
|
|
- <thead>
|
|
|
|
|
- <tr class="border-b border-default bg-elevated">
|
|
|
|
|
- <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Event</th>
|
|
|
|
|
- <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Payload</th>
|
|
|
|
|
- <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Description</th>
|
|
|
|
|
- </tr>
|
|
|
|
|
- </thead>
|
|
|
|
|
- <tbody>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">change</td><td class="px-4 py-2 text-xs">string</td><td class="px-4 py-2 text-xs text-muted">Content changed</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">focus</td><td class="px-4 py-2 text-xs">void</td><td class="px-4 py-2 text-xs text-muted">Editor gained focus</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">blur</td><td class="px-4 py-2 text-xs">void</td><td class="px-4 py-2 text-xs text-muted">Editor lost focus</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">selection-change</td><td class="px-4 py-2 text-xs">{ from, to }</td><td class="px-4 py-2 text-xs text-muted">Cursor/selection moved</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">split</td><td class="px-4 py-2 text-xs">string</td><td class="px-4 py-2 text-xs text-muted">Block split on Enter</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">merge-previous</td><td class="px-4 py-2 text-xs">void</td><td class="px-4 py-2 text-xs text-muted">Backspace at start merges blocks</td></tr>
|
|
|
|
|
- <tr class="border-b border-default"><td class="px-4 py-2 font-mono text-xs">delete-if-empty</td><td class="px-4 py-2 text-xs">void</td><td class="px-4 py-2 text-xs text-muted">Backspace on empty block</td></tr>
|
|
|
|
|
- </tbody>
|
|
|
|
|
- </table>
|
|
|
|
|
|
|
+ <h2 class="text-lg font-semibold text-highlighted">Built with</h2>
|
|
|
|
|
+ <div class="flex flex-wrap gap-2">
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">Vue 3</span>
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">TypeScript</span>
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">ProseMirror</span>
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">@lezer/markdown</span>
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">Nuxt UI</span>
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">Tailwind CSS</span>
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">CodeMirror 6</span>
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">KaTeX</span>
|
|
|
|
|
+ <span class="px-2.5 py-1 text-xs font-medium rounded-md bg-elevated border border-default">Vitest</span>
|
|
|
</div>
|
|
</div>
|
|
|
</section>
|
|
</section>
|
|
|
</div>
|
|
</div>
|