markdown-paper 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -16
- package/bin/mdp.ts +4 -4
- package/lib/docx.ts +2 -3
- package/lib/main.ts +79 -58
- package/package.json +2 -2
- package/theme/aps/aps.css +17 -17
- package/theme/aps/aps.ts +7 -15
- package/theme/theme.ts +3 -3
- package/theme/aps/aps.md +0 -41
- package/theme/bnu/bnu.css +0 -0
- package/theme/bnu/bnu.md +0 -0
- package/theme/bnu/bnu.ts +0 -0
package/README.md
CHANGED
|
@@ -1,33 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
以心理学报等学术论文的格式从 Markdown 生成 PDF / HTML / DOCX 文件
|
|
2
|
+
|
|
3
|
+
# 使用方法
|
|
4
|
+
|
|
5
|
+
## 1 用 Markdown 撰写论文
|
|
6
|
+
|
|
7
|
+
```markdown
|
|
8
|
+
# 中文标题
|
|
9
|
+
|
|
10
|
+
#author# 作者信息
|
|
11
|
+
|
|
12
|
+
#school# 单位信息
|
|
13
|
+
|
|
14
|
+
#abstract# 摘要内容
|
|
15
|
+
|
|
16
|
+
#keywords# 关键词内容
|
|
17
|
+
|
|
18
|
+
## 1 一级标题
|
|
19
|
+
|
|
20
|
+
### 1.1 二级标题
|
|
21
|
+
|
|
22
|
+
#### 1.1.1 三级标题
|
|
23
|
+
|
|
24
|
+
正文
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
> 图片标题
|
|
29
|
+
|
|
30
|
+
> 表格标题
|
|
31
|
+
|
|
32
|
+
| 表头1 | 表头2 |
|
|
33
|
+
| :---: | :---: |
|
|
34
|
+
| 内容1 | 内容2 |
|
|
35
|
+
|
|
36
|
+
##### 参考文献
|
|
37
|
+
|
|
38
|
+
- 文献1
|
|
39
|
+
- 文献2
|
|
40
|
+
- 文献3
|
|
41
|
+
|
|
42
|
+
##### 附录
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
> 详见下方的模板说明
|
|
46
|
+
|
|
47
|
+
## 2 安装 `Bun`
|
|
48
|
+
|
|
49
|
+
`Bun` 是一个现代的 `JavaScript` / `TypeScript` 运行环境, 本项目基于 `Bun` 环境开发; 请在官网 [bun.sh](https://bun.sh) 下载并安装 `Bun`, 也可以直接使用 `npm install -g bun` 安装
|
|
50
|
+
|
|
51
|
+
## 3 安装 `MarkdownPaper`
|
|
2
52
|
|
|
3
|
-
## 使用方法
|
|
4
53
|
```bash
|
|
5
|
-
# 安装 Bun (参见 bun.sh)
|
|
6
|
-
...
|
|
7
|
-
# 安装 MarkdownPaper
|
|
8
54
|
bun add -g markdown-paper
|
|
9
|
-
# 使用 (第一个参数为源文件相对路径)
|
|
10
|
-
mdp <path> [--option]
|
|
11
|
-
# 查看使用方法
|
|
12
|
-
mdp
|
|
13
55
|
```
|
|
14
56
|
|
|
15
57
|
> 如果您安装过旧版本的 `MarkdownPaper` (小于 `2.0.0`), 请先卸载旧版本再安装新版本
|
|
16
58
|
|
|
59
|
+
## 4 生成论文
|
|
60
|
+
|
|
61
|
+
运行 `mdp` 命令以使用 `MarkdownPaper` 命令行工具从 `Markdown` 文件生成论文
|
|
62
|
+
|
|
63
|
+
如果您不熟悉命令行工具, 可以尝试我的另一个项目 [EasyPaper](https://github.com/LeafYeeXYZ/EasyPaper), 它基于 `MarkdownPaper` 并提供了图形界面
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 查看帮助信息
|
|
67
|
+
mdp
|
|
68
|
+
# 从当前工作目录下的 example.md 文件生成 PDF 文件
|
|
69
|
+
mdp example.md
|
|
70
|
+
# 从当前工作目录下的 example.md 文件生成 PDF 文件并输出到指定路径
|
|
71
|
+
mdp example.md --out=D:/example.pdf
|
|
72
|
+
# 从当前工作目录下的 example.md 文件生成 PDF 和 HTML 文件
|
|
73
|
+
mdp example.md --outputHTML
|
|
74
|
+
# 从当前工作目录下的 example.md 文件生成 PDF 和 DOCX 文件
|
|
75
|
+
pip install pdf2docx # 仅生成 DOCX 文件时需要安装 pdf2docx, 只需安装一次
|
|
76
|
+
mdp example.md --outputDOCX
|
|
77
|
+
```
|
|
78
|
+
|
|
17
79
|
| 参数 | 说明 |
|
|
18
80
|
| :---: | :---: |
|
|
19
81
|
| `--out=xxx` | 输出文件相对路径<br>默认为源文件路径的同名 `PDF` 文件 |
|
|
20
82
|
| `--theme=xxx` | 论文模板, 默认为 `aps` (`Acta Psychologica Sinica`)<br>暂时没有其他模板, 欢迎贡献 |
|
|
21
83
|
| `--outputHTML` | 输出 `HTML` 文件, 默认不输出 |
|
|
22
|
-
| `--outputDOCX` | 输出 `DOCX` 文件, 默认不输出<br
|
|
84
|
+
| `--outputDOCX` | 输出 `DOCX` 文件, 默认不输出<br>**须先通过 `python` 安装依赖 `pdf2docx`**<br>使用时推荐开启 `--hideFooter` 参数 |
|
|
23
85
|
|
|
24
|
-
|
|
86
|
+
# 模板说明
|
|
25
87
|
`/theme/theme.ts` 中的 `Theme` 抽象类定义了模板的样式, 按照类似于 `aps` 文件夹的结构可自定义模板; 模板可以提供自定义功能
|
|
26
88
|
|
|
27
|
-
模板制作完成后, 在 `/lib/main.ts` 中导入并添加到 `class Options -> constructor -> case '--theme':`
|
|
89
|
+
模板制作完成后, 在 `/lib/main.ts` 中导入并添加到 `class Options -> constructor -> case '--theme':` 中, 并在下方添加使用文档即可
|
|
90
|
+
|
|
91
|
+
推荐所有主题的文档和编写格式都尽量与 `aps` 主题保持一致
|
|
28
92
|
|
|
29
|
-
|
|
30
|
-
|
|
93
|
+
## APS 模板
|
|
94
|
+
### 额外命令行参数
|
|
31
95
|
| 参数 | 说明 |
|
|
32
96
|
| :---: | :---: |
|
|
33
97
|
| `--showTitle` | 在页眉显示文件名, 默认不显示 |
|
|
@@ -35,7 +99,7 @@ mdp
|
|
|
35
99
|
| `--zhPunctuation` | 将正文中的英文标点符号替换为中文标点符号, 默认不替换<br>仅替换 `PDF` 和 `DOCX` 文件 |
|
|
36
100
|
| `--enPunctuation` | 将正文中的中文标点符号替换为英文标点符号, 默认不替换<br>仅替换 `PDF` 和 `DOCX` 文件 |
|
|
37
101
|
|
|
38
|
-
|
|
102
|
+
### 编写格式
|
|
39
103
|
```markdown
|
|
40
104
|
# 中文标题
|
|
41
105
|
#author# 作者信息
|
|
@@ -66,7 +130,9 @@ mdp
|
|
|
66
130
|
##### 附录
|
|
67
131
|
```
|
|
68
132
|
|
|
69
|
-
|
|
133
|
+
# 更新日志
|
|
134
|
+
- `2.2.0` (2024-08-26): 优化项目导入导出内容, 优化文档
|
|
135
|
+
- `2.1.1` (2024-07-12): 修复字体错误
|
|
70
136
|
- `2.1.0` (2024-06-26): 支持 `MacOS` 系统, 改为在线加载字体
|
|
71
137
|
- `2.0.0` (2024-06-20): 重构代码, 完善模板功能
|
|
72
138
|
- `1.4.0` (2024-05-29): 新增替换中英文标点符号功能
|
package/bin/mdp.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { MarkdownPaperOptions, renderMarkdown } from '../lib/main.ts'
|
|
4
4
|
/** 命令行参数 */
|
|
5
5
|
const args = process.argv.slice(2)
|
|
6
6
|
/** 当前工作目录 */
|
|
@@ -14,19 +14,19 @@ void async function main(args: string[], cwd: string) {
|
|
|
14
14
|
try {
|
|
15
15
|
// 如果没有参数, 显示帮助信息
|
|
16
16
|
if (args.length === 0) {
|
|
17
|
-
console.log(`\n使用方法:\n${
|
|
17
|
+
console.log(`\n使用方法:\n${MarkdownPaperOptions.format}\n`)
|
|
18
18
|
process.exit(0)
|
|
19
19
|
}
|
|
20
20
|
// 解析参数
|
|
21
21
|
console.log('\n开始生成\n')
|
|
22
|
-
const options = new
|
|
22
|
+
const options = new MarkdownPaperOptions(args, cwd)
|
|
23
23
|
// 渲染 markdown
|
|
24
24
|
await renderMarkdown(options)
|
|
25
25
|
console.log('生成成功\n')
|
|
26
26
|
}
|
|
27
27
|
catch (e) {
|
|
28
28
|
if (e instanceof SyntaxError) {
|
|
29
|
-
console.error(`参数错误, 正确格式:\n${
|
|
29
|
+
console.error(`参数错误, 正确格式:\n${MarkdownPaperOptions.format}\n`)
|
|
30
30
|
} else if (e instanceof Error) {
|
|
31
31
|
console.error(`错误:\n${e.message}\n`)
|
|
32
32
|
}
|
package/lib/docx.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
declare var self: Worker
|
|
2
2
|
|
|
3
3
|
import { $ } from 'bun'
|
|
4
|
-
import { Options } from './main'
|
|
5
4
|
|
|
6
5
|
self.onmessage = async (e) => {
|
|
7
|
-
const
|
|
8
|
-
await $`pdf2docx convert ${
|
|
6
|
+
const pdfPath = e.data as string
|
|
7
|
+
await $`pdf2docx convert ${pdfPath}`
|
|
9
8
|
.then(() => {
|
|
10
9
|
postMessage('success')
|
|
11
10
|
})
|
package/lib/main.ts
CHANGED
|
@@ -4,10 +4,11 @@ import fs from 'node:fs/promises'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { readFileSync } from 'node:fs'
|
|
6
6
|
import { APS } from '../theme/aps/aps'
|
|
7
|
-
import {
|
|
7
|
+
import { MarkdownPaperTheme } from '../theme/theme'
|
|
8
|
+
import type { PDFOptions } from 'puppeteer'
|
|
8
9
|
|
|
9
10
|
/** 应用参数 */
|
|
10
|
-
|
|
11
|
+
class MarkdownPaperOptions {
|
|
11
12
|
/** markdown 文件绝对路径 */
|
|
12
13
|
src: string
|
|
13
14
|
/** pdf 文件绝对路径 */
|
|
@@ -17,7 +18,7 @@ export class Options {
|
|
|
17
18
|
/** 是否输出 docx */
|
|
18
19
|
outputDOCX: boolean
|
|
19
20
|
/** 样式 */
|
|
20
|
-
theme:
|
|
21
|
+
theme: MarkdownPaperTheme
|
|
21
22
|
/** 正确格式 */
|
|
22
23
|
static format = `mdp <markdown> [--options]
|
|
23
24
|
|
|
@@ -26,7 +27,6 @@ export class Options {
|
|
|
26
27
|
--theme=<name>: 论文模板 (默认为 APS)
|
|
27
28
|
--outputHTML: 输出 html 文件 (默认不输出)
|
|
28
29
|
--outputDOCX: 输出 docx 文件 (默认不输出)
|
|
29
|
-
--browser=<path>: 自定义浏览器路径 (默认为 Edge)
|
|
30
30
|
|
|
31
31
|
模板的自定义参数见模板说明`
|
|
32
32
|
/**
|
|
@@ -90,79 +90,100 @@ export class Options {
|
|
|
90
90
|
/**
|
|
91
91
|
* 渲染 markdown
|
|
92
92
|
* @param options 参数
|
|
93
|
+
* @param rawMarkdown 如果传入此参数, 则不再读取文件
|
|
93
94
|
*/
|
|
94
|
-
|
|
95
|
+
async function renderMarkdown(
|
|
96
|
+
options: MarkdownPaperOptions,
|
|
97
|
+
rawMarkdown?: string,
|
|
98
|
+
): Promise<void> {
|
|
95
99
|
// 读取 markdown 文件
|
|
96
|
-
|
|
100
|
+
const raw = rawMarkdown ?? await fs.readFile(options.src, { encoding: 'utf-8' })
|
|
97
101
|
// 预处理 markdown
|
|
98
|
-
md = options.theme.preParseMarkdown(
|
|
102
|
+
const md = await options.theme.preParseMarkdown(raw)
|
|
99
103
|
// 转换 markdown 为 html
|
|
100
|
-
|
|
101
|
-
// 创建网页文件
|
|
102
|
-
const title = path.basename(options.src).replace('.md', '')
|
|
103
|
-
let web = `
|
|
104
|
+
let html = `
|
|
104
105
|
<!DOCTYPE html>
|
|
105
106
|
<html lang="zh-CN">
|
|
106
107
|
<head>
|
|
107
108
|
<meta charset="UTF-8">
|
|
108
|
-
<title>${
|
|
109
|
+
<title>${path.basename(options.src).replace('.md', '')}</title>
|
|
109
110
|
<style>${options.theme.css}</style>
|
|
110
111
|
</head>
|
|
111
112
|
<body>
|
|
112
|
-
${
|
|
113
|
+
${await marked(md)}
|
|
113
114
|
</body>
|
|
114
115
|
</html>
|
|
115
116
|
`
|
|
116
117
|
// 预处理 html
|
|
117
|
-
|
|
118
|
+
html = await options.theme.preParseHTML(html)
|
|
118
119
|
// 保存 html 文件
|
|
119
|
-
options.outputHTML && await fs.writeFile(options.out.replace('.pdf', '.html'),
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
120
|
+
options.outputHTML && await fs.writeFile(options.out.replace('.pdf', '.html'), html)
|
|
121
|
+
// 保存 pdf 文件
|
|
122
|
+
await htmlToPdf(
|
|
123
|
+
html.replace(/<img src="(.+?)"/g, (match, p1) => {
|
|
124
|
+
if (p1.startsWith('http')) return match
|
|
125
|
+
try {
|
|
126
|
+
const url = path.resolve(path.dirname(options.src), decodeURI(p1))
|
|
127
|
+
const data = readFileSync(url).toString('base64')
|
|
128
|
+
return `<img src="data:image/${path.extname(p1).replace('.', '')};base64,${data}"`
|
|
129
|
+
} catch (_) {
|
|
130
|
+
console.error(`图片 ${p1} 不存在`)
|
|
131
|
+
return match
|
|
132
|
+
}
|
|
133
|
+
}),
|
|
134
|
+
options.out,
|
|
135
|
+
options.theme.pdfOptions
|
|
136
|
+
)
|
|
137
|
+
// 保存 docx 文件
|
|
138
|
+
options.outputDOCX && await pdfToDocx(options.out)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 把 html 转换为 pdf
|
|
143
|
+
* @param html html 字符串, 图片为 base64
|
|
144
|
+
* @param dist pdf 文件绝对路径
|
|
145
|
+
* @param options pdf 参数, 无需设置路径
|
|
146
|
+
*/
|
|
147
|
+
async function htmlToPdf(html: string, dist: string, options: PDFOptions): Promise<void> {
|
|
133
148
|
const browser = await puppeteer.launch()
|
|
134
|
-
// 创建页面
|
|
135
149
|
const page = await browser.newPage()
|
|
136
|
-
|
|
137
|
-
await page.
|
|
138
|
-
// 执行脚本
|
|
139
|
-
await page.evaluate(options.theme.script)
|
|
140
|
-
// 生成 pdf
|
|
141
|
-
await page.pdf({ path: options.out, ...options.theme.pdfOptions })
|
|
142
|
-
// 关闭浏览器
|
|
150
|
+
await page.setContent(html)
|
|
151
|
+
await page.pdf({ path: dist, ...options })
|
|
143
152
|
await browser.close()
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 把 pdf 转换为 docx
|
|
157
|
+
* @param pdfPath pdf 文件绝对路径
|
|
158
|
+
*/
|
|
159
|
+
function pdfToDocx(pdfPath: string): Promise<void> {
|
|
160
|
+
return new Promise<void>((resolve, reject) => {
|
|
161
|
+
const worker = new Worker(new URL('docx.ts', import.meta.url).href)
|
|
162
|
+
worker.onmessage = (e) => {
|
|
163
|
+
switch (e.data) {
|
|
164
|
+
case 'success': {
|
|
165
|
+
console.log('')
|
|
166
|
+
resolve()
|
|
167
|
+
break
|
|
168
|
+
}
|
|
169
|
+
case 'error': {
|
|
170
|
+
reject(Error('生成 docx 文件失败'))
|
|
171
|
+
break
|
|
172
|
+
}
|
|
173
|
+
default: {
|
|
174
|
+
reject(Error('调用 python 时发生未知错误'))
|
|
175
|
+
break
|
|
163
176
|
}
|
|
164
177
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
178
|
+
}
|
|
179
|
+
worker.postMessage(pdfPath)
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
MarkdownPaperTheme,
|
|
185
|
+
MarkdownPaperOptions,
|
|
186
|
+
renderMarkdown,
|
|
187
|
+
htmlToPdf,
|
|
188
|
+
pdfToDocx,
|
|
168
189
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdown-paper",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "LeafYeeXYZ",
|
|
7
7
|
"email": "xiaoyezi@leafyee.xyz"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"mdp": "bun ./bin/mdp.ts",
|
|
12
12
|
"pub": "npm publish",
|
|
13
|
-
"try": "bun mdp
|
|
13
|
+
"try": "bun mdp ./demo/论文.md --outputHTML --outputDOCX"
|
|
14
14
|
},
|
|
15
15
|
"bin": {
|
|
16
16
|
"mdp": "./bin/mdp.ts"
|
package/theme/aps/aps.css
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
* {
|
|
2
|
-
font-family: '
|
|
2
|
+
font-family: 'Times', 'Times New Roman', '宋体', 'SimSun', '华文宋体', 'STSong'; /* 所有数字和英文字体都用 Times New Roman */
|
|
3
3
|
line-height: 1.55em; /* 1.5倍行距 */
|
|
4
4
|
margin: 0;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
h1 { /* 中文题目: 二号黑体 */
|
|
8
8
|
font-size: 29px;
|
|
9
|
-
font-weight:
|
|
10
|
-
font-family: '
|
|
9
|
+
font-weight: normal;
|
|
10
|
+
font-family: '黑体', 'SimHei', '华文黑体', 'STHeiti';
|
|
11
11
|
text-align: center;
|
|
12
12
|
margin-bottom: 9px;
|
|
13
13
|
}
|
|
14
14
|
.author { /* 作者姓名: 四号仿宋 */
|
|
15
15
|
font-size: 18px;
|
|
16
|
-
font-weight:
|
|
17
|
-
font-family: '
|
|
16
|
+
font-weight: normal;
|
|
17
|
+
font-family: '仿宋', 'Fangsong', '华文仿宋', 'STFangsong';
|
|
18
18
|
text-align: center;
|
|
19
19
|
margin-bottom: 3px;
|
|
20
20
|
}
|
|
@@ -29,8 +29,8 @@ h1 { /* 中文题目: 二号黑体 */
|
|
|
29
29
|
padding: 0 28px;
|
|
30
30
|
&::before {
|
|
31
31
|
content: '摘 要';
|
|
32
|
-
font-weight:
|
|
33
|
-
font-family: '
|
|
32
|
+
font-weight: normal;
|
|
33
|
+
font-family: '黑体', 'SimHei', '华文黑体', 'STHeiti';
|
|
34
34
|
display: inline-block;
|
|
35
35
|
margin-right: 14px;
|
|
36
36
|
}
|
|
@@ -41,8 +41,8 @@ h1 { /* 中文题目: 二号黑体 */
|
|
|
41
41
|
padding: 0 28px;
|
|
42
42
|
&::before {
|
|
43
43
|
content: '关键词';
|
|
44
|
-
font-weight:
|
|
45
|
-
font-family: '
|
|
44
|
+
font-weight: normal;
|
|
45
|
+
font-family: '黑体', 'SimHei', '华文黑体', 'STHeiti';
|
|
46
46
|
display: inline-block;
|
|
47
47
|
margin-right: 14px;
|
|
48
48
|
}
|
|
@@ -55,14 +55,14 @@ h2 { /* 一级标题: 四号宋体 */
|
|
|
55
55
|
}
|
|
56
56
|
h3 { /* 二级标题: 五号黑体 */
|
|
57
57
|
font-size: 14px;
|
|
58
|
-
font-weight:
|
|
59
|
-
font-family: '
|
|
58
|
+
font-weight: normal;
|
|
59
|
+
font-family: '黑体', 'SimHei', '华文黑体', 'STHeiti';
|
|
60
60
|
margin: 5px 0;
|
|
61
61
|
}
|
|
62
62
|
h4 { /* 三级标题: 五号黑体 */
|
|
63
63
|
font-size: 14px;
|
|
64
|
-
font-weight:
|
|
65
|
-
font-family: '
|
|
64
|
+
font-weight: normal;
|
|
65
|
+
font-family: '黑体', 'SimHei', '华文黑体', 'STHeiti';
|
|
66
66
|
margin: 3px 0;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -74,8 +74,8 @@ p { /* 正文: 五号宋体 */
|
|
|
74
74
|
|
|
75
75
|
h5 { /* "参考文献": 五号黑体 */
|
|
76
76
|
font-size: 14px;
|
|
77
|
-
font-weight:
|
|
78
|
-
font-family: '
|
|
77
|
+
font-weight: normal;
|
|
78
|
+
font-family: '黑体', 'SimHei', '华文黑体', 'STHeiti';
|
|
79
79
|
text-align: center;
|
|
80
80
|
margin-bottom: 7px;
|
|
81
81
|
margin-top: 20px;
|
|
@@ -132,6 +132,6 @@ table { /* 表格: 小五号宋体 */
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
b, strong { /* 加粗按黑体处理 */
|
|
135
|
-
font-weight:
|
|
136
|
-
font-family: '
|
|
135
|
+
font-weight: normal;
|
|
136
|
+
font-family: '黑体', 'SimHei', '华文黑体', 'STHeiti';
|
|
137
137
|
}
|
package/theme/aps/aps.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MarkdownPaperTheme } from '../theme'
|
|
2
2
|
import { readFileSync } from 'node:fs'
|
|
3
3
|
import { resolve } from 'node:path'
|
|
4
4
|
import type { PDFOptions } from 'puppeteer-core'
|
|
5
5
|
|
|
6
|
-
export class APS extends
|
|
6
|
+
export class APS extends MarkdownPaperTheme {
|
|
7
7
|
|
|
8
8
|
css: string
|
|
9
|
-
preParseMarkdown: (md: string) => string
|
|
10
|
-
preParseHTML: (html: string) => string
|
|
9
|
+
preParseMarkdown: (md: string) => Promise<string>
|
|
10
|
+
preParseHTML: (html: string) => Promise<string>
|
|
11
11
|
script: () => void
|
|
12
12
|
pdfOptions: PDFOptions
|
|
13
13
|
|
|
@@ -34,7 +34,7 @@ export class APS extends Theme {
|
|
|
34
34
|
this.css = readFileSync(resolve(import.meta.dir, 'aps.css'), 'utf-8')
|
|
35
35
|
|
|
36
36
|
// preParseMarkdown
|
|
37
|
-
this.preParseMarkdown = (md: string): string => {
|
|
37
|
+
this.preParseMarkdown = async (md: string): Promise<string> => {
|
|
38
38
|
// 作者
|
|
39
39
|
md = md.replace(/#author# (.*)/mg, '<div class="author">$1</div>')
|
|
40
40
|
// 单位
|
|
@@ -48,17 +48,10 @@ export class APS extends Theme {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// preParseHTML
|
|
51
|
-
this.preParseHTML = (html: string): string => {
|
|
51
|
+
this.preParseHTML = async (html: string): Promise<string> => {
|
|
52
52
|
// 把包裹图片的 p 标签去掉
|
|
53
53
|
html = html.replace(/<p><img (.*?)><\/p>/g, '<img $1>')
|
|
54
|
-
//
|
|
55
|
-
html = html.replace(/<\/head>/, `
|
|
56
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
57
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
58
|
-
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@200..900&display=swap" rel="stylesheet">
|
|
59
|
-
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@200..900&display=swap" rel="stylesheet">
|
|
60
|
-
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif:wght@200..900&display=swap" rel="stylesheet">
|
|
61
|
-
`)
|
|
54
|
+
// 返回处理后的字符串
|
|
62
55
|
return html
|
|
63
56
|
}
|
|
64
57
|
|
|
@@ -125,6 +118,5 @@ export class APS extends Theme {
|
|
|
125
118
|
headerTemplate: showTitle ? `<div style="font-size: 9px; font-family: 'SimSun'; color: #333; padding: 5px; margin-left: 0.6cm;"> <span class="title"></span> </div>` : `<div></div>`,
|
|
126
119
|
footerTemplate: hideFooter ? `<div></div>` : `<div style="font-size: 9px; font-family: 'SimSun'; color: #333; padding: 5px; margin: 0 auto;">第 <span class="pageNumber"></span> 页 / 共 <span class="totalPages"></span> 页</div>`,
|
|
127
120
|
}
|
|
128
|
-
|
|
129
121
|
}
|
|
130
122
|
}
|
package/theme/theme.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PDFOptions } from 'puppeteer-core'
|
|
2
2
|
|
|
3
|
-
export abstract class
|
|
3
|
+
export abstract class MarkdownPaperTheme {
|
|
4
4
|
/**
|
|
5
5
|
* @param args 命令行参数
|
|
6
6
|
* @param cwd 当前工作目录
|
|
@@ -24,14 +24,14 @@ export abstract class Theme {
|
|
|
24
24
|
* @param md markdown 字符串
|
|
25
25
|
* @returns 转换后的 markdown 字符串
|
|
26
26
|
*/
|
|
27
|
-
abstract preParseMarkdown(md: string): string
|
|
27
|
+
abstract preParseMarkdown(md: string): Promise<string>
|
|
28
28
|
/**
|
|
29
29
|
* 预处理 html 字符串
|
|
30
30
|
* 将在保存 html 文件前调用
|
|
31
31
|
* @param html html 字符串
|
|
32
32
|
* @returns 转换后的 html 字符串
|
|
33
33
|
*/
|
|
34
|
-
abstract preParseHTML(html: string): string
|
|
34
|
+
abstract preParseHTML(html: string): Promise<string>
|
|
35
35
|
/**
|
|
36
36
|
* 在网页中要执行的函数
|
|
37
37
|
* 将在保存 html 文件后调用
|
package/theme/aps/aps.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# APS 模板
|
|
2
|
-
`Acta Psychologica Sinica`, 心理学报
|
|
3
|
-
|
|
4
|
-
## 额外命令行参数
|
|
5
|
-
| 参数 | 说明 |
|
|
6
|
-
| :---: | :---: |
|
|
7
|
-
| `--showTitle` | 在页眉显示文件名, 默认不显示 |
|
|
8
|
-
| `--hideFooter` | 隐藏页码, 默认显示 |
|
|
9
|
-
| `--zhPunctuation` | 将正文中的英文标点符号替换为中文标点符号, 默认不替换<br>仅替换 `PDF` 和 `DOCX` 文件 |
|
|
10
|
-
| `--enPunctuation` | 将正文中的中文标点符号替换为英文标点符号, 默认不替换<br>仅替换 `PDF` 和 `DOCX` 文件 |
|
|
11
|
-
|
|
12
|
-
## 编写格式
|
|
13
|
-
```markdown
|
|
14
|
-
# 中文标题
|
|
15
|
-
#author# 作者信息
|
|
16
|
-
#school# 单位信息
|
|
17
|
-
#abstract# 摘要内容
|
|
18
|
-
#keywords# 关键词内容
|
|
19
|
-
|
|
20
|
-
## 1 一级标题
|
|
21
|
-
### 1.1 二级标题
|
|
22
|
-
#### 1.1.1 三级标题
|
|
23
|
-
正文
|
|
24
|
-
|
|
25
|
-

|
|
26
|
-
|
|
27
|
-
> 图片标题
|
|
28
|
-
|
|
29
|
-
> 表格标题
|
|
30
|
-
|
|
31
|
-
| 表头1 | 表头2 |
|
|
32
|
-
| :---: | :---: |
|
|
33
|
-
| 内容1 | 内容2 |
|
|
34
|
-
|
|
35
|
-
##### 参考文献
|
|
36
|
-
- 文献1
|
|
37
|
-
- 文献2
|
|
38
|
-
- 文献3
|
|
39
|
-
|
|
40
|
-
##### 附录
|
|
41
|
-
```
|
package/theme/bnu/bnu.css
DELETED
|
File without changes
|
package/theme/bnu/bnu.md
DELETED
|
File without changes
|
package/theme/bnu/bnu.ts
DELETED
|
File without changes
|