Skip to content

Commit

Permalink
✨ feat: add editor component
Browse files Browse the repository at this point in the history
  • Loading branch information
shurco committed Aug 29, 2023
1 parent 950efde commit 2b4a3b1
Show file tree
Hide file tree
Showing 17 changed files with 773 additions and 2 deletions.
5 changes: 5 additions & 0 deletions web/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
"preview": "vite preview --host"
},
"dependencies": {
"@tiptap/extension-link": "^2.1.7",
"@tiptap/pm": "^2.1.7",
"@tiptap/starter-kit": "^2.1.7",
"@tiptap/vue-3": "^2.1.7",
"@vee-validate/rules": "^4.11.2",
"nprogress": "^0.2.0",
"vee-validate": "^4.11.2",
Expand All @@ -21,6 +25,7 @@
"autoprefixer": "^10.4.15",
"daisyui": "^3.5.1",
"postcss": "^8.4.28",
"sass": "^1.66.1",
"tailwindcss": "^3.3.3",
"vite": "^4.4.9",
"vite-plugin-vue-devtools": "^1.0.0-rc.2",
Expand Down
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/blockquote.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/bold.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/bulletlist.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/code.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions web/admin/src/assets/svg/codeblock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/h1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/h2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/h3.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/italic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions web/admin/src/assets/svg/orderedlist.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/paragraph.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/redo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/strike.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/admin/src/assets/svg/undo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
187 changes: 187 additions & 0 deletions web/admin/src/components/Editor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<template>
<div v-if="editor">
<button @click="editor.chain().focus().undo().run()" :disabled="!editor.can().chain().focus().undo().run()">
<SvgIcon name="undo" />
</button>
<button @click="editor.chain().focus().redo().run()" :disabled="!editor.can().chain().focus().redo().run()">
<SvgIcon name="redo" />
</button>

<button
@click="editor.chain().focus().toggleBold().run()"
:disabled="!editor.can().chain().focus().toggleBold().run()"
:class="{ 'is-active': editor.isActive('bold') }"
>
<SvgIcon name="bold" />
</button>
<button
@click="editor.chain().focus().toggleItalic().run()"
:disabled="!editor.can().chain().focus().toggleItalic().run()"
:class="{ 'is-active': editor.isActive('italic') }"
>
<SvgIcon name="italic" />
</button>
<button
@click="editor.chain().focus().toggleStrike().run()"
:disabled="!editor.can().chain().focus().toggleStrike().run()"
:class="{ 'is-active': editor.isActive('strike') }"
>
<SvgIcon name="strike" />
</button>

<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
<SvgIcon name="paragraph" />
</button>
<button
@click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
>
<SvgIcon name="h1" />
</button>
<button
@click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
>
<SvgIcon name="h2" />
</button>
<button
@click="editor.chain().focus().toggleHeading({ level: 3 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 3 }) }"
>
<SvgIcon name="h3" />
</button>
<button
@click="editor.chain().focus().toggleBulletList().run()"
:class="{ 'is-active': editor.isActive('bulletList') }"
>
<SvgIcon name="bulletlist" />
</button>
<button
@click="editor.chain().focus().toggleOrderedList().run()"
:class="{ 'is-active': editor.isActive('orderedList') }"
>
<SvgIcon name="orderedlist" />
</button>

<button
@click="editor.chain().focus().toggleBlockquote().run()"
:class="{ 'is-active': editor.isActive('blockquote') }"
>
<SvgIcon name="blockquote" />
</button>
</div>

<article class="mt-5">
<EditorContent :editor="editor" />
</article>
</template>

<script setup>
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { EditorContent, Editor } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
import SvgIcon from 'svg-icon'
const emits = defineEmits(['update:modelValue'])
const editor = ref()
const props = defineProps({
modelValue: {
type: String,
required: true,
default: ""
}
})
onMounted(() => {
editor.value = new Editor({
extensions: [StarterKit],
content: props.modelValue,
onUpdate: () => {
emits('update:modelValue', editor.value.getHTML())
}
})
})
onBeforeUnmount(() => {
editor.value.destroy()
})
watch(
() => props.modelValue,
(value) => {
const isSame = editor.value.getHTML() === value
if (isSame) {
return
}
editor.value.commands.setContent(value, false)
}
)
</script>

<style lang="scss">
.ProseMirror:focus {
outline: none;
}
button,
input,
select {
@apply text-black m-[0.2rem] px-[0.6rem] py-[0.2rem] rounded-[0.3rem] bg-slate-100;
}
button[disabled],
input[disabled],
select[disabled] {
opacity: 0.3;
}
.is-active {
background: black;
color: #fff;
}
.tiptap {
> * + * {
margin-top: 0.75em;
}
ul {
@apply list-disc pl-10;
}
ol {
@apply list-decimal pl-10;
}
h1 {
@apply text-2xl font-bold text-gray-900 sm:text-3xl;
}
h2 {
@apply text-xl font-bold text-gray-900 sm:text-2xl;
}
h3 {
@apply font-bold text-gray-900 sm:text-xl;
}
blockquote {
@apply pl-4 border-x-2 border-solid border-gray-500;
ul {
@apply list-disc pl-4;
}
ol {
@apply list-decimal pl-4;
}
}
hr {
border: none;
border-top: 2px solid rgba(#0d0d0d, 0.1);
margin: 2rem 0;
}
}
</style>
Loading

0 comments on commit 2b4a3b1

Please sign in to comment.