multi-publisher 1.0.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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +370 -0
  3. package/dist/adapters/baijiahao.d.ts +14 -0
  4. package/dist/adapters/baijiahao.js +77 -0
  5. package/dist/adapters/base-adapter.d.ts +41 -0
  6. package/dist/adapters/base-adapter.js +84 -0
  7. package/dist/adapters/bilibili.d.ts +14 -0
  8. package/dist/adapters/bilibili.js +86 -0
  9. package/dist/adapters/cnblogs.d.ts +14 -0
  10. package/dist/adapters/cnblogs.js +90 -0
  11. package/dist/adapters/csdn.d.ts +29 -0
  12. package/dist/adapters/csdn.js +174 -0
  13. package/dist/adapters/cto51.d.ts +14 -0
  14. package/dist/adapters/cto51.js +72 -0
  15. package/dist/adapters/douban.d.ts +14 -0
  16. package/dist/adapters/douban.js +49 -0
  17. package/dist/adapters/eastmoney.d.ts +14 -0
  18. package/dist/adapters/eastmoney.js +47 -0
  19. package/dist/adapters/imooc.d.ts +14 -0
  20. package/dist/adapters/imooc.js +78 -0
  21. package/dist/adapters/index.d.ts +26 -0
  22. package/dist/adapters/index.js +22 -0
  23. package/dist/adapters/interface.d.ts +44 -0
  24. package/dist/adapters/interface.js +1 -0
  25. package/dist/adapters/juejin.d.ts +23 -0
  26. package/dist/adapters/juejin.js +166 -0
  27. package/dist/adapters/oschina.d.ts +14 -0
  28. package/dist/adapters/oschina.js +77 -0
  29. package/dist/adapters/registry.d.ts +61 -0
  30. package/dist/adapters/registry.js +146 -0
  31. package/dist/adapters/segmentfault.d.ts +14 -0
  32. package/dist/adapters/segmentfault.js +73 -0
  33. package/dist/adapters/sohu.d.ts +14 -0
  34. package/dist/adapters/sohu.js +72 -0
  35. package/dist/adapters/toutiao.d.ts +9 -0
  36. package/dist/adapters/toutiao.js +199 -0
  37. package/dist/adapters/wechat-publisher.d.ts +55 -0
  38. package/dist/adapters/wechat-publisher.js +210 -0
  39. package/dist/adapters/weibo.d.ts +14 -0
  40. package/dist/adapters/weibo.js +99 -0
  41. package/dist/adapters/weixin.d.ts +14 -0
  42. package/dist/adapters/weixin.js +63 -0
  43. package/dist/adapters/woshipm.d.ts +14 -0
  44. package/dist/adapters/woshipm.js +72 -0
  45. package/dist/adapters/xiaohongshu.d.ts +9 -0
  46. package/dist/adapters/xiaohongshu.js +199 -0
  47. package/dist/adapters/xueqiu.d.ts +14 -0
  48. package/dist/adapters/xueqiu.js +74 -0
  49. package/dist/adapters/yuque.d.ts +13 -0
  50. package/dist/adapters/yuque.js +25 -0
  51. package/dist/adapters/zhihu.d.ts +23 -0
  52. package/dist/adapters/zhihu.js +142 -0
  53. package/dist/cli/cookie.d.ts +5 -0
  54. package/dist/cli/cookie.js +80 -0
  55. package/dist/cli/credential.d.ts +6 -0
  56. package/dist/cli/credential.js +32 -0
  57. package/dist/cli/index.d.ts +5 -0
  58. package/dist/cli/index.js +72 -0
  59. package/dist/cli/login.d.ts +3 -0
  60. package/dist/cli/login.js +101 -0
  61. package/dist/cli/platforms.d.ts +1 -0
  62. package/dist/cli/platforms.js +35 -0
  63. package/dist/cli/publish-all.d.ts +6 -0
  64. package/dist/cli/publish-all.js +101 -0
  65. package/dist/cli/publish.d.ts +7 -0
  66. package/dist/cli/publish.js +78 -0
  67. package/dist/cli/render.d.ts +9 -0
  68. package/dist/cli/render.js +40 -0
  69. package/dist/commands/login.d.ts +43 -0
  70. package/dist/commands/login.js +248 -0
  71. package/dist/commands/publish.d.ts +19 -0
  72. package/dist/commands/publish.js +275 -0
  73. package/dist/config.d.ts +177 -0
  74. package/dist/config.js +333 -0
  75. package/dist/core/mathjax.d.ts +4 -0
  76. package/dist/core/mathjax.js +33 -0
  77. package/dist/core/parser.d.ts +17 -0
  78. package/dist/core/parser.js +42 -0
  79. package/dist/core/renderer.d.ts +18 -0
  80. package/dist/core/renderer.js +30 -0
  81. package/dist/core/styler.d.ts +8 -0
  82. package/dist/core/styler.js +11 -0
  83. package/dist/core/theme.d.ts +9 -0
  84. package/dist/core/theme.js +420 -0
  85. package/dist/index.d.ts +8 -0
  86. package/dist/index.js +7 -0
  87. package/dist/runtime/browser-runtime.d.ts +79 -0
  88. package/dist/runtime/browser-runtime.js +501 -0
  89. package/dist/runtime/index.d.ts +12 -0
  90. package/dist/runtime/index.js +1 -0
  91. package/dist/runtime/node-runtime.d.ts +5 -0
  92. package/dist/runtime/node-runtime.js +25 -0
  93. package/dist/tools/xiaohongshu-sniffer.d.ts +1 -0
  94. package/dist/tools/xiaohongshu-sniffer.js +54 -0
  95. package/package.json +62 -0
  96. package/themes/all-themes-preview.html +522 -0
  97. package/themes/previews/cyberpunk.png +0 -0
  98. package/themes/previews/minimal.png +0 -0
  99. package/themes/previews/nord.png +0 -0
  100. package/themes/previews/wechat.png +0 -0
