Compare commits

...

7 commits

Author SHA1 Message Date
3544b30b60
Add Drop&Drag Block 2023-03-23 23:49:51 +08:00
d8f5a3d553
Remove Cursor 2023-03-23 23:13:50 +08:00
dcfc0717b0
Add Twemoji 2023-03-23 23:12:27 +08:00
35a79a2e43
Add Clipboad 2023-03-23 23:10:56 +08:00
1d31d4e540
Add gfm & Fix Tooltip 2023-03-23 23:05:10 +08:00
1ae12e6bf5
Add Tooltip 2023-03-23 22:11:42 +08:00
sevichecc
8bfa655af5
Add Milkdown editor 2023-03-23 20:13:01 +08:00
12 changed files with 1788 additions and 217 deletions

View file

@ -9,13 +9,34 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@milkdown/core": "^7.1.0",
"@milkdown/ctx": "^7.1.0",
"@milkdown/plugin-block": "^7.1.0",
"@milkdown/plugin-clipboard": "^7.1.0",
"@milkdown/plugin-cursor": "^7.1.0",
"@milkdown/plugin-emoji": "^7.1.0",
"@milkdown/plugin-history": "^7.1.0",
"@milkdown/plugin-indent": "^7.1.0",
"@milkdown/plugin-math": "^7.1.0",
"@milkdown/plugin-slash": "^7.1.0",
"@milkdown/plugin-tooltip": "^7.1.0",
"@milkdown/preset-commonmark": "^7.1.0",
"@milkdown/preset-gfm": "^7.1.0",
"@milkdown/prose": "^7.1.0",
"@milkdown/theme-nord": "^7.1.0",
"@milkdown/transformer": "^7.1.0",
"@milkdown/utils": "^7.1.0",
"@milkdown/vue": "^7.1.0",
"@prosemirror-adapter/vue": "^0.2.2",
"masto": "^5.10.0", "masto": "^5.10.0",
"vue": "^3.2.45" "vue": "^3.2.45"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^0.35.2", "@antfu/eslint-config": "^0.35.2",
"@tailwindcss/typography": "^0.5.9",
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^4.0.0",
"eslint": "^8.34.0", "eslint": "^8.34.0",
"tailwindcss": "^3.2.7",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^4.1.0", "vite": "^4.1.0",
"vue-tsc": "^1.0.24" "vue-tsc": "^1.0.24"

File diff suppressed because it is too large Load diff

6
postcss.config.cjs Normal file
View file

@ -0,0 +1,6 @@
/* Copyright 2021, Milkdown by Mirone. */
module.exports = {
plugins: {
tailwindcss: {},
},
}

View file

@ -1,3 +1,13 @@
<script setup lang="ts">
import { MilkdownProvider } from '@milkdown/vue'
import { ProsemirrorAdapterProvider } from '@prosemirror-adapter/vue'
import Milkdown from './components/Milkdown/Editor.vue'
</script>
<template> <template>
<h2>App</h2> <MilkdownProvider>
<ProsemirrorAdapterProvider>
<Milkdown />
</ProsemirrorAdapterProvider>
</MilkdownProvider>
</template> </template>

View file

@ -0,0 +1,59 @@
<script setup lang="ts">
import { BlockProvider } from '@milkdown/plugin-block'
import { useInstance } from '@milkdown/vue'
import { usePluginViewContext } from '@prosemirror-adapter/vue'
import { onUnmounted, ref, watch } from 'vue'
import type { VNodeRef } from 'vue'
const { view } = usePluginViewContext()
const [loading, get] = useInstance()
const divRef = ref<VNodeRef>()
let tooltipProvider: BlockProvider | undefined
watch([loading], () => {
const editor = get()
if (loading.value || !editor || tooltipProvider) return
editor.action((ctx) => {
tooltipProvider = new BlockProvider({
ctx,
content: divRef.value as any,
})
tooltipProvider.update(view.value)
})
})
watch([view], () => {
tooltipProvider?.update(view.value)
})
onUnmounted(() => {
tooltipProvider?.destroy()
tooltipProvider = undefined
})
</script>
<template>
<div
ref="divRef"
className="w-6 bg-slate-200 rounded hover:bg-slate-300 cursor-grab"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="{1.5}"
stroke="currentColor"
className="w-6 h-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 6.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 12.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 18.75a.75.75 0 110-1.5.75.75 0 010 1.5z"
/>
</svg>
</div>
</template>

View file

