index.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <script setup lang="ts">
  2. import { EditorBlock } from "@enesis/editor"
  3. import { ref } from "vue"
  4. const example = ref(`# Welcome to the Editor
  5. This is a **block-based markdown editor** built with Vue 3, TypeScript, and ProseMirror.
  6. > [!NOTE] Every paragraph is its own Block component.
  7. > Blocks are independent editors with their own state.
  8. Try editing any of the examples on the left.
  9. `)
  10. </script>
  11. <template>
  12. <UPage>
  13. <UPageHeader
  14. title="Editor"
  15. description="A block-based markdown editor with live preview, decorations, and extensible syntax."
  16. />
  17. <UPageBody>
  18. <div class="space-y-8">
  19. <section class="space-y-4">
  20. <h2 class="text-lg font-semibold text-highlighted">What is this?</h2>
  21. <p class="text-sm text-muted leading-relaxed">
  22. 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.
  23. Markdown syntax is rendered as rich decorations in live-preview mode: delimiters fade when blurred, syntax elements get contextual styling.
  24. </p>
  25. <div class="rounded-lg border border-default dark:bg-neutral-950/50 p-4">
  26. <EditorBlock
  27. v-model:content="example"
  28. :focused="true"
  29. cursor-position="end"
  30. marker-mode="always-visible"
  31. />
  32. </div>
  33. </section>
  34. <section class="space-y-4">
  35. <h2 class="text-lg font-semibold text-highlighted">Key Concepts</h2>
  36. <div class="grid gap-4 sm:grid-cols-2">
  37. <div class="rounded-lg border border-default p-4 space-y-2">
  38. <div class="flex items-center gap-2">
  39. <span class="i-lucide-layers size-4 text-primary shrink-0" />
  40. <h3 class="text-sm font-medium text-highlighted">Blocks</h3>
  41. </div>
  42. <p class="text-xs text-muted leading-relaxed">
  43. Documents are split into distinct Block components — each one is an independent editor.
  44. Blocks communicate through a shared document model.
  45. </p>
  46. </div>
  47. <div class="rounded-lg border border-default p-4 space-y-2">
  48. <div class="flex items-center gap-2">
  49. <span class="i-lucide-palette size-4 text-primary shrink-0" />
  50. <h3 class="text-sm font-medium text-highlighted">Decorations</h3>
  51. </div>
  52. <p class="text-xs text-muted leading-relaxed">
  53. Markdown syntax is rendered as ProseMirror decorations — styled spans overlaid on the source text.
  54. Delimiters animate in and out based on focus.
  55. </p>
  56. </div>
  57. <div class="rounded-lg border border-default p-4 space-y-2">
  58. <div class="flex items-center gap-2">
  59. <span class="i-lucide-parse size-4 text-primary shrink-0" />
  60. <h3 class="text-sm font-medium text-highlighted">Parsing Pipeline</h3>
  61. </div>
  62. <p class="text-xs text-muted leading-relaxed">
  63. A 3-stage pipeline classifies blocks, builds a Lezer AST, then extracts decorations.
  64. Everything runs in under 16ms per keystroke.
  65. </p>
  66. </div>
  67. <div class="rounded-lg border border-default p-4 space-y-2">
  68. <div class="flex items-center gap-2">
  69. <span class="i-lucide-plug size-4 text-primary shrink-0" />
  70. <h3 class="text-sm font-medium text-highlighted">Extensible</h3>
  71. </div>
  72. <p class="text-xs text-muted leading-relaxed">
  73. Inline and block rules are registered as factories. Add new syntax by creating a rule, registering it, and writing a test.
  74. </p>
  75. </div>
  76. </div>
  77. </section>
  78. <section class="space-y-4">
  79. <h2 class="text-lg font-semibold text-highlighted">Block API</h2>
  80. <div class="rounded-lg border border-default overflow-hidden">
  81. <table class="w-full text-sm">
  82. <thead>
  83. <tr class="border-b border-default bg-elevated">
  84. <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Prop</th>
  85. <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Type</th>
  86. <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Default</th>
  87. <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Description</th>
  88. </tr>
  89. </thead>
  90. <tbody>
  91. <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>
  92. <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>
  93. <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>
  94. <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>
  95. <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>
  96. </tbody>
  97. </table>
  98. </div>
  99. </section>
  100. <section class="space-y-4">
  101. <h2 class="text-lg font-semibold text-highlighted">Events</h2>
  102. <div class="rounded-lg border border-default overflow-hidden">
  103. <table class="w-full text-sm">
  104. <thead>
  105. <tr class="border-b border-default bg-elevated">
  106. <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Event</th>
  107. <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Payload</th>
  108. <th class="text-left px-4 py-2 font-medium text-muted text-xs uppercase tracking-wider">Description</th>
  109. </tr>
  110. </thead>
  111. <tbody>
  112. <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>
  113. <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>
  114. <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>
  115. <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>
  116. <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>
  117. <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>
  118. <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>
  119. </tbody>
  120. </table>
  121. </div>
  122. </section>
  123. </div>
  124. </UPageBody>
  125. </UPage>
  126. </template>