├── .DS_Store ├── .gitattributes ├── .hintrc ├── 404.html ├── README.md ├── i18n.js ├── images ├── .DS_Store ├── apple-touch-icon.png ├── favicon-16x16.png ├── favicon-2048x2048.png ├── favicon-32x32.png ├── favicon-512x512.png ├── favicon.ico ├── favicon.svg ├── logo.png └── og-image.png ├── index.html ├── package.json ├── privacy.html ├── script.js ├── styles.css └── terms.html /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "development" 4 | ], 5 | "hints": { 6 | "compat-api/html": [ 7 | "default", 8 | { 9 | "ignore": [ 10 | "meta[name=theme-color]" 11 | ] 12 | } 13 | ] 14 | } 15 | } -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 页面未找到 - 404 7 | 149 | 150 | 151 |
152 |
153 | Logo 154 | MD2HTML 155 |
156 |

157 | 一个简单易用的 AI 对话格式转换工具(Markdown 转成 HTML),帮助你快速整理和分享 AI 对话内容,并用于博客、论坛、文档等。 158 |

159 |
160 |

404

161 |

抱歉,您访问的页面不存在

162 | 返回首页试试看 163 |
164 | 165 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MD2HTML - Markdown & HTML Converter 2 | 3 | 一个简单但功能强大的在线 Markdown 和 HTML 互转工具。 4 | 5 | ## 功能特点 6 | 7 | - 🔄 双向转换:支持 Markdown 转 HTML 和 HTML 转 Markdown 8 | - 🌓 深色/浅色主题切换 9 | - 🌐 支持中英文界面切换 10 | - 🧹 自动清理引用标记功能 11 | - 📋 便捷的复制功能 12 | - 💻 完全在浏览器端运行,无需后端服务 13 | 14 | ## 技术栈 15 | 16 | - HTML5 17 | - CSS3 18 | - JavaScript 19 | - [Marked.js](https://marked.js.org/) - Markdown 解析器 20 | - [Turndown](https://github.com/mixmark-io/turndown) - HTML 转 Markdown 工具 21 | 22 | ## 快速开始 23 | 24 | 1. 克隆仓库: 25 | ```bash 26 | git clone https://github.com/yourusername/md2html.git 27 | ``` 28 | 29 | 2. 打开项目目录: 30 | ```bash 31 | cd md2html 32 | ``` 33 | 34 | 3. 使用任意 Web 服务器运行项目,例如: 35 | ```bash 36 | npx serve 37 | ``` 38 | 39 | 4. 在浏览器中访问 `http://localhost:3000` 40 | 41 | ## 使用说明 42 | 43 | 1. 选择转换模式(Markdown 转 HTML 或 HTML 转 Markdown) 44 | 2. 在左侧输入框中粘贴源代码 45 | 3. 点击"转换"按钮 46 | 4. 在右侧查看转换结果 47 | 5. 使用"复制输出"按钮复制转换后的内容 48 | 49 | ## 自定义设置 50 | 51 | - 切换深色/浅色主题 52 | - 切换中英文界面 53 | - 选择是否移除引用标记 54 | 55 | ## 贡献指南 56 | 57 | 欢迎提交 Pull Requests 来改进这个项目。 58 | 59 | ## 许可证 60 | 61 | MIT License - 查看 [LICENSE](LICENSE) 文件了解详情 62 | 63 | ## 联系方式 64 | 65 | 如有问题或建议,请通过以下方式联系: 66 | 67 | - 提交 Issue(推荐) 68 | - 发送邮件至:[hi@md2html.com](mailto:hi@md2html.com) 69 | 70 | ## 致谢 71 | 72 | 感谢以下开源项目: 73 | - Marked.js 74 | - Turndown 75 | -------------------------------------------------------------------------------- /i18n.js: -------------------------------------------------------------------------------- 1 | const i18n = { 2 | en: { 3 | // 页面标题和描述 4 | title: 'Markdown and HTML Converter', 5 | subtitle: 'Specially designed for Wordpress publishing, HTML page generation; Perfect for converting outputs from ChatGPT, Claude, Perplexity and other AI tools to HTML format.', 6 | 7 | // 转换模式 8 | md2html: 'Markdown to HTML', 9 | html2md: 'HTML to Markdown', 10 | 11 | // 输入输出区域 12 | inputTitle: 'Markdown Input', 13 | outputTitle: 'HTML Output', 14 | inputPlaceholder: 'Enter your content here...', 15 | 16 | // 按钮和操作 17 | convert: 'Convert', 18 | copy: 'Copy Output', 19 | download: 'Download HTML', 20 | clearInput: 'Clear Input', 21 | clearOutput: 'Clear Output', 22 | 23 | // 预览控制 24 | preview: 'Preview HTML', 25 | rawHtml: 'Show HTML', 26 | togglePreview: 'Hide Preview', 27 | showPreview: 'Show Preview', 28 | 29 | // 引文控制 30 | removeCitations: 'Remove Citations (From Perplexity.ai)', 31 | 32 | // 提示消息 33 | copySuccess: 'Content copied to clipboard!', 34 | copyError: 'Copy failed, please copy manually', 35 | 36 | // 文档标题 37 | docTitle: 'MD2HTML - Markdown Converter', 38 | 39 | // Footer 部分 40 | footerAboutTitle: "About MD2HTML", 41 | footerAboutText: "MD2HTML is a free online tool that helps users easily convert between Markdown and HTML formats. The product is open source, feel free to send any feedback to hi@md2html.com", 42 | footerAgreementTitle: "User Agreement", 43 | footerPrivacyPolicy: "Privacy Policy", 44 | footerTerms: "Terms of Use", 45 | footerContactTitle: "Contact Us", 46 | footerCopyright: "© 2024 MD2HTML. All rights reserved.", 47 | footerFriendlyLinks: "Friendly Links", 48 | footerWatermark: "Watermark Adder", 49 | footerResearchTitle: "Research Title Generator", 50 | 51 | // 隐私政策翻译 52 | privacyTitle: "Privacy Policy - MD2HTML", 53 | privacyIntroTitle: "Privacy Protection Commitment", 54 | privacyIntroText: "MD2HTML highly values user privacy protection. Our tool is a pure frontend application, all data processing is done locally in your browser and no content is transmitted to servers.", 55 | dataCollectionTitle: "Data Collection", 56 | dataCollectionText: "We do not collect any user data. All content you input in the tool is processed only in your browser, and we cannot access this content.", 57 | localStorageTitle: "Local Storage", 58 | localStorageText: "We only use browser local storage (localStorage) to save your theme preferences (dark/light mode) and language selection. This data is stored entirely on your device and we cannot access it.", 59 | noAccountTitle: "No Account Required", 60 | noAccountText: "Our tool can be used without registration or login, so we do not collect any personal identification information.", 61 | securityTitle: "Security", 62 | securityText: "Since all operations are performed locally, your content always remains private. We recommend using trusted devices and browsers when handling sensitive information.", 63 | 64 | // 使用条款翻译 65 | termsTitle: "Terms of Use - MD2HTML", 66 | termsIntroTitle: "Service Description", 67 | termsIntroText: "MD2HTML provides online Markdown and HTML format conversion services. This tool is completely free and implemented with pure frontend technology, all conversions are performed locally in the user's browser.", 68 | usageTitle: "Usage Guidelines", 69 | usageText: "You can freely use this tool to convert any legal content. We do not review or store user input, but please ensure your use complies with relevant laws and regulations.", 70 | openSourceTitle: "Open Source License", 71 | openSourceText: "MD2HTML is an open source project, you can view the source code on GitHub. Under the open source license, you are free to use, modify and distribute this tool.", 72 | disclaimerTitle: "Disclaimer", 73 | disclaimerText: "This tool is provided 'as is', we make no guarantees about the accuracy of conversion results. Please check the converted content before use. We are not responsible for any direct or indirect losses caused by using this tool.", 74 | updatesTitle: "Terms Updates", 75 | updatesText: "We reserve the right to update these terms at any time. Major changes will be notified to users through website announcements. Continued use of this tool indicates your acceptance of the new terms.", 76 | langSwitchText: '中文', 77 | convertSuccess: 'Conversion successful!', 78 | copySuccess: 'Copied to clipboard!', 79 | copyError: 'Copy failed, please copy manually', 80 | clearSuccess: 'Content cleared', 81 | }, 82 | zh: { 83 | // 页面标题和描述 84 | title: 'Markdown 和 HTML 双向转换', 85 | subtitle: '特别用于 Wordpress 内容发表、HTML 网页生成等场景;适合将 ChatGPT、Claude、Perplexity 等 AI 工具的输出转换为 HTML 格式。', 86 | 87 | // 转换模式 88 | md2html: 'Markdown 转 HTML', 89 | html2md: 'HTML 转 Markdown', 90 | 91 | // 输入输出区域 92 | inputTitle: 'Markdown 输入', 93 | outputTitle: 'HTML 输出', 94 | inputPlaceholder: '在这里输入内容...', 95 | 96 | // 按钮和操作 97 | convert: '转换', 98 | copy: '复制输出', 99 | download: '下载 HTML', 100 | clearInput: '清空输入', 101 | clearOutput: '清空输出', 102 | 103 | // 预览控制 104 | preview: '预览 HTML', 105 | rawHtml: '显示 HTML', 106 | togglePreview: '隐藏预览', 107 | showPreview: '显示预览', 108 | 109 | // 引文控制 110 | removeCitations: '去除引文(来自 Perplexity.ai)', 111 | 112 | // 提示消息 113 | copySuccess: '内容已复制到剪贴板!', 114 | copyError: '复制失败,请手动复制', 115 | 116 | // 文档标题 117 | docTitle: 'MD2HTML - Markdown 转换工具', 118 | 119 | // Footer 部分 120 | footerAboutTitle: "关于 MD2HTML", 121 | footerAboutText: "MD2HTML 是一个免费的在线工具,帮助用户在 Markdown 和 HTML 格式之间轻松转换。产品开源,欢迎反馈任何需求到 hi@md2html.com", 122 | footerAgreementTitle: "用户协议", 123 | footerPrivacyPolicy: "隐私政策", 124 | footerTerms: "使用条款", 125 | footerContactTitle: "联系我们", 126 | footerCopyright: "© 2024 MD2HTML. 保留所有权利。", 127 | footerFriendlyLinks: "友情链接", 128 | footerWatermark: "水印添加器", 129 | footerResearchTitle: "论文标题生成器", 130 | 131 | // 隐私政策翻译 132 | privacyTitle: "隐私政策 - MD2HTML", 133 | privacyIntroTitle: "隐私保护承诺", 134 | privacyIntroText: "MD2HTML 高度重视用户隐私保护。我们的工具是一个纯前端应用程序,所有数据处理都在您的浏览器本地完成,不会将任何内容传输到服务器。", 135 | dataCollectionTitle: "数据收集", 136 | dataCollectionText: "我们不收集任何用户数据。您在工具中输入的所有内容都只在您的浏览器中进行处理,我们无法访问这些内容。", 137 | localStorageTitle: "本地存储", 138 | localStorageText: "我们仅使用浏览器的本地存储(localStorage)来保存您的主题偏好设置(深色/浅色模式)和语言选择。这些数据完全存储在您的设备上,我们无法访问。", 139 | noAccountTitle: "无需账户", 140 | noAccountText: "我们的工具无需注册或登录即可使用,因此我们不会收集任何个人身份信息。", 141 | securityTitle: "安全性", 142 | securityText: "由于所有操作都在本地完成,您的内容始终保持私密。我们建议您在处理敏感信息时,确保使用可信的设备和浏览器。", 143 | 144 | // 使用条款翻译 145 | termsTitle: "使用条款 - MD2HTML", 146 | termsIntroTitle: "服务说明", 147 | termsIntroText: "MD2HTML 提供在线 Markdown 和 HTML 格式转换服务。本工具完全免费,采用纯前端技术实现,所有转换都在用户浏览器本地完成。", 148 | usageTitle: "使用规范", 149 | usageText: "您可以自由使用本工具进行任何合法内容的格式转换。我们不对用户输入的内容进行审查或存储,但请确保您的使用符合相关法律法规。", 150 | openSourceTitle: "开源协议", 151 | openSourceText: "MD2HTML 是一个开源项目,您可以在 GitHub 上查看源代码。在遵守开源协议的前提下,您可以自由使用、修改和分发本工具", 152 | disclaimerTitle: "免责声明", 153 | disclaimerText: "本工具按现状提供,我们不对转换结果的准确性做出保证。请在使用转换后的内容前自行检查。我们不对使用本工具造成的任何直接或间接损失负责", 154 | updatesTitle: "条款更新", 155 | updatesText: "我们保留随时更新这些条款的权利。重大变更会通过网站公告通知用户。继续使用本工具即表示您同意接受新的条款内容", 156 | footerFriendlyLinks: "友情链接", 157 | footerWatermark: "水印添加器", 158 | footerResearchTitle: "论文标题生成器", 159 | langSwitchText: 'English', 160 | convertSuccess: '转换成功!', 161 | copySuccess: '已复制到剪贴板!', 162 | copyError: '复制失败,请手动复制', 163 | clearSuccess: '已清空内容', 164 | } 165 | }; 166 | 167 | // 导出语言包和工具函数 168 | export default i18n; -------------------------------------------------------------------------------- /images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/.DS_Store -------------------------------------------------------------------------------- /images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/apple-touch-icon.png -------------------------------------------------------------------------------- /images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/favicon-16x16.png -------------------------------------------------------------------------------- /images/favicon-2048x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/favicon-2048x2048.png -------------------------------------------------------------------------------- /images/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/favicon-32x32.png -------------------------------------------------------------------------------- /images/favicon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/favicon-512x512.png -------------------------------------------------------------------------------- /images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/favicon.ico -------------------------------------------------------------------------------- /images/favicon.svg: -------------------------------------------------------------------------------- 1 | M2H -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/logo.png -------------------------------------------------------------------------------- /images/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdmaker/Markdown-to-HTML/9fb9f69f82bec2e2403c52f5aa8c74b02e56b31f/images/og-image.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | MD2HTML - Markdown 和 HTML 在线转换工具 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 63 | 64 | 65 | 66 | 80 | 81 |
82 |
83 |

