mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-28 21:42:27 +08:00
feat: enhance PDF export functionality with syntax highlighting and localized messages
This commit is contained in:
parent
60e69ad49c
commit
a17d62f3ec
@ -29,8 +29,8 @@ export const PRINT_HTML_TEMPLATE = `
|
||||
{{richtextCss}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root" theme-mode="light" os=${isMac ? 'mac' : isWin ? 'windows' : 'linux'}>
|
||||
<body theme-mode="light" os=${isMac ? 'mac' : isWin ? 'windows' : 'linux'}>
|
||||
<div id="root">
|
||||
<div class="tiptap">{{content}}</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@ -1389,6 +1389,9 @@
|
||||
"no_api_key": "Notion ApiKey or Notion DatabaseID is not configured",
|
||||
"no_content": "There is nothing to export to Notion."
|
||||
},
|
||||
"pdf": {
|
||||
"export": "Failed to export to PDF"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "Failed to export to Siyuan Note, please check connection status and configuration according to documentation",
|
||||
"no_config": "Siyuan Note API address or token is not configured"
|
||||
@ -1491,6 +1494,9 @@
|
||||
"notion": {
|
||||
"export": "Successfully exported to Notion"
|
||||
},
|
||||
"pdf": {
|
||||
"export": "Successfully exported to PDF"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "Successfully exported to Siyuan Note"
|
||||
},
|
||||
|
||||
@ -1390,6 +1390,9 @@
|
||||
"no_api_key": "未配置 Notion API Key 或 Notion Database ID",
|
||||
"no_content": "无可导出到 Notion 的内容"
|
||||
},
|
||||
"pdf": {
|
||||
"export": "导出 PDF 失败"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "导出思源笔记失败,请检查连接状态并对照文档检查配置",
|
||||
"no_config": "未配置思源笔记 API 地址或令牌"
|
||||
@ -1492,6 +1495,9 @@
|
||||
"notion": {
|
||||
"export": "成功导出到 Notion"
|
||||
},
|
||||
"pdf": {
|
||||
"export": "成功导出为 PDF"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "导出到思源笔记成功"
|
||||
},
|
||||
|
||||
@ -1389,6 +1389,9 @@
|
||||
"no_api_key": "未設定 Notion API Key 或 Notion Database ID",
|
||||
"no_content": "沒有可匯出至 Notion 的內容"
|
||||
},
|
||||
"pdf": {
|
||||
"export": "導出 PDF 失敗"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "導出思源筆記失敗,請檢查連接狀態並對照文檔檢查配置",
|
||||
"no_config": "未配置思源筆記 API 地址或令牌"
|
||||
@ -1491,6 +1494,9 @@
|
||||
"notion": {
|
||||
"export": "成功匯出到 Notion"
|
||||
},
|
||||
"pdf": {
|
||||
"export": "成功導出為 PDF"
|
||||
},
|
||||
"siyuan": {
|
||||
"export": "導出到思源筆記成功"
|
||||
},
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { loggerService } from '@logger'
|
||||
import { RichEditorRef } from '@renderer/components/RichEditor/types'
|
||||
import i18n from '@renderer/i18n'
|
||||
import { getHighlighter } from '@renderer/utils/shiki'
|
||||
import { RefObject } from 'react'
|
||||
|
||||
const logger = loggerService.withContext('exportUtils')
|
||||
@ -10,21 +12,85 @@ export interface ExportContext {
|
||||
fileName: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加语法高亮
|
||||
* @param html 原始 HTML
|
||||
* @returns 添加语法高亮后的 HTML
|
||||
*/
|
||||
const addSyntaxHighlighting = async (html: string): Promise<string> => {
|
||||
try {
|
||||
const highlighter = await getHighlighter()
|
||||
const parser = new DOMParser()
|
||||
const doc = parser.parseFromString(html, 'text/html')
|
||||
|
||||
const codeBlocks = doc.querySelectorAll('pre code')
|
||||
|
||||
for (const codeElement of codeBlocks) {
|
||||
const preElement = codeElement.parentElement as HTMLPreElement
|
||||
const codeText = codeElement.textContent || ''
|
||||
|
||||
if (!codeText.trim()) continue
|
||||
|
||||
let languageMatch = preElement.className.match(/language-(\w+)/)
|
||||
if (!languageMatch) {
|
||||
languageMatch = codeElement.className.match(/language-(\w+)/)
|
||||
}
|
||||
const language = languageMatch ? languageMatch[1] : 'text'
|
||||
|
||||
// Skip highlighting for plain text
|
||||
if (language === 'text' || language === 'plain' || language === 'plaintext') {
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
const loadedLanguages = highlighter.getLoadedLanguages()
|
||||
|
||||
if (loadedLanguages.includes(language)) {
|
||||
const highlightedHtml = highlighter.codeToHtml(codeText, {
|
||||
lang: language,
|
||||
theme: 'one-light'
|
||||
})
|
||||
|
||||
const tempDoc = parser.parseFromString(highlightedHtml, 'text/html')
|
||||
const highlightedCode = tempDoc.querySelector('code')
|
||||
|
||||
if (highlightedCode) {
|
||||
codeElement.innerHTML = highlightedCode.innerHTML
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to highlight ${language} code block:`, error as Error)
|
||||
}
|
||||
}
|
||||
|
||||
return doc.documentElement.outerHTML
|
||||
} catch (error) {
|
||||
logger.warn('Failed to add syntax highlighting, using original HTML:', error as Error)
|
||||
return html
|
||||
}
|
||||
}
|
||||
|
||||
export const handleExportPDF = async (context: ExportContext) => {
|
||||
if (!context.editorRef?.current || !context.currentContent?.trim()) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// Use Tiptap's getHTML API to get HTML content
|
||||
const htmlContent = context.editorRef.current.getHtml()
|
||||
let htmlContent = context.editorRef.current.getHtml()
|
||||
|
||||
htmlContent = await addSyntaxHighlighting(htmlContent)
|
||||
|
||||
const filename = context.fileName ? `${context.fileName}.pdf` : 'note.pdf'
|
||||
const result = await window.api.export.toPDF(htmlContent, filename)
|
||||
|
||||
if (result.success) {
|
||||
logger.info('PDF exported successfully to:', result.filePath)
|
||||
window.toast.success(i18n.t('message.success.pdf.export'))
|
||||
} else {
|
||||
logger.error('PDF export failed:', result.message)
|
||||
if (!result.message.includes('canceled')) {
|
||||
window.toast.error(i18n.t('message.error.pdf.export', { message: result.message }))
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error('PDF export error:', error)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user