mirror of https://github.com/halo-dev/halo-admin
parent
8281a996bb
commit
e3fc574b30
|
@ -35,7 +35,8 @@
|
||||||
"@halo-dev/admin-shared": "workspace:*",
|
"@halo-dev/admin-shared": "workspace:*",
|
||||||
"@halo-dev/api-client": "^0.0.12",
|
"@halo-dev/api-client": "^0.0.12",
|
||||||
"@halo-dev/components": "workspace:*",
|
"@halo-dev/components": "workspace:*",
|
||||||
"@halo-dev/richtext-editor": "^0.0.0-alpha.4",
|
"@halo-dev/richtext-editor": "^0.0.0-alpha.5",
|
||||||
|
"@tiptap/extension-character-count": "2.0.0-beta.31",
|
||||||
"@vueuse/components": "^8.9.4",
|
"@vueuse/components": "^8.9.4",
|
||||||
"@vueuse/core": "^8.9.4",
|
"@vueuse/core": "^8.9.4",
|
||||||
"@vueuse/router": "^9.1.0",
|
"@vueuse/router": "^9.1.0",
|
||||||
|
|
|
@ -43,6 +43,9 @@ import IconForbidLine from "~icons/ri/forbid-line";
|
||||||
import IconCodeBoxLine from "~icons/ri/code-box-line";
|
import IconCodeBoxLine from "~icons/ri/code-box-line";
|
||||||
import IconDatabase2Line from "~icons/ri/database-2-line";
|
import IconDatabase2Line from "~icons/ri/database-2-line";
|
||||||
import IconTeam from "~icons/ri/team-fill";
|
import IconTeam from "~icons/ri/team-fill";
|
||||||
|
import IconCharacterRecognition from "~icons/ri/character-recognition-line";
|
||||||
|
import IconCalendar from "~icons/ri/calendar-line";
|
||||||
|
import IconLink from "~icons/ri/link";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
IconDashboard,
|
IconDashboard,
|
||||||
|
@ -90,4 +93,7 @@ export {
|
||||||
IconCodeBoxLine,
|
IconCodeBoxLine,
|
||||||
IconDatabase2Line,
|
IconDatabase2Line,
|
||||||
IconTeam,
|
IconTeam,
|
||||||
|
IconCharacterRecognition,
|
||||||
|
IconCalendar,
|
||||||
|
IconLink,
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,9 +15,10 @@ importers:
|
||||||
'@halo-dev/admin-shared': workspace:*
|
'@halo-dev/admin-shared': workspace:*
|
||||||
'@halo-dev/api-client': ^0.0.12
|
'@halo-dev/api-client': ^0.0.12
|
||||||
'@halo-dev/components': workspace:*
|
'@halo-dev/components': workspace:*
|
||||||
'@halo-dev/richtext-editor': ^0.0.0-alpha.4
|
'@halo-dev/richtext-editor': ^0.0.0-alpha.5
|
||||||
'@rushstack/eslint-patch': ^1.1.4
|
'@rushstack/eslint-patch': ^1.1.4
|
||||||
'@tailwindcss/aspect-ratio': ^0.4.0
|
'@tailwindcss/aspect-ratio': ^0.4.0
|
||||||
|
'@tiptap/extension-character-count': 2.0.0-beta.31
|
||||||
'@types/jsdom': ^20.0.0
|
'@types/jsdom': ^20.0.0
|
||||||
'@types/lodash.clonedeep': 4.5.7
|
'@types/lodash.clonedeep': 4.5.7
|
||||||
'@types/lodash.isequal': ^4.5.6
|
'@types/lodash.isequal': ^4.5.6
|
||||||
|
@ -89,7 +90,8 @@ importers:
|
||||||
'@halo-dev/admin-shared': link:packages/shared
|
'@halo-dev/admin-shared': link:packages/shared
|
||||||
'@halo-dev/api-client': 0.0.12
|
'@halo-dev/api-client': 0.0.12
|
||||||
'@halo-dev/components': link:packages/components
|
'@halo-dev/components': link:packages/components
|
||||||
'@halo-dev/richtext-editor': 0.0.0-alpha.4_vue@3.2.37
|
'@halo-dev/richtext-editor': 0.0.0-alpha.5_vue@3.2.37
|
||||||
|
'@tiptap/extension-character-count': 2.0.0-beta.31
|
||||||
'@vueuse/components': 8.9.4_vue@3.2.37
|
'@vueuse/components': 8.9.4_vue@3.2.37
|
||||||
'@vueuse/core': 8.9.4_vue@3.2.37
|
'@vueuse/core': 8.9.4_vue@3.2.37
|
||||||
'@vueuse/router': 9.1.0_26a4nhf5pwzjzqc5ckt7ohj5zi
|
'@vueuse/router': 9.1.0_26a4nhf5pwzjzqc5ckt7ohj5zi
|
||||||
|
@ -2119,16 +2121,33 @@ packages:
|
||||||
resolution: {integrity: sha512-fOI3DB9rOA1Z+h1aKiEQ+2kWkNSmdWIDvd+39dR5b3X0DmKH+zWrNmygA5Qe2gBPX28TNt/zr2qCKUjGjb99CA==}
|
resolution: {integrity: sha512-fOI3DB9rOA1Z+h1aKiEQ+2kWkNSmdWIDvd+39dR5b3X0DmKH+zWrNmygA5Qe2gBPX28TNt/zr2qCKUjGjb99CA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@halo-dev/richtext-editor/0.0.0-alpha.4_vue@3.2.37:
|
/@halo-dev/richtext-editor/0.0.0-alpha.5_vue@3.2.37:
|
||||||
resolution: {integrity: sha512-38K+eQSOCNBx/i1Mu+/krdXDdZq6I6n0YBdJY4FZ/v70fxQsdCrK28QBo5aUFaG/WrNH69HVl8HbuQLN8cmxtA==}
|
resolution: {integrity: sha512-q+Ukq9Y57DwB2+KguHJI/xWDdVqzilG4sqfkDv+uuElHt4mu5CPtrLTzOHtvSqlqLM2kK2S5mNwJMlAPPHQ9Rw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.2.37
|
vue: ^3.2.37
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/core': 2.0.0-beta.182
|
'@tiptap/core': 2.0.0-beta.182
|
||||||
|
'@tiptap/extension-blockquote': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-bold': 2.0.0-beta.28_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-bullet-list': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-code': 2.0.0-beta.28_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-code-block': 2.0.0-beta.42_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-code-block-lowlight': 2.0.0-beta.73_giic42g7xysntyllbw3z33pheu
|
'@tiptap/extension-code-block-lowlight': 2.0.0-beta.73_giic42g7xysntyllbw3z33pheu
|
||||||
|
'@tiptap/extension-document': 2.0.0-beta.17_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-dropcursor': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-gapcursor': 2.0.0-beta.39_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-hard-break': 2.0.0-beta.33_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-heading': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-history': 2.0.0-beta.26_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-horizontal-rule': 2.0.0-beta.36_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-image': 2.0.0-beta.30_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-image': 2.0.0-beta.30_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-italic': 2.0.0-beta.28_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-link': 2.0.0-beta.43_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-link': 2.0.0-beta.43_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-list-item': 2.0.0-beta.23_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-ordered-list': 2.0.0-beta.30_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-paragraph': 2.0.0-beta.26_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-placeholder': 2.0.0-beta.53_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-placeholder': 2.0.0-beta.53_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-strike': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-subscript': 2.0.0-beta.13_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-subscript': 2.0.0-beta.13_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-superscript': 2.0.0-beta.13_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-superscript': 2.0.0-beta.13_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-table': 2.0.0-beta.54_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-table': 2.0.0-beta.54_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
@ -2137,9 +2156,9 @@ packages:
|
||||||
'@tiptap/extension-table-row': 2.0.0-beta.22_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-table-row': 2.0.0-beta.22_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-task-item': 2.0.0-beta.37_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-task-item': 2.0.0-beta.37_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-task-list': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-task-list': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
|
'@tiptap/extension-text': 2.0.0-beta.17_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-text-align': 2.0.0-beta.31_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-text-align': 2.0.0-beta.31_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/extension-underline': 2.0.0-beta.25_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/extension-underline': 2.0.0-beta.25_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/starter-kit': 2.0.0-beta.191
|
|
||||||
'@tiptap/suggestion': 2.0.0-beta.97_jdrcmhoxj44u3cq7gnenksjiqq
|
'@tiptap/suggestion': 2.0.0-beta.97_jdrcmhoxj44u3cq7gnenksjiqq
|
||||||
'@tiptap/vue-3': 2.0.0-beta.96_z53wbejway3kikyipxsiftrlse
|
'@tiptap/vue-3': 2.0.0-beta.96_z53wbejway3kikyipxsiftrlse
|
||||||
floating-vue: 2.0.0-beta.19_vue@3.2.37
|
floating-vue: 2.0.0-beta.19_vue@3.2.37
|
||||||
|
@ -2767,6 +2786,15 @@ packages:
|
||||||
'@tiptap/core': 2.0.0-beta.182
|
'@tiptap/core': 2.0.0-beta.182
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@tiptap/extension-character-count/2.0.0-beta.31:
|
||||||
|
resolution: {integrity: sha512-NNA9MN1IjZe+yYQLuYVAg9RNG/3RonYrHiM5mL6vsegd+PF4uMqyZLgsM0/9dMhxh9K/pDPaCRxhuDoZC8V1wA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': ^2.0.0-beta.1
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model: 1.18.1
|
||||||
|
prosemirror-state: 1.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@tiptap/extension-code-block-lowlight/2.0.0-beta.73_giic42g7xysntyllbw3z33pheu:
|
/@tiptap/extension-code-block-lowlight/2.0.0-beta.73_giic42g7xysntyllbw3z33pheu:
|
||||||
resolution: {integrity: sha512-57jqDd2jzQPlYKPtnDIlwwaZrHLlgUVCe+NIWgK6bpP1yF4bUE3Dguqw1owN6oBWBf0kQnm0TQjbn50B/wnUjQ==}
|
resolution: {integrity: sha512-57jqDd2jzQPlYKPtnDIlwwaZrHLlgUVCe+NIWgK6bpP1yF4bUE3Dguqw1owN6oBWBf0kQnm0TQjbn50B/wnUjQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3033,30 +3061,6 @@ packages:
|
||||||
'@tiptap/core': 2.0.0-beta.182
|
'@tiptap/core': 2.0.0-beta.182
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@tiptap/starter-kit/2.0.0-beta.191:
|
|
||||||
resolution: {integrity: sha512-YRrBCi9W4jiH/xLTJJOCdD7pL4Wb98Ip8qCJ94RElShDj0O1i5tT9wWlgVWoGIU+CRAds5XENRwZ97sJ+YfYyg==}
|
|
||||||
dependencies:
|
|
||||||
'@tiptap/core': 2.0.0-beta.182
|
|
||||||
'@tiptap/extension-blockquote': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-bold': 2.0.0-beta.28_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-bullet-list': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-code': 2.0.0-beta.28_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-code-block': 2.0.0-beta.42_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-document': 2.0.0-beta.17_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-dropcursor': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-gapcursor': 2.0.0-beta.39_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-hard-break': 2.0.0-beta.33_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-heading': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-history': 2.0.0-beta.26_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-horizontal-rule': 2.0.0-beta.36_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-italic': 2.0.0-beta.28_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-list-item': 2.0.0-beta.23_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-ordered-list': 2.0.0-beta.30_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-paragraph': 2.0.0-beta.26_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-strike': 2.0.0-beta.29_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
'@tiptap/extension-text': 2.0.0-beta.17_jdrcmhoxj44u3cq7gnenksjiqq
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@tiptap/suggestion/2.0.0-beta.97_jdrcmhoxj44u3cq7gnenksjiqq:
|
/@tiptap/suggestion/2.0.0-beta.97_jdrcmhoxj44u3cq7gnenksjiqq:
|
||||||
resolution: {integrity: sha512-3NWG+HE7v2w97Ek6z1tUosoZKpCDH+oAtIG9XoNkK1PmlaVV/H4d6HT9uPX+Y6SeN7fSAqlcXFUGLXcDi9d+Zw==}
|
resolution: {integrity: sha512-3NWG+HE7v2w97Ek6z1tUosoZKpCDH+oAtIG9XoNkK1PmlaVV/H4d6HT9uPX+Y6SeN7fSAqlcXFUGLXcDi9d+Zw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
|
@ -1,18 +1,31 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import {
|
||||||
IconBookRead,
|
IconBookRead,
|
||||||
|
IconCalendar,
|
||||||
|
IconCharacterRecognition,
|
||||||
|
IconLink,
|
||||||
IconSave,
|
IconSave,
|
||||||
|
IconUserFollow,
|
||||||
VButton,
|
VButton,
|
||||||
VPageHeader,
|
VPageHeader,
|
||||||
VSpace,
|
VSpace,
|
||||||
|
VTabItem,
|
||||||
|
VTabs,
|
||||||
} from "@halo-dev/components";
|
} from "@halo-dev/components";
|
||||||
import PostSettingModal from "./components/PostSettingModal.vue";
|
import PostSettingModal from "./components/PostSettingModal.vue";
|
||||||
import type { PostRequest } from "@halo-dev/api-client";
|
import type { PostRequest } from "@halo-dev/api-client";
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref, watch } from "vue";
|
||||||
import cloneDeep from "lodash.clonedeep";
|
import cloneDeep from "lodash.clonedeep";
|
||||||
import { apiClient } from "@halo-dev/admin-shared";
|
import { apiClient } from "@halo-dev/admin-shared";
|
||||||
import { useRouteQuery } from "@vueuse/router";
|
import { useRouteQuery } from "@vueuse/router";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
|
import {
|
||||||
|
allExtensions,
|
||||||
|
RichTextEditor,
|
||||||
|
useEditor,
|
||||||
|
} from "@halo-dev/richtext-editor";
|
||||||
|
import ExtensionCharacterCount from "@tiptap/extension-character-count";
|
||||||
|
import { formatDatetime } from "@/utils/date";
|
||||||
|
|
||||||
const initialFormState: PostRequest = {
|
const initialFormState: PostRequest = {
|
||||||
post: {
|
post: {
|
||||||
|
@ -53,11 +66,77 @@ const initialFormState: PostRequest = {
|
||||||
const formState = ref<PostRequest>(cloneDeep(initialFormState));
|
const formState = ref<PostRequest>(cloneDeep(initialFormState));
|
||||||
const settingModal = ref(false);
|
const settingModal = ref(false);
|
||||||
const saving = ref(false);
|
const saving = ref(false);
|
||||||
|
const extraActiveId = ref("toc");
|
||||||
|
|
||||||
const isUpdateMode = computed(() => {
|
const isUpdateMode = computed(() => {
|
||||||
return !!formState.value.post.metadata.creationTimestamp;
|
return !!formState.value.post.metadata.creationTimestamp;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface TocNode {
|
||||||
|
id: string;
|
||||||
|
level: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const toc = ref<TocNode[]>();
|
||||||
|
const editor = useEditor({
|
||||||
|
content: formState.value.content.raw,
|
||||||
|
extensions: [...allExtensions, ExtensionCharacterCount],
|
||||||
|
autofocus: "start",
|
||||||
|
onUpdate: () => {
|
||||||
|
formState.value.content.raw = editor.value?.getHTML() + "";
|
||||||
|
handleGenerateTableOfContent();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => formState.value.content.raw,
|
||||||
|
(newValue) => {
|
||||||
|
const isSame = editor.value?.getHTML() === newValue;
|
||||||
|
|
||||||
|
if (isSame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.value?.commands.setContent(newValue as string, false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleGenerateTableOfContent = () => {
|
||||||
|
if (!editor.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headings: TocNode[] = [];
|
||||||
|
const transaction = editor.value.state.tr;
|
||||||
|
|
||||||
|
editor.value.state.doc.descendants((node, pos) => {
|
||||||
|
if (node.type.name === "heading") {
|
||||||
|
const id = `heading-${headings.length + 1}`;
|
||||||
|
|
||||||
|
if (node.attrs.id !== id) {
|
||||||
|
transaction?.setNodeMarkup(pos, undefined, {
|
||||||
|
...node.attrs,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
headings.push({
|
||||||
|
level: node.attrs.level,
|
||||||
|
text: node.textContent,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.setMeta("addToHistory", false);
|
||||||
|
transaction.setMeta("preventUpdate", true);
|
||||||
|
|
||||||
|
editor.value.view.dispatch(transaction);
|
||||||
|
|
||||||
|
toc.value = headings;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
try {
|
try {
|
||||||
saving.value = true;
|
saving.value = true;
|
||||||
|
@ -119,6 +198,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
// fetch post content
|
// fetch post content
|
||||||
await handleFetchContent();
|
await handleFetchContent();
|
||||||
|
handleGenerateTableOfContent();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -148,6 +228,139 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
</VPageHeader>
|
</VPageHeader>
|
||||||
<div class="editor border-t" style="height: calc(100vh - 3.5rem)">
|
<div class="editor border-t" style="height: calc(100vh - 3.5rem)">
|
||||||
<RichTextEditor v-model="formState.content.raw" />
|
<RichTextEditor v-if="editor" :editor="editor">
|
||||||
|
<template #extra>
|
||||||
|
<div class="h-full w-72 overflow-y-auto border-l bg-white">
|
||||||
|
<VTabs v-model:active-id="extraActiveId" type="outline">
|
||||||
|
<VTabItem id="toc" label="大纲">
|
||||||
|
<div class="p-1 pt-0">
|
||||||
|
<ul class="space-y-1">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in toc"
|
||||||
|
:key="index"
|
||||||
|
:class="[{ 'bg-gray-100': index === 0 }]"
|
||||||
|
class="cursor-pointer rounded-base px-1.5 py-1 text-sm text-gray-600 hover:bg-gray-100 hover:text-gray-900"
|
||||||
|
>
|
||||||
|
{{ item.text }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</VTabItem>
|
||||||
|
<VTabItem id="information" label="详情">
|
||||||
|
<div class="flex flex-col gap-2 p-1 pt-0">
|
||||||
|
<div class="grid grid-cols-2 gap-2">
|
||||||
|
<div
|
||||||
|
class="group flex cursor-pointer flex-col gap-y-5 rounded-md bg-gray-100 px-1.5 py-1 transition-all"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
class="text-sm text-gray-500 group-hover:text-gray-900"
|
||||||
|
>
|
||||||
|
字符数
|
||||||
|
</div>
|
||||||
|
<div class="rounded bg-gray-200 p-0.5">
|
||||||
|
<IconCharacterRecognition
|
||||||
|
class="h-4 w-4 text-gray-600 group-hover:text-gray-900"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-medium text-gray-900">
|
||||||
|
{{ editor.storage.characterCount.characters() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="group flex cursor-pointer flex-col gap-y-5 rounded-md bg-gray-100 px-1.5 py-1 transition-all"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
class="text-sm text-gray-500 group-hover:text-gray-900"
|
||||||
|
>
|
||||||
|
词数
|
||||||
|
</div>
|
||||||
|
<div class="rounded bg-gray-200 p-0.5">
|
||||||
|
<IconCharacterRecognition
|
||||||
|
class="h-4 w-4 text-gray-600 group-hover:text-gray-900"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-medium text-gray-900">
|
||||||
|
{{ editor.storage.characterCount.words() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 gap-2">
|
||||||
|
<div
|
||||||
|
class="group flex cursor-pointer flex-col gap-y-5 rounded-md bg-gray-100 px-1.5 py-1 transition-all"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
class="text-sm text-gray-500 group-hover:text-gray-900"
|
||||||
|
>
|
||||||
|
创建时间
|
||||||
|
</div>
|
||||||
|
<div class="rounded bg-gray-200 p-0.5">
|
||||||
|
<IconCalendar
|
||||||
|
class="h-4 w-4 text-gray-600 group-hover:text-gray-900"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-medium text-gray-900">
|
||||||
|
{{
|
||||||
|
formatDatetime(
|
||||||
|
formState.post.metadata.creationTimestamp
|
||||||
|
) || "未发布"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 gap-2">
|
||||||
|
<div
|
||||||
|
class="group flex cursor-pointer flex-col gap-y-5 rounded-md bg-gray-100 px-1.5 py-1 transition-all"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
class="text-sm text-gray-500 group-hover:text-gray-900"
|
||||||
|
>
|
||||||
|
创建者
|
||||||
|
</div>
|
||||||
|
<div class="rounded bg-gray-200 p-0.5">
|
||||||
|
<IconUserFollow
|
||||||
|
class="h-4 w-4 text-gray-600 group-hover:text-gray-900"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-medium text-gray-900">
|
||||||
|
{{ formState.post.spec.owner }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 gap-2">
|
||||||
|
<div
|
||||||
|
class="group flex cursor-pointer flex-col gap-y-5 rounded-md bg-gray-100 px-1.5 py-1 transition-all"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
class="text-sm text-gray-500 group-hover:text-gray-900"
|
||||||
|
>
|
||||||
|
访问链接
|
||||||
|
</div>
|
||||||
|
<div class="rounded bg-gray-200 p-0.5">
|
||||||
|
<IconLink
|
||||||
|
class="h-4 w-4 text-gray-600 group-hover:text-gray-900"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-900 hover:text-blue-600">
|
||||||
|
{{ formState.post.status?.["permalink"] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VTabItem>
|
||||||
|
</VTabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RichTextEditor>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -5,11 +5,9 @@ import "floating-vue/dist/style.css";
|
||||||
import VueGridLayout from "vue-grid-layout";
|
import VueGridLayout from "vue-grid-layout";
|
||||||
import { defaultConfig, plugin as FormKit } from "@formkit/vue";
|
import { defaultConfig, plugin as FormKit } from "@formkit/vue";
|
||||||
import FormKitConfig from "@/formkit/formkit.config";
|
import FormKitConfig from "@/formkit/formkit.config";
|
||||||
import RichTextEditor from "@halo-dev/richtext-editor";
|
|
||||||
|
|
||||||
export function setupComponents(app: App) {
|
export function setupComponents(app: App) {
|
||||||
app.use(VueGridLayout);
|
app.use(VueGridLayout);
|
||||||
app.use(RichTextEditor);
|
|
||||||
app.use(
|
app.use(
|
||||||
FormKit,
|
FormKit,
|
||||||
defaultConfig({
|
defaultConfig({
|
||||||
|
|
Loading…
Reference in New Issue