From 272bcae9049c9d813999f7fcdb5754eebe8d326a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Fri, 22 May 2026 22:46:13 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=20MarkdownToHtml?= =?UTF-8?q?=20=E9=A2=84=E8=A7=88=E6=A0=B7=E5=BC=8F=EF=BC=8C=E5=89=A5?= =?UTF-8?q?=E7=A6=BB=20CSS=20=E5=8F=98=E9=87=8F=E5=9B=9E=E9=80=80=E5=80=BC?= =?UTF-8?q?=E5=B9=B6=E5=A2=9E=E5=BC=BA=20iframe=20=E6=9A=97=E8=89=B2?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E8=87=AA=E9=80=82=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/MarkdownToHtml/index.tsx | 98 +++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 36 deletions(-) diff --git a/pages/MarkdownToHtml/index.tsx b/pages/MarkdownToHtml/index.tsx index 3e9b346..cd86703 100644 --- a/pages/MarkdownToHtml/index.tsx +++ b/pages/MarkdownToHtml/index.tsx @@ -4,7 +4,7 @@ import { useLazyTranslation } from '@/utils/useLazyTranslation'; import PageHeader from '@/components/PageHeader'; import CopyButton from '@/components/CopyButton'; import SwitchButtonGroup from '@/components/SwitchButtonGroup'; -import { Button } from '@/components/ui/button'; // 💡 1. 全面回归原子组件规范 +import { Button } from '@/components/ui/button'; import { useStorageState } from '@/utils/useStorageState'; import type { MarkdownToHtmlPreviewMode } from '@/types/storage'; import { @@ -19,41 +19,43 @@ import { cn } from '@/lib/utils'; const isValidPreviewMode = (val: unknown): val is MarkdownToHtmlPreviewMode => typeof val === 'string' && ['split', 'preview', 'html'].includes(val); -// 💡 2. 样式超进化:将实色系全部改为标准 rgba 通道,确保在 iframe 内部能跟随宿主主题自适应混色 +// 💡 规范回归:保持最纯净的通用选择器集合,内部变量全部交由全局 :root 驱动 const PREVIEW_STYLES = ` .markdown-body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; - color: var(--md-foreground, #1f2328); + color: var(--md-foreground); background-color: transparent; + font-size: 14px; } .markdown-body h1, .markdown-body h2, .markdown-body h3 { margin-top: 24px; margin-bottom: 16px; font-weight: 600; line-height: 1.25; + color: var(--md-foreground); } - .markdown-body h1 { font-size: 1.6em; border-bottom: 1px solid var(--md-border, rgba(128,128,128,0.2)); padding-bottom: 0.3em; } - .markdown-body h2 { font-size: 1.35em; border-bottom: 1px solid var(--md-border, rgba(128,128,128,0.2)); padding-bottom: 0.3em; } - .markdown-body p { margin-top: 0; margin-bottom: 16px; font-size: 14px; } - .markdown-body a { color: #2563eb; text-decoration: none; } + .markdown-body h1 { border-bottom: 1px solid var(--md-border); padding-bottom: 0.3em; font-size: 1.6em; } + .markdown-body h2 { border-bottom: 1px solid var(--md-border); padding-bottom: 0.3em; font-size: 1.35em; } + .markdown-body p { margin-top: 0; margin-bottom: 16px; } + .markdown-body a { color: #3b82f6; text-decoration: none; } .markdown-body a:hover { text-decoration: underline; } .markdown-body code { - background-color: var(--md-code-bg, rgba(128,128,128,0.08)); + background-color: var(--md-code-bg); border-radius: 4px; font-size: 85%; padding: 0.2em 0.4em; font-family: Menlo, Consolas, monospace; } .markdown-body pre { - background-color: var(--md-pre-bg, rgba(128,128,128,0.05)); + background-color: var(--md-pre-bg); border-radius: 8px; font-size: 85%; line-height: 1.45; overflow: auto; padding: 16px; margin: 0 0 16px; - border: 1px solid var(--md-border, rgba(128,128,128,0.15)); + border: 1px solid var(--md-border); } .markdown-body pre code { background-color: transparent; @@ -61,8 +63,8 @@ const PREVIEW_STYLES = ` padding: 0; } .markdown-body blockquote { - border-left: 0.25em solid var(--md-quote-line, rgba(128,128,128,0.3)); - color: var(--md-muted, rgba(128,128,128,0.6)); + border-left: 0.25em solid var(--md-quote-line); + color: var(--md-muted); margin: 0 0 16px; padding: 0 1em; } @@ -73,11 +75,11 @@ const PREVIEW_STYLES = ` font-size: 13px; } .markdown-body table th, .markdown-body table td { - border: 1px solid var(--md-border, rgba(128,128,128,0.2)); + border: 1px solid var(--md-border); padding: 6px 13px; } - .markdown-body table tr:nth-child(2n) { background-color: var(--md-code-bg, rgba(128,128,128,0.03)); } - .markdown-body table th { font-weight: 600; background-color: var(--md-code-bg, rgba(128,128,128,0.05)); } + .markdown-body table tr:nth-child(2n) { background-color: var(--md-code-bg); } + .markdown-body table th { font-weight: 600; background-color: var(--md-code-bg); } `; export default function MarkdownToHtmlPage() { @@ -93,42 +95,62 @@ export default function MarkdownToHtmlPage() { const result = useMemo(() => markdownToHtml(markdown), [markdown]); const error = result.hasError ? (result.error ?? null) : null; - // 💡 3. 沙箱暗黑模式自适应守卫(Sandbox Dark Mode Synchronizer): - // 根据宿主最外层的 HTML 是否包含 .dark 类名,动态向 iframe 注入对应的明暗模式 CSS 变量色轴 + // 💡 自适应大总管:以极高严谨度拼装明暗大闸,用标准换行切断粘连风险 useEffect(() => { const iframe = iframeRef.current; if (!iframe) return; const isDarkMode = document.documentElement.classList.contains('dark'); + const themeVariables = isDarkMode ? `:root { + --md-bg: #090d16; --md-foreground: #e6edf3; --md-border: rgba(255,255,255,0.15); - --md-code-bg: rgba(255,255,255,0.1); - --md-pre-bg: rgba(255,255,255,0.05); + --md-code-bg: rgba(255,255,255,0.12); + --md-pre-bg: rgba(255,255,255,0.04); --md-muted: #8b949e; + --md-quote-line: rgba(255,255,255,0.25); }` : `:root { + --md-bg: #ffffff; --md-foreground: #1f2328; --md-border: rgba(128,128,128,0.2); --md-code-bg: rgba(128,128,128,0.08); - --md-pre-bg: rgba(128,128,128,0.04); - --md-muted: #636c76; + --md-pre-bg: rgba(128,128,128,0.03); + --md-muted: #4b5563; + --md-quote-line: rgba(128,128,128,0.3); }`; + // 💡 3. 核心大清洗:将全局基础树(html, body)与派生样式完全独立硬编码,杜绝任何语法踩踏 + const baseGlobalStyles = ` + html, body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + background-color: var(--md-bg); + color: var(--md-foreground); + } + body { + padding: 16px; + box-sizing: border-box; + } + `; + iframe.srcdoc = ` - + ${result.html} `; - }, [result.html, previewMode]); // 当切换预览模式或 HTML 改变时,自发刷新沙箱 + }, [result.html, previewMode]); const handleModeChange = useCallback( (newMode: MarkdownToHtmlPreviewMode) => { @@ -159,10 +181,11 @@ export default function MarkdownToHtmlPage() { title={t('pageTitle')} subtitle={t('pageSubtitle')} icon={} + className="pb-1" /> -
- {/* 工具集成控制护栏 */} +
+ {/* 工具集成控制中枢 */}
+
{error}
)} @@ -219,13 +245,13 @@ export default function MarkdownToHtmlPage() { {/* 主框架多栏联动排版轴 */}
{/* Markdown 输入翼终端 */} {showInput && ( -
+
{t('inputLabel')} @@ -238,14 +264,14 @@ export default function MarkdownToHtmlPage() { value={markdown} onChange={(e) => setMarkdown(e.target.value)} placeholder={t('inputPlaceholder')} - className="flex-1 min-h-[380px] p-4 bg-transparent font-mono text-xs leading-relaxed resize-none focus:outline-none text-foreground/90 select-text" + className="flex-1 min-h-[390px] p-4 bg-transparent font-mono text-xs leading-relaxed resize-none focus:outline-none text-foreground/90 select-text" />
)} {/* 实时 HTML/Iframe 预览翼终端 */} {showPreview && ( -
+
{(previewMode as string) === 'html' ? t('htmlOutputLabel') : t('previewLabel')} @@ -265,14 +291,14 @@ export default function MarkdownToHtmlPage() {