@wenyan-md/mcp 1.0.1

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.
Files changed (54) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +216 -0
  3. package/dist/highlight/highlight/styles/atom-one-dark.min.css +1 -0
  4. package/dist/highlight/highlight/styles/atom-one-light.min.css +1 -0
  5. package/dist/highlight/highlight/styles/dracula.min.css +8 -0
  6. package/dist/highlight/highlight/styles/github-dark.min.css +10 -0
  7. package/dist/highlight/highlight/styles/github.min.css +10 -0
  8. package/dist/highlight/highlight/styles/monokai.min.css +1 -0
  9. package/dist/highlight/highlight/styles/solarized-dark.min.css +8 -0
  10. package/dist/highlight/highlight/styles/solarized-light.min.css +8 -0
  11. package/dist/highlight/highlight/styles/xcode.min.css +1 -0
  12. package/dist/highlight/styles/atom-one-dark.min.css +1 -0
  13. package/dist/highlight/styles/atom-one-light.min.css +1 -0
  14. package/dist/highlight/styles/dracula.min.css +8 -0
  15. package/dist/highlight/styles/github-dark.min.css +10 -0
  16. package/dist/highlight/styles/github.min.css +10 -0
  17. package/dist/highlight/styles/monokai.min.css +1 -0
  18. package/dist/highlight/styles/solarized-dark.min.css +8 -0
  19. package/dist/highlight/styles/solarized-light.min.css +8 -0
  20. package/dist/highlight/styles/xcode.min.css +1 -0
  21. package/dist/index.d.ts +11 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +118 -0
  24. package/dist/mac_style.css +8 -0
  25. package/dist/main.js +495 -0
  26. package/dist/publish.d.ts +2 -0
  27. package/dist/publish.d.ts.map +1 -0
  28. package/dist/publish.js +142 -0
  29. package/dist/resources.d.ts +3 -0
  30. package/dist/resources.d.ts.map +1 -0
  31. package/dist/resources.js +42 -0
  32. package/dist/theme.d.ts +7 -0
  33. package/dist/theme.d.ts.map +1 -0
  34. package/dist/theme.js +42 -0
  35. package/dist/themes/default.css +180 -0
  36. package/dist/themes/lapis.css +190 -0
  37. package/dist/themes/maize.css +190 -0
  38. package/dist/themes/orangeheart.css +180 -0
  39. package/dist/themes/phycat.css +331 -0
  40. package/dist/themes/pie.css +236 -0
  41. package/dist/themes/purple.css +179 -0
  42. package/dist/themes/rainbow.css +163 -0
  43. package/dist/themes/themes/default.css +180 -0
  44. package/dist/themes/themes/lapis.css +190 -0
  45. package/dist/themes/themes/maize.css +190 -0
  46. package/dist/themes/themes/orangeheart.css +180 -0
  47. package/dist/themes/themes/phycat.css +331 -0
  48. package/dist/themes/themes/pie.css +236 -0
  49. package/dist/themes/themes/purple.css +179 -0
  50. package/dist/themes/themes/rainbow.css +163 -0
  51. package/dist/types.d.ts +10 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +1 -0
  54. package/package.json +31 -0
