fix(editor): hide YAML frontmatter in Markdown preview

This commit is contained in:
Beverly621
2026-09-02 23:15:19 +08:00
committed by Menghuan1918
parent dde0923980
commit e31130adb8
3 changed files with 115 additions and 10 deletions
+14 -10
View File
@@ -22,6 +22,7 @@ import { defaultKeymap, history, historyKeymap } from '@codemirror/commands'
import { IconCheckOutline16, MarkdownText } from '@deepseek-ai/dsh-client-ui-primitives'
import { markdownTextProps } from './markdown-labels.tsx'
import { api, htmlUrl } from './api.ts'
import { markdownPreviewSource } from './markdown-frontmatter.ts'
import { rewriteLocalImageUrls } from './markdown-images.ts'
import { languageForPath } from './lang.ts'
import { cmSurfaceTheme, CmThemeCompartment } from './cm-themes.ts'
@@ -237,25 +238,28 @@ export function TextEditor(props: FileViewerProps) {
/** The markdown source the preview renders (draft wins over saved content). */
const mdText = draft ?? content ?? ''
/** The preview source: `mdText` with local image destinations rewritten to
* absolute media URLs (see {@link rewriteLocalImageUrls}); the raw
* `mdText` stays untouched for selection/line lookup and for mermaid-block
* detection, which are unaffected by image syntax. */
/** Preview-only source with a closed leading YAML frontmatter block hidden.
* The raw `mdText` stays untouched for editing, saving, and selection line
* lookup. All preview renderers share this source so plain Markdown,
* Mermaid, and documents containing raw HTML behave consistently. */
const previewMdText = markdown ? markdownPreviewSource(mdText) : mdText
/** The preview source with local image destinations rewritten to absolute
* media URLs (see {@link rewriteLocalImageUrls}). */
const previewText = markdown
? rewriteLocalImageUrls(mdText, scope, path, window.location.origin)
: mdText
? rewriteLocalImageUrls(previewMdText, scope, path, window.location.origin)
: previewMdText
/** md/mermaid block split for the preview (mermaid fences lift out). Split
* only in preview mode: edit-mode keystrokes must not re-scan the source. */
const mdBlocks = useMemo(
() => (markdown && mode === 'preview' ? splitMermaidBlocks(mdText) : []),
[markdown, mode, mdText],
() => (markdown && mode === 'preview' ? splitMermaidBlocks(previewMdText) : []),
[markdown, mode, previewMdText],
)
/** Raw-HTML analysis (block runs lifted out + inline gate). Non-null only
* for documents that actually contain HTML — plain markdown keeps the
* legacy single-pass render path below, byte-for-byte. */
const htmlInfo = useMemo(
() => (markdown && mode === 'preview' ? analyzeMarkdownHtml(mdText) : null),
[markdown, mode, mdText],
() => (markdown && mode === 'preview' ? analyzeMarkdownHtml(previewMdText) : null),
[markdown, mode, previewMdText],
)
const hasMermaid = useMemo(
() => htmlInfo !== null
+29
View File
@@ -0,0 +1,29 @@
/**
* Return the Markdown source used by preview renderers.
*
* A closed YAML frontmatter block is metadata, but the shared MarkdownText
* parser treats its delimiters as a thematic break and a setext heading. Hide
* only a block that starts on the first line and has its own closing `---`
* line. Unclosed or non-leading delimiters remain byte-for-byte unchanged so
* ordinary Markdown is never truncated. The editor and save path keep using
* the original source; this helper is preview-only.
*/
export function markdownPreviewSource(source: string): string {
const firstLineEnd = source.indexOf('\n')
if (firstLineEnd === -1) return source
const firstLineStart = source.charCodeAt(0) === 0xFEFF ? 1 : 0
const firstLine = source.slice(firstLineStart, firstLineEnd).replace(/\r$/u, '')
if (firstLine !== '---') return source
let lineStart = firstLineEnd + 1
while (lineStart <= source.length) {
const newline = source.indexOf('\n', lineStart)
const lineEnd = newline === -1 ? source.length : newline
const line = source.slice(lineStart, lineEnd).replace(/\r$/u, '')
if (line === '---') return newline === -1 ? '' : source.slice(newline + 1)
if (newline === -1) return source
lineStart = newline + 1
}
return source
}