no message
This commit is contained in:
parent
966cb55c25
commit
bb1b91b6a6
@ -6,5 +6,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { TiptapEditor, ThemeToggle } from "@tiptap/component";
|
import { TiptapEditor, ThemeToggle, useTiptapContext } from "@tiptap/component";
|
||||||
|
useTiptapContext();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
88
web3/packages/tiptap/src/context/useTiptapStore.ts
Normal file
88
web3/packages/tiptap/src/context/useTiptapStore.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { provide, inject, reactive, readonly, type InjectionKey } from "vue";
|
||||||
|
|
||||||
|
const TiptapStoreKey: InjectionKey<TiptapStore> = Symbol("TiptapStore");
|
||||||
|
|
||||||
|
export interface TiptapState {
|
||||||
|
content: any;
|
||||||
|
theme: string | null;
|
||||||
|
hideToolbar: boolean;
|
||||||
|
hideMenubar: boolean;
|
||||||
|
disabled: boolean;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useTiptapStore(initialState?: Partial<TiptapState>) {
|
||||||
|
const state = reactive<TiptapState>({
|
||||||
|
content: "",
|
||||||
|
theme: null,
|
||||||
|
hideToolbar: false,
|
||||||
|
hideMenubar: false,
|
||||||
|
disabled: false,
|
||||||
|
minimal: false,
|
||||||
|
...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,
|
||||||
|
};
|
||||||
|
|
||||||
|
provide(TiptapStoreKey, store);
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTiptapContext() {
|
||||||
|
const store = inject(TiptapStoreKey);
|
||||||
|
if (!store) {
|
||||||
|
throw new Error("useTiptapContext must be used within a TiptapProvider");
|
||||||
|
}
|
||||||
|
return store;
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import TiptapEditor from "./views/index.vue";
|
import TiptapEditor from "./views/index.vue";
|
||||||
|
import { useTiptapStore, useTiptapContext } from "./context/useTiptapStore";
|
||||||
import { ThemeToggle } from "echo-editor";
|
import { ThemeToggle } from "echo-editor";
|
||||||
|
|
||||||
export { TiptapEditor, ThemeToggle };
|
export { TiptapEditor, ThemeToggle, useTiptapStore, useTiptapContext };
|
||||||
|
|||||||
@ -1,54 +1,57 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="min-h-screen bg-background">
|
<div class="min-h-screen bg-background">
|
||||||
<EditorActions
|
<EditorActions
|
||||||
:minimal="minimal"
|
:minimal="state.minimal"
|
||||||
:hide-toolbar="hideToolbar"
|
:hide-toolbar="state.hideToolbar"
|
||||||
:hide-menubar="hideMenubar"
|
:hide-menubar="state.hideMenubar"
|
||||||
:disabled="disabled"
|
:disabled="state.disabled"
|
||||||
@toggle-minimal="toggleMinimal"
|
@toggle-minimal="actions.toggleMinimal"
|
||||||
@toggle-toolbar="hideToolbar = !hideToolbar"
|
@toggle-toolbar="actions.toggleToolbar"
|
||||||
@toggle-menubar="hideMenubar = !hideMenubar"
|
@toggle-menubar="actions.toggleMenubar"
|
||||||
@toggle-editable="disabled = !disabled"
|
@toggle-editable="actions.toggleEditable"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<echo-editor
|
<echo-editor
|
||||||
v-model="content"
|
:model-value="state.content"
|
||||||
:extensions="extensions"
|
@update:model-value="actions.updateContent"
|
||||||
:hideToolbar="hideToolbar"
|
:extensions="editorExtensions"
|
||||||
:hideMenubar="hideMenubar || minimal"
|
:hideToolbar="state.hideToolbar"
|
||||||
:key="minimal ? 'minimal' : 'full'"
|
:hideMenubar="state.hideMenubar || state.minimal"
|
||||||
:disabled="disabled"
|
:key="state.minimal ? 'minimal' : 'full'"
|
||||||
|
:disabled="state.disabled"
|
||||||
:maxHeight="512"
|
:maxHeight="512"
|
||||||
output="html"
|
output="html"
|
||||||
v-model:theme="theme"
|
:theme="state.theme"
|
||||||
:dark="theme === 'dark'"
|
@update:theme="actions.setTheme"
|
||||||
|
:dark="state.theme === 'dark'"
|
||||||
/>
|
/>
|
||||||
<HtmlOutput :content="content" />
|
<HtmlOutput :content="state.content" />
|
||||||
|
|
||||||
minimal : {{ minimal }}
|
minimal : {{ state.minimal }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { computed } from "vue";
|
||||||
import { EchoEditor } from "echo-editor";
|
import { EchoEditor } from "echo-editor";
|
||||||
import { DEMO_CONTENT } from "./initContent";
|
import { DEMO_CONTENT } from "./initContent";
|
||||||
import EditorActions from "../components/EditorActions.vue";
|
import EditorActions from "../components/EditorActions.vue";
|
||||||
import HtmlOutput from "../components/HtmlOutput.vue";
|
import HtmlOutput from "../components/HtmlOutput.vue";
|
||||||
import { useEditorConfig } from "../components/useEditorConfig";
|
import { useEditorConfig } from "../components/useEditorConfig";
|
||||||
|
import { useTiptapStore, type TiptapState } from "../context/useTiptapStore";
|
||||||
|
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
import "echo-editor/style.css";
|
import "echo-editor/style.css";
|
||||||
|
|
||||||
const content = ref(DEMO_CONTENT);
|
const props = defineProps<{
|
||||||
const theme = ref<string | null>(null);
|
initialState?: Partial<TiptapState>;
|
||||||
const hideToolbar = ref<boolean>(false);
|
}>();
|
||||||
const hideMenubar = ref<boolean>(false);
|
|
||||||
const disabled = ref<boolean>(false);
|
|
||||||
const minimal = ref(false);
|
|
||||||
|
|
||||||
const { extensions } = useEditorConfig(minimal.value);
|
const { state, actions } = useTiptapStore({
|
||||||
|
...props.initialState,
|
||||||
|
content: props.initialState?.content || DEMO_CONTENT,
|
||||||
|
});
|
||||||
|
|
||||||
function toggleMinimal() {
|
const editorExtensions = computed(
|
||||||
minimal.value = !minimal.value;
|
() => useEditorConfig(state.minimal).extensions
|
||||||
}
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,3 +1,279 @@
|
|||||||
export const DEMO_CONTENT = `
|
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>
|
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 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user