Add WYSIWYG toolbar (bold, italic, headings, lists, quote, link, hr)
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"@milkdown/plugin-collab": "^7.6.0",
|
"@milkdown/plugin-collab": "^7.6.0",
|
||||||
"@milkdown/plugin-listener": "^7.6.0",
|
"@milkdown/plugin-listener": "^7.6.0",
|
||||||
"@milkdown/theme-nord": "^7.6.0",
|
"@milkdown/theme-nord": "^7.6.0",
|
||||||
|
"@milkdown/utils": "^7.6.0",
|
||||||
"@codemirror/lang-markdown": "^6.3.0",
|
"@codemirror/lang-markdown": "^6.3.0",
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.5.0",
|
||||||
"@codemirror/view": "^6.35.0",
|
"@codemirror/view": "^6.35.0",
|
||||||
|
|||||||
@@ -1,13 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div class="milkdown-wrap">
|
||||||
|
<div class="milkdown-toolbar">
|
||||||
|
<button @click="cmd('ToggleBold')" title="Bold"><b>B</b></button>
|
||||||
|
<button @click="cmd('ToggleItalic')" title="Italic"><i>I</i></button>
|
||||||
|
<button @click="cmd('ToggleStrikethrough')" title="Strikethrough"><s>S</s></button>
|
||||||
|
<button @click="cmd('ToggleInlineCode')" title="Code"></></button>
|
||||||
|
<span class="sep"></span>
|
||||||
|
<button @click="cmd('WrapInHeading', 1)" title="H1">H1</button>
|
||||||
|
<button @click="cmd('WrapInHeading', 2)" title="H2">H2</button>
|
||||||
|
<button @click="cmd('WrapInHeading', 3)" title="H3">H3</button>
|
||||||
|
<span class="sep"></span>
|
||||||
|
<button @click="cmd('WrapInBulletList')" title="Bullet list">•</button>
|
||||||
|
<button @click="cmd('WrapInOrderedList')" title="Ordered list">1.</button>
|
||||||
|
<button @click="cmd('TurnIntoBlockquote')" title="Quote">❝</button>
|
||||||
|
<button @click="cmd('InsertHr')" title="Horizontal rule">―</button>
|
||||||
|
<button @click="cmd('InsertLink')" title="Link">🔗</button>
|
||||||
|
</div>
|
||||||
<div ref="editorRoot" class="milkdown-editor"></div>
|
<div ref="editorRoot" class="milkdown-editor"></div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
import { Editor, rootCtx, defaultValueCtx } from '@milkdown/core'
|
import { Editor, rootCtx, defaultValueCtx, editorViewCtx } from '@milkdown/core'
|
||||||
import { commonmark } from '@milkdown/preset-commonmark'
|
import { commonmark, toggleStrongCommand, toggleEmphasisCommand, toggleInlineCodeCommand, wrapInHeadingCommand, wrapInBulletListCommand, wrapInOrderedListCommand, wrapInBlockquoteCommand, insertHrCommand } from '@milkdown/preset-commonmark'
|
||||||
import { gfm } from '@milkdown/preset-gfm'
|
import { gfm, toggleStrikethroughCommand } from '@milkdown/preset-gfm'
|
||||||
import { listener, listenerCtx } from '@milkdown/plugin-listener'
|
import { listener, listenerCtx } from '@milkdown/plugin-listener'
|
||||||
|
import { callCommand } from '@milkdown/utils'
|
||||||
import { nord } from '@milkdown/theme-nord'
|
import { nord } from '@milkdown/theme-nord'
|
||||||
import '@milkdown/theme-nord/style.css'
|
import '@milkdown/theme-nord/style.css'
|
||||||
|
|
||||||
@@ -21,6 +40,23 @@ const editorRoot = ref(null)
|
|||||||
let editorInstance = null
|
let editorInstance = null
|
||||||
let suppressUpdate = false
|
let suppressUpdate = false
|
||||||
|
|
||||||
|
const commands = {
|
||||||
|
ToggleBold: toggleStrongCommand.key,
|
||||||
|
ToggleItalic: toggleEmphasisCommand.key,
|
||||||
|
ToggleStrikethrough: toggleStrikethroughCommand.key,
|
||||||
|
ToggleInlineCode: toggleInlineCodeCommand.key,
|
||||||
|
WrapInBulletList: wrapInBulletListCommand.key,
|
||||||
|
WrapInOrderedList: wrapInOrderedListCommand.key,
|
||||||
|
TurnIntoBlockquote: wrapInBlockquoteCommand.key,
|
||||||
|
InsertHr: insertHrCommand.key,
|
||||||
|
WrapInHeading: wrapInHeadingCommand.key,
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmd(name, payload) {
|
||||||
|
if (!editorInstance) return
|
||||||
|
editorInstance.action(callCommand(commands[name], payload))
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
editorInstance = await Editor.make()
|
editorInstance = await Editor.make()
|
||||||
.config((ctx) => {
|
.config((ctx) => {
|
||||||
@@ -41,13 +77,6 @@ onMounted(async () => {
|
|||||||
.create()
|
.create()
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => props.modelValue, (newVal) => {
|
|
||||||
if (suppressUpdate || !editorInstance) return
|
|
||||||
// Only update if content actually differs (avoid cursor jump)
|
|
||||||
// For now, we don't force-update the editor from outside
|
|
||||||
// since the user is typing in it directly
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (editorInstance) {
|
if (editorInstance) {
|
||||||
editorInstance.destroy()
|
editorInstance.destroy()
|
||||||
@@ -56,8 +85,40 @@ onBeforeUnmount(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.milkdown-editor {
|
.milkdown-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
}
|
||||||
|
.milkdown-toolbar {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-bottom: 1px solid var(--border, #313244);
|
||||||
|
background: var(--bg-secondary, #181825);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.milkdown-toolbar button {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
color: var(--text, #cdd6f4);
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
min-width: 28px;
|
||||||
|
}
|
||||||
|
.milkdown-toolbar button:hover {
|
||||||
|
background: var(--bg-hover, #313244);
|
||||||
|
border-color: var(--border, #313244);
|
||||||
|
}
|
||||||
|
.milkdown-toolbar .sep {
|
||||||
|
width: 1px;
|
||||||
|
background: var(--border, #313244);
|
||||||
|
margin: 2px 6px;
|
||||||
|
}
|
||||||
|
.milkdown-editor {
|
||||||
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.milkdown-editor .milkdown {
|
.milkdown-editor .milkdown {
|
||||||
|
|||||||
Reference in New Issue
Block a user