@@ -0,0 +1,420 @@
1
+ /**
2
+ * 主题加载与管理
3
+ */
4
+ import fs from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ // 获取 themes 目录路径(dist 同级 themes/)
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const THEMES_DIR = path.resolve(__dirname, '../../themes');
10
+ // 默认微信公众号主题 CSS(导出让 renderer.ts 也能用)
11
+ export const DEFAULT_CSS = `
12
+ p {
13
+ color: rgb(51, 51, 51);
14
+ font-size: 15px;
15
+ line-height: 1.75em;
16
+ margin: 0 0 1em 0;
17
+ word-wrap: break-word;
18
+ }
19
+ h1, h2, h3, h4, h5, h6 {
20
+ font-weight: bold;
21
+ margin: 1em 0 0.5em 0;
22
+ }
23
+ h1 { font-size: 1.25em; line-height: 1.4em; }
24
+ h2 { font-size: 1.125em; }
25
+ h3 { font-size: 1.05em; }
26
+ h4, h5, h6 { font-size: 1em; }
27
+ li p { margin: 0; }
28
+ ul, ol { margin: 1em 0; padding-left: 2em; }
29
+ li { margin-bottom: 0.4em; }
30
+ pre {
31
+ background-color: #f6f8fa;
32
+ border-radius: 6px;
33
+ padding: 16px;
34
+ overflow-x: auto;
35
+ font-size: 14px;
36
+ line-height: 1.6;
37
+ margin: 1em 0;
38
+ }
39
+ code {
40
+ background-color: rgba(175, 184, 193, 0.2);
41
+ border-radius: 3px;
42
+ padding: 0.2em 0.4em;
43
+ font-size: 0.9em;
44
+ font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
45
+ }
46
+ pre code { background: none; padding: 0; font-size: 14px; }
47
+ blockquote { border-left: 4px solid #ddd; padding-left: 1em; margin: 1em 0; color: #666; }
48
+ hr { border: none; border-top: 1px solid #ddd; margin: 1.5em 0; }
49
+ i, cite, em, var, address { font-style: italic; }
50
+ b, strong { font-weight: bolder; }
51
+ img { max-width: 100%; height: auto; display: block; margin: 1em auto; }
52
+ table { border-collapse: collapse; width: 100%; margin: 1em 0; }
53
+ table th, table td { border: 1px solid #ddd; padding: 8px 12px; }
54
+ table th { background-color: #f6f8fa; font-weight: bold; }
55
+ a { color: #0579b7; text-decoration: none; }
56
+ `;
57
+ // 内置主题
58
+ const BUILTIN_THEMES = {
59
+ default: {
60
+ name: 'Default',
61
+ description: '默认简洁主题,适合大多数文章',
62
+ css: DEFAULT_CSS,
63
+ },
64
+ wechat: {
65
+ name: 'Wechat',
66
+ description: '微信风格,仿微信官方文章样式',
67
+ css: DEFAULT_CSS + `
68
+ h1 { font-size: 1.35em; border-bottom: 1px solid #e8e8e8; padding-bottom: 0.3em; }
69
+ blockquote { border-left: 3px solid #c8a96e; background: #faf9f7; }
70
+ img { border-radius: 4px; } table th { background-color: #f8f8f8; }
71
+ a { color: #576b95; border-bottom: 1px solid rgba(87, 107, 149, 0.3); }
72
+ `,
73
+ },
74
+ modern: {
75
+ name: 'Modern',
76
+ description: '现代风格,深色代码块,清晰的视觉层次',
77
+ css: `
78
+ p { color: rgb(45, 45, 45); font-size: 15.5px; line-height: 1.85em; margin: 0 0 1.3em 0; }
79
+ h1, h2, h3 { font-weight: 700; line-height: 1.35em; color: #111; }
80
+ h1 { font-size: 1.4em; border-bottom: 2px solid #4a90d9; padding-bottom: 0.25em; }
81
+ h2 { font-size: 1.2em; }
82
+ pre { background-color: #1e1e1e; border-radius: 10px; padding: 18px 22px; font-size: 13.5px; margin: 1.3em 0; border: 1px solid #333; }
83
+ code { background-color: rgba(74, 144, 217, 0.12); border-radius: 4px; padding: 0.15em 0.45em; font-size: 0.88em; color: #4a90d9; }
84
+ pre code { background: none; padding: 0; color: #d4d4d4; }
85
+ blockquote { border-left: 4px solid #4a90d9; background: linear-gradient(135deg, #f0f7ff 0%, #fff 100%); padding: 0.6em 1.2em; border-radius: 0 6px 6px 0; }
86
+ img { border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); }
87
+ table th { background-color: #4a90d9; color: #fff; }
88
+ a { color: #4a90d9; }
89
+ `,
90
+ },
91
+ minimal: {
92
+ name: 'Minimal',
93
+ description: '简约风格,干净留白,适合阅读',
94
+ css: `
95
+ p { color: rgb(60, 60, 60); font-size: 16px; line-height: 2em; margin: 0 0 1.5em 0; }
96
+ h1 { font-size: 1.5em; text-align: center; letter-spacing: 0.05em; }
97
+ h2 { font-size: 1.25em; border-bottom: 1px solid #eee; padding-bottom: 0.3em; }
98
+ pre { background-color: #fafafa; border-radius: 6px; border: 1px solid #eee; }
99
+ code { background-color: rgba(0,0,0,0.04); border-radius: 3px; color: #c7254e; }
100
+ blockquote { border-left: none; background: #f9f9f9; font-style: italic; }
101
+ img { border-radius: 4px; }
102
+ a { color: #0969da; }
103
+ `,
104
+ },
105
+ cyberpunk: {
106
+ name: 'Cyberpunk',
107
+ description: '赛博朋克风格,炫酷霓虹发光效果',
108
+ css: `
109
+ p { color: #c8c8ff; font-size: 15px; line-height: 1.8em; margin: 0 0 1em 0; }
110
+ h1, h2, h3, h4, h5, h6 { font-weight: bold; margin: 1.2em 0 0.6em 0; line-height: 1.4em; }
111
+ h1 { font-size: 1.6em; color: #00fff5; text-shadow: 0 0 20px #00fff5, 0 0 40px #00fff5; border-bottom: 2px solid #ff00ff; padding-bottom: 0.4em; }
112
+ h2 { font-size: 1.3em; color: #ff00ff; text-shadow: 0 0 10px #ff00ff; }
113
+ h3 { font-size: 1.15em; color: #00fff5; }
114
+ li p { margin: 0; }
115
+ ul, ol { margin: 0.8em 0; padding-left: 1.5em; }
116
+ li { margin-bottom: 0.4em; color: #c8c8ff; }
117
+ pre { background: linear-gradient(135deg, #0d022155, #0a0a1f); border: 1px solid #ff00ff33; border-radius: 8px; padding: 16px; overflow-x: auto; font-size: 13.5px; line-height: 1.7; margin: 1em 0; box-shadow: 0 0 20px #ff00ff22; }
118
+ code { background: linear-gradient(90deg, #ff00ff22, #00fff522); border: 1px solid #ff00ff55; border-radius: 4px; padding: 0.2em 0.5em; color: #00fff5; font-size: 0.9em; font-family: 'SF Mono', Consolas, monospace; }
119
+ pre code { background: none; border: none; padding: 0; color: #00fff5; }
120
+ blockquote { border-left: 3px solid #ff00ff; background: linear-gradient(90deg, #ff00ff11, transparent); padding: 0.8rem 1rem; margin: 1em 0; color: #ff88ff; border-radius: 0 4px 4px 0; }
121
+ hr { border: none; border-top: 1px solid #ff00ff44; margin: 2em 0; }
122
+ i, cite, em, var, address { font-style: italic; color: #ff88ff; }
123
+ b, strong { font-weight: bold; color: #fff; }
124
+ img { max-width: 100%; height: auto; display: block; margin: 1em auto; border-radius: 8px; box-shadow: 0 0 20px #00fff544; }
125
+ table { border-collapse: collapse; width: 100%; margin: 1em 0; }
126
+ table th, table td { border: 1px solid #ff00ff44; padding: 8px 12px; }
127
+ table th { background: linear-gradient(90deg, #ff00ff33, #00fff533); color: #00fff5; font-weight: bold; }
128
+ table tr:nth-child(even) { background-color: #ff00ff11; }
129
+ a { color: #00fff5; text-decoration: none; border-bottom: 1px solid #00fff5; }
130
+ a:hover { text-shadow: 0 0 10px #00fff5; }
131
+ `,
132
+ },
133
+ nord: {
134
+ name: 'Nord',
135
+ description: '北欧冷淡风格,蓝灰色调克制简洁',
136
+ css: `
137
+ p { color: #d8dee9; font-size: 15px; line-height: 1.8em; margin: 0 0 1em 0; }
138
+ h1, h2, h3, h4, h5, h6 { font-weight: 600; margin: 1.2em 0 0.6em 0; line-height: 1.4em; }
139
+ h1 { font-size: 1.6em; color: #88c0d0; border-bottom: 2px solid #4c566a; padding-bottom: 0.4em; }
140
+ h2 { font-size: 1.3em; color: #81a1c1; }
141
+ h3 { font-size: 1.15em; color: #88c0d0; }
142
+ li p { margin: 0; }
143
+ ul, ol { margin: 0.8em 0; padding-left: 1.5em; }
144
+ li { margin-bottom: 0.4em; color: #d8dee9; }
145
+ pre { background: #3b4252; border-radius: 8px; padding: 16px; overflow-x: auto; font-size: 13.5px; line-height: 1.7; margin: 1em 0; border-left: 3px solid #88c0d0; }
146
+ code { background: #3b4252; border-radius: 4px; padding: 0.2em 0.5em; color: #a3be8c; font-size: 0.9em; font-family: 'SF Mono', Consolas, monospace; }
147
+ pre code { background: none; padding: 0; color: #eceff4; }
148
+ blockquote { border-left: 3px solid #5e81ac; background: #3b425255; padding: 0.8rem 1rem; margin: 1em 0; color: #d8dee9; font-style: italic; border-radius: 0 4px 4px 0; }
149
+ hr { border: none; border-top: 1px solid #4c566a; margin: 2em 0; }
150
+ i, cite, em, var, address { font-style: italic; }
151
+ b, strong { font-weight: bold; color: #eceff4; }
152
+ img { max-width: 100%; height: auto; display: block; margin: 1em auto; border-radius: 8px; }
153
+ table { border-collapse: collapse; width: 100%; margin: 1em 0; }
154
+ table th, table td { border: 1px solid #4c566a; padding: 8px 12px; }
155
+ table th { background: #3b4252; color: #88c0d0; font-weight: bold; }
156
+ table tr:nth-child(even) { background-color: #3b425255; }
157
+ a { color: #88c0d0; text-decoration: none; }
158
+ a:hover { color: #81a1c1; }
159
+ `,
160
+ },
161
+ paper: {
162
+ name: 'Paper',
163
+ description: '笔记本风格,纸张纹理文艺复古',
164
+ css: `
165
+ body { background-image: linear-gradient(transparent 95%, #e8e4dc 95%); background-size: 100% 2em; }
166
+ p { color: #444; font-size: 15px; line-height: 2em; margin: 0 0 1em 0; text-indent: 2em; }
167
+ h1, h2, h3, h4, h5, h6 { font-weight: bold; margin: 1.5em 0 0.6em 0; line-height: 1.4em; color: #1a1a1a; font-family: Georgia, serif; }
168
+ h1 { font-size: 1.8em; text-align: center; letter-spacing: 0.05em; text-indent: 0; }
169
+ h2 { font-size: 1.4em; color: #2d2d2d; border-bottom: 1px solid #ccc; padding-bottom: 0.3em; text-indent: 0; }
170
+ h3 { font-size: 1.1em; color: #3d3d3d; text-indent: 0; }
171
+ li p { margin: 0; }
172
+ ul, ol { margin: 0.8em 0; padding-left: 2em; }
173
+ li { margin-bottom: 0.4em; color: #444; }
174
+ pre { background: #f5f5f5; border: 1px solid #ddd; border-radius: 6px; padding: 16px; overflow-x: auto; font-size: 13.5px; line-height: 1.6; margin: 1em 0; font-family: 'Courier New', monospace; }
175
+ code { background: #f5f5f5; border: 1px solid #ddd; border-radius: 3px; padding: 0.15em 0.4em; color: #c7254e; font-size: 0.9em; font-family: 'Courier New', monospace; }
176
+ pre code { background: none; border: none; padding: 0; color: #333; }
177
+ blockquote { border-left: 3px solid #c8a96e; background: #f9f7f3; padding: 0.8rem 1rem; margin: 1em 0; color: #666; font-style: italic; border-radius: 0 4px 4px 0; }
178
+ hr { border: none; border-top: 1px solid #ccc; margin: 2em 0; }
179
+ i, cite, em, var, address { font-style: italic; }
180
+ b, strong { font-weight: bold; color: #111; }
181
+ img { max-width: 100%; height: auto; display: block; margin: 1em auto; border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
182
+ table { border-collapse: collapse; width: 100%; margin: 1em 0; }
183
+ table th, table td { border: 1px solid #ddd; padding: 8px 12px; }
184
+ table th { background: #f5f5f5; color: #333; font-weight: bold; }
185
+ a { color: #0969da; text-decoration: none; border-bottom: 1px dashed #0969da; }
186
+ a:hover { border-bottom-style: solid; }
187
+ `,
188
+ },
189
+ darkelite: {
190
+ name: 'Dark Elite',
191
+ description: '深色精英风格,GitHub 式专业硬核',
192
+ css: `
193
+ p { color: #c9d1d9; font-size: 15px; line-height: 1.8em; margin: 0 0 1em 0; }
194
+ h1, h2, h3, h4, h5, h6 { font-weight: bold; margin: 1.2em 0 0.6em 0; line-height: 1.4em; }
195
+ h1 { font-size: 1.6em; color: #fff; border-bottom: 1px solid #30363d; padding-bottom: 0.4em; }
196
+ h2 { font-size: 1.3em; color: #58a6ff; }
197
+ h3 { font-size: 1.15em; color: #8b949e; }
198
+ li p { margin: 0; }
199
+ ul, ol { margin: 0.8em 0; padding-left: 1.5em; }
200
+ li { margin-bottom: 0.4em; color: #c9d1d9; }
201
+ pre { background: #161b22; border: 1px solid #30363d; border-radius: 6px; padding: 16px; overflow-x: auto; font-size: 13.5px; line-height: 1.7; margin: 1em 0; }
202
+ code { background: #21262d; border: 1px solid #30363d; border-radius: 4px; padding: 0.2em 0.5em; color: #f0883e; font-size: 0.9em; font-family: 'SF Mono', Consolas, monospace; }
203
+ pre code { background: none; border: none; padding: 0; color: #c9d1d9; }
204
+ blockquote { border-left: 3px solid #238636; background: #161b22; padding: 0.8rem 1rem; margin: 1em 0; color: #8b949e; border-radius: 0 4px 4px 0; }
205
+ hr { border: none; border-top: 1px solid #30363d; margin: 2em 0; }
206
+ i, cite, em, var, address { font-style: italic; }
207
+ b, strong { font-weight: bold; color: #fff; }
208
+ img { max-width: 100%; height: auto; display: block; margin: 1em auto; border-radius: 6px; }
209
+ table { border-collapse: collapse; width: 100%; margin: 1em 0; border: 1px solid #30363d; }
210
+ table th, table td { border: 1px solid #30363d; padding: 8px 12px; }
211
+ table th { background: #161b22; color: #58a6ff; font-weight: bold; }
212
+ a { color: #58a6ff; text-decoration: none; }
213
+ a:hover { color: #79c0ff; }
214
+ `,
215
+ },
216
+ sunset: {
217
+ name: 'Sunset',
218
+ description: '日落暖调风格,温暖治愈系',
219
+ css: `
220
+ body { background: linear-gradient(180deg, #1a1a2e 0%, #16213e 50%, #1a1a2e 100%); }
221
+ p { color: #ddd; font-size: 15px; line-height: 1.8em; margin: 0 0 1em 0; }
222
+ h1, h2, h3, h4, h5, h6 { font-weight: bold; margin: 1.2em 0 0.6em 0; line-height: 1.4em; color: #f5f5f5; }
223
+ h1 { font-size: 1.6em; color: #ff6b6b; text-shadow: 0 0 30px #ff6b6b55; text-align: center; }
224
+ h2 { font-size: 1.3em; color: #ffa07a; border-bottom: 1px solid #ffa07a44; padding-bottom: 0.3em; }
225
+ h3 { font-size: 1.15em; color: #ffd93d; }
226
+ li p { margin: 0; }
227
+ ul, ol { margin: 0.8em 0; padding-left: 1.5em; }
228
+ li { margin-bottom: 0.4em; color: #ddd; }
229
+ pre { background: #2d2d44; border-radius: 8px; padding: 16px; overflow-x: auto; font-size: 13.5px; line-height: 1.7; margin: 1em 0; border-left: 3px solid #ff6b6b; }
230
+ code { background: #2d2d44; border-radius: 4px; padding: 0.2em 0.5em; color: #ffd93d; font-size: 0.9em; font-family: 'SF Mono', Consolas, monospace; }
231
+ pre code { background: none; padding: 0; color: #ffa07a; }
232
+ blockquote { background: linear-gradient(90deg, #ff6b6b11, transparent); border-left: 3px solid #ff6b6b; padding: 0.8rem 1rem; margin: 1em 0; color: #bbb; border-radius: 0 4px 4px 0; }
233
+ hr { border: none; border-top: 1px solid #444; margin: 2em 0; }
234
+ i, cite, em, var, address { font-style: italic; color: #ffa07a; }
235
+ b, strong { font-weight: bold; color: #fff; }
236
+ img { max-width: 100%; height: auto; display: block; margin: 1em auto; border-radius: 8px; }
237
+ table { border-collapse: collapse; width: 100%; margin: 1em 0; }
238
+ table th, table td { border: 1px solid #444; padding: 8px 12px; }
239
+ table th { background: #2d2d44; color: #ffd93d; font-weight: bold; }
240
+ a { color: #ffa07a; text-decoration: none; }
241
+ a:hover { color: #ff6b6b; }
242
+ `,
243
+ },
244
+ zen: {
245
+ name: 'Zen',
246
+ description: '禅意风格,日式极简留白',
247
+ css: `
248
+ body { background: #f7f5f0; }
249
+ p { color: #4a4a4a; font-size: 15px; line-height: 2em; margin: 0 0 1.5em 0; }
250
+ h1, h2, h3, h4, h5, h6 { font-weight: normal; margin: 2em 0 0.8em 0; line-height: 1.6em; color: #2d2d2d; font-family: 'Noto Serif SC', 'Songti SC', serif; }
251
+ h1 { font-size: 1.8em; text-align: center; letter-spacing: 0.15em; border-bottom: 1px solid #d4d4d4; padding-bottom: 0.5em; }
252
+ h2 { font-size: 1.4em; letter-spacing: 0.1em; border-left: 3px solid #8b7355; padding-left: 0.8em; }
253
+ h3 { font-size: 1.15em; color: #5a5a5a; }
254
+ li p { margin: 0; }
255
+ ul, ol { margin: 1em 0; padding-left: 1.5em; }
256
+ li { margin-bottom: 0.6em; color: #4a4a4a; line-height: 1.9; }
257
+ pre { background: #ebe8e0; border-radius: 4px; padding: 16px; overflow-x: auto; font-size: 13px; line-height: 1.7; margin: 1.5em 0; border-left: 2px solid #8b7355; }
258
+ code { background: #ebe8e0; border-radius: 3px; padding: 0.15em 0.4em; color: #6b5b4f; font-size: 0.9em; font-family: 'SF Mono', monospace; }
259
+ pre code { background: none; padding: 0; color: #4a4a4a; }
260
+ blockquote { border-left: none; border-top: 1px solid #d4d4d4; border-bottom: 1px solid #d4d4d4; background: none; padding: 1em 1.5em; margin: 2em 0; color: #7a7a7a; font-style: normal; text-align: center; }
261
+ hr { border: none; text-align: center; margin: 3em 0; }
262
+ hr::after { content: '· · ·'; color: #8b7355; letter-spacing: 0.5em; font-size: 1.2em; }
263
+ i, cite, em, var, address { font-style: italic; color: #7a7a7a; }
264
+ b, strong { font-weight: normal; color: #3d3d3d; }
265
+ img { max-width: 100%; height: auto; display: block; margin: 2em auto; border-radius: 2px; }
266
+ table { border-collapse: collapse; width: 100%; margin: 1.5em 0; }
267
+ table th, table td { border: none; border-top: 1px solid #d4d4d4; padding: 10px 12px; }
268
+ table th { color: #8b7355; font-weight: normal; text-align: left; }
269
+ a { color: #8b7355; text-decoration: none; border-bottom: 1px solid transparent; }
270
+ a:hover { border-bottom-color: #8b7355; }
271
+ `,
272
+ },
273
+ retro: {
274
+ name: 'Retro Futurism',
275
+ description: '80年代复古未来主义,霓虹几何',
276
+ css: `
277
+ body { background: #0d0d1a; background-image: repeating-linear-gradient(0deg, transparent, transparent 50px, #1a1a2e 50px, #1a1a2e 51px), repeating-linear-gradient(90deg, transparent, transparent 50px, #1a1a2e 50px, #1a1a2e 51px); }
278
+ p { color: #e0e0e0; font-size: 15px; line-height: 1.8em; margin: 0 0 1em 0; }
279
+ h1, h2, h3, h4, h5, h6 { font-weight: bold; margin: 1.5em 0 0.8em 0; line-height: 1.3em; color: #fff; text-transform: uppercase; letter-spacing: 0.1em; }
280
+ h1 { font-size: 2em; color: #ff6ec7; text-shadow: 3px 3px 0 #00d4ff, -1px -1px 0 #ffff00; transform: skewX(-5deg); }
281
+ h2 { font-size: 1.4em; color: #00d4ff; border-bottom: 2px solid #ff6ec7; padding-bottom: 0.3em; }
282
+ h3 { font-size: 1.15em; color: #ffff00; }
283
+ li p { margin: 0; }
284
+ ul, ol { margin: 1em 0; padding-left: 1.5em; }
285
+ li { margin-bottom: 0.5em; color: #e0e0e0; }
286
+ pre { background: linear-gradient(135deg, #1a1a2e 0%, #0d0d1a 100%); border: 2px solid #ff6ec7; border-radius: 0; padding: 16px; overflow-x: auto; font-size: 13px; line-height: 1.7; margin: 1.5em 0; transform: perspective(500px) rotateX(2deg); box-shadow: 5px 5px 0 #00d4ff; }
287
+ code { background: #ff6ec755; border: 1px solid #ff6ec7; border-radius: 0; padding: 0.2em 0.5em; color: #ff6ec7; font-size: 0.9em; font-family: 'Courier New', monospace; }
288
+ pre code { background: none; border: none; padding: 0; color: #00d4ff; }
289
+ blockquote { border-left: 4px solid #ffff00; background: #1a1a2e; padding: 1rem 1.5rem; margin: 1.5em 0; color: #e0e0e0; transform: skewX(-3deg); }
290
+ hr { border: none; border-top: 2px dashed #ff6ec7; margin: 2.5em 0; }
291
+ i, cite, em, var, address { font-style: italic; color: #ff6ec7; }
292
+ b, strong { font-weight: bold; color: #ffff00; }
293
+ img { max-width: 100%; height: auto; display: block; margin: 1.5em auto; border: 3px solid #00d4ff; filter: contrast(1.1) saturate(1.2); }
294
+ table { border-collapse: separate; border-spacing: 2px; width: 100%; margin: 1.5em 0; }
295
+ table th, table td { background: #1a1a2e; padding: 10px 14px; border: 1px solid #ff6ec7; }
296
+ table th { color: #ffff00; text-align: center; }
297
+ a { color: #00d4ff; text-decoration: none; text-transform: uppercase; }
298
+ a:hover { color: #ff6ec7; text-shadow: 0 0 10px #ff6ec7; }
299
+ `,
300
+ },
301
+ midnight: {
302
+ name: 'Midnight Library',
303
+ description: '深夜图书馆,暖黄灯光书香氛围',
304
+ css: `
305
+ body { background: #0f1a14; background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%231a2f23' fill-opacity='0.3'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); }
306
+ p { color: #d4c5a9; font-size: 15.5px; line-height: 1.9em; margin: 0 0 1.2em 0; font-family: 'Lora', 'Noto Serif SC', Georgia, serif; }
307
+ h1, h2, h3, h4, h5, h6 { font-weight: normal; margin: 1.8em 0 0.8em 0; line-height: 1.5em; color: #f5e6c8; font-family: 'Playfair Display', 'Noto Serif SC', serif; }
308
+ h1 { font-size: 1.9em; text-align: center; letter-spacing: 0.08em; text-shadow: 0 0 40px #ffd70044; border-bottom: 1px solid #3d5a45; padding-bottom: 0.5em; }
309
+ h2 { font-size: 1.4em; color: #c9a962; border-left: 3px solid #8b7355; padding-left: 0.8em; }
310
+ h3 { font-size: 1.15em; color: #b8956e; }
311
+ li p { margin: 0; }
312
+ ul, ol { margin: 1em 0; padding-left: 1.5em; }
313
+ li { margin-bottom: 0.5em; color: #d4c5a9; }
314
+ pre { background: #1a2f23; border: 1px solid #3d5a45; border-radius: 4px; padding: 16px; overflow-x: auto; font-size: 13px; line-height: 1.7; margin: 1.5em 0; box-shadow: inset 0 0 20px #0d1a1444; }
315
+ code { background: #2a3f33; border-radius: 3px; padding: 0.15em 0.4em; color: #ffd700; font-size: 0.9em; font-family: 'Courier New', monospace; }
316
+ pre code { background: none; padding: 0; color: #d4c5a9; }
317
+ blockquote { border-left: 3px solid #8b7355; background: linear-gradient(90deg, #1a2f2344, transparent); padding: 1rem 1.5rem; margin: 2em 0; color: #b8956e; font-style: italic; border-radius: 0 4px 4px 0; }
318
+ hr { border: none; border-top: 1px solid #3d5a45; margin: 3em 0; }
319
+ i, cite, em, var, address { font-style: italic; color: #c9a962; }
320
+ b, strong { font-weight: normal; color: #f5e6c8; }
321
+ img { max-width: 100%; height: auto; display: block; margin: 2em auto; border-radius: 2px; box-shadow: 0 4px 20px #00000055; }
322
+ table { border-collapse: collapse; width: 100%; margin: 1.5em 0; }
323
+ table th, table td { border: 1px solid #3d5a45; padding: 10px 14px; }
324
+ table th { background: #1a2f23; color: #c9a962; text-align: left; }
325
+ a { color: #c9a962; text-decoration: none; border-bottom: 1px dotted #8b7355; }
326
+ a:hover { color: #ffd700; border-bottom-color: #ffd700; }
327
+ `,
328
+ },
329
+ brutalism: {
330
+ name: 'Brutalism',
331
+ description: '粗野主义,大字体原始美学',
332
+ css: `
333
+ body { background: #fff; }
334
+ p { color: #000; font-size: 16px; line-height: 1.6em; margin: 0 0 1em 0; font-weight: 500; }
335
+ h1, h2, h3, h4, h5, h6 { font-weight: 900; margin: 1.5em 0 0.5em 0; line-height: 1.1em; color: #000; text-transform: uppercase; }
336
+ h1 { font-size: 3em; border: 4px solid #000; padding: 0.2em 0.4em; transform: rotate(-1deg); display: inline-block; }
337
+ h2 { font-size: 1.8em; border-bottom: 4px solid #000; padding-bottom: 0.2em; }
338
+ h3 { font-size: 1.3em; }
339
+ li p { margin: 0; }
340
+ ul, ol { margin: 1em 0; padding-left: 1.5em; }
341
+ li { margin-bottom: 0.5em; color: #000; font-weight: 600; }
342
+ pre { background: #000; border-radius: 0; padding: 16px; overflow-x: auto; font-size: 13px; line-height: 1.6; margin: 1.5em 0; }
343
+ code { background: #000; border-radius: 0; padding: 0.2em 0.4em; color: #fff; font-size: 1em; font-family: 'SF Mono', monospace; font-weight: bold; }
344
+ pre code { background: none; padding: 0; color: #fff; }
345
+ blockquote { border: 4px solid #000; background: #f0f0f0; padding: 1rem 1.5rem; margin: 2em 0; }
346
+ blockquote p { font-size: 1.2em; font-weight: 900; margin: 0; }
347
+ hr { border: none; border-top: 4px solid #000; margin: 3em 0; }
348
+ i, cite, em, var, address { font-style: normal; text-decoration: underline; text-decoration-thickness: 3px; }
349
+ b, strong { font-weight: 900; }
350
+ img { max-width: 100%; height: auto; display: block; margin: 1.5em 0; border: 4px solid #000; }
351
+ table { border-collapse: collapse; width: 100%; margin: 1.5em 0; border: 4px solid #000; }
352
+ table th, table td { border: 2px solid #000; padding: 10px 14px; }
353
+ table th { background: #000; color: #fff; font-weight: 900; text-transform: uppercase; }
354
+ a { color: #000; text-decoration: none; background: #ffff00; padding: 0 0.2em; }
355
+ a:hover { background: #000; color: #fff; }
356
+ `,
357
+ },
358
+ neumorphism: {
359
+ name: 'Neumorphism',
360
+ description: '新拟态风格,柔和立体软UI',
361
+ css: `
362
+ body { background: #e0e5ec; }
363
+ p { color: #4a5568; font-size: 15px; line-height: 1.8em; margin: 0 0 1em 0; }
364
+ h1, h2, h3, h4, h5, h6 { font-weight: 600; margin: 1.2em 0 0.6em 0; line-height: 1.4em; color: #2d3748; }
365
+ h1 { font-size: 1.7em; text-align: center; text-shadow: 6px 6px 12px #b8bcc2, -6px -6px 12px #ffffff; padding: 0.5em; }
366
+ h2 { font-size: 1.3em; color: #4a5568; border-left: 4px solid #7c3aed; padding-left: 0.6em; }
367
+ h3 { font-size: 1.1em; color: #5a6577; }
368
+ li p { margin: 0; }
369
+ ul, ol { margin: 0.8em 0; padding-left: 1.5em; }
370
+ li { margin-bottom: 0.5em; color: #4a5568; }
371
+ pre { background: #e0e5ec; border-radius: 16px; padding: 16px; overflow-x: auto; font-size: 13px; line-height: 1.7; margin: 1.2em 0; box-shadow: 8px 8px 16px #b8bcc2, -8px -8px 16px #ffffff; }
372
+ code { background: #e0e5ec; border-radius: 8px; padding: 0.2em 0.5em; color: #7c3aed; font-size: 0.9em; font-family: 'SF Mono', monospace; box-shadow: inset 2px 2px 4px #b8bcc2, inset -2px -2px 4px #ffffff; }
373
+ pre code { background: none; padding: 0; color: #4a5568; box-shadow: none; }
374
+ blockquote { background: #e0e5ec; border-radius: 16px; padding: 1rem 1.5rem; margin: 1.2em 0; color: #5a6577; box-shadow: 8px 8px 16px #b8bcc2, -8px -8px 16px #ffffff; border-left: 4px solid #7c3aed; }
375
+ hr { border: none; margin: 2em 0; }
376
+ hr::after { content: '···'; color: #7c3aed; font-size: 1.5em; letter-spacing: 0.5em; }
377
+ i, cite, em, var, address { font-style: italic; color: #7c3aed; }
378
+ b, strong { font-weight: 600; color: #2d3748; }
379
+ img { max-width: 100%; height: auto; display: block; margin: 1.2em auto; border-radius: 16px; box-shadow: 8px 8px 16px #b8bcc2, -8px -8px 16px #ffffff; }
380
+ table { border-collapse: collapse; width: 100%; margin: 1.2em 0; background: #e0e5ec; border-radius: 16px; overflow: hidden; box-shadow: 8px 8px 16px #b8bcc2, -8px -8px 16px #ffffff; }
381
+ table th, table td { padding: 12px 16px; }
382
+ table th { background: linear-gradient(145deg, #e6ebf2, #d1d9e6); color: #7c3aed; font-weight: 600; }
383
+ table tr:nth-child(even) { background: rgba(124, 58, 237, 0.05); }
384
+ a { color: #7c3aed; text-decoration: none; font-weight: 600; }
385
+ a:hover { color: #5b21b6; text-decoration: underline; }
386
+ `,
387
+ },
388
+ };
389
+ export async function listThemes() {
390
+ const themes = [];
391
+ for (const [id, meta] of Object.entries(BUILTIN_THEMES)) {
392
+ themes.push({ id, name: meta.name, description: meta.description, isBuiltin: true });
393
+ }
394
+ try {
395
+ const files = await fs.readdir(THEMES_DIR);
396
+ for (const file of files) {
397
+ if (file.endsWith('.css')) {
398
+ const id = path.basename(file, '.css');
399
+ if (!BUILTIN_THEMES[id]) {
400
+ themes.push({ id, name: id, description: 'Custom theme', isBuiltin: false });
401
+ }
402
+ }
403
+ }
404
+ }
405
+ catch {
406
+ // themes dir not exist, skip
407
+ }
408
+ return themes;
409
+ }
410
+ export async function loadThemeCss(themeId) {
411
+ if (BUILTIN_THEMES[themeId]) {
412
+ return BUILTIN_THEMES[themeId].css;
413
+ }
414
+ try {
415
+ return await fs.readFile(path.join(THEMES_DIR, `${themeId}.css`), 'utf-8');
416
+ }
417
+ catch {
418
+ return null;
419
+ }
420
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Multi-Publisher CLI - 主入口
3
+ */
4
+ export { createProgram } from './cli/index.js';
5
+ export { renderMarkdown } from './core/renderer.js';
6
+ export type { RenderOptions, RenderResult } from './core/renderer.js';
7
+ export { WeixinAdapter } from './adapters/weixin.js';
8
+ export { ZhihuAdapter } from './adapters/zhihu.js';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Multi-Publisher CLI - 主入口
3
+ */
4
+ export { createProgram } from './cli/index.js';
5
+ export { renderMarkdown } from './core/renderer.js';
6
+ export { WeixinAdapter } from './adapters/weixin.js';
7
+ export { ZhihuAdapter } from './adapters/zhihu.js';
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Playwright 浏览器运行时
3
+ * 用于自动登录获取 Cookie
4
+ */
5
+ import { type Page } from 'playwright';
6
+ export interface PlatformLoginConfig {
7
+ /** 平台 ID */
8
+ id: string;
9
+ /** 平台名称 */
10
+ name: string;
11
+ /** 登录页面 URL */
12
+ loginUrl: string;
13
+ /** 登录成功检测方式 */
14
+ successCondition: {
15
+ /** 检测 URL 变化(登录后跳转的 URL) */
16
+ urlPattern?: string | RegExp;
17
+ /** 检测 DOM 元素出现 */
18
+ selector?: string;
19
+ /** 检测 Cookie 名称 */
20
+ cookieName?: string;
21
+ /** 等待时间(毫秒),如果设置了则等待指定时间后自动完成 */
22
+ waitMs?: number;
23
+ };
24
+ /** 额外的 Cookie 域名 */
25
+ extraCookieDomains?: string[];
26
+ }
27
+ export interface LoginResult {
28
+ success: boolean;
29
+ cookies: Record<string, string>;
30
+ error?: string;
31
+ }
32
+ /**
33
+ * 浏览器运行时管理器
34
+ */
35
+ export declare class BrowserRuntime {
36
+ private browser;
37
+ private page;
38
+ /**
39
+ * 打开浏览器并导航到登录页面
40
+ * 使用用户默认浏览器配置文件,保持登录状态
41
+ */
42
+ open(loginConfig: PlatformLoginConfig): Promise<void>;
43
+ /**
44
+ * 等待用户完成登录
45
+ */
46
+ waitForLogin(config: PlatformLoginConfig): Promise<LoginResult>;
47
+ /**
48
+ * 等待特定 Cookie 出现
49
+ */
50
+ private waitForCookie;
51
+ /**
52
+ * 等待特定 Cookie 出现,带超时
53
+ */
54
+ private waitForCookieOrTimeout;
55
+ /**
56
+ * 关闭浏览器
57
+ */
58
+ close(): Promise<void>;
59
+ /**
60
+ * 获取当前页面(供外部使用)
61
+ */
62
+ getPage(): Page | null;
63
+ /**
64
+ * 获取当前页面的 cookies
65
+ */
66
+ getCookies(domains?: string[]): Promise<Record<string, string>>;
67
+ /**
68
+ * 检测是否已登录(通过检查是否存在登录 Cookie)
69
+ */
70
+ checkLogin(config: PlatformLoginConfig): Promise<boolean>;
71
+ }
72
+ /**
73
+ * 预配置的平台登录信息
74
+ */
75
+ export declare const PLATFORM_LOGIN_CONFIGS: Record<string, PlatformLoginConfig>;
76
+ /**
77
+ * 执行平台登录
78
+ */
79
+ export declare function loginPlatform(platformId: string): Promise<LoginResult>;