From 382bdf6579ab20e7203186bc65e3eeb103682977 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?wifi=E6=AD=AAf?= <1402772884@qq.com>
Date: Wed, 29 Jan 2025 13:22:06 +0800
Subject: [PATCH 1/2] =?UTF-8?q?fix(mini-markdown-editor):=20=E4=BF=AE?=
=?UTF-8?q?=E5=A4=8D=E5=BD=93=E5=86=85=E5=AE=B9=E4=BF=AE=E6=94=B9=E5=90=8E?=
=?UTF-8?q?,=20=E7=9B=AE=E5=BD=95=E6=A0=87=E9=A2=98=E4=B8=8D=E5=90=8C?=
=?UTF-8?q?=E6=AD=A5=E6=BB=9A=E5=8A=A8=E6=83=85=E5=86=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/components/Sidebar/Contents.tsx | 59 ++++++++++++++++---
1 file changed, 51 insertions(+), 8 deletions(-)
diff --git a/packages/mini-markdown-editor/src/components/Sidebar/Contents.tsx b/packages/mini-markdown-editor/src/components/Sidebar/Contents.tsx
index cc68ed1..5319fc6 100644
--- a/packages/mini-markdown-editor/src/components/Sidebar/Contents.tsx
+++ b/packages/mini-markdown-editor/src/components/Sidebar/Contents.tsx
@@ -6,6 +6,7 @@ import { useEditorContentStore } from "@/store/editor";
const Contents: FC = () => {
const previewView = useEditorContentStore((state) => state.previewView);
const [titles, setTitles] = useState
([]);
+ const [activeLink, setActiveLink] = useState("");
const preview = document.querySelector(".markdown-editor-preview") as HTMLElement | null;
const getRootElement = () => {
return preview?.querySelectorAll("h1, h2, h3, h4, h5, h6") as NodeListOf;
@@ -29,7 +30,11 @@ const Contents: FC = () => {
// 初始化时立即执行一次
if (rootElement.length > 0) {
- setTitles(addAnchor());
+ const initialTitles = addAnchor();
+ setTitles(initialTitles);
+ if (initialTitles.length > 0) {
+ setActiveLink(initialTitles[0].href);
+ }
}
const observer = new MutationObserver(() => {
@@ -37,7 +42,11 @@ const Contents: FC = () => {
const elements = getRootElement();
if (elements && elements.length > 0) {
requestAnimationFrame(() => {
- setTitles(formatContents(elements));
+ const newTitles = formatContents(elements);
+ setTitles(newTitles);
+ if (newTitles.length > 0 && !activeLink) {
+ setActiveLink(newTitles[0].href);
+ }
});
}
});
@@ -54,11 +63,42 @@ const Contents: FC = () => {
};
}, [preview, rootElement]);
- // 自定义高亮锚点(默认选中第一个)
- const getCurrentAnchor = (activeLink: string): string => {
- if (!activeLink && titles.length > 0) {
- activeLink = titles[0].href;
- }
+ // 监听滚动更新高亮
+ useEffect(() => {
+ if (!preview) return;
+
+ const handleScroll = () => {
+ const elements = getRootElement();
+ if (!elements) return;
+
+ // 找到当前视口中最靠近顶部的标题
+ let closestTitle = null;
+ let minDistance = Infinity;
+
+ elements.forEach((element) => {
+ // 判断哪个标题离视口顶部最近
+ const rect = element.getBoundingClientRect();
+ const distance = Math.abs(rect.top);
+ if (distance < minDistance) {
+ minDistance = distance;
+ closestTitle = element;
+ }
+ });
+
+ if (closestTitle) {
+ const line = (closestTitle as HTMLElement).getAttribute("data-line");
+ if (line) {
+ setActiveLink(`#${line}`);
+ }
+ }
+ };
+
+ preview.addEventListener("scroll", handleScroll);
+ return () => preview.removeEventListener("scroll", handleScroll);
+ }, [preview]);
+
+ // 自定义高亮锚点
+ const getCurrentAnchor = () => {
return activeLink;
};
@@ -71,8 +111,11 @@ const Contents: FC = () => {
) => {
e.preventDefault();
if (link.href && previewView) {
- const targetElement = previewView.querySelector(`[data-line="${link.href}"]`);
+ // 从href中提取data-line值
+ const dataLine = link.href.replace("#", "");
+ const targetElement = previewView.querySelector(`[data-line="${dataLine}"]`);
if (targetElement) {
+ setActiveLink(link.href);
targetElement.scrollIntoView({
behavior: "smooth",
block: "center",
--
Gitee
From b384199738c8fb09b26e4e10d712c7be0e3874eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?wifi=E6=AD=AAf?= <1402772884@qq.com>
Date: Fri, 31 Jan 2025 04:22:54 +0800
Subject: [PATCH 2/2] =?UTF-8?q?feat(mini-markdown-editor):=20=E6=96=B0?=
=?UTF-8?q?=E5=A2=9E=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/assets/images/output-pdf.svg | 1 -
.../src/assets/images/output.svg | 1 +
.../src/assets/styles/preview.css | 1 -
.../src/components/Sidebar/Output.tsx | 73 +++++++++++++++++++
.../src/components/Toolbar/ShowLayout.tsx | 18 +++++
.../src/config/toolbar/base.tsx | 10 +--
.../mini-markdown-editor/src/types/toolbar.ts | 2 +-
.../src/utils/output-html.ts | 54 ++++++++++++++
.../src/utils/output-pdf.ts | 3 +
9 files changed, 154 insertions(+), 9 deletions(-)
delete mode 100644 packages/mini-markdown-editor/src/assets/images/output-pdf.svg
create mode 100644 packages/mini-markdown-editor/src/assets/images/output.svg
create mode 100644 packages/mini-markdown-editor/src/components/Sidebar/Output.tsx
create mode 100644 packages/mini-markdown-editor/src/utils/output-html.ts
create mode 100644 packages/mini-markdown-editor/src/utils/output-pdf.ts
diff --git a/packages/mini-markdown-editor/src/assets/images/output-pdf.svg b/packages/mini-markdown-editor/src/assets/images/output-pdf.svg
deleted file mode 100644
index 04e056a..0000000
--- a/packages/mini-markdown-editor/src/assets/images/output-pdf.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/packages/mini-markdown-editor/src/assets/images/output.svg b/packages/mini-markdown-editor/src/assets/images/output.svg
new file mode 100644
index 0000000..5583c43
--- /dev/null
+++ b/packages/mini-markdown-editor/src/assets/images/output.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/mini-markdown-editor/src/assets/styles/preview.css b/packages/mini-markdown-editor/src/assets/styles/preview.css
index 6080978..dd022b9 100644
--- a/packages/mini-markdown-editor/src/assets/styles/preview.css
+++ b/packages/mini-markdown-editor/src/assets/styles/preview.css
@@ -56,7 +56,6 @@
}
.mini-md-image {
- width: 100%;
max-width: 100%;
border: 1px solid #e6e6e6;
border-radius: 3px;
diff --git a/packages/mini-markdown-editor/src/components/Sidebar/Output.tsx b/packages/mini-markdown-editor/src/components/Sidebar/Output.tsx
new file mode 100644
index 0000000..faa9306
--- /dev/null
+++ b/packages/mini-markdown-editor/src/components/Sidebar/Output.tsx
@@ -0,0 +1,73 @@
+import styled from "styled-components";
+import { Button, Form, Input, Select } from "antd";
+import { exportHTML } from "@/utils/output-html";
+import { useEditorContentStore } from "@/store/editor";
+import { useState } from "react";
+import { exportPdf } from "@/utils/output-pdf";
+
+const Wrapper = styled.div`
+ width: 100%;
+ height: 100%;
+ padding: 10px;
+ color: #3f4a54;
+`;
+
+type FieldType = {
+ "file-type": "PDF" | "HTML";
+ "file-name": string;
+};
+
+const Output = () => {
+ const [form] = Form.useForm();
+ const preview = useEditorContentStore((state) => state.previewView);
+ const [loading, setLoading] = useState(false);
+
+ const handleExport = async () => {
+ const { "file-type": fileType, "file-name": fileName } = form.getFieldsValue();
+ setLoading(true);
+ switch (fileType) {
+ case "PDF": {
+ await exportPdf(preview!, fileName);
+ break;
+ }
+ case "HTML": {
+ if (!preview) return;
+ await exportHTML(preview, fileName);
+ break;
+ }
+ default:
+ break;
+ }
+ setLoading(false);
+ };
+
+ return (
+
+ label="导出文件类型" name="file-type">
+
+
+ label="导出文件名" name="file-name">
+
+
+
+
+
+
+
+ );
+};
+
+export default Output;
diff --git a/packages/mini-markdown-editor/src/components/Toolbar/ShowLayout.tsx b/packages/mini-markdown-editor/src/components/Toolbar/ShowLayout.tsx
index de7727d..736c555 100644
--- a/packages/mini-markdown-editor/src/components/Toolbar/ShowLayout.tsx
+++ b/packages/mini-markdown-editor/src/components/Toolbar/ShowLayout.tsx
@@ -5,9 +5,11 @@ import WriteIcon from "@/assets/images/write.svg?raw";
import PreviewIcon from "@/assets/images/perview.svg?raw";
import ContentsIcon from "@/assets/images/contents.svg?raw";
import HelpIcon from "@/assets/images/help.svg?raw";
+import OutputIcon from "@/assets/images/output.svg?raw";
import { useToolbarStore } from "@/store/toolbar";
import SidebarContents from "@/components/Sidebar/Contents";
import SidebarHelp from "@/components/Sidebar/Help";
+import SidebarOutput from "@/components/Sidebar/Output";
const Wrapper = styled.div<{ $isSelect: boolean }>`
display: flex;
@@ -78,3 +80,19 @@ export const Help: FC = () => {
>
);
};
+
+// 导出按钮
+export const Output: FC = () => {
+ const ComponentsMark = "Output";
+ const { isSidebar, componentMark, setSidebar } = useToolbarStore();
+ return (
+ <>
+ setSidebar(, ComponentsMark)}>
+
+
+ >
+ );
+};
diff --git a/packages/mini-markdown-editor/src/config/toolbar/base.tsx b/packages/mini-markdown-editor/src/config/toolbar/base.tsx
index 8ee235b..5ff8d98 100644
--- a/packages/mini-markdown-editor/src/config/toolbar/base.tsx
+++ b/packages/mini-markdown-editor/src/config/toolbar/base.tsx
@@ -14,13 +14,12 @@ import ImageIcon from "@/assets/images/image.svg";
import TableIcon from "@/assets/images/table.svg";
import Undo from "@/assets/images/undo.svg";
import Redo from "@/assets/images/redo.svg";
-import OutputPDFIcon from "@/assets/images/output-pdf.svg";
import { InsertTextEvent } from "./event";
import { ToolbarItem } from "@/types/toolbar";
// 组件
import Upload from "@/components/Toolbar/Upload";
import FullScreen from "@/components/Toolbar/FullScreen";
-import { Contents, Read, Write, Help } from "@/components/Toolbar/ShowLayout";
+import { Contents, Read, Write, Help, Output } from "@/components/Toolbar/ShowLayout";
export const toolbar: ToolbarItem[] = [
{
@@ -182,13 +181,12 @@ export const toolbar: ToolbarItem[] = [
component: ,
},
{
- type: "pdf",
- icon: OutputPDFIcon,
- title: "导出为PDF",
+ type: "output",
+ component: ,
},
];
-// 渲染其他定制节点
+// 渲染列表其他定制节点
export const render = {
"image-upload": ,
};
diff --git a/packages/mini-markdown-editor/src/types/toolbar.ts b/packages/mini-markdown-editor/src/types/toolbar.ts
index 75647c5..5295325 100644
--- a/packages/mini-markdown-editor/src/types/toolbar.ts
+++ b/packages/mini-markdown-editor/src/types/toolbar.ts
@@ -53,4 +53,4 @@ export type ToolbarType =
| "preview"
| "contents"
| "help"
- | "pdf";
+ | "output";
diff --git a/packages/mini-markdown-editor/src/utils/output-html.ts b/packages/mini-markdown-editor/src/utils/output-html.ts
new file mode 100644
index 0000000..9867b30
--- /dev/null
+++ b/packages/mini-markdown-editor/src/utils/output-html.ts
@@ -0,0 +1,54 @@
+export const exportHTML = (element: HTMLElement, fileName: string) => {
+ return new Promise((resolve) => {
+ if (!element) {
+ console.error("Element not found");
+ return;
+ }
+
+ // 获取元素的HTML内容
+ const htmlContent = element.outerHTML;
+
+ // 获取所有样式
+ const styles = Array.from(document.styleSheets)
+ .map((sheet) => {
+ try {
+ return Array.from(sheet.cssRules)
+ .map((rule) => rule.cssText)
+ .join("\n");
+ } catch (e) {
+ console.error("Error accessing stylesheet:", e);
+ return "";
+ }
+ })
+ .join("\n");
+
+ // 创建包含样式的HTML内容
+ const fullHtmlContent = `
+
+
+
+
+
+ Exported HTML
+
+
+
+ ${htmlContent}
+
+
+ `;
+
+ const blob = new Blob([fullHtmlContent], { type: "text/html" });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement("a");
+ a.href = url;
+ a.download = `${fileName}.html`;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ resolve({});
+ });
+};
diff --git a/packages/mini-markdown-editor/src/utils/output-pdf.ts b/packages/mini-markdown-editor/src/utils/output-pdf.ts
new file mode 100644
index 0000000..6c5c09a
--- /dev/null
+++ b/packages/mini-markdown-editor/src/utils/output-pdf.ts
@@ -0,0 +1,3 @@
+export const exportPdf = async (element: HTMLElement, filename: string) => {
+ console.log(element, filename);
+};
--
Gitee