@zzclub/pipeline 0.13.2 → 0.16.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 (60) hide show
  1. package/ARTICLE-THEMES.md +86 -0
  2. package/LICENSE +21 -0
  3. package/README.md +182 -788
  4. package/THIRD-PARTY-NOTICES.md +25 -0
  5. package/package.json +6 -2
  6. package/src/adapter-types.ts +3 -0
  7. package/src/adapters/builtin-markdown-renderer.ts +1 -0
  8. package/src/article-theme.test.ts +87 -0
  9. package/src/article-theme.ts +115 -0
  10. package/src/commands/abandon.test.ts +1 -1
  11. package/src/commands/article-theme.ts +16 -0
  12. package/src/commands/checkpoint.test.ts +2 -2
  13. package/src/commands/ingest-handoff.ts +6 -0
  14. package/src/commands/init.ts +10 -0
  15. package/src/commands/prepare.ts +5 -1
  16. package/src/commands/publish.ts +4 -0
  17. package/src/commands/reset.ts +2 -0
  18. package/src/commands/wechat-export.ts +4 -0
  19. package/src/commands/wechat-preview.ts +35 -0
  20. package/src/plugins.ts +2 -0
  21. package/src/providers/index.ts +17 -2
  22. package/src/providers/publish-core.ts +32 -1
  23. package/src/providers/wechat.test.ts +12 -0
  24. package/src/providers/wechat.ts +60 -39
  25. package/src/render-branding.ts +1 -1
  26. package/src/schema/config.ts +12 -0
  27. package/src/schema/state.ts +5 -0
  28. package/src/wechat-preview/assets/browser-dist/.vite/manifest.json +21 -1
  29. package/src/wechat-preview/assets/browser-dist/assets/style-C9-YtTIm.css +1 -0
  30. package/src/wechat-preview/assets/browser-dist/assets/wechat-renderer-D1jHoaM2.js +624 -0
  31. package/src/wechat-preview/assets/browser-dist/editor-export.js +1 -512
  32. package/src/wechat-preview/assets/browser-dist/src/wechat-preview/browser/studio/studio.html +293 -0
  33. package/src/wechat-preview/assets/browser-dist/studio.js +332 -0
  34. package/src/wechat-preview/browser/editor-export.ts +17 -2
  35. package/src/wechat-preview/browser/highlight.ts +2 -0
  36. package/src/wechat-preview/browser/studio/color-palettes.test.ts +31 -0
  37. package/src/wechat-preview/browser/studio/color-palettes.ts +115 -0
  38. package/src/wechat-preview/browser/studio/studio.css +638 -0
  39. package/src/wechat-preview/browser/studio/studio.html +292 -0
  40. package/src/wechat-preview/browser/studio/studio.ts +721 -0
  41. package/src/wechat-preview/browser/studio/syntax-presets.test.ts +74 -0
  42. package/src/wechat-preview/browser/studio/syntax-presets.ts +590 -0
  43. package/src/wechat-preview/fixtures/all-nodes.md +38 -0
  44. package/src/wechat-preview/index.ts +36 -5
  45. package/src/wechat-preview/plugins/builtin-badge.ts +152 -0
  46. package/src/wechat-preview/plugins/builtin-callout.ts +261 -0
  47. package/src/wechat-preview/plugins/builtin-highlight.ts +46 -0
  48. package/src/wechat-preview/plugins/builtin-kbd.ts +133 -0
  49. package/src/wechat-preview/plugins/index.test.ts +313 -0
  50. package/src/wechat-preview/plugins/index.ts +6 -0
  51. package/src/wechat-preview/plugins/registry.ts +62 -0
  52. package/src/wechat-preview/plugins/types.ts +31 -0
  53. package/src/wechat-preview/server/http.ts +160 -3
  54. package/src/wechat-preview/server/paths.ts +2 -2
  55. package/src/wechat-preview/server/singleton.ts +14 -12
  56. package/src/wechat-preview/server/studio.test.ts +92 -0
  57. package/src/wechat-preview/server/ui.ts +1 -0
  58. package/src/wechat-preview/wechat-export.integration.test.ts +9 -1
  59. package/src/wechat-preview/wechat-renderer.ts +72 -7
  60. package/src/workflow.test.ts +1 -0
