mirror of
https://codeberg.org/Sevichecc/Seigwai.git
synced 2025-04-30 07:49:30 +08:00
Add Url input menu
This commit is contained in:
parent
d2f26c1f64
commit
e34e051f41
5 changed files with 147 additions and 48 deletions
|
@ -16,6 +16,7 @@
|
||||||
"@prosemirror-adapter/vue": "^0.2.3",
|
"@prosemirror-adapter/vue": "^0.2.3",
|
||||||
"@tiptap/extension-bubble-menu": "2.0.0-beta.220",
|
"@tiptap/extension-bubble-menu": "2.0.0-beta.220",
|
||||||
"@tiptap/extension-character-count": "2.0.0-beta.220",
|
"@tiptap/extension-character-count": "2.0.0-beta.220",
|
||||||
|
"@tiptap/extension-link": "2.0.0-beta.220",
|
||||||
"@tiptap/extension-typography": "2.0.0-beta.220",
|
"@tiptap/extension-typography": "2.0.0-beta.220",
|
||||||
"@tiptap/pm": "2.0.0-beta.220",
|
"@tiptap/pm": "2.0.0-beta.220",
|
||||||
"@tiptap/starter-kit": "2.0.0-beta.220",
|
"@tiptap/starter-kit": "2.0.0-beta.220",
|
||||||
|
|
|
@ -16,6 +16,9 @@ dependencies:
|
||||||
'@tiptap/extension-character-count':
|
'@tiptap/extension-character-count':
|
||||||
specifier: 2.0.0-beta.220
|
specifier: 2.0.0-beta.220
|
||||||
version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220)
|
version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220)
|
||||||
|
'@tiptap/extension-link':
|
||||||
|
specifier: 2.0.0-beta.220
|
||||||
|
version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220)
|
||||||
'@tiptap/extension-typography':
|
'@tiptap/extension-typography':
|
||||||
specifier: 2.0.0-beta.220
|
specifier: 2.0.0-beta.220
|
||||||
version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)
|
version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)
|
||||||
|
@ -780,6 +783,17 @@ packages:
|
||||||
'@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220)
|
'@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@tiptap/extension-link@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220):
|
||||||
|
resolution: {integrity: sha512-vjEA8cE37ZZVVgPHSpttw3kbJoClb+ya/BVukDtJ1h6C7mIR1rqzNxTgpbnXJuA8xww0JOjpa5dpzEgcs294fA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': ^2.0.0-beta.209
|
||||||
|
'@tiptap/pm': ^2.0.0-beta.209
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220)
|
||||||
|
'@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)
|
||||||
|
linkifyjs: 4.1.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@tiptap/extension-list-item@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220):
|
/@tiptap/extension-list-item@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220):
|
||||||
resolution: {integrity: sha512-+O0ivwxPP2l/m9PAowb2ytDT/cM5kwu0s1W5MUsHPIqf+M6ahnl4ESjhWZfDHUzvjqPq6MTbqoQLHbB1KS/N7w==}
|
resolution: {integrity: sha512-+O0ivwxPP2l/m9PAowb2ytDT/cM5kwu0s1W5MUsHPIqf+M6ahnl4ESjhWZfDHUzvjqPq6MTbqoQLHbB1KS/N7w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -2870,6 +2884,10 @@ packages:
|
||||||
uc.micro: 1.0.6
|
uc.micro: 1.0.6
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/linkifyjs@4.1.1:
|
||||||
|
resolution: {integrity: sha512-zFN/CTVmbcVef+WaDXT63dNzzkfRBKT1j464NJQkV7iSgJU0sLBus9W0HBwnXK13/hf168pbrx/V/bjEHOXNHA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/local-pkg@0.4.3:
|
/local-pkg@0.4.3:
|
||||||
resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
|
resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
|
@ -1,59 +1,110 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Editor
|
import type { Editor } from '@tiptap/vue-3'
|
||||||
} from '@tiptap/vue-3';
|
|
||||||
|
|
||||||
import { BubbleMenu } from '@tiptap/vue-3'
|
import { BubbleMenu } from '@tiptap/vue-3'
|
||||||
|
import { nextTick, ref } from 'vue'
|
||||||
|
|
||||||
const { editor } = defineProps<{ editor: Editor }>()
|
const { editor } = defineProps<{ editor: Editor }>()
|
||||||
|
|
||||||
|
const url = ref('')
|
||||||
|
const showUrlInput = ref(false)
|
||||||
|
const placeholder = ref('Add Link to text')
|
||||||
|
const inputUrl = ref<HTMLInputElement | null>(null)
|
||||||
|
|
||||||
|
const openLinkInput = () => {
|
||||||
|
showUrlInput.value = true
|
||||||
|
nextTick(() => inputUrl.value?.focus())
|
||||||
|
}
|
||||||
|
|
||||||
|
const setLink = () => {
|
||||||
|
const previousUrl = editor.getAttributes('link').href
|
||||||
|
|
||||||
|
if (previousUrl)
|
||||||
|
placeholder.value = previousUrl
|
||||||
|
|
||||||
|
// cancelled
|
||||||
|
if (url.value === null)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (url.value === '') {
|
||||||
|
editor.chain().focus().extendMarkRange('link').unsetAllMarks().run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
editor
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.extendMarkRange('link')
|
||||||
|
.setLink({ href: url.value })
|
||||||
|
.run()
|
||||||
|
|
||||||
|
return (showUrlInput.value = false)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<BubbleMenu
|
<BubbleMenu
|
||||||
:editor="editor"
|
:editor="editor"
|
||||||
:tippy-options="{ duration: 100 }"
|
:tippy-options="{ duration: 50 }"
|
||||||
class="flex text-gray-700 bg-white grass rounded-md p-[2px] shadow-xl border-slate-100 border"
|
class="flex text-gray-700 bg-white grass rounded-md p-[2px] shadow-xl border-slate-100 border"
|
||||||
>
|
>
|
||||||
<button
|
<div v-show="!showUrlInput">
|
||||||
class="menu-btn"
|
<button
|
||||||
placement="bold"
|
class="menu-btn"
|
||||||
@click="editor.chain().focus().toggleBold().run()"
|
:class="{ 'btn-active': editor.isActive('bold') }"
|
||||||
|
@click="editor.chain().focus().toggleBold().run()"
|
||||||
|
>
|
||||||
|
<span class="i-tabler-bold" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="menu-btn"
|
||||||
|
:class="{ 'btn-active': editor.isActive('italic') }"
|
||||||
|
@click="editor.chain().focus().toggleItalic().run()"
|
||||||
|
>
|
||||||
|
<span class="i-tabler-italic" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="menu-btn"
|
||||||
|
:class="{ 'btn-active': editor.isActive('strike') }"
|
||||||
|
@click="editor.chain().focus().toggleStrike().run()"
|
||||||
|
>
|
||||||
|
<span class="i-tabler-strikethrough" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="menu-btn"
|
||||||
|
:class="{ 'btn-active': editor.isActive('code') }"
|
||||||
|
@click="editor.chain().focus().toggleCode().run()"
|
||||||
|
>
|
||||||
|
<span class="i-tabler-code" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="menu-btn"
|
||||||
|
:class="{ 'btn-active': editor.isActive('quote') }"
|
||||||
|
@click="editor.chain().focus().toggleBlockquote().run()"
|
||||||
|
>
|
||||||
|
<span class="i-tabler-quote" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:class="{ 'btn-active': editor.isActive('link') }"
|
||||||
|
class="menu-btn"
|
||||||
|
@click="openLinkInput"
|
||||||
|
>
|
||||||
|
<span class="i-tabler-link" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-show="showUrlInput"
|
||||||
|
class="input-group input-group-sm border-slate-300 border-1"
|
||||||
>
|
>
|
||||||
<span class="i-tabler-bold" />
|
<input
|
||||||
</button>
|
ref="inputUrl"
|
||||||
<button
|
v-model.trim="url"
|
||||||
class="menu-btn"
|
class="input input-sm focus:outline-none"
|
||||||
@click="editor.chain().focus().toggleItalic().run()"
|
:placeholder="placeholder"
|
||||||
>
|
@blur="showUrlInput = false"
|
||||||
<span class="i-tabler-italic" />
|
>
|
||||||
</button>
|
<button class="btn btn-sm btn-square" @click="setLink">
|
||||||
<button
|
<span class="i-tabler-link p-2" />
|
||||||
class="menu-btn"
|
</button>
|
||||||
@click="editor.chain().focus().toggleStrike().run()"
|
</div>
|
||||||
>
|
|
||||||
<span class="i-tabler-strikethrough" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="menu-btn"
|
|
||||||
@click="editor.chain().focus().toggleCode().run()"
|
|
||||||
>
|
|
||||||
<span class="i-tabler-code" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="menu-btn"
|
|
||||||
@click="editor.chain().focus().toggleBlockquote().run()"
|
|
||||||
>
|
|
||||||
<span class="i-tabler-quote" />
|
|
||||||
</button>
|
|
||||||
</BubbleMenu>
|
</BubbleMenu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="pcss">
|
|
||||||
.menu-btn {
|
|
||||||
@apply btn btn-ghost btn-sm hover:bg-slate-200 rounded-md p-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-btn > span {
|
|
||||||
@apply w-4;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -2,19 +2,24 @@
|
||||||
import { EditorContent, useEditor } from '@tiptap/vue-3'
|
import { EditorContent, useEditor } from '@tiptap/vue-3'
|
||||||
import StarterKit from '@tiptap/starter-kit'
|
import StarterKit from '@tiptap/starter-kit'
|
||||||
import Typography from '@tiptap/extension-typography'
|
import Typography from '@tiptap/extension-typography'
|
||||||
|
import Link from '@tiptap/extension-link'
|
||||||
import BubbleMenu from './BubbleMenu.vue'
|
import BubbleMenu from './BubbleMenu.vue'
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
content: '<p>I’m running Tiptap with Vue.js. 🎉</p>',
|
content: '<p>I’m running Tiptap with Vue.js. 🎉</p>',
|
||||||
extensions: [StarterKit, Typography],
|
extensions: [
|
||||||
|
StarterKit,
|
||||||
|
Typography,
|
||||||
|
Link.configure({
|
||||||
|
openOnClick: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
editable: true,
|
editable: true,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<BubbleMenu
|
<BubbleMenu v-if="editor" :editor="editor" />
|
||||||
v-if="editor"
|
|
||||||
:editor="editor" />
|
|
||||||
<EditorContent :editor="editor" />
|
<EditorContent :editor="editor" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -9,3 +9,27 @@
|
||||||
.editor {
|
.editor {
|
||||||
@apply mx-auto;
|
@apply mx-auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-ghost {
|
||||||
|
@apply hover:bg-slate-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-active{
|
||||||
|
@apply bg-slate-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-btn {
|
||||||
|
@apply btn btn-ghost btn-sm rounded-md p-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-btn > span {
|
||||||
|
@apply w-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-btn.btn-active {
|
||||||
|
@apply bg-slate-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group{
|
||||||
|
@apply h-4;
|
||||||
|
}
|
Loading…
Reference in a new issue