Skip to content

Commit

Permalink
feat: 支持导出 docx 文件
Browse files Browse the repository at this point in the history
  • Loading branch information
LeafYeeXYZ committed Dec 8, 2024
1 parent aad6d73 commit b363b30
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 2 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^3.0.0",
"antd": "^5.21.1",
"html-docx-js-typescript": "^0.1.5",
"katex": "^0.16.11",
"marked": "^14.1.2",
"marked-katex-extension": "^5.1.2",
Expand Down
39 changes: 39 additions & 0 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import path from 'node:path'
import { mdToHtml } from '../../lib/render'
import { getTheme } from '../../lib/utils'
import { embedImageIntoHtml } from './utils'
import { asBlob } from 'html-docx-js-typescript'

function createWindow(): void {
// Create the browser window.
Expand Down Expand Up @@ -158,6 +159,44 @@ app.whenReady().then(() => {
return true
}
)
ipcMain.handle(
'createDocx',
async (
_,
markdown: string,
themeName: string = 'aps',
filepath: string,
filename: string
): Promise<boolean> => {
const { response } = await dialog.showMessageBox({
type: 'warning',
title: '导出 Word',
message:
'导出的 DOCX 文件可能存在部分样式丢失,请手动调整或或选择导出为 PDF 文件. 是否继续?',
buttons: ['取消', '继续']
})
if (response === 0) {
return false
}
const { filePath, canceled } = await dialog.showSaveDialog({
title: '导出论文',
filters: [{ name: 'Word 文件', extensions: ['docx'] }],
defaultPath: filename.split('.')[0] + '.docx',
showsTagField: false,
properties: ['createDirectory']
})
if (canceled) {
return false
}
const theme = getTheme(themeName)
const dist = path.resolve(filePath)
const html = await embedImageIntoHtml(await mdToHtml(markdown, theme), filepath)
const docx = await asBlob(html)
const docxBuffer = Buffer.from(docx instanceof Blob ? await docx.arrayBuffer() : docx)
await fs.writeFile(dist, docxBuffer)
return true
}
)

createWindow()

Expand Down
6 changes: 6 additions & 0 deletions src/preload/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ declare global {
filepath: string,
filename: string
) => Promise<boolean>
createDocx: (
markdown: string,
themeName: string,
filepath: string,
filename: string
) => Promise<boolean>
}
}
}
8 changes: 8 additions & 0 deletions src/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ const api = {
filename: string
): Promise<boolean> => {
return electronAPI.ipcRenderer.invoke('createPdf', markdown, themeName, filepath, filename)
},
createDocx: (
markdown: string,
themeName: string,
filepath: string,
filename: string
): Promise<boolean> => {
return electronAPI.ipcRenderer.invoke('createDocx', markdown, themeName, filepath, filename)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/renderer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html>
<head>
<meta charset="UTF-8" />
<title>EasyPaper v1.5.0</title>
<title>EasyPaper v1.6.0</title>
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
Expand Down
28 changes: 27 additions & 1 deletion src/renderer/src/components/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
QuestionCircleOutlined,
FileMarkdownOutlined,
FilePdfOutlined,
FileTextOutlined
FileTextOutlined,
FileWordOutlined
} from '@ant-design/icons'
import { useStore } from '../lib/useStore'
import { mdToHtml } from '../../../../lib/render'
Expand Down Expand Up @@ -136,6 +137,31 @@ export default function Toolbar(): JSX.Element {
>
<FileTextOutlined /> HTML
</Button>
<Button
disabled={!filepath || !filename || !markdown.length || !messageApi || disabled}
onClick={async () => {
flushSync(() => setDisabled(true))
messageApi!.open({
content: '导出中...',
type: 'loading',
duration: 0,
key: 'exporting'
})
await window.api
.createDocx(markdown, theme.themeName, filepath, filename)
.then((res) => {
messageApi!.destroy()
res && messageApi!.success('导出成功')
})
.catch(() => {
messageApi!.destroy()
messageApi!.error('导出失败')
})
.finally(() => setDisabled(false))
}}
>
<FileWordOutlined /> DOCX
</Button>
<p className="text-xs px-1 font-bold text-nowrap text-gray-600 dark:text-white">论文格式:</p>
<Select
defaultValue={getDefalutTheme().themeName}
Expand Down

0 comments on commit b363b30

Please sign in to comment.