Markdown 和 HTML 双向转换

84 |

特别用于 Wordpress 内容发表、HTML 网页生成等场景;适合将 ChatGPT、Claude、Perplexity 等 AI 工具的输出转换为 HTML 格式。

85 |
86 | 87 |
88 |
89 | 93 |
94 |
95 | 96 | 97 |
98 |
99 | 100 |
101 |
102 |
103 |

Markdown 输入

104 | 105 |
106 | 140 |
141 | 142 | 143 |
144 |
145 |
146 |
147 |

HTML 输出

148 | 149 |
150 |
151 |
152 |
153 |
154 |
155 | 156 | 157 |
158 |
159 |
160 |
161 | 162 | 163 | 203 | 204 | 205 |
206 | 207 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "project", 3 | "lockfileVersion": 1, 4 | "requires": true, 5 | "packages": {} 6 | } 7 | -------------------------------------------------------------------------------- /privacy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 隐私政策 - MD2HTML 7 | 8 | 9 | 10 | 11 | 25 | 26 | 27 |
28 |

隐私政策

29 | 30 |
31 |

隐私保护承诺

32 |

MD2HTML 高度重视用户隐私保护。我们的工具是一个纯前端应用程序,所有数据处理都在您的浏览器本地完成,不会将任何内容传输到服务器。