@@ -0,0 +1,142 @@
1
+ import { JSDOM } from "jsdom";
2
+ import { FormData } from 'formdata-node';
3
+ import { fileFromPath } from 'formdata-node/file-from-path';
4
+ import path from "path";
5
+ const tokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
6
+ const publishUrl = "https://api.weixin.qq.com/cgi-bin/draft/add";
7
+ const uploadUrl = `https://api.weixin.qq.com/cgi-bin/material/add_material`;
8
+ const appId = process.env.WECHAT_APP_ID || "";
9
+ const appSecret = process.env.WECHAT_APP_SECRET || "";
10
+ const hostImagePath = process.env.HOST_IMAGE_PATH || "";
11
+ const dockerImagePath = "/mnt/host-downloads";
12
+ async function fetchAccessToken() {
13
+ try {
14
+ const response = await fetch(`${tokenUrl}?grant_type=client_credential&appid=${appId}&secret=${appSecret}`);
15
+ const data = await response.json();
16
+ if (data.access_token) {
17
+ return data;
18
+ }
19
+ else if (data.errcode) {
20
+ throw new Error(`获取 Access Token 失败,错误码:${data.errcode},${data.errmsg}`);
21
+ }
22
+ else {
23
+ throw new Error(`获取 Access Token 失败: ${data}`);
24
+ }
25
+ }
26
+ catch (error) {
27
+ throw error;
28
+ }
29
+ }
30
+ async function uploadMaterial(type, fileData, fileName, accessToken) {
31
+ const form = new FormData();
32
+ form.append("media", fileData, fileName);
33
+ const response = await fetch(`${uploadUrl}?access_token=${accessToken}&type=${type}`, {
34
+ method: 'POST',
35
+ body: form,
36
+ });
37
+ if (!response.ok) {
38
+ const errorText = await response.text();
39
+ throw new Error(`上传失败: ${response.status} ${errorText}`);
40
+ }
41
+ const data = await response.json();
42
+ if (data.errcode) {
43
+ throw new Error(`上传失败,错误码:${data.errcode},错误信息:${data.errmsg}`);
44
+ }
45
+ const result = data.url.replace("http://", "https://");
46
+ data.url = result;
47
+ return data;
48
+ }
49
+ async function uploadImage(imageUrl, accessToken, fileName) {
50
+ if (imageUrl.startsWith("http")) {
51
+ const response = await fetch(imageUrl);
52
+ if (!response.ok || !response.body) {
53
+ throw new Error(`Failed to download image from URL: ${imageUrl}`);
54
+ }
55
+ const fileNameFromUrl = path.basename(imageUrl.split("?")[0]);
56
+ const ext = path.extname(fileNameFromUrl);
57
+ const imageName = fileName ?? (ext === "" ? `${fileNameFromUrl}.jpg` : fileNameFromUrl);
58
+ const buffer = await response.arrayBuffer();
59
+ return await uploadMaterial('image', new Blob([buffer]), imageName, accessToken);
60
+ }
61
+ else {
62
+ const localImagePath = hostImagePath ? imageUrl.replace(hostImagePath, dockerImagePath) : imageUrl;
63
+ const fileNameFromLocal = path.basename(localImagePath);
64
+ const ext = path.extname(fileNameFromLocal);
65
+ const imageName = fileName ?? (ext === "" ? `${fileNameFromLocal}.jpg` : fileNameFromLocal);
66
+ const file = await fileFromPath(localImagePath);
67
+ return await uploadMaterial('image', file, imageName, accessToken);
68
+ }
69
+ }
70
+ async function uploadImages(content, accessToken) {
71
+ if (!content.includes('<img')) {
72
+ return { html: content, firstImageId: "" };
73
+ }
74
+ const dom = new JSDOM(content);
75
+ const document = dom.window.document;
76
+ const images = Array.from(document.querySelectorAll('img'));
77
+ const uploadPromises = images.map(async (element) => {
78
+ const dataSrc = element.getAttribute('src');
79
+ if (dataSrc) {
80
+ if (!dataSrc.startsWith('https://mmbiz.qpic.cn')) {
81
+ const resp = await uploadImage(dataSrc, accessToken);
82
+ element.setAttribute('src', resp.url);
83
+ return resp.media_id;
84
+ }
85
+ else {
86
+ return dataSrc;
87
+ }
88
+ }
89
+ return null;
90
+ });
91
+ const mediaIds = (await Promise.all(uploadPromises)).filter(Boolean);
92
+ const firstImageId = mediaIds[0] || "";
93
+ const updatedHtml = dom.serialize();
94
+ return { html: updatedHtml, firstImageId };
95
+ }
96
+ export async function publishToDraft(title, content, cover) {
97
+ try {
98
+ const accessToken = await fetchAccessToken();
99
+ const handledContent = content.replace(/\n<li/g, "<li").replace(/<\/li>\n/g, "<\/li>");
100
+ const { html, firstImageId } = await uploadImages(handledContent, accessToken.access_token);
101
+ let thumbMediaId = "";
102
+ if (cover) {
103
+ const resp = await uploadImage(cover, accessToken.access_token, "cover.jpg");
104
+ thumbMediaId = resp.media_id;
105
+ }
106
+ else {
107
+ if (firstImageId.startsWith("https://mmbiz.qpic.cn")) {
108
+ const resp = await uploadImage(firstImageId, accessToken.access_token, "cover.jpg");
109
+ thumbMediaId = resp.media_id;
110
+ }
111
+ else {
112
+ thumbMediaId = firstImageId;
113
+ }
114
+ }
115
+ if (!thumbMediaId) {
116
+ throw new Error("你必须指定一张封面图或者在正文中至少出现一张图片。");
117
+ }
118
+ const response = await fetch(`${publishUrl}?access_token=${accessToken.access_token}`, {
119
+ method: 'POST',
120
+ body: JSON.stringify({
121
+ articles: [{
122
+ title: title,
123
+ content: html,
124
+ thumb_media_id: thumbMediaId,
125
+ }]
126
+ })
127
+ });
128
+ const data = await response.json();
129
+ if (data.media_id) {
130
+ return data;
131
+ }
132
+ else if (data.errcode) {
133
+ throw new Error(`上传到公众号草稿失败,错误码:${data.errcode},${data.errmsg}`);
134
+ }
135
+ else {
136
+ throw new Error(`上传到公众号草稿失败: ${data}`);
137
+ }
138
+ }
139
+ catch (error) {
140
+ throw error;
141
+ }
142
+ }
@@ -0,0 +1,3 @@
1
+ import { Theme } from "./types.js";
2
+ export declare const themes: Record<string, Theme>;
3
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAyCxC,CAAC"}
@@ -0,0 +1,42 @@
1
+ export const themes = {
2
+ default: {
3
+ id: "default",
4
+ name: "Default",
5
+ description: "A clean and traditional layout for articles.",
6
+ },
7
+ orangeHeart: {
8
+ id: "orangeHeart",
9
+ name: "Orange Heart",
10
+ description: "Modern look with bold headers and minimalistic styling.",
11
+ },
12
+ rainbow: {
13
+ id: "rainbow",
14
+ name: "Rainbow",
15
+ description: "Typewriter-style layout for retro aesthetics.",
16
+ },
17
+ lapis: {
18
+ id: "lapis",
19
+ name: "Lapis",
20
+ description: "Typewriter-style layout for retro aesthetics.",
21
+ },
22
+ pie: {
23
+ id: "pie",
24
+ name: "Pie",
25
+ description: "Typewriter-style layout for retro aesthetics.",
26
+ },
27
+ maize: {
28
+ id: "maize",
29
+ name: "Maize",
30
+ description: "Typewriter-style layout for retro aesthetics.",
31
+ },
32
+ purple: {
33
+ id: "purple",
34
+ name: "Purple",
35
+ description: "Typewriter-style layout for retro aesthetics.",
36
+ },
37
+ phycat: {
38
+ id: "phycat",
39
+ name: "物理猫-薄荷",
40
+ description: "A well-structured, hierarchical mint green theme.",
41
+ },
42
+ };
@@ -0,0 +1,7 @@
1
+ export type Theme = {
2
+ id: string;
3
+ name: string;
4
+ description: string;
5
+ };
6
+ export declare const themes: Record<string, Theme>;
7
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAyCxC,CAAC"}
package/dist/theme.js ADDED
@@ -0,0 +1,42 @@
1
+ export const themes = {
2
+ default: {
3
+ id: "default",
4
+ name: "Default",
5
+ description: "A clean, classic layout ideal for long-form reading.",
6
+ },
7
+ orangeHeart: {
8
+ id: "orangeheart",
9
+ name: "OrangeHeart",
10
+ description: "A vibrant and elegant theme in warm orange tones.",
11
+ },
12
+ rainbow: {
13
+ id: "rainbow",
14
+ name: "Rainbow",
15
+ description: "A colorful, lively theme with a clean layout.",
16
+ },
17
+ lapis: {
18
+ id: "lapis",
19
+ name: "Lapis",
20
+ description: "A minimal and refreshing theme in cool blue tones.",
21
+ },
22
+ pie: {
23
+ id: "pie",
24
+ name: "Pie",
25
+ description: "Inspired by sspai.com and Misty — modern, sharp, and stylish.",
26
+ },
27
+ maize: {
28
+ id: "maize",
29
+ name: "Maize",
30
+ description: "A crisp, light theme with a soft maize palette.",
31
+ },
32
+ purple: {
33
+ id: "purple",
34
+ name: "Purple",
35
+ description: "Clean and minimalist, with a subtle purple accent.",
36
+ },
37
+ phycat: {
38
+ id: "phycat",
39
+ name: "phycat",
40
+ description: "物理猫-薄荷:a mint-green theme with clear structure and hierarchy.",
41
+ },
42
+ };
@@ -0,0 +1,180 @@
1
+ /**
2
+ * 欢迎使用自定义主题功能,使用教程:
3
+ * https://babyno.top/posts/2024/11/wenyan-supports-customized-themes/
4
+ */
5
+ /* 全局属性 */
6
+ #wenyan {
7
+ font-family: var(--sans-serif-font);
8
+ line-height: 1.75;
9
+ font-size: 16px;
10
+ }
11
+ /* 全局子元素属性 */
12
+ /* 支持分组 */
13
+ #wenyan h1,
14
+ #wenyan h2,
15
+ #wenyan h3,
16
+ #wenyan h4,
17
+ #wenyan h5,
18
+ #wenyan h6,
19
+ #wenyan p,
20
+ #wenyan pre {
21
+ margin: 1em 0;
22
+ }
23
+ /* 段落 */
24
+ #wenyan p {
25
+ }
26
+ /* 加粗 */
27
+ #wenyan p strong {
28
+ }
29
+ /* 斜体 */
30
+ #wenyan p em {
31
+ }
32
+ /* 一级标题 */
33
+ #wenyan h1 {
34
+ text-align: center;
35
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
36
+ font-size: 1.5em;
37
+ }
38
+ /* 标题文字 */
39
+ #wenyan h1 span {
40
+ }
41
+ /* 标题前缀,h1-h6都支持前缀 */
42
+ #wenyan h1::before {
43
+ }
44
+ /* 标题后缀,h1-h6都支持后缀 */
45
+ #wenyan h1::after {
46
+ }
47
+ /* 二级标题 */
48
+ #wenyan h2 {
49
+ text-align: center;
50
+ font-size: 1.2em;
51
+ border-bottom: 1px solid #f7f7f7;
52
+ font-weight: bold;
53
+ }
54
+ /* 三-六级标题 */
55
+ #wenyan h3,
56
+ #wenyan h4,
57
+ #wenyan h5,
58
+ #wenyan h6 {
59
+ font-size: 1em;
60
+ font-weight: bold;
61
+ }
62
+ /* 列表 */
63
+ #wenyan ul,
64
+ #wenyan ol {
65
+ padding-left: 1.2em;
66
+ }
67
+ /* 列表元素 */
68
+ #wenyan li {
69
+ margin-left: 1.2em;
70
+ }
71
+ /* 图片 */
72
+ #wenyan img {
73
+ max-width: 100%;
74
+ height: auto;
75
+ margin: 0 auto;
76
+ display: block;
77
+ }
78
+ /* 表格 */
79
+ #wenyan table {
80
+ border-collapse: collapse;
81
+ margin: 1.4em auto;
82
+ max-width: 100%;
83
+ table-layout: fixed;
84
+ text-align: left;
85
+ overflow: auto;
86
+ display: table;
87
+ word-wrap: break-word;
88
+ word-break: break-all;
89
+ }
90
+ /* 表格单元格 */
91
+ #wenyan table td,
92
+ #wenyan table th {
93
+ font-size: 0.75em;
94
+ padding: 9px 12px;
95
+ line-height: 22px;
96
+ color: #222;
97
+ border: 1px solid #d8d8d8;
98
+ vertical-align: top;
99
+ }
100
+ /* 表格表头 */
101
+ #wenyan table th {
102
+ font-weight: bold;
103
+ background-color: #f0f0f0;
104
+ }
105
+ /* 表格斑马条纹效果 */
106
+ #wenyan table tr:nth-child(2n) {
107
+ background-color: #f8f8f8;
108
+ }
109
+ /* 引用块 */
110
+ #wenyan blockquote {
111
+ background: #afb8c133;
112
+ border-left: 0.5em solid #ccc;
113
+ margin: 1.5em 0;
114
+ padding: 0.5em 10px;
115
+ font-style: italic;
116
+ font-size: 0.9em;
117
+ }
118
+ /* 引用块前缀 */
119
+ #wenyan blockquote::before {
120
+ }
121
+ /* 引用块后缀 */
122
+ #wenyan blockquote::after {
123
+ }
124
+ /* 行内代码 */
125
+ #wenyan p code {
126
+ font-family: var(--monospace-font);
127
+ color: #ff502c;
128
+ padding: 4px 6px;
129
+ font-size: 0.78em;
130
+ }
131
+ /* 代码块外围 */
132
+ #wenyan pre {
133
+ border-radius: 5px;
134
+ line-height: 2;
135
+ margin: 1em 0.5em;
136
+ padding: .5em;
137
+ box-shadow: rgba(0, 0, 0, 0.55) 0px 1px 5px;
138
+ }
139
+ /* 代码块 */
140
+ #wenyan pre code {
141
+ font-family: var(--monospace-font);
142
+ display: block;
143
+ overflow-x: auto;
144
+ margin: .5em;
145
+ padding: 0;
146
+ }
147
+ /* 分割线 */
148
+ #wenyan hr {
149
+ border: none;
150
+ border-top: 1px solid #ddd;
151
+ margin-top: 2em;
152
+ margin-bottom: 2em;
153
+ }
154
+ /* 链接 */
155
+ #wenyan a {
156
+ word-wrap: break-word;
157
+ color: #0069c2;
158
+ }
159
+ /* 原始链接旁脚注上标 */
160
+ #wenyan .footnote {
161
+ color: #0069c2;
162
+ }
163
+ /* 脚注行 */
164
+ #wenyan #footnotes p {
165
+ display: flex;
166
+ margin: 0;
167
+ font-size: 0.9em;
168
+ }
169
+ /* 脚注行内编号 */
170
+ #wenyan .footnote-num {
171
+ display: inline;
172
+ width: 10%;
173
+ }
174
+ /* 脚注行内文字 */
175
+ #wenyan .footnote-txt {
176
+ display: inline;
177
+ width: 90%;
178
+ word-wrap: break-word;
179
+ word-break: break-all;
180
+ }
@@ -0,0 +1,190 @@
1
+ /*
2
+ * Typora Theme - Lapis / Author - YiNN
3
+ * https://github.com/YiNNx/typora-theme-lapis
4
+ */
5
+
6
+ :root {
7
+ --text-color: #40464f;
8
+ --primary-color: #4870ac;
9
+ --bg-color: #ffffff;
10
+ --marker-color: #a2b6d4;
11
+ --source-color: #a8a8a9;
12
+ --header-span-color: var(--primary-color);
13
+ --block-bg-color: #f6f8fa;
14
+ }
15
+ #wenyan {
16
+ color: var(--text-color);
17
+ font-family: var(--sans-serif-font);
18
+ line-height: 1.75;
19
+ font-size: 16px;
20
+ }
21
+ #wenyan p,
22
+ #wenyan pre {
23
+ margin: 1em 0.8em;
24
+ }
25
+ #wenyan strong {
26
+ color: var(--primary-color);
27
+ }
28
+ #wenyan a {
29
+ word-wrap: break-word;
30
+ color: var(--primary-color);
31
+ }
32
+ #wenyan p {
33
+ color: var(--text-color);
34
+ }
35
+ #wenyan h4,
36
+ #wenyan h5,
37
+ #wenyan h6 {
38
+ font-weight: normal;
39
+ }
40
+ #wenyan h1,
41
+ #wenyan h2,
42
+ #wenyan h3,
43
+ #wenyan h4,
44
+ #wenyan h5,
45
+ #wenyan h6 {
46
+ padding: 0px;
47
+ color: var(--primary-color);
48
+ margin: 1.2em 0 1em;
49
+ }
50
+ #wenyan h1 {
51
+ text-align: center;
52
+ }
53
+ #wenyan h2 {
54
+ padding: 1px 12.5px;
55
+ border-radius: 4px;
56
+ display: inline-block;
57
+ }
58
+ #wenyan h2,
59
+ #wenyan h2 code {
60
+ background-color: var(--header-span-color);
61
+ }
62
+ #wenyan h2,
63
+ #wenyan h2 a,
64
+ #wenyan h2 code,
65
+ #wenyan h2 strong {
66
+ color: var(--bg-color);
67
+ }
68
+ #wenyan h1 {
69
+ font-size: 1.5em;
70
+ }
71
+ #wenyan h2 {
72
+ font-size: 1.3em;
73
+ }
74
+ #wenyan h3 {
75
+ font-size: 1.3em;
76
+ }
77
+ #wenyan h4 {
78
+ font-size: 1.2em;
79
+ }
80
+ #wenyan h5 {
81
+ font-size: 1.2em;
82
+ }
83
+ #wenyan h6 {
84
+ font-size: 1.2em;
85
+ }
86
+ #wenyan ul {
87
+ list-style-type: disc;
88
+ }
89
+ #wenyan em {
90
+ padding: 0 3px 0 0;
91
+ }
92
+ #wenyan ul ul {
93
+ list-style-type: square;
94
+ }
95
+ #wenyan ol {
96
+ list-style-type: decimal;
97
+ }
98
+ #wenyan blockquote {
99
+ display: block;
100
+ font-size: 0.9em;
101
+ border-left: 3px solid var(--primary-color);
102
+ padding: 0.5em 1em;
103
+ margin: 0;
104
+ background: var(--block-bg-color);
105
+ }
106
+ #wenyan p code {
107
+ color: var(--primary-color);
108
+ font-size: 0.9em;
109
+ font-weight: normal;
110
+ word-wrap: break-word;
111
+ padding: 2px 4px 2px;
112
+ border-radius: 3px;
113
+ margin: 2px;
114
+ background-color: var(--block-bg-color);
115
+ font-family: var(--monospace-font);
116
+ word-break: break-all;
117
+ }
118
+ #wenyan img {
119
+ max-width: 100%;
120
+ max-width: 100%;
121
+ height: auto;
122
+ margin: 0 auto;
123
+ display: block;
124
+ }
125
+ #wenyan table {
126
+ display: table;
127
+ text-align: justify;
128
+ overflow-x: auto;
129
+ border-collapse: collapse;
130
+ margin: 1.4em auto;
131
+ max-width: 100%;
132
+ table-layout: fixed;
133
+ text-align: left;
134
+ overflow: auto;
135
+ word-wrap: break-word;
136
+ word-break: break-all;
137
+ }
138
+ #wenyan table th,
139
+ #wenyan table td {
140
+ border: 1px solid #d9dfe4;
141
+ padding: 9px 12px;
142
+ font-size: 0.75em;
143
+ line-height: 22px;
144
+ vertical-align: top;
145
+ }
146
+ #wenyan table th {
147
+ text-align: center;
148
+ font-weight: bold;
149
+ color: var(--primary-color);
150
+ background: #f7f7f7;
151
+ }
152
+ #wenyan hr {
153
+ margin-top: 20px;
154
+ margin-bottom: 20px;
155
+ border: 0;
156
+ border-top: 2px solid #eef2f5;
157
+ border-radius: 2px;
158
+ }
159
+ #wenyan pre {
160
+ border-radius: 5px;
161
+ line-height: 2;
162
+ margin: 1em 0.5em;
163
+ padding: .5em;
164
+ box-shadow: rgba(0, 0, 0, 0.55) 0px 1px 5px;
165
+ }
166
+ #wenyan pre code {
167
+ display: block;
168
+ overflow-x: auto;
169
+ margin: .5em;
170
+ padding: 0;
171
+ font-family: var(--monospace-font);
172
+ }
173
+ #wenyan .footnote {
174
+ color: var(--primary-color);
175
+ }
176
+ #wenyan #footnotes p {
177
+ display: flex;
178
+ margin: 0;
179
+ font-size: 0.9em;
180
+ }
181
+ #wenyan .footnote-num {
182
+ display: inline;
183
+ width: 10%;
184
+ }
185
+ #wenyan .footnote-txt {
186
+ display: inline;
187
+ width: 90%;
188
+ word-wrap: break-word;
189
+ word-break: break-all;
190
+ }