@@ -0,0 +1,293 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>WeChat Article Visual Studio - 排版可视化工作台</title>
7
+ <script type="module" crossorigin src="/studio.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/assets/wechat-renderer-D1jHoaM2.js">
9
+ <link rel="stylesheet" crossorigin href="/assets/style-C9-YtTIm.css">
10
+ </head>
11
+ <body>
12
+ <!-- Header -->
13
+ <header class="studio-header">
14
+ <div class="brand-section">
15
+ <span class="brand-logo">🎨</span>
16
+ <h1 class="brand-title">WeChat Visual Studio</h1>
17
+ <span class="brand-badge">实时调优</span>
18
+ </div>
19
+
20
+ <div class="header-controls">
21
+ <div class="account-select-wrap">
22
+ <span>公众号账号:</span>
23
+ <select id="account-select" class="account-select">
24
+ <option value="default">默认账号 (default)</option>
25
+ </select>
26
+ </div>
27
+
28
+ <button id="btn-reset" class="btn" title="恢复当前账号默认样式">
29
+ <span>🔄 重置</span>
30
+ </button>
31
+
32
+ <button id="btn-save" class="btn btn-primary" title="保存当前调整至本地 config.json">
33
+ <span>💾 保存至配置</span>
34
+ </button>
35
+
36
+ <button id="btn-copy" class="btn btn-success" title="复制内联富文本,可直接粘贴到微信公众号后台">
37
+ <span>📋 一键复制到公众号</span>
38
+ </button>
39
+
40
+ <a href="/" class="btn" title="返回导出历史">
41
+ <span>📜 历史记录</span>
42
+ </a>
43
+ </div>
44
+ </header>
45
+
46
+ <!-- Body -->
47
+ <main class="studio-body">
48
+ <!-- Left: Tuning & Plugins -->
49
+ <aside class="panel left-panel">
50
+ <nav class="tab-nav">
51
+ <button id="tab-btn-style" class="tab-btn active">🎨 样式调优</button>
52
+ <button id="tab-btn-syntax" class="tab-btn">🧩 语法与组件</button>
53
+ </nav>
54
+
55
+ <!-- Tab 1: Style Tuning -->
56
+ <div id="tab-content-style" class="tab-content">
57
+ <!-- Typography -->
58
+ <div class="config-section">
59
+ <div class="section-label">
60
+ <span>📐 字号与排版</span>
61
+ </div>
62
+
63
+ <div class="form-group">
64
+ <div class="form-label">
65
+ <span>正文字号</span>
66
+ <span id="val-font-size" class="form-val">16px</span>
67
+ </div>
68
+ <input type="range" id="input-font-size" class="slider-input" min="14" max="18" step="1" value="16">
69
+ </div>
70
+
71
+ <div class="form-group">
72
+ <div class="form-label">
73
+ <span>行高倍数</span>
74
+ <span id="val-line-height" class="form-val">1.84</span>
75
+ </div>
76
+ <input type="range" id="input-line-height" class="slider-input" min="1.5" max="2.2" step="0.02" value="1.84">
77
+ </div>
78
+
79
+ <div class="form-group">
80
+ <div class="form-label">
81
+ <span>字间距 (Letter Spacing)</span>
82
+ <span id="val-letter-spacing" class="form-val">0.012em</span>
83
+ </div>
84
+ <input type="range" id="input-letter-spacing" class="slider-input" min="0" max="0.05" step="0.002" value="0.012">
85
+ </div>
86
+
87
+ <div class="form-group">
88
+ <div class="form-label">
89
+ <span>段落间距 (Margin Bottom)</span>
90
+ <span id="val-para-spacing" class="form-val">1.2em</span>
91
+ </div>
92
+ <input type="range" id="input-para-spacing" class="slider-input" min="0.8" max="2.0" step="0.1" value="1.2">
93
+ </div>
94
+ </div>
95
+
96
+ <!-- Colors -->
97
+ <div class="config-section">
98
+ <div class="section-label">
99
+ <span>🎨 颜色系统</span>
100
+ </div>
101
+
102
+ <div class="form-group" style="margin-bottom: 16px;">
103
+ <div class="form-label">
104
+ <span>🌟 推荐高级配色方案 (杂志 / 服装 / App)</span>
105
+ </div>
106
+ <select id="palette-select" class="preset-select">
107
+ <option value="">-- 选择推荐调色盘 (一键应用) --</option>
108
+ </select>
109
+ <div id="palette-desc" class="preset-desc">可一键应用 Kinfolk 森林绿、Loro Piana 燕麦大地、纽约客石板蓝等</div>
110
+ </div>
111
+
112
+ <div class="form-group">
113
+ <div class="form-label">
114
+ <span>品牌主色 (Brand)</span>
115
+ </div>
116
+ <div class="color-input-row">
117
+ <input type="color" id="picker-brand-color" class="color-picker" value="#ca6093">
118
+ <input type="text" id="hex-brand-color" class="color-hex" value="#ca6093">
119
+ </div>
120
+ </div>
121
+
122
+ <div class="form-group">
123
+ <div class="form-label">
124
+ <span>正文字色 (Body Text)</span>
125
+ </div>
126
+ <div class="color-input-row">
127
+ <input type="color" id="picker-text-color" class="color-picker" value="#292526">
128
+ <input type="text" id="hex-text-color" class="color-hex" value="#292526">
129
+ </div>
130
+ </div>
131
+
132
+ <div class="form-group">
133
+ <div class="form-label">
134
+ <span>二级标题颜色 (H2)</span>
135
+ </div>
136
+ <div class="color-input-row">
137
+ <input type="color" id="picker-h2-color" class="color-picker" value="#1f1b1c">
138
+ <input type="text" id="hex-h2-color" class="color-hex" value="#1f1b1c">
139
+ </div>
140
+ </div>
141
+
142
+ <div class="form-group">
143
+ <div class="form-label">
144
+ <span>三级标题颜色 (H3)</span>
145
+ </div>
146
+ <div class="color-input-row">
147
+ <input type="color" id="picker-h3-color" class="color-picker" value="#5c5658">
148
+ <input type="text" id="hex-h3-color" class="color-hex" value="#5c5658">
149
+ </div>
150
+ </div>
151
+
152
+ <div class="form-group">
153
+ <div class="form-label">
154
+ <span>引用边框与重点色</span>
155
+ </div>
156
+ <div class="color-input-row">
157
+ <input type="color" id="picker-quote-color" class="color-picker" value="#e8c9d7">
158
+ <input type="text" id="hex-quote-color" class="color-hex" value="#e8c9d7">
159
+ </div>
160
+ </div>
161
+
162
+ <div class="form-group">
163
+ <div class="form-label">
164
+ <span>分割线颜色 (Divider)</span>
165
+ </div>
166
+ <div class="color-input-row">
167
+ <input type="color" id="picker-divider-color" class="color-picker" value="#e2dcdf">
168
+ <input type="text" id="hex-divider-color" class="color-hex" value="#e2dcdf">
169
+ </div>
170
+ </div>
171
+ </div>
172
+
173
+ <!-- Syntax Presets -->
174
+ <div class="config-section">
175
+ <div class="section-label">
176
+ <span>🧩 语法节点风格预设 (H2 / H3 / 引用 / 分割线)</span>
177
+ </div>
178
+ <div id="syntax-preset-container">
179
+ <!-- Populated dynamically by studio.ts from SYNTAX_CATEGORIES -->
180
+ </div>
181
+ </div>
182
+
183
+ <!-- Structure -->
184
+ <div class="config-section">
185
+ <div class="section-label">
186
+ <span>🏛️ 装饰与结构</span>
187
+ </div>
188
+
189
+ <div class="form-group">
190
+ <label class="switch-label">
191
+ <span>二级标题自动编号 (01, 02)</span>
192
+ <span class="switch-toggle">
193
+ <input type="checkbox" id="switch-numbered-headings">
194
+ <span class="slider-round"></span>
195
+ </span>
196
+ </label>
197
+ </div>
198
+
199
+ <div class="form-group">
200
+ <div class="form-label">
201
+ <span>标题前缀标签 (例: CHAPTER)</span>
202
+ </div>
203
+ <input type="text" id="input-heading-label" class="color-hex" style="width:100%" placeholder="如:CHAPTER">
204
+ </div>
205
+
206
+ <div class="form-group">
207
+ <div class="form-label">
208
+ <span>引言前缀标签 (例: 摘录)</span>
209
+ </div>
210
+ <input type="text" id="input-quote-label" class="color-hex" style="width:100%" placeholder="如:摘录">
211
+ </div>
212
+ </div>
213
+
214
+ <!-- Custom CSS -->
215
+ <div class="config-section">
216
+ <div class="section-label">
217
+ <span>💻 自定义 CSS 覆盖</span>
218
+ </div>
219
+ <textarea id="input-custom-css" class="css-editor" placeholder="/* 在此处输入自定义 CSS 规则,实时生效 */&#10;h2 { letter-spacing: 0.05em; }&#10;p { text-align: justify; }"></textarea>
220
+ </div>
221
+ </div>
222
+
223
+ <!-- Tab 2: Syntax Cheatsheet -->
224
+ <div id="tab-content-syntax" class="tab-content" style="display: none;">
225
+ <div id="syntax-card-list">
226
+ <!-- Populated dynamically by studio.ts -->
227
+ </div>
228
+ </div>
229
+ </aside>
230
+
231
+ <!-- Center: Markdown Input -->
232
+ <section class="panel editor-panel">
233
+ <div class="panel-header">
234
+ <div class="panel-title">
235
+ <span>📝</span>
236
+ <span>Markdown 草稿编辑</span>
237
+ </div>
238
+ <div class="editor-toolbar">
239
+ <button id="btn-load-sample" class="btn" title="加载全语法验收用例">📄 官方测试稿</button>
240
+ <button id="btn-clear-md" class="btn" title="清空编辑器内容">🗑️ 清空</button>
241
+ </div>
242
+ </div>
243
+
244
+ <textarea id="editor-markdown" class="editor-textarea" spellcheck="false" placeholder="在此粘贴或输入 Markdown 文章内容..."></textarea>
245
+
246
+ <div class="editor-footer">
247
+ <span id="editor-stats">字数: 0 字 | 预计阅读: 1 分钟</span>
248
+ <span>实时渲染: 50ms 防抖</span>
249
+ </div>
250
+ </section>
251
+
252
+ <!-- Right: Live WeChat Viewport -->
253
+ <section class="panel preview-panel">
254
+ <div class="panel-header">
255
+ <div class="panel-title">
256
+ <span>📱</span>
257
+ <span>微信手机仿真视口 (430px)</span>
258
+ </div>
259
+ <div>
260
+ <button id="btn-toggle-view" class="btn" style="font-size: 11px;">🔍 查看 HTML 源码</button>
261
+ </div>
262
+ </div>
263
+
264
+ <div class="preview-container">
265
+ <!-- Phone Simulator Frame -->
266
+ <div class="device-frame">
267
+ <div class="device-notch-bar">
268
+ <span>9:41</span>
269
+ <span>WeChat Article</span>
270
+ <span>100% 🔋</span>
271
+ </div>
272
+ <div id="preview-screen" class="device-screen">
273
+ <!-- Injected by live renderer -->
274
+ </div>
275
+ </div>
276
+
277
+ <!-- HTML Code Viewer (Hidden by default) -->
278
+ <div id="html-source-container" style="display: none; width: 100%; margin-top: 16px;">
279
+ <textarea id="html-source-code" class="css-editor" style="height: 380px; width: 100%;" readonly></textarea>
280
+ </div>
281
+ </div>
282
+ </section>
283
+ </main>
284
+
285
+ <!-- Toast Notification -->
286
+ <div id="toast-container" class="toast-container"></div>
287
+
288
+ <!-- Hidden Milkdown Engine Mount Host -->
289
+ <div id="studio-editor-host"></div>
290
+
291
+ <!-- Studio Script -->
292
+ </body>
293
+ </html>
@@ -0,0 +1,332 @@
1
+ import{E as ge,r as be,d as xe,c as he,g as ve,a as ye,b as ke,e as we,f as Ce}from"./assets/wechat-renderer-D1jHoaM2.js";(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))i(n);new MutationObserver(n=>{for(const a of n)if(a.type==="childList")for(const c of a.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&i(c)}).observe(document,{childList:!0,subtree:!0});function t(n){const a={};return n.integrity&&(a.integrity=n.integrity),n.referrerPolicy&&(a.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?a.credentials="include":n.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(n){if(n.ep)return;n.ep=!0;const a=t(n);fetch(n.href,a)}})();const R=[{key:"h1",label:"一级标题 (H1)",icon:"👑",description:"文章大标题:26px,加粗,紧贴后续正文,无边框背景修饰",css:`.milkdown .editor h1 {
2
+ margin: 2.45em 0 0.85em;
3
+ color: var(--wx-h2-color, #1f1b1c);
4
+ font-size: 26px;
5
+ font-weight: 700;
6
+ line-height: 1.38;
7
+ letter-spacing: -0.01em;
8
+ }`},{key:"h2",label:"二级标题 (H2)",icon:"📌",defaultPresetId:"pillar",presets:[{id:"pillar",name:"左侧呼吸柱(推荐)",description:"2.5px 品牌色垂直微线 + 9px 内边距 + 2.8em 非对称呼吸留白",css:`.milkdown .editor h2 {
9
+ margin: 2.8em 0 0.65em;
10
+ padding-left: 9px;
11
+ border-left: 2.5px solid var(--wx-brand-accent, #ca6093);
12
+ border-bottom: none;
13
+ background: none;
14
+ font-size: 20px;
15
+ font-weight: 700;
16
+ line-height: 1.36;
17
+ letter-spacing: 0.01em;
18
+ color: var(--wx-h2-color, #1f1b1c);
19
+ }`},{id:"bottom-line",name:"极浅底部分割",description:"1px 细底线 + 紧凑下边距 + 3.0em 开阔章节上留白",css:`.milkdown .editor h2 {
20
+ margin: 3.0em 0 0.8em;
21
+ padding-bottom: 0.45em;
22
+ padding-left: 0;
23
+ border-left: none;
24
+ border-bottom: 1px solid var(--wx-divider-color, #ebe6e8);
25
+ background: none;
26
+ font-size: 20px;
27
+ font-weight: 700;
28
+ line-height: 1.35;
29
+ letter-spacing: 0.015em;
30
+ color: var(--wx-h2-color, #1f1b1c);
31
+ }`},{id:"gradient-pill",name:"渐变微衬底(背景色块)",description:"水平柔和渐变微底色 + 左侧 3px 标柱 + 4px 圆角",css:`.milkdown .editor h2 {
32
+ margin: 2.8em 0 0.7em;
33
+ padding: 7px 14px;
34
+ border-left: 3px solid var(--wx-brand-accent, #ca6093);
35
+ border-bottom: none;
36
+ background: linear-gradient(90deg, rgba(202, 96, 147, 0.09) 0%, rgba(202, 96, 147, 0.01) 100%);
37
+ border-radius: 4px;
38
+ font-size: 19px;
39
+ font-weight: 700;
40
+ line-height: 1.38;
41
+ letter-spacing: 0.01em;
42
+ color: var(--wx-h2-color, #1f1b1c);
43
+ }`},{id:"contrast-green",name:"反差色绿底(白字反色块)",description:"高级生态绿底色 + 纯白文字 + 4px 圆角 + 8px 14px 饱满内边距",css:`.milkdown .editor h2 {
44
+ margin: 2.8em 0 0.8em;
45
+ padding: 8px 14px;
46
+ background-color: #1f7a4d;
47
+ border-left: none;
48
+ border-bottom: none;
49
+ border-radius: 4px;
50
+ color: #ffffff;
51
+ font-size: 18px;
52
+ font-weight: 700;
53
+ line-height: 1.36;
54
+ letter-spacing: 0.02em;
55
+ }
56
+ .milkdown .editor h2 span {
57
+ color: #ffffff;
58
+ }`},{id:"card-tag",name:"温润小卡片",description:"包裹式浅色暖底 + 居左微内边距 + 紧实字号",css:`.milkdown .editor h2 {
59
+ margin: 2.7em 0 0.75em;
60
+ padding: 6px 12px;
61
+ border-left: none;
62
+ border-bottom: none;
63
+ background-color: var(--wx-soft-surface, #faf8f9);
64
+ border-radius: 4px;
65
+ font-size: 18px;
66
+ font-weight: 700;
67
+ line-height: 1.4;
68
+ letter-spacing: 0.01em;
69
+ color: var(--wx-h2-color, #1f1b1c);
70
+ }`},{id:"plain",name:"经典纯文字",description:"纯字号与字重,无边框与背景修饰",css:`.milkdown .editor h2 {
71
+ margin: 2.7em 0 0.7em;
72
+ padding: 0;
73
+ border-left: none;
74
+ border-bottom: none;
75
+ background: none;
76
+ font-size: 20px;
77
+ font-weight: 700;
78
+ line-height: 1.38;
79
+ letter-spacing: 0.005em;
80
+ color: var(--wx-h2-color, #1f1b1c);
81
+ }`}]},{key:"h3",label:"三级标题 (H3)",icon:"🔹",defaultPresetId:"plain",presets:[{id:"plain",name:"经典纯文字(默认)",description:"16px,深灰次级字色,font-weight 700",css:`.milkdown .editor h3 {
82
+ margin: 1.55em 0 0.4em;
83
+ padding-left: 0;
84
+ border-left: none;
85
+ background: none;
86
+ font-size: 16px;
87
+ font-weight: 700;
88
+ line-height: 1.48;
89
+ letter-spacing: 0.02em;
90
+ color: var(--wx-h3-color, #5c5658);
91
+ }`},{id:"left-bar",name:"左侧微短线",description:"2px 细色柱 + 7px 内边距",css:`.milkdown .editor h3 {
92
+ margin: 1.6em 0 0.45em;
93
+ padding-left: 7px;
94
+ border-left: 2px solid var(--wx-brand-accent, #ca6093);
95
+ background: none;
96
+ font-size: 16px;
97
+ font-weight: 700;
98
+ line-height: 1.45;
99
+ letter-spacing: 0.015em;
100
+ color: var(--wx-h3-color, #5c5658);
101
+ }`},{id:"badge",name:"胶囊小微标",description:"行内微底色衬托,紧凑突出",css:`.milkdown .editor h3 {
102
+ display: inline-block;
103
+ margin: 1.6em 0 0.45em;
104
+ padding: 3px 8px;
105
+ border-left: none;
106
+ background-color: var(--wx-soft-surface, #faf8f9);
107
+ border-radius: 3px;
108
+ font-size: 15px;
109
+ font-weight: 700;
110
+ line-height: 1.4;
111
+ color: var(--wx-brand-ink, #ca6093);
112
+ }`}]},{key:"h4",label:"四级/次级标题 (H4-H6)",icon:"🔸",description:"更低层级小标题:16px 次深灰,1.55 行高,紧贴段落",css:`.milkdown .editor h4,
113
+ .milkdown .editor h5,
114
+ .milkdown .editor h6 {
115
+ margin: 1.45em 0 0.45em;
116
+ color: var(--wx-h3-color, #5c5658);
117
+ font-size: 16px;
118
+ font-weight: 700;
119
+ line-height: 1.55;
120
+ letter-spacing: 0.02em;
121
+ }`},{key:"p",label:"正文段落 (Paragraph)",icon:"📄",description:"标准段落:两端对齐,排版行高 1.84,下边距 1.2em",css:`.milkdown .editor p {
122
+ margin: 0 0 1.2em;
123
+ color: var(--wx-body-color, #292526);
124
+ font-size: 16px;
125
+ line-height: 1.84;
126
+ letter-spacing: 0.012em;
127
+ text-align: justify;
128
+ }`},{key:"strong",label:"加粗与斜体 (Bold / Italic)",icon:"🖋️",description:"重点强调:深沉字重 700 与斜体字色跟随",css:`.milkdown .editor strong,
129
+ .milkdown .editor b {
130
+ color: var(--wx-body-color, #292526);
131
+ font-weight: 700;
132
+ }
133
+ .milkdown .editor em,
134
+ .milkdown .editor i {
135
+ color: var(--wx-body-color, #292526);
136
+ font-style: italic;
137
+ }`},{key:"del",label:"删除线 (Strikethrough)",icon:"✂️",description:"废弃内容:静音深灰与中线划除",css:`.milkdown .editor s,
138
+ .milkdown .editor del {
139
+ color: var(--wx-muted-color, #6f696b);
140
+ text-decoration: line-through;
141
+ text-decoration-color: var(--wx-muted-color, #6f696b);
142
+ }`},{key:"mark",label:"文本高亮 (Mark ==...==)",icon:"🖍️",description:"马克笔荧光衬底:柔和品牌色淡背景 + 1.5px 下划强调线",css:`.milkdown .editor mark {
143
+ margin: 0 2px;
144
+ padding: 2px 5px;
145
+ background-color: rgba(202, 96, 147, 0.16);
146
+ color: var(--wx-body-color, #292526);
147
+ border-radius: 3px;
148
+ border-bottom: 1.5px solid var(--wx-brand-accent, #ca6093);
149
+ }`},{key:"inline-code",label:"行内代码 (Inline Code)",icon:"💻",description:"行内等宽代码:14px,等宽字体,浅色微边框衬底",css:`.milkdown .editor code:not(pre code),
150
+ .milkdown .editor [data-wechat-node="inline-code"] {
151
+ margin: 0 2px;
152
+ padding: 2px 6px;
153
+ border: 1px solid var(--wx-divider-color, #ded9db);
154
+ border-radius: 4px;
155
+ background-color: var(--wx-soft-surface, #f7f5f6);
156
+ color: #4d484a;
157
+ font-family: Menlo, Monaco, Consolas, monospace;
158
+ font-size: 14px;
159
+ line-height: 1.55;
160
+ }`},{key:"code-block",label:"代码块 (Code Block)",icon:"📟",description:"多行代码框:浅灰底色,6px 圆角,深色等宽字符与水平横滚",css:`.milkdown .editor pre {
161
+ margin: 1.55em 0;
162
+ padding: 14px 16px;
163
+ border: 1px solid var(--wx-divider-color, #e2dcdf);
164
+ border-radius: 6px;
165
+ background-color: var(--wx-soft-surface, #f8fafc);
166
+ color: var(--wx-body-color, #292526);
167
+ font-family: Menlo, Monaco, Consolas, monospace;
168
+ font-size: 13px;
169
+ line-height: 1.72;
170
+ overflow-x: auto;
171
+ }
172
+ .milkdown .editor pre code {
173
+ font-family: inherit;
174
+ font-size: inherit;
175
+ }`},{key:"blockquote",label:"引用块 (Blockquote)",icon:"💬",defaultPresetId:"left-border",presets:[{id:"left-border",name:"经典左单线(默认)",description:"3px 品牌色微边框 + 浅灰底色 + 4px 右圆角",css:`.milkdown .editor blockquote {
176
+ margin: 1.6em 0;
177
+ padding: 10px 16px;
178
+ border: none;
179
+ border-left: 3px solid var(--wx-blockquote-border, #ca6093);
180
+ border-radius: 0 4px 4px 0;
181
+ background-color: var(--wx-soft-surface, #fbfafb);
182
+ }`},{id:"tint-card",name:"全包裹微卡片",description:"四边 1px 极细边框 + 6px 圆角,整体成盒",css:`.milkdown .editor blockquote {
183
+ margin: 1.6em 0;
184
+ padding: 12px 18px;
185
+ border: 1px solid var(--wx-divider-color, #ebe6e8);
186
+ border-radius: 6px;
187
+ background-color: var(--wx-soft-surface, #fbfafb);
188
+ }`},{id:"minimal-indent",name:"极简纯缩进",description:"无底色,仅左侧细灰线与自然缩进",css:`.milkdown .editor blockquote {
189
+ margin: 1.5em 0;
190
+ padding: 6px 0 6px 16px;
191
+ border: none;
192
+ border-left: 2px solid rgba(0, 0, 0, 0.15);
193
+ border-radius: 0;
194
+ background: none;
195
+ }`}]},{key:"list",label:"列表 (Unordered & Ordered)",icon:"📋",description:"标准列表:自然外缩进,1.78 行高,小圆点与阿拉伯数字序号",css:`.milkdown .editor ul,
196
+ .milkdown .editor ol {
197
+ margin: 1.05em 0 1.3em;
198
+ padding-left: 1.6em;
199
+ color: var(--wx-body-color, #292526);
200
+ }
201
+ .milkdown .editor li {
202
+ margin: 0.4em 0;
203
+ line-height: 1.78;
204
+ }
205
+ .milkdown .editor li p {
206
+ margin: 0.15em 0;
207
+ }`},{key:"task-list",label:"任务清单 (Task List)",icon:"☑️",description:"待办复选框:品牌色勾选标记,紧凑缩进",css:`.milkdown .editor [data-wechat-node="task-list-item"] {
208
+ list-style: none;
209
+ }
210
+ .milkdown .editor [data-wechat-node="task-marker"] {
211
+ display: inline-block;
212
+ min-width: 1.35em;
213
+ color: var(--wx-brand-accent, #ca6093);
214
+ font-weight: 700;
215
+ }`},{key:"divider",label:"分割线 (Divider)",icon:"➖",defaultPresetId:"hairline",presets:[{id:"hairline",name:"极细实线(默认)",description:"1px 浅灰色水平实线",css:`.milkdown .editor hr {
216
+ margin: 2.4em 0;
217
+ width: 100%;
218
+ border: none;
219
+ border-top: 1px solid var(--wx-divider-color, #e2dcdf);
220
+ }`},{id:"dashed",name:"极简虚线",description:"1px 虚线划分节奏",css:`.milkdown .editor hr {
221
+ margin: 2.4em 0;
222
+ width: 100%;
223
+ border: none;
224
+ border-top: 1px dashed var(--wx-divider-color, #d4cecf);
225
+ }`},{id:"short-center",name:"居中短呼吸线",description:"宽度 36%,居中呼吸线",css:`.milkdown .editor hr {
226
+ margin: 2.8em auto;
227
+ width: 36%;
228
+ border: none;
229
+ border-top: 1px solid var(--wx-divider-color, #e2dcdf);
230
+ }`}]},{key:"link",label:"超链接与附注 (Links & Ref)",icon:"🔗",description:"文章链接与文末尾注:品牌色下划细线与上标数字角标",css:`.milkdown .editor a,
231
+ .milkdown .editor [data-wechat-node="external-link"] {
232
+ border-bottom: 1px solid var(--wx-brand-accent, #ca6093);
233
+ color: var(--wx-brand-accent, #ca6093);
234
+ text-decoration: none;
235
+ }
236
+ .milkdown .editor [data-wechat-node="link-marker"] {
237
+ margin-left: 2px;
238
+ color: var(--wx-brand-accent, #ca6093);
239
+ font-size: 11px;
240
+ vertical-align: super;
241
+ }`},{key:"image",label:"图片与图注 (Image & Caption)",icon:"🖼️",description:"文章插图与下方图注:居中包裹,4px 微圆角与 13px 浅灰居中说明",css:`.milkdown .editor figure,
242
+ .milkdown .editor [data-wechat-node="image-block"] {
243
+ margin: 1.65em 0 1.8em;
244
+ text-align: center;
245
+ }
246
+ .milkdown .editor img {
247
+ display: block;
248
+ max-width: 100%;
249
+ height: auto;
250
+ margin: 0 auto;
251
+ border-radius: 4px;
252
+ }
253
+ .milkdown .editor figcaption,
254
+ .milkdown .editor [data-wechat-node="image-caption"] {
255
+ margin-top: 8px;
256
+ color: var(--wx-muted-color, #6f696b);
257
+ font-size: 13px;
258
+ line-height: 1.62;
259
+ text-align: center;
260
+ }`},{key:"table",label:"数据表格 (Table)",icon:"📊",description:"数据对比表格:折叠边框,浅暖色表头背景,紧凑对齐内边距",css:`.milkdown .editor table {
261
+ width: 100%;
262
+ margin: 1.5em 0;
263
+ border-collapse: collapse;
264
+ table-layout: fixed;
265
+ font-size: 14px;
266
+ line-height: 1.62;
267
+ }
268
+ .milkdown .editor th,
269
+ .milkdown .editor td {
270
+ padding: 8px 10px;
271
+ border: 1px solid var(--wx-divider-color, #e2dcdf);
272
+ text-align: left;
273
+ }
274
+ .milkdown .editor th {
275
+ background-color: var(--wx-soft-surface, #faf8f9);
276
+ color: var(--wx-h2-color, #1f1b1c);
277
+ font-weight: 700;
278
+ }`},{key:"callout",label:"扩展:提示卡片 (Callout Alert)",icon:"💡",description:"高亮提示盒:左侧品牌色标线,浅底色包裹与加粗小标",css:`.milkdown .editor [data-wechat-node="callout"] {
279
+ margin: 1.4em 0;
280
+ padding: 12px 16px;
281
+ border-left: 3px solid var(--wx-brand-accent, #ca6093);
282
+ border-radius: 0 6px 6px 0;
283
+ background-color: var(--wx-soft-surface, #fbfafb);
284
+ }
285
+ .milkdown .editor [data-wechat-node="callout-header"],
286
+ .milkdown .editor .wechat-callout-header {
287
+ font-weight: 700;
288
+ font-size: 14px;
289
+ margin-bottom: 6px;
290
+ color: var(--wx-h2-color, #1f1b1c);
291
+ }`},{key:"kbd",label:"扩展:键盘键帽 (Kbd Key)",icon:"⌨️",description:"按键徽章:立体立体阴影边框,12px 等宽字体",css:`.milkdown .editor kbd,
292
+ .milkdown .editor [data-wechat-node="kbd"] {
293
+ display: inline-block;
294
+ margin: 0 3px;
295
+ padding: 2px 6px;
296
+ font-family: Menlo, Monaco, Consolas, monospace;
297
+ font-size: 12px;
298
+ font-weight: 600;
299
+ color: #374151;
300
+ background-color: #f3f4f6;
301
+ border: 1px solid #d1d5db;
302
+ border-bottom: 2px solid #9ca3af;
303
+ border-radius: 4px;
304
+ line-height: 1.3;
305
+ }`},{key:"badge",label:"扩展:彩色徽章 (Badge Pill)",icon:"🏷️",description:"胶囊微标签:全圆角胶囊底色,紧凑居中",css:`.milkdown .editor [data-wechat-node="badge"] {
306
+ display: inline-block;
307
+ margin: 0 2px;
308
+ padding: 2px 8px;
309
+ font-size: 12px;
310
+ font-weight: 600;
311
+ border-radius: 9999px;
312
+ line-height: 1.3;
313
+ background-color: rgba(202, 96, 147, 0.12);
314
+ color: var(--wx-brand-accent, #ca6093);
315
+ }`}];function Ee(o){const e=[];for(const t of R)if(t.presets&&t.presets.length>1){const i=o[t.key]||t.defaultPresetId||t.presets[0].id,n=t.presets.find(a=>a.id===i)||t.presets[0];n&&n.css.trim()&&e.push(`/* [${t.label}] - ${n.name} */
316
+ ${n.css.trim()}`)}return e.join(`
317
+
318
+ `)}const Z=[{id:"forest-sage",name:"🌿 森林墨绿 (Kinfolk / 少数派)",category:"生活方式与编辑部",description:"《Kinfolk》生活美学:沉稳深松绿强调色,搭配松针深黑与浅灰绿分割线",colors:{brand:"#1f6f4a",text:"#1f2320",h2:"#154c33",h3:"#2e7d58",quote:"#3d8e64",divider:"#e1ebe5"}},{id:"oatmeal-earth",name:"☕ 燕麦大地 (理想国 / 暖调成衣)",category:"时尚与书籍出版",description:"Loro Piana 暖调成衣美学:深焦糖陶土棕、浓咖啡黑与温润燕麦米灰",colors:{brand:"#945938",text:"#2b2623",h2:"#1f1b18",h3:"#6b3f27",quote:"#b37954",divider:"#eae4dd"}},{id:"slate-indigo",name:"🏛️ 石板深蓝 (纽约客 / Substack)",category:"深度专栏与智识",description:"经典严肃刊物:午夜深藏青做标识,石板灰文字与干净蓝灰分割",colors:{brand:"#2563eb",text:"#1e293b",h2:"#0f172a",h3:"#334155",quote:"#3b82f6",divider:"#e2e8f0"}},{id:"burgundy-velvet",name:"🍷 勃艮第红 (Vogue / 先锋艺术)",category:"高级时尚与设计",description:"复古先锋美学:丝绒绛红做点睛,黑绒字色与淡玫瑰粉灰底线",colors:{brand:"#881337",text:"#231f20",h2:"#1a1617",h3:"#4c1d2e",quote:"#9f1239",divider:"#f2e5ea"}},{id:"matcha-bamboo",name:"🍵 极简煎茶 (无印良品 / 东方和风)",category:"极简器物与禅意",description:"日系器物美学:深橄榄煎茶色、竹炭色正文与和纸灰底线",colors:{brand:"#556b2f",text:"#262923",h2:"#1c211a",h3:"#435528",quote:"#708846",divider:"#e7eae1"}},{id:"titanium-cyan",name:"🌌 极客钛灰 (Linear / Arc 现代界面)",category:"现代数字与 App",description:"当代高端数字界面:极光冷青点缀、深空曜黑文字与钛金属浅灰",colors:{brand:"#0284c7",text:"#18181b",h2:"#09090b",h3:"#27272a",quote:"#0ea5e9",divider:"#e4e4e7"}},{id:"rose-ledger",name:"🌸 晚樱柔粉 (古一软件经典标配)",category:"人文与故事叙述",description:"经典温润配色:干枯玫瑰粉与深铅黑文字,温柔克制",colors:{brand:"#ca6093",text:"#292526",h2:"#1f1b1c",h3:"#5c5658",quote:"#ca6093",divider:"#dadce0"}}];let x={},p="default",ee=[],k="",F=null,V=!1,y={};const z=document.getElementById("account-select"),f=document.getElementById("editor-markdown"),te=document.getElementById("preview-screen"),Le=document.getElementById("editor-stats"),oe=document.getElementById("html-source-container"),Be=document.getElementById("html-source-code"),Se=document.getElementById("toast-container"),ne=document.getElementById("studio-editor-host"),E=document.getElementById("input-font-size"),ie=document.getElementById("val-font-size"),L=document.getElementById("input-line-height"),ae=document.getElementById("val-line-height"),B=document.getElementById("input-letter-spacing"),de=document.getElementById("val-letter-spacing"),j=document.getElementById("input-para-spacing"),Ie=document.getElementById("val-para-spacing"),C=document.getElementById("palette-select"),re=document.getElementById("palette-desc"),W=document.getElementById("picker-brand-color"),S=document.getElementById("hex-brand-color"),G=document.getElementById("picker-text-color"),I=document.getElementById("hex-text-color"),Q=document.getElementById("picker-h2-color"),H=document.getElementById("hex-h2-color"),Y=document.getElementById("picker-h3-color"),$=document.getElementById("hex-h3-color"),_=document.getElementById("picker-quote-color"),P=document.getElementById("hex-quote-color"),J=document.getElementById("picker-divider-color"),T=document.getElementById("hex-divider-color"),M=document.getElementById("switch-numbered-headings"),q=document.getElementById("input-heading-label"),N=document.getElementById("input-quote-label"),b=document.getElementById("input-custom-css");function g(o,e="info"){const t=document.createElement("div");t.className=`toast ${e==="success"?"toast-success":""}`,t.textContent=o,Se.appendChild(t),requestAnimationFrame(()=>t.classList.add("show")),setTimeout(()=>{t.classList.remove("show"),setTimeout(()=>t.remove(),300)},3e3)}function w(o,e,t){o.addEventListener("input",()=>{e.value=o.value,t()}),e.addEventListener("input",()=>{/^#[0-9a-f]{6}$/i.test(e.value)&&(o.value=e.value,t())})}function He(){const e=f.value.replace(/\s+/g,"").length,t=Math.max(1,Math.round(e/400));Le.textContent=`字数: ${e.toLocaleString()} 字 | 预计阅读: ${t} 分钟`}async function $e(){const o=f.value;He();try{ne.innerHTML="";const e=ge.make().config(X=>{X.set(be,ne),X.set(xe,o)}).use(he).use(ve).use(ye());await e.create();const t=e.action(ke());await e.destroy();const i=Number(E.value)||16,n=L.value||"1.84",a=`${B.value}em`,c=`${j.value}em`,r=S.value||"#ca6093",m=I.value||"#292526",s=H.value||"#1f1b1c",l=$.value||"#5c5658",h=P.value||"#ca6093",u=T.value||"#dadce0",v=x[p]?.theme?.exportTheme||{},O=x[p]?.theme?.editorVars||{},le=["max-width: 100%","margin: 0","padding: 10px 4px 30px","background: #ffffff","box-sizing: border-box","font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif",`font-size: ${i}px`,`color: ${m}`,"overflow-wrap: break-word","word-break: break-word",`line-height: ${n}`,`letter-spacing: ${a}`,"-webkit-text-size-adjust: 100%"].join("; "),me={...v,containerStyle:le,footerText:v.footerText??"",footerStyle:v.footerStyle??"margin-top: 32px; text-align: center; font-size: 12px; color: #6f696b;",fontFamily:v.fontFamily||"-apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif",bodyColor:m,mutedColor:v.mutedColor||"#5f6368",h2Color:s,h3Color:l,primaryColor:r,dividerColor:u,blockquoteBorderColor:h,bodyLineHeight:n,bodyLetterSpacing:a},pe={...O,"--primary":r,"--brand":r,"--brand-soft":O["--brand-soft"]||r,"--brand-bg":O["--brand-bg"]||"rgba(202, 96, 147, 0.08)","--text":m,"--divider":u},ue={numberedHeadings:M.checked,headingLabel:q.value.trim()||void 0,quoteLabel:N.value.trim()||void 0,calloutPresets:x[p]?.theme?.structure?.calloutPresets},fe=[Ee(y),b.value,`.milkdown .editor p { margin: 0 0 ${c}; }`].filter(Boolean).join(`
319
+
320
+ `),A=await we({semanticHtml:t,baseCss:Ce,customCss:fe,structure:ue,editorVars:pe,theme:me});k=A,te.innerHTML=A,Be.value=A}catch(e){console.error("Studio render error:",e);const t=e instanceof Error?e.message:String(e);te.innerHTML=`<div style="color:#b91c1c;padding:16px;background:#fef2f2;border-radius:8px;">渲染错误: ${t}</div>`}}function d(o=60){F&&clearTimeout(F),F=setTimeout(()=>{$e()},o)}function Pe(o){const e=document.getElementById("syntax-card-list");if(e){e.innerHTML="";for(const t of o){const i=document.createElement("div");i.className="syntax-card";const n=document.createElement("div");n.className="syntax-card-header";const a=document.createElement("span");a.className="syntax-card-title",a.textContent=t.name;const c=document.createElement("span");c.className="syntax-card-badge",c.textContent=t.category==="inline"?"行内扩展":"块级组件",n.appendChild(a),n.appendChild(c),i.appendChild(n);const r=document.createElement("p");r.className="syntax-card-desc",r.textContent=t.description,i.appendChild(r);const m=document.createElement("pre");m.className="syntax-code-snippet",m.textContent=t.sampleMarkdown,i.appendChild(m);const s=document.createElement("button");s.className="syntax-btn-insert",s.textContent="+ 插入示例到文章中",s.addEventListener("click",()=>{Te(t.sampleMarkdown),g(`已插入「${t.name}」示例`,"info")}),i.appendChild(s),e.appendChild(i)}}}function Te(o){const e=f.selectionStart,t=f.selectionEnd,i=f.value,n=`
321
+
322
+ ${o}
323
+
324
+ `;f.value=i.slice(0,e)+n+i.slice(t),f.focus(),f.selectionStart=f.selectionEnd=e+n.length,d(20)}function ze(){const o=document.getElementById("syntax-preset-container");if(o){o.innerHTML="";for(const e of R){const t=document.createElement("div");t.className="preset-group";const i=document.createElement("div");i.className="preset-header";const n=document.createElement("span");n.className="preset-title",n.textContent=`${e.icon} ${e.label}`,i.appendChild(n);const a=!!(e.presets&&e.presets.length>1),c=document.createElement("button");if(c.type="button",c.className="btn-extract-css",c.textContent="📋 提取 CSS",c.title="将此语法的 CSS 追加到底部自定义编辑器,方便微调覆盖",c.addEventListener("click",()=>{let r="";if(a&&e.presets){const m=y[e.key]||e.defaultPresetId||e.presets[0].id,s=e.presets.find(l=>l.id===m)||e.presets[0];r=`/* [${e.label}] - ${s.name} */
325
+ ${s.css.trim()}
326
+ `}else{const m=e.css||e.presets&&e.presets[0]?.css||"";r=`/* [${e.label}] 基础样式 */
327
+ ${m.trim()}
328
+ `}r&&(b.value=b.value?`${b.value.trim()}
329
+
330
+ ${r}`:r,b.focus(),b.scrollTop=b.scrollHeight,g(`已将「${e.label}」CSS 追加到底部编辑框!`,"info"),d(20))}),i.appendChild(c),t.appendChild(i),a&&e.presets){const r=document.createElement("select");r.className="preset-select",r.dataset.category=e.key;for(const h of e.presets){const u=document.createElement("option");u.value=h.id,u.textContent=h.name,r.appendChild(u)}const m=y[e.key]||e.defaultPresetId||e.presets[0].id;r.value=m,t.appendChild(r);const s=document.createElement("div");s.className="preset-desc";const l=e.presets.find(h=>h.id===m)||e.presets[0];s.textContent=l?.description||"",t.appendChild(s),r.addEventListener("change",()=>{y[e.key]=r.value;const h=e.presets.find(u=>u.id===r.value);s.textContent=h?.description||"",d(20)})}else if(e.description){const r=document.createElement("div");r.className="preset-desc",r.textContent=e.description,t.appendChild(r)}o.appendChild(t)}}}function U(o){const e=x[o];if(!e)return;const t=e.theme?.exportTheme||{},i=e.theme?.editorVars||{};if(t.containerStyle){const l=t.containerStyle.match(/font-size:\s*(\d+)px/);l&&(E.value=l[1],ie.textContent=`${l[1]}px`)}if(t.bodyLineHeight&&(L.value=t.bodyLineHeight,ae.textContent=t.bodyLineHeight),t.bodyLetterSpacing){const l=parseFloat(t.bodyLetterSpacing);isNaN(l)||(B.value=String(l),de.textContent=`${l}em`)}const n=i["--brand"]||t.primaryColor;n&&(W.value=n,S.value=n);const a=t.bodyColor||i["--text"];a&&(G.value=a,I.value=a),t.h2Color&&(Q.value=t.h2Color,H.value=t.h2Color),t.h3Color&&(Y.value=t.h3Color,$.value=t.h3Color);const c=t.blockquoteBorderColor||n;c&&(_.value=c,P.value=c);const r=t.dividerColor||i["--divider"];r&&(J.value=r,T.value=r),e.customCssContent?b.value=e.customCssContent:b.value="";const m=e.theme?.syntaxPresets||{};y={};for(const l of R)l.defaultPresetId&&(y[l.key]=m[l.key]||l.defaultPresetId);ze();const s=e.theme?.structure||{};M.checked=!!s.numberedHeadings,q.value=s.headingLabel||"",N.value=s.quoteLabel||"",d(20)}function Me(){if(C){C.innerHTML='<option value="">-- 选择推荐调色盘 (一键应用) --</option>';for(const o of Z){const e=document.createElement("option");e.value=o.id,e.textContent=`${o.name} · ${o.category}`,C.appendChild(e)}C.addEventListener("change",()=>{const o=Z.find(e=>e.id===C.value);o&&(W.value=S.value=o.colors.brand,G.value=I.value=o.colors.text,Q.value=H.value=o.colors.h2,Y.value=$.value=o.colors.h3,_.value=P.value=o.colors.quote,J.value=T.value=o.colors.divider,re&&(re.textContent=o.description),g(`已应用「${o.name}」高级配色方案!`,"info"),d(20))})}}async function qe(){Me();try{const o=await fetch("/api/studio/config");if(!o.ok)throw new Error(`HTTP ${o.status}`);const e=await o.json();x=e.accounts||{},p=e.defaultAccount||"default",ee=e.plugins||[],z.innerHTML="";for(const[t,i]of Object.entries(x)){const n=document.createElement("option");n.value=t,n.textContent=`${i.name||t} (${t})`,t===p&&(n.selected=!0),z.appendChild(n)}f.value=e.sampleMarkdown||`# 微信排版标题
331
+
332
+ 欢迎使用 WeChat Visual Studio!`,Pe(ee),U(p)}catch(o){console.error("Failed to load studio config:",o),g("无法加载配置,使用默认设置","error"),d(20)}}z.addEventListener("change",()=>{p=z.value,U(p)});f.addEventListener("input",()=>d(40));E.addEventListener("input",()=>{ie.textContent=`${E.value}px`,d(20)});L.addEventListener("input",()=>{ae.textContent=L.value,d(20)});B.addEventListener("input",()=>{de.textContent=`${B.value}em`,d(20)});j.addEventListener("input",()=>{Ie.textContent=`${j.value}em`,d(20)});w(W,S,()=>d(20));w(G,I,()=>d(20));w(Q,H,()=>d(20));w(Y,$,()=>d(20));w(_,P,()=>d(20));w(J,T,()=>d(20));M.addEventListener("change",()=>d(20));q.addEventListener("input",()=>d(40));N.addEventListener("input",()=>d(40));b.addEventListener("input",()=>d(60));const D=document.getElementById("tab-btn-style"),K=document.getElementById("tab-btn-syntax"),ce=document.getElementById("tab-content-style"),se=document.getElementById("tab-content-syntax");D.addEventListener("click",()=>{D.classList.add("active"),K.classList.remove("active"),ce.style.display="block",se.style.display="none"});K.addEventListener("click",()=>{K.classList.add("active"),D.classList.remove("active"),ce.style.display="none",se.style.display="block"});document.getElementById("btn-load-sample")?.addEventListener("click",async()=>{const e=await(await fetch("/api/studio/config")).json();f.value=e.sampleMarkdown||"",d(20),g("已加载官方全语法测试稿","info")});document.getElementById("btn-clear-md")?.addEventListener("click",()=>{f.value="",d(20)});document.getElementById("btn-toggle-view")?.addEventListener("click",o=>{const e=o.currentTarget;V=!V,V?(oe.style.display="block",e.textContent="📱 返回视图"):(oe.style.display="none",e.textContent="🔍 查看 HTML 源码")});document.getElementById("btn-reset")?.addEventListener("click",()=>{U(p),g("已重置为当前账号默认样式","info")});document.getElementById("btn-save")?.addEventListener("click",async()=>{const o=Number(E.value)||16,e=L.value||"1.84",t=`${B.value}em`,i=S.value,n=I.value,a=H.value,c=$.value,r=P.value,m=T.value,s=x[p]?.theme?.editorVars||{},l=x[p]?.theme?.exportTheme||{},h={account:p,editorVars:{...s,"--primary":i,"--brand":i,"--text":n,"--divider":m},exportTheme:{...l,fontSize:`${o}px`,bodyColor:n,h2Color:a,h3Color:c,primaryColor:i,dividerColor:m,blockquoteBorderColor:r,bodyLineHeight:e,bodyLetterSpacing:t},syntaxPresets:y,customCss:b.value,structure:{...x[p]?.theme?.structure,numberedHeadings:M.checked,headingLabel:q.value.trim()||void 0,quoteLabel:N.value.trim()||void 0}};try{const u=await fetch("/api/studio/save-config",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(h)}),v=await u.json();u.ok&&v.ok?(x[p]?.theme&&(x[p].theme.syntaxPresets={...y}),g("✅ 配置已成功保存至本地 config.json!","success")):g(`保存失败: ${v.error||"未知错误"}`,"error")}catch(u){g(`网络请求失败: ${String(u)}`,"error")}});document.getElementById("btn-copy")?.addEventListener("click",async()=>{if(!k){g("文章内容为空","error");return}try{const o=new Blob([k],{type:"text/html"}),e=new Blob([k],{type:"text/plain"});await navigator.clipboard.write([new ClipboardItem({"text/html":o,"text/plain":e})]),g("📋 已复制富文本!可在微信公众号后台直接粘贴 (Cmd+V)","success")}catch(o){console.error("Clipboard write error:",o);const e=t=>{t.clipboardData?.setData("text/html",k),t.clipboardData?.setData("text/plain",k),t.preventDefault()};document.addEventListener("copy",e),document.execCommand("copy"),document.removeEventListener("copy",e),g("📋 已复制富文本(后备通道)","success")}});qe();