33 |
34 | 35 |
36 |

数据收集

37 |

我们不收集任何用户数据。您在工具中输入的所有内容都只在您的浏览器中进行处理,我们无法访问这些内容。

38 |
39 | 40 |
41 |

本地存储

42 |

我们仅使用浏览器的本地存储(localStorage)来保存您的主题偏好设置(深色/浅色模式)和语言选择。这些数据完全存储在您的设备上,我们无法访问。

43 |
44 | 45 |
46 |

无需账户

47 |

我们的工具无需注册或登录即可使用,因此我们不会收集任何个人身份信息。

48 |
49 | 50 |
51 |

安全性

52 |

由于所有操作都在本地完成,您的内容始终保持私密。我们建议您在处理敏感信息时,确保使用可信的设备和浏览器。

53 |
54 |
55 | 56 | 57 | 90 | 91 | 174 |
175 | 176 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | import i18n from './i18n.js'; 2 | 3 | let currentLang = 'zh'; 4 | 5 | // 检查是否在英文路径 6 | if (window.location.pathname.includes('/en')) { 7 | currentLang = 'en'; 8 | document.documentElement.lang = 'en'; 9 | } else { 10 | document.documentElement.lang = 'zh-CN'; 11 | } 12 | 13 | function updateThemeIcon() { 14 | const themeIcon = document.querySelector('.theme-icon'); 15 | const isDark = document.documentElement.getAttribute('data-theme') === 'dark'; 16 | themeIcon.textContent = isDark ? '☀️' : '🌙'; 17 | } 18 | 19 | function toggleTheme() { 20 | const currentTheme = document.documentElement.getAttribute('data-theme') || 'light'; 21 | const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; 22 | 23 | document.documentElement.setAttribute('data-theme', newTheme); 24 | localStorage.setItem('theme', newTheme); 25 | updateThemeIcon(); 26 | } 27 | 28 | // 检查系统主题偏好并设置初始主题 29 | function initializeTheme() { 30 | // 先检查本地存储是否有保存的主题设置 31 | const savedTheme = localStorage.getItem('theme'); 32 | if (savedTheme) { 33 | document.documentElement.setAttribute('data-theme', savedTheme); 34 | updateThemeIcon(); 35 | return; 36 | } 37 | 38 | // 如果没有保存的设置,则检查系统偏好 39 | const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; 40 | const initialTheme = prefersDark ? 'dark' : 'light'; 41 | document.documentElement.setAttribute('data-theme', initialTheme); 42 | localStorage.setItem('theme', initialTheme); 43 | updateThemeIcon(); 44 | } 45 | 46 | // 翻译函数 47 | function translateElement(element) { 48 | const key = element.getAttribute('data-i18n'); 49 | if (!key) return; 50 | 51 | const translation = i18n[currentLang][key]; 52 | if (!translation) return; 53 | 54 | // 如果元素有 placeholder 属性,直接设置文本 55 | if (element.hasAttribute('data-i18n-placeholder')) { 56 | element.placeholder = translation; 57 | return; 58 | } 59 | 60 | // 对于其他元素,支持 HTML 内容 61 | element.innerHTML = translation; 62 | } 63 | 64 | // 更新页面上所有需要翻译的元素 65 | function updatePageLanguage() { 66 | document.querySelectorAll('[data-i18n]').forEach(translateElement); 67 | document.title = i18n[currentLang].docTitle; 68 | 69 | // 更新语言切换按钮文本 70 | const langSwitchBtn = document.querySelector('.lang-switch'); 71 | langSwitchBtn.textContent = i18n[currentLang].langSwitchText; 72 | } 73 | 74 | function toggleLanguage() { 75 | const newLang = currentLang === 'zh' ? 'en' : 'zh'; 76 | const newPath = newLang === 'en' ? '/en' : '/'; 77 | window.history.pushState({}, '', newPath); 78 | currentLang = newLang; 79 | document.documentElement.lang = currentLang === 'zh' ? 'zh-CN' : 'en'; 80 | 81 | // 保存当前输入框的内容 82 | const currentInput = document.getElementById('input-area').value; 83 | 84 | // 更新页面语言 85 | updatePageLanguage(); 86 | 87 | // 更新语言切换按钮文本 88 | const langSwitchBtn = document.querySelector('.lang-switch'); 89 | langSwitchBtn.textContent = i18n[currentLang].langSwitchText; 90 | 91 | // 恢复输入框的内容 92 | document.getElementById('input-area').value = currentInput; 93 | 94 | // 更新模式选择 95 | switchMode(); 96 | 97 | // 如果输入框有内容,重新执行转换 98 | if (currentInput.trim()) { 99 | convert(); 100 | } 101 | } 102 | 103 | const turndownService = new TurndownService(); 104 | let currentMode = 'md2html'; 105 | 106 | function removeCitations(markdown) { 107 | let processed = markdown; 108 | 109 | // 移除 Citations: 标题及其下方的引文列表 110 | processed = processed.replace(/Citations:\s*(\n\[\d+\].*)*$/gm, ''); 111 | 112 | // 移除文本中的引文标记 113 | processed = processed.replace(/\[[\d,\s]+\](?:\[\d+\])?/g, ''); 114 | 115 | // 移除 Perplexity 特有的 ***** 格式(包括可能的空格) 116 | processed = processed.replace(/\*{4,}\s*([^\n]+)/g, '$1'); // 添加 \s* 来匹配可选的空格 117 | 118 | // 移除空行 119 | processed = processed.replace(/^\s*[\r\n]/gm, '\n'); 120 | 121 | // 移除多余的空行(超过两个连续空行变成两个) 122 | processed = processed.replace(/\n{3,}/g, '\n\n'); 123 | 124 | return processed.trim(); 125 | } 126 | 127 | function switchMode() { 128 | currentMode = document.getElementById('convert-mode').value; 129 | const citationControl = document.getElementById('citation-control'); 130 | const inputTitle = document.getElementById('input-title'); 131 | const outputTitle = document.getElementById('output-title'); 132 | const inputArea = document.getElementById('input-area'); 133 | const previewArea = document.getElementById('preview-area'); 134 | 135 | if (currentMode === 'md2html') { 136 | inputTitle.textContent = i18n[currentLang].inputTitle; 137 | outputTitle.textContent = i18n[currentLang].outputTitle; 138 | inputArea.placeholder = i18n[currentLang].inputPlaceholder; 139 | citationControl.style.display = 'flex'; 140 | previewArea.style.display = 'block'; 141 | } else { 142 | inputTitle.textContent = 'HTML 输入'; 143 | outputTitle.textContent = 'Markdown 输出'; 144 | inputArea.placeholder = i18n[currentLang].inputPlaceholder; 145 | citationControl.style.display = 'none'; 146 | previewArea.style.display = 'none'; 147 | } 148 | 149 | // 如果有内容,重新执行转换 150 | if (inputArea.value.trim()) { 151 | convert(); 152 | } 153 | } 154 | 155 | function convert() { 156 | const input = document.getElementById('input-area').value; 157 | const mode = document.getElementById('convert-mode').value; 158 | const removeCitationsEnabled = document.getElementById('remove-citations').checked; 159 | 160 | let processedInput = input; 161 | 162 | // 如果启用了去除引文选项,先处理引文 163 | if (removeCitationsEnabled) { 164 | processedInput = removeCitations(processedInput); 165 | } 166 | 167 | let output = ''; 168 | if (mode === 'md2html') { 169 | output = marked.parse(processedInput); 170 | } else { 171 | const turndownService = new TurndownService(); 172 | output = turndownService.turndown(processedInput); 173 | } 174 | 175 | const rawArea = document.getElementById('raw-area'); 176 | rawArea.textContent = output; 177 | 178 | const previewArea = document.getElementById('preview-area'); 179 | previewArea.innerHTML = output; 180 | 181 | // 更新按钮状态 182 | updateButtonStates(); 183 | 184 | showToast(i18n[currentLang].convertSuccess); 185 | } 186 | 187 | function copyOutput() { 188 | const rawArea = document.getElementById('raw-area'); 189 | const content = rawArea.textContent; 190 | 191 | navigator.clipboard.writeText(content) 192 | .then(() => showToast(i18n[currentLang].copySuccess)) 193 | .catch(() => showToast(i18n[currentLang].copyError)); 194 | } 195 | 196 | function clearInput() { 197 | document.getElementById('input-area').value = ''; 198 | convert(); 199 | // 更新按钮状态 200 | updateButtonStates(); 201 | // 添加清空提示 202 | showToast(i18n[currentLang].clearSuccess); 203 | } 204 | 205 | function clearOutput() { 206 | document.getElementById('preview-area').innerHTML = ''; 207 | document.getElementById('raw-area').textContent = ''; 208 | // 更新按钮状态 209 | updateButtonStates(); 210 | // 添加清空提示 211 | showToast(i18n[currentLang].clearSuccess); 212 | } 213 | 214 | document.getElementById('input-area').addEventListener('input', convert); 215 | 216 | // 初始化语言和主题 217 | updatePageLanguage(); 218 | updateThemeIcon(); 219 | initializeTheme(); 220 | 221 | function switchTab(tab) { 222 | const previewArea = document.getElementById('preview-area'); 223 | const rawArea = document.getElementById('raw-area'); 224 | const buttons = document.querySelectorAll('.tab-btn'); 225 | 226 | buttons.forEach(btn => { 227 | btn.classList.remove('active'); 228 | }); 229 | 230 | if (tab === 'preview') { 231 | previewArea.classList.add('active'); 232 | rawArea.classList.remove('active'); 233 | buttons[0].classList.add('active'); 234 | } else { 235 | previewArea.classList.remove('active'); 236 | rawArea.classList.add('active'); 237 | buttons[1].classList.add('active'); 238 | } 239 | } 240 | 241 | function togglePreview() { 242 | const previewArea = document.getElementById('preview-area'); 243 | const rawArea = document.getElementById('raw-area'); 244 | const previewBtn = document.querySelector('.preview-btn'); 245 | 246 | const isPreviewMode = previewArea.classList.contains('active'); 247 | 248 | if (isPreviewMode) { 249 | previewArea.classList.remove('active'); 250 | rawArea.classList.add('active'); 251 | previewBtn.classList.remove('active'); 252 | previewBtn.textContent = i18n[currentLang].preview; 253 | } else { 254 | previewArea.classList.add('active'); 255 | rawArea.classList.remove('active'); 256 | previewBtn.classList.add('active'); 257 | previewBtn.textContent = i18n[currentLang].rawHtml; 258 | } 259 | } 260 | 261 | // 添加 Toast 显示函数 262 | function showToast(message, duration = 2000) { 263 | const toast = document.getElementById('toast'); 264 | toast.textContent = message; 265 | toast.classList.add('show'); 266 | 267 | setTimeout(() => { 268 | toast.classList.remove('show'); 269 | }, duration); 270 | } 271 | 272 | // 为输出区域添加点击复制功能 273 | function initializeOutputCopy() { 274 | const outputWrapper = document.getElementById('output-wrapper'); 275 | outputWrapper.addEventListener('click', (e) => { 276 | if (e.target.closest('.output')) { 277 | const rawArea = document.getElementById('raw-area'); 278 | const content = rawArea.textContent; 279 | 280 | navigator.clipboard.writeText(content) 281 | .then(() => showToast(i18n[currentLang].copySuccess)) 282 | .catch(() => showToast(i18n[currentLang].copyError)); 283 | } 284 | }); 285 | } 286 | 287 | // 在文件末尾初始化 288 | initializeOutputCopy(); 289 | 290 | // 添加下载 HTML 功能 291 | function downloadHtml() { 292 | const rawArea = document.getElementById('raw-area'); 293 | const content = rawArea.textContent; 294 | 295 | // 创建完整的 HTML 文档 296 | const fullHtml = ` 297 | 298 | 299 | 300 | 301 | Generated HTML 302 | 322 | 323 | 324 | ${content} 325 | 326 | `; 327 | 328 | // 创建 Blob 对象 329 | const blob = new Blob([fullHtml], { type: 'text/html' }); 330 | 331 | // 创建下载链接 332 | const url = window.URL.createObjectURL(blob); 333 | const a = document.createElement('a'); 334 | a.href = url; 335 | a.download = 'converted.html'; 336 | 337 | // 触发下载 338 | document.body.appendChild(a); 339 | a.click(); 340 | 341 | // 清理 342 | window.URL.revokeObjectURL(url); 343 | document.body.removeChild(a); 344 | 345 | // 显示提示 346 | showToast(i18n[currentLang].copySuccess); 347 | } 348 | 349 | // 修改按钮状态更新函数 350 | function updateButtonStates() { 351 | const rawArea = document.getElementById('raw-area'); 352 | const copyButton = document.querySelector('.output-buttons button[data-i18n="copy"]'); 353 | const downloadButton = document.querySelector('.output-buttons button[data-i18n="download"]'); 354 | 355 | // 检查输出区域是否有内容 356 | const hasContent = rawArea.textContent.trim().length > 0; 357 | 358 | // 根据内容状态启用/禁用按钮 359 | if (copyButton) copyButton.disabled = !hasContent; 360 | if (downloadButton) downloadButton.disabled = !hasContent; 361 | } 362 | 363 | // 初始化时调用一次 364 | updateButtonStates(); 365 | 366 | // 确保在 DOM 加载完成后初始化主题 367 | document.addEventListener('DOMContentLoaded', initializeTheme); 368 | 369 | // 将函数直接挂载到 window 对象上,确保全局可用 370 | window.toggleTheme = toggleTheme; 371 | window.toggleLanguage = toggleLanguage; 372 | window.switchMode = switchMode; 373 | window.convert = convert; 374 | window.copyOutput = copyOutput; 375 | window.clearInput = clearInput; 376 | window.clearOutput = clearOutput; 377 | window.togglePreview = togglePreview; 378 | window.downloadHtml = downloadHtml; 379 | 380 | // 导些函数以供模块化使用 381 | export { 382 | toggleTheme, 383 | toggleLanguage, 384 | switchMode, 385 | convert, 386 | copyOutput, 387 | clearInput, 388 | clearOutput, 389 | togglePreview, 390 | downloadHtml 391 | }; 392 | 393 | // 在文件开头添加这个函数 394 | function initializeWithDefaultContent() { 395 | // 获取输入内容 396 | const input = document.getElementById('input-area').value; 397 | if (input.trim()) { 398 | // 如果有默认内容,静默执行转换,不显示 Toast 399 | const mode = document.getElementById('convert-mode').value; 400 | const removeCitationsEnabled = document.getElementById('remove-citations').checked; 401 | 402 | let processedInput = input; 403 | 404 | if (removeCitationsEnabled) { 405 | processedInput = removeCitations(processedInput); 406 | } 407 | 408 | let output = ''; 409 | if (mode === 'md2html') { 410 | output = marked.parse(processedInput); 411 | } else { 412 | const turndownService = new TurndownService(); 413 | output = turndownService.turndown(processedInput); 414 | } 415 | 416 | const rawArea = document.getElementById('raw-area'); 417 | rawArea.textContent = output; 418 | 419 | const previewArea = document.getElementById('preview-area'); 420 | previewArea.innerHTML = output; 421 | 422 | // 更新按钮状态 423 | updateButtonStates(); 424 | } 425 | } 426 | 427 | // 在 DOMContentLoaded 事件中调用初始化函数 428 | document.addEventListener('DOMContentLoaded', () => { 429 | initializeWithDefaultContent(); 430 | updatePageLanguage(); // 确保语言切换按钮文本被正确设置 431 | }); -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /* 亮色主题(默认) */ 2 | :root { 3 | --background: #ffffff; 4 | --foreground: #020817; 5 | --muted: #f1f5f9; 6 | --muted-foreground: #64748b; 7 | --border: #e2e8f0; 8 | --input: #e2e8f0; 9 | --primary: #18181b; 10 | --primary-foreground: #ffffff; 11 | --ring: #18181b; 12 | --radius: 0.5rem; 13 | --navbar-bg: #ffffff; 14 | --navbar-border: #e2e8f0; 15 | } 16 | 17 | /* 暗色主题 */ 18 | [data-theme="dark"] { 19 | --background: #020817; 20 | --foreground: #ffffff; 21 | --muted: #1e293b; 22 | --muted-foreground: #94a3b8; 23 | --border: #1e293b; 24 | --input: #1e293b; 25 | --primary: #ffffff; 26 | --primary-foreground: #020817; 27 | --ring: #cbd5e1; 28 | --navbar-bg: #0f172a; 29 | --navbar-border: #1e293b; 30 | } 31 | 32 | * { 33 | margin: 0; 34 | padding: 0; 35 | box-sizing: border-box; 36 | } 37 | 38 | body { 39 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; 40 | background-color: var(--background); 41 | color: var(--foreground); 42 | line-height: 1.5; 43 | transition: background-color 0.3s ease, color 0.3s ease; 44 | } 45 | 46 | .navbar { 47 | background-color: var(--navbar-bg); 48 | border-bottom: 1px solid var(--navbar-border); 49 | padding: 1rem; 50 | position: sticky; 51 | top: 0; 52 | z-index: 100; 53 | transition: background-color 0.3s ease, border-color 0.3s ease; 54 | } 55 | 56 | .navbar-container { 57 | max-width: 1200px; 58 | margin: 0 auto; 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | } 63 | 64 | .logo { 65 | font-size: 1.5rem; 66 | font-weight: 700; 67 | color: var(--foreground); 68 | text-decoration: none; 69 | letter-spacing: -0.025em; 70 | } 71 | 72 | .navbar-controls { 73 | display: flex; 74 | gap: 1rem; 75 | align-items: center; 76 | } 77 | 78 | .theme-switch, .lang-switch { 79 | padding: 0.5rem; 80 | background: transparent; 81 | border: 1px solid var(--border); 82 | border-radius: var(--radius); 83 | color: var(--foreground); 84 | cursor: pointer; 85 | display: flex; 86 | align-items: center; 87 | justify-content: center; 88 | transition: all 0.2s ease; 89 | } 90 | 91 | .theme-switch:hover, .lang-switch:hover { 92 | background-color: var(--muted); 93 | } 94 | 95 | .main-content { 96 | max-width: 1200px; 97 | margin: 0 auto; 98 | padding: 1.5rem; 99 | } 100 | 101 | .container { 102 | display: grid; 103 | grid-template-columns: minmax(400px, 1fr) minmax(400px, 1fr); 104 | gap: 1.5rem; 105 | margin-top: 1.5rem; 106 | } 107 | 108 | textarea { 109 | width: 100%; 110 | height: 300px; 111 | padding: 0.75rem; 112 | background-color: var(--background); 113 | border: 2px solid var(--border); 114 | border-radius: var(--radius); 115 | color: var(--foreground); 116 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; 117 | font-size: 0.875rem; 118 | line-height: 1.5; 119 | resize: vertical; 120 | transition: all 0.2s ease; 121 | } 122 | 123 | /* 修改聚焦时的样式 */ 124 | textarea:focus { 125 | outline: none; 126 | border-color: var(--primary); 127 | border-width: 2px; 128 | box-shadow: none; 129 | } 130 | 131 | .output { 132 | height: 400px; 133 | padding: 0.75rem; 134 | background-color: var(--muted); 135 | border: 1px solid var(--border); 136 | border-radius: var(--radius); 137 | color: var(--foreground); 138 | font-size: 0.875rem; 139 | line-height: 1.5; 140 | overflow-y: auto; 141 | white-space: pre-wrap; 142 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; 143 | } 144 | 145 | .header { 146 | display: flex; 147 | flex-direction: column; 148 | gap: 0.5rem; 149 | margin-bottom: 1.5rem; 150 | text-align: left; 151 | } 152 | 153 | .header h1 { 154 | font-size: 2rem; 155 | line-height: 1.2; 156 | } 157 | 158 | .subtitle { 159 | font-size: 1rem; 160 | color: var(--muted-foreground); 161 | } 162 | 163 | .controls { 164 | display: flex; 165 | flex-wrap: wrap; 166 | gap: 1rem; 167 | margin-bottom: 1rem; 168 | align-items: center; 169 | } 170 | 171 | .mode-switch { 172 | flex: 1; 173 | min-width: 200px; 174 | } 175 | 176 | .citation-control { 177 | display: flex; 178 | align-items: center; 179 | gap: 0.5rem; 180 | margin-left: auto; 181 | color: var(--muted-foreground); 182 | font-size: 0.875rem; 183 | } 184 | 185 | .citation-control input[type="checkbox"] { 186 | width: 14px; 187 | height: 14px; 188 | margin: 0; 189 | vertical-align: middle; 190 | position: relative; 191 | top: -1px; 192 | } 193 | 194 | select { 195 | padding: 0.5rem 2.5rem 0.5rem 0.75rem; 196 | background-color: var(--background); 197 | background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); 198 | background-position: right 0.5rem center; 199 | background-repeat: no-repeat; 200 | background-size: 1.5em 1.5em; 201 | border: 1px solid var(--border); 202 | border-radius: var(--radius); 203 | color: var(--foreground); 204 | font-size: 0.875rem; 205 | line-height: 1.25rem; 206 | appearance: none; 207 | } 208 | 209 | select:focus { 210 | outline: none; 211 | border-color: var(--ring); 212 | box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--ring); 213 | } 214 | 215 | button { 216 | display: inline-flex; 217 | align-items: center; 218 | justify-content: center; 219 | padding: 0.5rem 1rem; 220 | background-color: var(--primary); 221 | color: var(--primary-foreground); 222 | font-size: 0.875rem; 223 | font-weight: 500; 224 | line-height: 1.25rem; 225 | border: 1px solid var(--primary); 226 | border-radius: var(--radius); 227 | cursor: pointer; 228 | transition: all 0.2s ease; 229 | } 230 | 231 | button:hover { 232 | opacity: 0.9; 233 | } 234 | 235 | button:focus { 236 | outline: none; 237 | box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--ring); 238 | } 239 | 240 | .buttons { 241 | display: flex; 242 | gap: 0.5rem; 243 | justify-content: flex-end; 244 | margin-top: 1rem; 245 | } 246 | 247 | .input-label, .output-label { 248 | display: flex; 249 | justify-content: space-between; 250 | align-items: center; 251 | margin-bottom: 0.5rem; 252 | } 253 | 254 | .input-label button, .output-label button { 255 | background-color: transparent; 256 | border-color: transparent; 257 | color: var(--muted-foreground); 258 | padding: 0.25rem 0.5rem; 259 | font-size: 0.75rem; 260 | } 261 | 262 | .input-label button:hover, .output-label button:hover { 263 | background-color: var(--muted); 264 | } 265 | 266 | @media (max-width: 900px) { 267 | .container { 268 | grid-template-columns: 1fr; 269 | } 270 | 271 | textarea, .output { 272 | min-width: 100%; 273 | } 274 | 275 | .navbar-container { 276 | flex-direction: column; 277 | gap: 1rem; 278 | } 279 | } 280 | 281 | .preview-area { 282 | margin-top: 1rem; 283 | border: 1px solid var(--border); 284 | border-radius: var(--radius); 285 | display: none; /* 默认隐藏 */ 286 | } 287 | 288 | .preview-area.active { 289 | display: block; 290 | } 291 | 292 | .preview-header { 293 | display: flex; 294 | justify-content: space-between; 295 | align-items: center; 296 | padding: 0.5rem 1rem; 297 | border-bottom: 1px solid var(--border); 298 | background: var(--muted); 299 | } 300 | 301 | .preview-header h3 { 302 | margin: 0; 303 | font-size: 0.9rem; 304 | color: var(--muted-foreground); 305 | } 306 | 307 | .preview-toggle { 308 | font-size: 0.8rem; 309 | padding: 0.25rem 0.5rem; 310 | } 311 | 312 | .preview-content { 313 | padding: 1rem; 314 | max-height: 200px; 315 | overflow-y: auto; 316 | background: var(--background); 317 | } 318 | 319 | /* 预览区域的内容样式 */ 320 | .preview-content h1, 321 | .preview-content h2, 322 | .preview-content h3, 323 | .preview-content h4, 324 | .preview-content h5, 325 | .preview-content h6 { 326 | margin-top: 0.5em; 327 | margin-bottom: 0.5em; 328 | } 329 | 330 | .preview-content p { 331 | margin: 0.5em 0; 332 | } 333 | 334 | .preview-content code { 335 | background: var(--muted); 336 | padding: 0.2em 0.4em; 337 | border-radius: 3px; 338 | } 339 | 340 | .preview-content pre { 341 | background: var(--muted); 342 | padding: 1em; 343 | border-radius: var(--radius); 344 | overflow-x: auto; 345 | } 346 | 347 | .tab-controls { 348 | display: flex; 349 | justify-content: center; 350 | gap: 1rem; 351 | margin-bottom: 1rem; 352 | padding: 0.5rem 0; 353 | } 354 | 355 | .tab-btn { 356 | background: transparent; 357 | border: none; 358 | color: var(--muted-foreground); 359 | padding: 0.5rem 1.5rem; 360 | font-size: 1rem; 361 | font-weight: 500; 362 | position: relative; 363 | transition: all 0.2s ease; 364 | } 365 | 366 | .tab-btn:hover { 367 | color: var(--foreground); 368 | } 369 | 370 | .tab-btn.active { 371 | color: var(--foreground); 372 | } 373 | 374 | .tab-btn.active::after { 375 | content: ''; 376 | position: absolute; 377 | bottom: 0; 378 | left: 0; 379 | width: 100%; 380 | height: 2px; 381 | background-color: var(--foreground); 382 | border-radius: 2px; 383 | } 384 | 385 | #output-wrapper { 386 | border: 1px solid var(--border); 387 | border-radius: var(--radius); 388 | height: 400px; 389 | position: relative; 390 | margin-top: 0; 391 | } 392 | 393 | #output-wrapper .output { 394 | position: absolute; 395 | top: 0; 396 | left: 0; 397 | right: 0; 398 | bottom: 0; 399 | height: 300px; 400 | padding: 1rem; 401 | display: none; 402 | overflow-y: auto; 403 | background: var(--background); 404 | } 405 | 406 | #output-wrapper .output.active { 407 | display: block; 408 | } 409 | 410 | /* 预览模式下的样式 */ 411 | #preview-area { 412 | white-space: normal; 413 | height: 300px; 414 | padding: 1rem; 415 | line-height: 1.6; 416 | } 417 | 418 | #preview-area h1, 419 | #preview-area h2, 420 | #preview-area h3, 421 | #preview-area h4, 422 | #preview-area h5, 423 | #preview-area h6 { 424 | margin: 1em 0 0.5em; 425 | } 426 | 427 | #preview-area p { 428 | margin: 0.5em 0; 429 | } 430 | 431 | #preview-area code { 432 | background: var(--muted); 433 | padding: 0.2em 0.4em; 434 | border-radius: 3px; 435 | } 436 | 437 | #preview-area pre { 438 | background: var(--muted); 439 | padding: 1em; 440 | border-radius: var(--radius); 441 | overflow-x: auto; 442 | } 443 | 444 | .output-label { 445 | display: flex; 446 | justify-content: space-between; 447 | align-items: center; 448 | margin-bottom: 0.5rem; 449 | } 450 | 451 | .preview-btn { 452 | background: transparent; 453 | border: none; 454 | color: var(--muted-foreground); 455 | padding: 0.25rem 0.75rem; 456 | font-size: 0.875rem; 457 | border-radius: var(--radius); 458 | cursor: pointer; 459 | transition: all 0.2s ease; 460 | } 461 | 462 | .preview-btn:hover { 463 | color: var(--foreground); 464 | } 465 | 466 | .preview-btn.active { 467 | color: var(--foreground); 468 | background: transparent; 469 | border: none; 470 | font-weight: 500; 471 | } 472 | 473 | #output-wrapper { 474 | border: 1px solid var(--border); 475 | border-radius: var(--radius); 476 | height: 400px; 477 | position: relative; 478 | } 479 | 480 | #output-wrapper .output { 481 | position: absolute; 482 | top: 0; 483 | left: 0; 484 | right: 0; 485 | bottom: 0; 486 | height: 300px; 487 | padding: 1rem; 488 | display: none; 489 | overflow-y: auto; 490 | background: var(--background); 491 | } 492 | 493 | #output-wrapper .output.active { 494 | display: block; 495 | } 496 | 497 | .toast { 498 | position: fixed; 499 | bottom: 2rem; 500 | left: 50%; 501 | transform: translateX(-50%); 502 | background: var(--primary); 503 | color: var(--primary-foreground); 504 | padding: 0.75rem 1.5rem; 505 | border-radius: var(--radius); 506 | font-size: 0.875rem; 507 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); 508 | z-index: 1000; 509 | opacity: 0; 510 | transition: opacity 0.3s ease; 511 | pointer-events: none; 512 | } 513 | 514 | .toast.show { 515 | opacity: 1; 516 | } 517 | 518 | /* 让输出区域看起来可点击 */ 519 | #output-wrapper .output { 520 | cursor: pointer; 521 | } 522 | 523 | #output-wrapper .output:hover { 524 | background: var(--muted); 525 | } 526 | 527 | .perplexity-link { 528 | color: var(--primary); 529 | text-decoration: none; 530 | font-weight: 500; 531 | padding: 0.1em 0.3em; 532 | border-radius: var(--radius); 533 | transition: all 0.2s ease; 534 | } 535 | 536 | .perplexity-link:hover { 537 | background: var(--muted); 538 | text-decoration: underline; 539 | } 540 | 541 | [data-theme="dark"] .perplexity-link { 542 | color: #94a3b8; 543 | } 544 | 545 | [data-theme="dark"] .perplexity-link:hover { 546 | color: var(--foreground); 547 | } 548 | 549 | /* 调整 header 部分的响应式布局 */ 550 | .header { 551 | display: flex; 552 | flex-direction: column; 553 | gap: 0.5rem; 554 | margin-bottom: 1.5rem; 555 | text-align: left; 556 | } 557 | 558 | .header h1 { 559 | font-size: 2rem; 560 | line-height: 1.2; 561 | } 562 | 563 | .subtitle { 564 | font-size: 1rem; 565 | color: var(--muted-foreground); 566 | } 567 | 568 | /* 调整控制区域的响应式布局 */ 569 | .controls { 570 | display: flex; 571 | flex-wrap: wrap; 572 | gap: 1rem; 573 | margin-bottom: 1rem; 574 | align-items: center; 575 | } 576 | 577 | .mode-switch { 578 | flex: 1; 579 | min-width: 200px; 580 | } 581 | 582 | .citation-control { 583 | display: flex; 584 | align-items: center; 585 | gap: 0.5rem; 586 | margin-left: auto; 587 | color: var(--muted-foreground); 588 | font-size: 0.875rem; 589 | } 590 | 591 | .citation-control input[type="checkbox"] { 592 | width: 14px; 593 | height: 14px; 594 | margin: 0; 595 | vertical-align: middle; 596 | position: relative; 597 | top: -1px; 598 | } 599 | 600 | /* 移动端适配 */ 601 | @media (max-width: 640px) { 602 | .citation-control { 603 | margin-left: 0; 604 | width: 100%; 605 | } 606 | } 607 | 608 | /* 修改导航栏的响应式布局 */ 609 | @media (max-width: 640px) { 610 | .navbar { 611 | padding: 0.75rem; /* 减小内边距 */ 612 | } 613 | 614 | .navbar-container { 615 | flex-direction: row; /* 改回横向排列 */ 616 | justify-content: space-between; /* 两端对齐 */ 617 | align-items: center; 618 | padding: 0; 619 | gap: 0.5rem; /* 减小间距 */ 620 | } 621 | 622 | .logo { 623 | font-size: 1.25rem; /* 稍微减小 logo 字体小 */ 624 | } 625 | 626 | .navbar-controls { 627 | gap: 0.5rem; /* 减小控制按钮之间的间距 */ 628 | } 629 | 630 | .theme-switch, .lang-switch { 631 | padding: 0.35rem; /* 减小按钮内边距 */ 632 | font-size: 0.875rem; /* 减小按钮文字大小 */ 633 | } 634 | } 635 | 636 | /* 调整中等屏幕的布局 */ 637 | @media (min-width: 641px) and (max-width: 1024px) { 638 | .container { 639 | grid-template-columns: 1fr; 640 | gap: 1.5rem; 641 | } 642 | 643 | .header h1 { 644 | font-size: 1.75rem; 645 | } 646 | 647 | .main-content { 648 | padding: 1.25rem; 649 | } 650 | } 651 | 652 | /* 优化按钮在移动端的显示 */ 653 | .buttons button { 654 | width: 100%; 655 | padding: 0.5rem; 656 | white-space: nowrap; 657 | } 658 | 659 | /* 优化链接在移动端的显示 */ 660 | .perplexity-link { 661 | display: inline-block; 662 | margin: 0.2em 0; 663 | } 664 | 665 | /* 优化 Toast 在移动端的显示 */ 666 | @media (max-width: 640px) { 667 | .toast { 668 | width: calc(100% - 2rem); 669 | margin: 0 1rem; 670 | text-align: center; 671 | } 672 | } 673 | 674 | button:disabled { 675 | opacity: 0.5; 676 | cursor: not-allowed; 677 | pointer-events: none; 678 | } 679 | 680 | .brand { 681 | display: flex; 682 | align-items: center; 683 | gap: 0.75rem; 684 | } 685 | 686 | .logo-image { 687 | width: 28px; 688 | height: 28px; 689 | object-fit: contain; 690 | } 691 | 692 | /* 在移动端适配中 */ 693 | @media (max-width: 640px) { 694 | .brand { 695 | gap: 0.5rem; 696 | } 697 | 698 | .logo-image { 699 | width: 24px; 700 | height: 24px; 701 | } 702 | } 703 | 704 | /* Footer 样式 */ 705 | .footer { 706 | background-color: var(--background-secondary); 707 | padding: 3rem 1rem 1rem; 708 | margin-top: 4rem; 709 | border-top: 1px solid var(--border-color); 710 | } 711 | 712 | .footer-content { 713 | max-width: 1200px; 714 | margin: 0 auto; 715 | display: grid; 716 | grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); 717 | gap: 2rem; 718 | padding: 0 1rem; 719 | } 720 | 721 | .footer-section h3 { 722 | color: var(--text-primary); 723 | font-size: 1.1rem; 724 | margin-bottom: 1rem; 725 | } 726 | 727 | .footer-section p { 728 | color: var(--text-secondary); 729 | line-height: 1.6; 730 | } 731 | 732 | .footer-section ul { 733 | list-style: none; 734 | padding: 0; 735 | } 736 | 737 | .footer-section ul li { 738 | margin-bottom: 0.5rem; 739 | } 740 | 741 | .footer-section a { 742 | color: var(--primary); 743 | text-decoration: none; 744 | font-weight: normal; 745 | padding: 0.1em 0.3em; 746 | border-radius: var(--radius); 747 | transition: all 0.2s ease; 748 | } 749 | 750 | .footer-section a:hover { 751 | background: var(--muted); 752 | text-decoration: underline; 753 | } 754 | 755 | [data-theme="dark"] .footer-section a { 756 | color: #94a3b8; 757 | } 758 | 759 | [data-theme="dark"] .footer-section a:hover { 760 | color: var(--foreground); 761 | } 762 | 763 | .social-links { 764 | display: flex; 765 | gap: 1rem; 766 | } 767 | 768 | .social-icon { 769 | color: var(--primary); 770 | transition: color 0.2s, transform 0.2s; 771 | width: 24px; 772 | height: 24px; 773 | } 774 | 775 | .social-icon:hover { 776 | color: var(--primary); 777 | opacity: 0.8; 778 | transform: scale(1.1); 779 | } 780 | 781 | [data-theme="dark"] .social-icon { 782 | color: #94a3b8; 783 | } 784 | 785 | [data-theme="dark"] .social-icon:hover { 786 | color: var(--foreground); 787 | } 788 | 789 | .footer-bottom { 790 | max-width: 1200px; 791 | margin: 2rem auto 0; 792 | padding: 1rem; 793 | text-align: center; 794 | border-top: 1px solid var(--border-color); 795 | color: var(--text-secondary); 796 | font-size: 0.9rem; 797 | } 798 | 799 | /* 响应式调整 */ 800 | @media (max-width: 768px) { 801 | .footer-content { 802 | grid-template-columns: 1fr; 803 | text-align: center; 804 | } 805 | 806 | .social-links { 807 | justify-content: center; 808 | } 809 | } 810 | 811 | /* 政策页面样式 */ 812 | .policy-content { 813 | max-width: 800px; 814 | margin: 2rem auto; 815 | padding: 0 1.5rem; 816 | } 817 | 818 | .policy-section { 819 | margin: 2rem 0; 820 | } 821 | 822 | .policy-section h2 { 823 | color: var(--foreground); 824 | font-size: 1.5rem; 825 | margin-bottom: 1rem; 826 | } 827 | 828 | .policy-section p { 829 | color: var(--muted-foreground); 830 | line-height: 1.6; 831 | margin-bottom: 1rem; 832 | } 833 | 834 | /* 响应式调整 */ 835 | @media (max-width: 640px) { 836 | .policy-content { 837 | margin: 1rem auto; 838 | padding: 0 1rem; 839 | } 840 | 841 | .policy-section { 842 | margin: 1.5rem 0; 843 | } 844 | 845 | .policy-section h2 { 846 | font-size: 1.25rem; 847 | } 848 | } 849 | 850 | /* 列表样式 */ 851 | ul, ol { 852 | padding-left: 2em; 853 | margin: 1em 0; 854 | } 855 | 856 | /* 嵌套列表的样式 */ 857 | ul ul, 858 | ul ol, 859 | ol ul, 860 | ol ol { 861 | margin: 0.5em 0; 862 | padding-left: 2em; 863 | } 864 | 865 | /* 列表项样式 */ 866 | li { 867 | margin: 0.5em 0; 868 | } 869 | 870 | /* 引用块样式 */ 871 | blockquote { 872 | margin: 1.5em 0; 873 | padding: 1em 1.5em; 874 | border-left: 4px solid #ddd; 875 | background-color: #f8f9fa; 876 | color: #555; 877 | } 878 | 879 | /* 深色模式下的引用块样式 */ 880 | [data-theme="dark"] blockquote { 881 | background-color: #1a1a1a; 882 | border-left-color: #444; 883 | color: #bbb; 884 | } 885 | 886 | /* 预览区域样式 */ 887 | #preview-area { 888 | padding: 2em; 889 | line-height: 1.6; 890 | } 891 | 892 | /* 确保预览区域内的列表和引用块样式正确显示 */ 893 | #preview-area ul, 894 | #preview-area ol { 895 | padding-left: 2em; 896 | margin: 1em 0; 897 | } 898 | 899 | #preview-area blockquote { 900 | margin: 1.5em 0; 901 | padding: 1em 1.5em; 902 | } 903 | 904 | /* 左右两个主容器的样式 */ 905 | .container > div { 906 | display: flex; 907 | flex-direction: column; 908 | min-height: 400px; 909 | } 910 | 911 | /* 文本区域和输出区域的样式 */ 912 | textarea, #output-wrapper { 913 | flex: 1; /* 让文本区域和输出区域占据剩余空间 */ 914 | height: 300px; /* 统一设置为 300px */ 915 | margin-bottom: 1rem; 916 | } 917 | 918 | /* 输入区域按钮组 */ 919 | .input-buttons { 920 | display: flex; 921 | gap: 0.5rem; 922 | margin-top: auto; /* 将按钮组推到底部 */ 923 | } 924 | 925 | /* 输出区域按钮组 */ 926 | .output-buttons { 927 | display: flex; 928 | gap: 0.5rem; 929 | margin-top: auto; /* 将按钮组推到底部 */ 930 | } 931 | 932 | /* 确保按钮样式一致 */ 933 | .input-buttons button, 934 | .output-buttons button { 935 | flex: 1; 936 | min-width: 0; 937 | white-space: nowrap; 938 | } 939 | 940 | /* 移动端适配 */ 941 | @media (max-width: 640px) { 942 | .input-buttons, 943 | .output-buttons { 944 | flex-direction: column; 945 | } 946 | } -------------------------------------------------------------------------------- /terms.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 使用条款 - MD2HTML 7 | 8 | 9 | 10 | 11 | 25 | 26 | 27 |
28 |

使用条款

29 | 30 |
31 |

服务说明

32 |

MD2HTML 提供在线 Markdown 和 HTML 格式转换服务。本工具完全免费,采用纯前端技术实现,所有转换都在用户浏览器本地完成。

33 |
34 | 35 |
36 |

使用规范

37 |

您可以自由使用本工具进行任何合法内容的格式转换。我们不对用户输入的内容进行审查或存储,但请确保您的使用符合相关法律法规。

38 |
39 | 40 |
41 |

开源协议

42 |

MD2HTML 是一个开源项目,您可以在 GitHub 上查看源代码。在遵守开源协议的前提下,您可以自由使用、修改和分发本工具。

43 |
44 | 45 |
46 |

免责声明

47 |

本工具按"现状"提供,我们不对转换结果的准确性做出保证。请在使用转换后的内容前自行检查。我们不对使用本工具造成的任何直接或间接损失负责。

48 |
49 | 50 |
51 |

条款更新

52 |

我们保留随时更新这些条款的权利。重大变更会通过网站公告通知用户。继续使用本工具即表示您同意接受新的条款内容。

53 |
54 |
55 | 56 | 57 | 90 | 91 | 174 |
175 | 176 | --------------------------------------------------------------------------------