@ -0,0 +1,67 @@
<script setup lang="ts">
import { Editor, defaultValueCtx, rootCtx } from '@milkdown/core'
import { commonmark } from '@milkdown/preset-commonmark'
import { nord } from '@milkdown/theme-nord'
import { history } from '@milkdown/plugin-history'
import { math } from '@milkdown/plugin-math'
import { Milkdown, useEditor } from '@milkdown/vue'
import { tooltipFactory } from '@milkdown/plugin-tooltip'
import { usePluginViewFactory } from '@prosemirror-adapter/vue'
import { gfm } from '@milkdown/preset-gfm'
import { clipboard } from '@milkdown/plugin-clipboard'
import { emoji } from '@milkdown/plugin-emoji'
import { block } from '@milkdown/plugin-block'
import { cursor } from '@milkdown/plugin-cursor'
import Tooltip from './Tooltip.vue'
import Slash from './Slash.vue'
import Block from './Block.vue'
const tooltip = tooltipFactory('Text')
const slash = tooltipFactory('Text')
const markdown = `# Milkdown Vue Commonmark
> You're scared of a world where you're needed.
This is a demo for using Milkdown with **Vue**.`
const pluginViewFactory = usePluginViewFactory()
useEditor((root) => {
return Editor.make()
.config(nord)
.config((ctx) => {
ctx.set(rootCtx, root)
ctx.set(defaultValueCtx, markdown)
ctx.set(tooltip.key, {
view: pluginViewFactory({
component: Tooltip,
}),
})
ctx.set(slash.key, {
view: pluginViewFactory({
component: Slash,
}),
})
ctx.set(block.key, {
view: pluginViewFactory({
component: Block,
}),
})
})
.use(commonmark)
.use(tooltip)
.use(slash)
.use(history)
.use(math)
.use(gfm)
.use(clipboard)
.use(emoji)
.use(block)
.use(cursor)
})
</script>
<template>
<Milkdown />
</template>

View file

@ -0,0 +1,59 @@
<script setup lang="ts">
import { editorViewCtx } from '@milkdown/core'
import { SlashProvider } from '@milkdown/plugin-slash'
import { createCodeBlockCommand } from '@milkdown/preset-commonmark'
import { callCommand } from '@milkdown/utils'
import { useInstance } from '@milkdown/vue'
import { usePluginViewContext } from '@prosemirror-adapter/vue'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import type { VNodeRef } from 'vue'
const { view, prevState } = usePluginViewContext()
const [loading, get] = useInstance()
const divRef = ref<VNodeRef>()
let tooltipProvider: SlashProvider
onMounted(() => {
tooltipProvider = new SlashProvider({
content: divRef.value as any,
})
tooltipProvider.update(view.value, prevState.value)
})
watch([view, prevState], () => {
tooltipProvider?.update(view.value, prevState.value)
})
onUnmounted(() => {
tooltipProvider.destroy()
})
const addCodeBlock = (e: Event) => {
if (loading.value) return
e.preventDefault()
get()!.action((ctx) => {
const view = ctx.get(editorViewCtx)
const { dispatch, state } = view
const { tr, selection } = state
const { from } = selection
dispatch(tr.deleteRange(from - 1, from))
return callCommand(createCodeBlockCommand.key)(ctx)
})
}
</script>
<template>
<div ref="divRef">
<button
className="text-gray-600 bg-slate-200 px-2 py-1 rounded-lg hover:bg-slate-300 border hover:text-gray-900"
@mousedown="addCodeBlock"
>
Code Block
</button>
</div>
</template>

View file

@ -0,0 +1,50 @@
<script setup lang="ts">
import { TooltipProvider } from '@milkdown/plugin-tooltip'
import { toggleStrongCommand } from '@milkdown/preset-commonmark'
import { callCommand } from '@milkdown/utils'
import { useInstance } from '@milkdown/vue'
import { usePluginViewContext } from '@prosemirror-adapter/vue'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import type { VNodeRef } from 'vue'
const { view, prevState } = usePluginViewContext()
const [loading, get] = useInstance()
const divRef = ref<VNodeRef>()
let tooltipProvider: TooltipProvider
onMounted(() => {
tooltipProvider = new TooltipProvider({
content: divRef.value as any,
})
tooltipProvider.update(view.value, prevState.value)
})
watch([view, prevState], () => {
tooltipProvider?.update(view.value, prevState.value)
})
onUnmounted(() => {
tooltipProvider.destroy()
})
const toggleBold = (e: Event) => {
if (loading.value) return
e.preventDefault()
get()!.action(callCommand(toggleStrongCommand.key))
}
</script>
<template>
<div ref="divRef">
<button
className="text-gray-600 bg-slate-200 px-2 py-1 rounded-lg hover:bg-slate-300 border hover:text-gray-900"
@mousedown="toggleBold"
>
Bold
</button>
</div>
</template>

View file

@ -1,80 +1,11 @@
:root { @tailwind base;
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; @tailwind components;
line-height: 1.5; @tailwind utilities;
font-weight: 400;
color-scheme: light dark; .milkdown {
color: rgba(255, 255, 255, 0.87); @apply bg-slate-50 px-2 py-4 m-5 border rounded;
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
} }
a { .editor {
font-weight: 500; @apply mx-auto;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
} }

4
src/vite-env.d.ts vendored
View file

@ -1 +1,5 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
declare module '*.vue' {
export = any;
}

9
tailwind.config.cjs Normal file
View file

@ -0,0 +1,9 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['**/*.tsx', '**/*.ts', '**/*.vue', '**/*.html'],
darkMode: 'class',
theme: {
extend: {},
},
plugins: [require('@tailwindcss/typography')],
}

View file

@ -11,7 +11,9 @@
"esModuleInterop": true, "esModuleInterop": true,
"lib": ["ESNext", "DOM"], "lib": ["ESNext", "DOM"],
"skipLibCheck": true, "skipLibCheck": true,
"noEmit": true "noEmit": true,
"noPropertyAccessFromIndexSignature": false,
"allowJs": true
}, },
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }] "references": [{ "path": "./tsconfig.node.json" }]