diff --git a/bun.lockb b/bun.lockb index 390e349..6946227 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index fefba0e..98e1778 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@tiptap/extension-heading": "^2.10.3", "@tiptap/extension-highlight": "^2.10.3", "@tiptap/extension-horizontal-rule": "^2.10.3", + "@tiptap/extension-image": "^2.10.3", "@tiptap/extension-paragraph": "^2.10.3", "@tiptap/extension-text": "^2.10.3", "@tiptap/vue-3": "^2.10.3", @@ -71,7 +72,7 @@ "tailwindcss": "^3.4.14", "typescript": "^5.5.3", "typescript-eslint": "^8.11.0", - "vite": "^5.4.11" + "vite": "^6.0.1" }, "lint-staged": { "*.(ts|vue)": [ diff --git a/src/composables/useRequest.ts b/src/composables/useRequest.ts index ddf3be1..e5be67d 100644 --- a/src/composables/useRequest.ts +++ b/src/composables/useRequest.ts @@ -5,54 +5,54 @@ import apiClient from "@/api/axios"; type HttpMethod = "get" | "post" | "put" | "delete"; interface RequestOptions { - url: string; - method?: HttpMethod; - requestData?: Record | FormData; - headers?: Record; // 新增 headers 参数 + url: string; + method?: HttpMethod; + requestData?: Record | FormData; + headers?: Record; // 新增 headers 参数 } // 定义 useRequest 返回的类型 interface UseRequestResult { - data: Ref; - error: Ref; - loading: Ref; - executeRequest: (options: RequestOptions) => Promise; + data: Ref; + error: Ref; + loading: Ref; + executeRequest: (options: RequestOptions) => Promise; } export function useRequest(): UseRequestResult { - const data = shallowRef(null); - const error = shallowRef(null); - const loading = shallowRef(false); - - const executeRequest = async ({ + const data = shallowRef(null); + const error = shallowRef(null); + const loading = shallowRef(false); + + const executeRequest = async ({ + url, + method = "get", + requestData, + headers, // 接收 headers 参数 + }: RequestOptions): Promise => { + loading.value = true; + error.value = null; + + try { + const response = await apiClient.request({ url, - method = "get", - requestData, - headers, // 接收 headers 参数 - }: RequestOptions): Promise => { - loading.value = true; - error.value = null; - - try { - const response = await apiClient.request({ - url, - method, - headers, // 添加 headers 到请求配置 - ...(method !== "get" ? { data: requestData } : {}), - }); - - data.value = response; - } catch (err) { - error.value = err instanceof Error ? err : new Error(String(err)); - } finally { - loading.value = false; - } - }; - - return { - data, - error, - loading, - executeRequest, - }; + method, + headers, // 添加 headers 到请求配置 + ...(method !== "get" ? { data: requestData } : {}), + }); + + data.value = response; + } catch (err) { + error.value = err instanceof Error ? err : new Error(String(err)); + } finally { + loading.value = false; + } + }; + + return { + data, + error, + loading, + executeRequest, + }; } diff --git a/src/features/post/components/AppEditor.vue b/src/features/post/components/AppEditor.vue index 9e88b9e..53d2af7 100644 --- a/src/features/post/components/AppEditor.vue +++ b/src/features/post/components/AppEditor.vue @@ -6,16 +6,42 @@ import Text from "@tiptap/extension-text"; import Paragraph from "@tiptap/extension-paragraph"; import CodeBlock from "@tiptap/extension-code-block"; import Heading from "@tiptap/extension-heading"; -import { onBeforeUnmount } from "vue"; +import { onBeforeUnmount, onMounted } from "vue"; import HorizontalRule from "@tiptap/extension-horizontal-rule"; import Bold from "@tiptap/extension-bold"; import AppTableExtension from "../extensions/app-table"; import EditorMenuBar from "@post/components/editor-menu-bar/index.vue"; +import Image from "@tiptap/extension-image"; + +const jsonData = { + type: "doc", + content: [ + { + type: "paragraph", + content: [ + { + type: "text", + text: "哈哈哈", + }, + ], + }, + { + type: "appTable", + attrs: { + tableData: [ + [null, null, null, null, null], + [null, null, null, "32", "32"], + [null, null, "", null, "32"], + [null, null, "32", "32", "32"], + [null, null, null, "32", "32"], + ], + }, + }, + ], +}; const editor = useEditor({ - content: ` - 测试 - `, + content: jsonData, extensions: [ Document, Paragraph, @@ -23,89 +49,58 @@ const editor = useEditor({ Blockquote, CodeBlock, Heading.configure({ - levels: [1, 2, 3], + levels: [1, 2, 3, 4, 5], }), HorizontalRule, Bold, + Image.configure({ + allowBase64: true, + }), AppTableExtension, ], }); +const handleClick = () => { + console.log("tiptap 数据:", editor?.value?.getJSON()); +}; + +onMounted(() => {}); + onBeforeUnmount(() => { editor.value?.destroy(); }); diff --git a/src/features/post/components/editor-extension-views/AppTable.vue b/src/features/post/components/editor-extension-views/AppTable.vue index 011928e..9cd7e8f 100644 --- a/src/features/post/components/editor-extension-views/AppTable.vue +++ b/src/features/post/components/editor-extension-views/AppTable.vue @@ -1,17 +1,17 @@ - - diff --git a/src/features/post/components/editor-menu-bar/ItalicItem.vue b/src/features/post/components/editor-menu-bar/ItalicItem.vue deleted file mode 100644 index 7acda1e..0000000 --- a/src/features/post/components/editor-menu-bar/ItalicItem.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/src/features/post/components/editor-menu-bar/UnderlineItem.vue b/src/features/post/components/editor-menu-bar/UnderlineItem.vue deleted file mode 100644 index 7acda1e..0000000 --- a/src/features/post/components/editor-menu-bar/UnderlineItem.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/src/features/post/components/editor-menu-bar/index.vue b/src/features/post/components/editor-menu-bar/index.vue index 76105e0..0a2dd16 100644 --- a/src/features/post/components/editor-menu-bar/index.vue +++ b/src/features/post/components/editor-menu-bar/index.vue @@ -1,27 +1,98 @@ + + diff --git a/src/features/post/composables/useCreatePost.ts b/src/features/post/composables/useCreatePost.ts new file mode 100644 index 0000000..2ab4d03 --- /dev/null +++ b/src/features/post/composables/useCreatePost.ts @@ -0,0 +1,16 @@ +import { useRequest } from "@/composables/useRequest"; + +export default function useCreatePost() { + const { executeRequest } = useRequest(); + + async function createPost() { + await executeRequest({ + url: "/post/put", + method: "post", + }); + } + + return { + createPost, + }; +} diff --git a/src/features/post/extensions/app-table.ts b/src/features/post/extensions/app-table.ts index 6e8ce4e..db9fbab 100644 --- a/src/features/post/extensions/app-table.ts +++ b/src/features/post/extensions/app-table.ts @@ -13,12 +13,36 @@ const AppTableExtension = Node.create({ return [ { tag: "app-table", + getAttrs: (element) => { + return { + tableData: JSON.parse(element.getAttribute("table-data") || "[]"), + }; + }, }, ]; }, renderHTML({ HTMLAttributes }) { - return ["app-table", mergeAttributes(HTMLAttributes)]; + return [ + "app-table", + mergeAttributes(HTMLAttributes, { + "table-data": JSON.stringify(HTMLAttributes.tableData), + }), + ]; + }, + + addAttributes() { + return { + tableData: { + default: [ + [null, null, null, null, null], + [null, null, null, null, null], + [null, null, null, null, null], + [null, null, null, null, null], + [null, null, null, null, null], + ], + }, + }; }, addNodeView() { diff --git a/src/features/post/styles/markdown.scss b/src/features/post/styles/markdown.scss new file mode 100644 index 0000000..b654c8b --- /dev/null +++ b/src/features/post/styles/markdown.scss @@ -0,0 +1,41 @@ +blockquote { + border-left: 3px solid red; + margin: 1.5rem 0; + padding-left: 1rem; +} + +code { + background: none; + color: inherit; + font-size: 0.8rem; + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 1.1; + margin-top: 2.5rem; + text-wrap: pretty; +} + +h1, +h2 { + margin-top: 3.5rem; + margin-bottom: 1.5rem; +} + +h1 { + font-size: 1.4rem; +} + +h2 { + font-size: 1.2rem; +} + +h3 { + font-size: 1.1rem; +} diff --git a/src/pages/post.vue b/src/pages/post.vue index f7f1e2b..2d6b554 100644 --- a/src/pages/post.vue +++ b/src/pages/post.vue @@ -4,6 +4,13 @@ import AppEditor from "@post/components/AppEditor.vue"; - +