no message

This commit is contained in:
KuroSago 2025-07-10 16:49:59 +08:00
parent bb1b91b6a6
commit 78823734da
6 changed files with 47 additions and 379 deletions

View File

@ -7,5 +7,9 @@
<script lang="ts" setup>
import { TiptapEditor, ThemeToggle, useTiptapContext } from "@tiptap/component";
useTiptapContext();
import { onMounted } from "vue";
onMounted(() => {
// useTiptapContext();
});
</script>

View File

@ -1,58 +1,47 @@
<template>
<div class="mb-2">
<div class="flex items-center justify-between">
<button
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors rounded-md hover:bg-accent hover:text-accent-foreground"
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors border rounded-md hover:bg-accent hover:text-accent-foreground"
@click="locale.setLang('zhHans')"
>
中文
</button>
<button
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors rounded-md hover:bg-accent hover:text-accent-foreground"
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors border rounded-md hover:bg-accent hover:text-accent-foreground"
@click="locale.setLang('en')"
>
English
</button>
<button
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors rounded-md hover:bg-accent hover:text-accent-foreground"
@click="emit('toggle-minimal')"
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors border rounded-md hover:bg-accent hover:text-accent-foreground"
@click="state.minimal = !state.minimal"
>
{{ minimal ? "Full" : "Minimal" }}
{{ state.minimal ? "Full" : "Minimal" }}
</button>
<button
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors rounded-md hover:bg-accent hover:text-accent-foreground"
@click="emit('toggle-toolbar')"
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors border rounded-md hover:bg-accent hover:text-accent-foreground"
@click="state.hideToolbar = !state.hideToolbar"
>
{{ !hideToolbar ? "Hide Toolbar" : "Show Toolbar" }}
{{ !state.hideToolbar ? "Hide Toolbar" : "Show Toolbar" }}
</button>
<button
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors rounded-md hover:bg-accent hover:text-accent-foreground"
@click="emit('toggle-menubar')"
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors border rounded-md hover:bg-accent hover:text-accent-foreground"
@click="state.hideMenubar = !state.hideMenubar"
>
{{ !hideMenubar ? "Hide Menubar" : "Show Menubar" }}
{{ !state.hideMenubar ? "Hide Menubar" : "Show Menubar" }}
</button>
<button
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors rounded-md hover:bg-accent hover:text-accent-foreground"
@click="emit('toggle-editable')"
class="inline-flex items-center justify-center px-3 py-2 text-sm transition-colors border rounded-md hover:bg-accent hover:text-accent-foreground"
@click="state.disabled = !state.disabled"
>
{{ disabled ? "Editable" : "Readonly" }}
{{ state.disabled ? "Editable" : "Readonly" }}
</button>
</div>
</template>
<script setup lang="ts">
import { locale } from "echo-editor";
import { useTiptapContext } from "../context/useTiptapStore";
defineProps<{
minimal: boolean;
hideToolbar: boolean;
hideMenubar: boolean;
disabled: boolean;
}>();
const emit = defineEmits([
"toggle-minimal",
"toggle-toolbar",
"toggle-menubar",
"toggle-editable",
]);
const { state } = useTiptapContext();
</script>

View File

@ -1,4 +1,4 @@
import { provide, inject, reactive, readonly, type InjectionKey } from "vue";
import { provide, inject, reactive, type InjectionKey } from "vue";
const TiptapStoreKey: InjectionKey<TiptapStore> = Symbol("TiptapStore");
@ -11,18 +11,8 @@ export interface TiptapState {
minimal: boolean;
}
export interface TiptapActions {
toggleMinimal: () => void;
updateContent: (newContent: string) => void;
setTheme: (theme: string) => void;
toggleToolbar: () => void;
toggleMenubar: () => void;
toggleEditable: () => void;
}
export type TiptapStore = {
state: Readonly<TiptapState>;
actions: TiptapActions;
state: TiptapState;
};
export function useTiptapStore(initialState?: Partial<TiptapState>) {
@ -36,42 +26,8 @@ export function useTiptapStore(initialState?: Partial<TiptapState>) {
...initialState,
});
const toggleMinimal = () => {
state.minimal = !state.minimal;
};
const updateContent = (newContent: string) => {
state.content = newContent;
};
const setTheme = (theme: string) => {
state.theme = theme;
};
const toggleToolbar = () => {
state.hideToolbar = !state.hideToolbar;
};
const toggleMenubar = () => {
state.hideMenubar = !state.hideMenubar;
};
const toggleEditable = () => {
state.disabled = !state.disabled;
};
const actions: TiptapActions = {
toggleMinimal,
updateContent,
setTheme,
toggleToolbar,
toggleMenubar,
toggleEditable,
};
const store: TiptapStore = {
state: readonly(state),
actions,
state: state,
};
provide(TiptapStoreKey, store);

