fix(export): handle metadata-only notes and HTML image resources

This commit is contained in:
2026-09-07 14:45:47 +08:00
parent 894f220239
commit ca5b52bc8a
6 changed files with 60 additions and 2 deletions
@@ -58,3 +58,19 @@ it('does not invent a metadata bar for plain notes or unsupported frontmatter',a
expect(renderMarkdown).toHaveBeenCalledWith(source,expect.anything())
}
})
it('exports metadata-only notes without submitting an empty resource request',async()=>{
for(const tail of ['', '\n \n']) {
const html=await preparePdfSnapshot('---\ntitle: Metadata only\ntags: [draft]\n---\n'+tail,'note',{theme_id:'light',include_title:false,page_size:'A4'})
const doc=new DOMParser().parseFromString(html,'text/html')
expect(doc.querySelector('.note-metadata h1')?.textContent).toBe('Metadata only')
expect(doc.querySelector('.metadata-tag')?.textContent).toBe('draft')
}
expect(apiClient.post).not.toHaveBeenCalled()
})
it('embeds prepared HTML images without retaining local URLs',async()=>{
vi.mocked(renderMarkdown).mockResolvedValueOnce('<p><img src="assets/a&amp;b.png"></p>')
vi.mocked(apiClient.post).mockResolvedValueOnce({images:[{source:'assets/a&b.png',data:'data:image/png;base64,aGVsbG8=',warnings:[]}],plots:[]})
const html=await preparePdfSnapshot('<img src="assets/a&amp;b.png">','note',{theme_id:'light',include_title:false,page_size:'A4'})
expect(new DOMParser().parseFromString(html,'text/html').querySelector('img')?.getAttribute('src')).toBe('data:image/png;base64,aGVsbG8=')
})
+1 -1
View File
@@ -78,7 +78,7 @@ export async function preparePdfSnapshot(markdown:string,title:string,options:Op
const scope=scopeAttributes(VisualMarkdownEditor)
// Match the editor DOM and scoped styles, with read-only metadata controls.
const metadataHtml=metadata ? `<section class="note-metadata"${scope} aria-label="${escape(t('笔记属性','Note properties'))}"><span class="metadata-caption"${scope}>${escape(t('笔记属性','Note properties'))}</span>${metadata.title ? `<h1${scope}>${escape(metadata.title)}</h1>` : ''}<div class="metadata-tags"${scope}><span class="metadata-label"${scope}>${escape(t('标签','Tags'))}</span>${metadata.tags.map(tag=>`<span class="metadata-tag"${scope}><span${scope}>${escape(tag)}</span></span>`).join('')}</div></section>` : ''
const resources=await apiClient.post<Resources>('/api/exports/preview-resources',{format:'pdf',source:{type:'markdown',markdown:body,file_path:filePath},options})
const resources:Resources=body.trim() ? await apiClient.post<Resources>('/api/exports/preview-resources',{format:'pdf',source:{type:'markdown',markdown:body,file_path:filePath},options}) : {images:[],plots:[]}
signal?.throwIfAborted()
const rendered=await renderMarkdown(body,{themeId:options.theme_id,theme:dark?'dark':'light',preferences,pdf:{mermaidVariables:diagramVariables,plot:async source=>{
const plot=resources.plots.find(p=>p.source.trim()===source.trim()); if(!plot?.svg)throw Error(plot?.warnings.join('; ')||'函数图像无法导出');return plot