2024-12-25 20:46:14 +01:00
|
|
|
<template>
|
|
|
|
|
<EditorContent :editor="editor"
|
2025-04-10 18:44:53 +02:00
|
|
|
:class="[$style.content, 'prose prose-sm dark:prose-invert break-words prose-a:no-underline prose-a:hover:underline prose-p:first-of-type:mt-0']" />
|
2024-12-25 20:46:14 +01:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
import Highlight from "@tiptap/extension-highlight";
|
|
|
|
|
import Link from "@tiptap/extension-link";
|
|
|
|
|
import Mention from "@tiptap/extension-mention";
|
|
|
|
|
import Placeholder from "@tiptap/extension-placeholder";
|
|
|
|
|
import Subscript from "@tiptap/extension-subscript";
|
|
|
|
|
import Superscript from "@tiptap/extension-superscript";
|
|
|
|
|
import Underline from "@tiptap/extension-underline";
|
|
|
|
|
import StarterKit from "@tiptap/starter-kit";
|
|
|
|
|
import { Editor, EditorContent } from "@tiptap/vue-3";
|
2024-12-26 18:11:38 +01:00
|
|
|
import { Emoji } from "./emoji.ts";
|
2024-12-25 20:46:14 +01:00
|
|
|
import suggestion from "./suggestion.ts";
|
|
|
|
|
|
|
|
|
|
const content = defineModel<string>("content");
|
|
|
|
|
const {
|
|
|
|
|
placeholder,
|
|
|
|
|
disabled,
|
|
|
|
|
mode = "rich",
|
|
|
|
|
} = defineProps<{
|
|
|
|
|
placeholder?: string;
|
|
|
|
|
mode?: "rich" | "plain";
|
|
|
|
|
disabled?: boolean;
|
|
|
|
|
}>();
|
|
|
|
|
|
|
|
|
|
const editor = new Editor({
|
|
|
|
|
extensions: [
|
|
|
|
|
StarterKit,
|
|
|
|
|
Placeholder.configure({
|
|
|
|
|
placeholder,
|
|
|
|
|
}),
|
|
|
|
|
Highlight,
|
|
|
|
|
Link,
|
|
|
|
|
Subscript,
|
|
|
|
|
Superscript,
|
|
|
|
|
Underline,
|
|
|
|
|
Mention.configure({
|
|
|
|
|
HTMLAttributes: {
|
|
|
|
|
class: "mention",
|
|
|
|
|
},
|
|
|
|
|
suggestion,
|
|
|
|
|
}),
|
2024-12-26 18:11:38 +01:00
|
|
|
Emoji,
|
2024-12-25 20:46:14 +01:00
|
|
|
],
|
|
|
|
|
content: content.value,
|
|
|
|
|
onUpdate: ({ editor }) => {
|
|
|
|
|
content.value = mode === "rich" ? editor.getHTML() : editor.getText();
|
|
|
|
|
},
|
|
|
|
|
autofocus: true,
|
|
|
|
|
editable: !disabled,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
watchEffect(() => {
|
|
|
|
|
if (disabled) {
|
|
|
|
|
editor.setEditable(false);
|
|
|
|
|
} else {
|
|
|
|
|
editor.setEditable(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
editor.destroy();
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style module>
|
|
|
|
|
@import url("~/styles/content.css");
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<style>
|
2025-04-10 13:55:56 +02:00
|
|
|
@reference "../../styles/index.css";
|
|
|
|
|
|
2024-12-25 20:46:14 +01:00
|
|
|
.tiptap p.is-editor-empty:first-child::before {
|
|
|
|
|
color: hsl(var(--muted-foreground));
|
|
|
|
|
content: attr(data-placeholder);
|
|
|
|
|
float: left;
|
|
|
|
|
height: 0;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tiptap .mention {
|
|
|
|
|
@apply font-bold rounded-sm text-primary-foreground bg-primary px-1 py-0.5;
|
|
|
|
|
}
|
|
|
|
|
</style>
|