|
|
@@ -0,0 +1,136 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { Block } from "@enesis/editor"
|
|
|
+import { ref } from "vue"
|
|
|
+
|
|
|
+const example = ref(`# Welcome to the Editor
|
|
|
+
|
|
|
+This is a **block-based markdown editor** built with Vue 3, TypeScript, and ProseMirror.
|
|
|
+
|
|
|
+> [!NOTE] Every paragraph is its own Block component.
|
|
|
+> Blocks are independent editors with their own state.
|
|
|
+
|
|
|
+Try editing any of the examples on the left.
|
|
|
+`)
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <UPage>
|
|
|
+ <UPageHeader
|
|
|
+ title="Editor"
|
|
|
+ description="A block-based markdown editor with live preview, decorations, and extensible syntax."
|
|
|
+ />
|
|
|
+
|
|
|
+ <UPageBody>
|
|
|
+ <div class="space-y-8">
|
|
|
+ <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 bg-elevated p-4">
|
|
|
+ <Block
|
|
|
+ v-model:content="example"
|
|
|
+ :focused="true"
|
|
|
+ cursor-position="end"
|
|
|
+ marker-mode="always-visible"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <section class="space-y-4">
|
|
|
+ <h2 class="text-lg font-semibold text-highlighted">Key Concepts</h2>
|
|
|
+ <div class="grid gap-4 sm:grid-cols-2">
|
|
|
+ <div class="rounded-lg border border-default p-4 space-y-2">
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <span class="i-lucide-layers size-4 text-primary shrink-0" />
|
|
|
+ <h3 class="text-sm font-medium text-highlighted">Blocks</h3>
|
|
|
+ </div>
|
|
|
+ <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.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="rounded-lg border border-default p-4 space-y-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>
|
|
|
+ </div>
|
|
|
+ <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.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="rounded-lg border border-default p-4 space-y-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>
|
|
|
+ </div>
|
|
|
+ <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.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="rounded-lg border border-default p-4 space-y-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>
|
|
|
+ </div>
|
|
|
+ <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.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <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>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <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>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+ </div>
|
|
|
+ </UPageBody>
|
|
|
+ </UPage>
|
|
|
+</template>
|