View File

@ -1,5 +1,12 @@
import TiptapEditor from "./views/index.vue";
import { useTiptapStore, useTiptapContext } from "./context/useTiptapStore";
import { ThemeToggle } from "echo-editor";
import EditorActions from "./components/EditorActions.vue";
export { TiptapEditor, ThemeToggle, useTiptapStore, useTiptapContext };
export {
TiptapEditor,
ThemeToggle,
useTiptapStore,
useTiptapContext,
EditorActions,
};

View File

@ -1,19 +1,8 @@
<template>
<div class="min-h-screen bg-background">
<EditorActions
:minimal="state.minimal"
:hide-toolbar="state.hideToolbar"
:hide-menubar="state.hideMenubar"
:disabled="state.disabled"
@toggle-minimal="actions.toggleMinimal"
@toggle-toolbar="actions.toggleToolbar"
@toggle-menubar="actions.toggleMenubar"
@toggle-editable="actions.toggleEditable"
/>
<div class="">
<EditorActions />
<echo-editor
:model-value="state.content"
@update:model-value="actions.updateContent"
:extensions="editorExtensions"
:hideToolbar="state.hideToolbar"
:hideMenubar="state.hideMenubar || state.minimal"
@ -21,13 +10,11 @@
:disabled="state.disabled"
:maxHeight="512"
output="html"
:theme="state.theme"
@update:theme="actions.setTheme"
@update:theme="state.theme"
@update:model-value="state.content"
:dark="state.theme === 'dark'"
:theme="state.theme"
/>
<HtmlOutput :content="state.content" />
minimal : {{ state.minimal }}
</div>
</template>
<script setup lang="ts">
@ -35,7 +22,6 @@ import { computed } from "vue";
import { EchoEditor } from "echo-editor";
import { DEMO_CONTENT } from "./initContent";
import EditorActions from "../components/EditorActions.vue";
import HtmlOutput from "../components/HtmlOutput.vue";
import { useEditorConfig } from "../components/useEditorConfig";
import { useTiptapStore, type TiptapState } from "../context/useTiptapStore";
@ -46,12 +32,14 @@ const props = defineProps<{
initialState?: Partial<TiptapState>;
}>();
const { state, actions } = useTiptapStore({
const { state } = useTiptapStore({
...props.initialState,
content: props.initialState?.content || DEMO_CONTENT,
});
const editorExtensions = computed(
() => useEditorConfig(state.minimal).extensions
);
console.log("Tiptap state:", state);
const editorExtensions = computed(() => {
return useEditorConfig(state.minimal).extensions.value;
});
</script>

View File

@ -1,279 +1,3 @@
export const DEMO_CONTENT = {
type: "doc",
content: [
{
type: "heading",
attrs: { textAlign: "center", indent: 0, lineHeight: null, level: 1 },
content: [{ type: "text", text: "Echo Editor" }],
},
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [
{
type: "text",
text: "A modern WYSIWYG AI rich text editor based on ",
},
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://github.com/scrumpy/tiptap",
target: "_blank",
rel: "noopener noreferrer nofollow",
class: "link",
},
},
],
text: "tiptap",
},
{ type: "text", text: " and " },
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://www.shadcn-vue.com/",
target: "_blank",
rel: "noopener noreferrer nofollow",
class: "link",
},
},
],
text: "shadcn ui",
},
{ type: "text", text: " for Vue.js" },
],
},
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
},
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
},
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
},
{
type: "image",
attrs: {
textAlign: "center",
src: "https://picsum.photos/1920/1080.webp?t=1",
alt: null,
title: null,
width: 500,
},
},
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
},
{ type: "horizontalRule" },
{
type: "heading",
attrs: { textAlign: "left", indent: 0, lineHeight: null, level: 2 },
content: [{ type: "text", text: "Demo" }],
},
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [
{ type: "text", text: "👉" },
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://echo-editor.jzcloud.site/",
target: "_blank",
rel: "noopener noreferrer nofollow",
class: "link",
},
},
],
text: "Demo",
},
],
},
{
type: "heading",
attrs: { textAlign: "left", indent: 0, lineHeight: null, level: 2 },
content: [{ type: "text", text: "Features" }],
},
{
type: "bulletList",
attrs: { listStyleType: "disc" },
content: [
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [
{ type: "text", text: "Use " },
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://www.shadcn-vue.com/",
target: "_blank",
rel: "noopener noreferrer nofollow",
class: "link",
},
},
],
text: "shadcn ui",
},
{ type: "text", text: " components" },
],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "Markdown support" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "TypeScript support" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "I18n support" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "Vue 3.x support" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "Slash Command" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "Dark Mode" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "Multi Column" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "AI Power" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "Embed" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
content: [{ type: "text", text: "TailwindCss" }],
},
],
},
],
},
{
type: "heading",
attrs: { textAlign: "left", indent: 0, lineHeight: null, level: 2 },
content: [{ type: "text", text: "Installation" }],
},
{
type: "codeBlock",
attrs: { language: "bash" },
content: [
{
type: "text",
text: "pnpm add echo-editor\n// or\nor yarn add echo-editor\n// or\nor npm i echo-editor -S",
},
],
},
{
type: "heading",
attrs: { textAlign: "left", indent: 0, lineHeight: null, level: 3 },
content: [{ type: "text", text: "install plugin" }],
},
{
type: "codeBlock",
attrs: { language: "typescript" },
content: [
{
type: "text",
text: "import { createApp } from 'vue'\nimport App from './App.vue'\nimport EchoEditor from 'echo-editor'\nimport 'echo-editor/style.css'\nconst app = createApp(App)\napp.use(EchoEditor)\napp.mount('#app')",
},
],
},
{
type: "paragraph",
attrs: { textAlign: "left", indent: 0, lineHeight: null },
},
],
};
export const DEMO_CONTENT = `
<h1 style="text-align: center">Echo Editor</h1><p style="text-align: left">A modern WYSIWYG AI rich text editor based on <a target="_blank" rel="noopener noreferrer nofollow" class="link" href="https://github.com/scrumpy/tiptap" stricturl="true">tiptap</a> and <a target="_blank" rel="noopener noreferrer nofollow" class="link" href="https://www.shadcn-vue.com/" stricturl="true">shadcn ui</a> for Vue.js</p><p style="text-align: left"></p><p style="text-align: left"></p><p style="text-align: left"></p><img height="auto" style="margin-left: auto; margin-right: auto; text-align: center" src="https://picsum.photos/1920/1080.webp?t=1" flipx="false" flipy="false" originwidth="500" originheight="281.25" width="500"><p style="text-align: left"></p><div data-type="horizontalRule"><hr></div><h2 style="text-align: left">Demo</h2><p style="text-align: left">👉<a target="_blank" rel="noopener noreferrer nofollow" class="link" href="https://echo-editor.jzcloud.site/" stricturl="true">Demo</a></p><h2 style="text-align: left">Features</h2><ul style="list-style-type: disc"><li><p style="text-align: left">Use <a target="_blank" rel="noopener noreferrer nofollow" class="link" href="https://www.shadcn-vue.com/" stricturl="true">shadcn ui</a> components</p></li><li><p style="text-align: left">Markdown support</p></li><li><p style="text-align: left">TypeScript support</p></li><li><p style="text-align: left">I18n support</p></li><li><p style="text-align: left">Vue 3.x support</p></li><li><p style="text-align: left">Slash Command</p></li><li><p style="text-align: left">Dark Mode</p></li><li><p style="text-align: left">Multi Column</p></li><li><p style="text-align: left">AI Power</p></li><li><p style="text-align: left">Embed</p></li><li><p style="text-align: left">TailwindCss</p></li></ul><h2 style="text-align: left">Installation</h2><pre vnode="true" code="pnpm add echo-editor // or or yarn add echo-editor // or or npm i echo-editor -S" language="bash" linenumbers="true" wordwrap="false" tabsize="2" shouldfocus="false"><code>pnpm add echo-editor // or or yarn add echo-editor // or or npm i echo-editor -S</code></pre><h3 style="text-align: left">install plugin</h3><pre vnode="true" code="import { createApp } from 'vue' import App from './App.vue' import EchoEditor from 'echo-editor' import 'echo-editor/style.css' const app = createApp(App) app.use(EchoEditor) app.mount('#app')" language="typescript" linenumbers="true" wordwrap="false" tabsize="2" shouldfocus="false"><code>import { createApp } from 'vue' import App from './App.vue' import EchoEditor from 'echo-editor' import 'echo-editor/style.css' const app = createApp(App) app.use(EchoEditor) app.mount('#app')</code></pre><p style="text-align: left"></p>
`;