@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,638 @@
1
+ :root {
2
+ --bg-main: #f8fafc;
3
+ --bg-panel: #ffffff;
4
+ --border: #e2e8f0;
5
+ --border-focus: #ca6093;
6
+ --text-main: #1e293b;
7
+ --text-muted: #64748b;
8
+ --brand: #ca6093;
9
+ --brand-hover: #b35082;
10
+ --brand-light: rgba(202, 96, 147, 0.08);
11
+ --success: #10b981;
12
+ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
13
+ --font-mono: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
14
+ }
15
+
16
+ * {
17
+ box-sizing: border-box;
18
+ margin: 0;
19
+ padding: 0;
20
+ }
21
+
22
+ body {
23
+ font-family: var(--font-sans);
24
+ color: var(--text-main);
25
+ background: var(--bg-main);
26
+ height: 100vh;
27
+ display: flex;
28
+ flex-direction: column;
29
+ overflow: hidden;
30
+ }
31
+
32
+ /* Header */
33
+ .studio-header {
34
+ height: 52px;
35
+ background: var(--bg-panel);
36
+ border-bottom: 1px solid var(--border);
37
+ display: flex;
38
+ align-items: center;
39
+ justify-content: space-between;
40
+ padding: 0 16px;
41
+ z-index: 10;
42
+ }
43
+
44
+ .brand-section {
45
+ display: flex;
46
+ align-items: center;
47
+ gap: 10px;
48
+ }
49
+
50
+ .brand-logo {
51
+ font-size: 18px;
52
+ }
53
+
54
+ .brand-title {
55
+ font-size: 15px;
56
+ font-weight: 700;
57
+ color: var(--text-main);
58
+ letter-spacing: -0.01em;
59
+ }
60
+
61
+ .brand-badge {
62
+ font-size: 11px;
63
+ font-weight: 600;
64
+ background: var(--brand-light);
65
+ color: var(--brand);
66
+ padding: 2px 8px;
67
+ border-radius: 999px;
68
+ }
69
+
70
+ .header-controls {
71
+ display: flex;
72
+ align-items: center;
73
+ gap: 12px;
74
+ }
75
+
76
+ .account-select-wrap {
77
+ display: flex;
78
+ align-items: center;
79
+ gap: 6px;
80
+ font-size: 13px;
81
+ color: var(--text-muted);
82
+ }
83
+
84
+ .account-select {
85
+ padding: 5px 10px;
86
+ font-size: 13px;
87
+ border-radius: 6px;
88
+ border: 1px solid var(--border);
89
+ background: #fff;
90
+ color: var(--text-main);
91
+ outline: none;
92
+ cursor: pointer;
93
+ }
94
+
95
+ .account-select:focus {
96
+ border-color: var(--border-focus);
97
+ }
98
+
99
+ .btn {
100
+ display: inline-flex;
101
+ align-items: center;
102
+ gap: 6px;
103
+ padding: 6px 12px;
104
+ border-radius: 6px;
105
+ font-size: 13px;
106
+ font-weight: 500;
107
+ cursor: pointer;
108
+ border: 1px solid var(--border);
109
+ background: #fff;
110
+ color: var(--text-main);
111
+ transition: all 0.15s ease;
112
+ text-decoration: none;
113
+ }
114
+
115
+ .btn:hover {
116
+ background: #f1f5f9;
117
+ }
118
+
119
+ .btn-primary {
120
+ background: var(--brand);
121
+ color: #fff;
122
+ border-color: var(--brand);
123
+ }
124
+
125
+ .btn-primary:hover {
126
+ background: var(--brand-hover);
127
+ border-color: var(--brand-hover);
128
+ }
129
+
130
+ .btn-success {
131
+ background: #059669;
132
+ color: #fff;
133
+ border-color: #059669;
134
+ }
135
+
136
+ .btn-success:hover {
137
+ background: #047857;
138
+ border-color: #047857;
139
+ }
140
+
141
+ /* Layout */
142
+ .studio-body {
143
+ flex: 1;
144
+ display: flex;
145
+ min-height: 0;
146
+ overflow: hidden;
147
+ }
148
+
149
+ /* Panel Common */
150
+ .panel {
151
+ display: flex;
152
+ flex-direction: column;
153
+ background: var(--bg-panel);
154
+ min-height: 0;
155
+ }
156
+
157
+ .panel-header {
158
+ padding: 10px 16px;
159
+ border-bottom: 1px solid var(--border);
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: space-between;
163
+ background: #fafbfc;
164
+ }
165
+
166
+ .panel-title {
167
+ font-size: 13px;
168
+ font-weight: 650;
169
+ color: var(--text-main);
170
+ display: flex;
171
+ align-items: center;
172
+ gap: 6px;
173
+ }
174
+
175
+ /* Left Panel - Style & Syntax */
176
+ .left-panel {
177
+ width: 360px;
178
+ border-right: 1px solid var(--border);
179
+ flex-shrink: 0;
180
+ }
181
+
182
+ .tab-nav {
183
+ display: flex;
184
+ border-bottom: 1px solid var(--border);
185
+ background: #f8fafc;
186
+ }
187
+
188
+ .tab-btn {
189
+ flex: 1;
190
+ padding: 10px 12px;
191
+ font-size: 13px;
192
+ font-weight: 600;
193
+ border: none;
194
+ background: transparent;
195
+ color: var(--text-muted);
196
+ cursor: pointer;
197
+ border-bottom: 2px solid transparent;
198
+ transition: all 0.15s;
199
+ }
200
+
201
+ .tab-btn:hover {
202
+ color: var(--text-main);
203
+ }
204
+
205
+ .tab-btn.active {
206
+ color: var(--brand);
207
+ background: #fff;
208
+ border-bottom-color: var(--brand);
209
+ }
210
+
211
+ .tab-content {
212
+ flex: 1;
213
+ overflow-y: auto;
214
+ padding: 16px;
215
+ }
216
+
217
+ .config-section {
218
+ margin-bottom: 22px;
219
+ }
220
+
221
+ .section-label {
222
+ font-size: 12px;
223
+ font-weight: 700;
224
+ text-transform: uppercase;
225
+ letter-spacing: 0.05em;
226
+ color: var(--text-muted);
227
+ margin-bottom: 12px;
228
+ display: flex;
229
+ align-items: center;
230
+ gap: 6px;
231
+ }
232
+
233
+ .form-group {
234
+ margin-bottom: 14px;
235
+ }
236
+
237
+ .form-label {
238
+ display: flex;
239
+ justify-content: space-between;
240
+ align-items: center;
241
+ font-size: 12px;
242
+ color: var(--text-main);
243
+ margin-bottom: 6px;
244
+ }
245
+
246
+ .form-val {
247
+ font-family: var(--font-mono);
248
+ font-size: 11px;
249
+ color: var(--text-muted);
250
+ }
251
+
252
+ .slider-input {
253
+ width: 100%;
254
+ accent-color: var(--brand);
255
+ cursor: pointer;
256
+ }
257
+
258
+ .color-input-row {
259
+ display: flex;
260
+ align-items: center;
261
+ gap: 8px;
262
+ }
263
+
264
+ .color-picker {
265
+ -webkit-appearance: none;
266
+ appearance: none;
267
+ border: 1px solid var(--border);
268
+ border-radius: 6px;
269
+ width: 32px;
270
+ height: 32px;
271
+ cursor: pointer;
272
+ padding: 2px;
273
+ background: #fff;
274
+ }
275
+
276
+ .color-picker::-webkit-color-swatch-wrapper {
277
+ padding: 0;
278
+ }
279
+
280
+ .color-picker::-webkit-color-swatch {
281
+ border: none;
282
+ border-radius: 4px;
283
+ }
284
+
285
+ .color-hex {
286
+ flex: 1;
287
+ padding: 6px 10px;
288
+ font-family: var(--font-mono);
289
+ font-size: 12px;
290
+ border: 1px solid var(--border);
291
+ border-radius: 6px;
292
+ color: var(--text-main);
293
+ }
294
+
295
+ .switch-label {
296
+ display: flex;
297
+ align-items: center;
298
+ justify-content: space-between;
299
+ cursor: pointer;
300
+ font-size: 12px;
301
+ }
302
+
303
+ .switch-toggle {
304
+ position: relative;
305
+ display: inline-block;
306
+ width: 38px;
307
+ height: 20px;
308
+ }
309
+
310
+ .switch-toggle input {
311
+ opacity: 0;
312
+ width: 0;
313
+ height: 0;
314
+ }
315
+
316
+ .slider-round {
317
+ position: absolute;
318
+ cursor: pointer;
319
+ top: 0;
320
+ left: 0;
321
+ right: 0;
322
+ bottom: 0;
323
+ background-color: #cbd5e1;
324
+ transition: 0.2s;
325
+ border-radius: 20px;
326
+ }
327
+
328
+ .slider-round:before {
329
+ position: absolute;
330
+ content: "";
331
+ height: 14px;
332
+ width: 14px;
333
+ left: 3px;
334
+ bottom: 3px;
335
+ background-color: white;
336
+ transition: 0.2s;
337
+ border-radius: 50%;
338
+ }
339
+
340
+ input:checked + .slider-round {
341
+ background-color: var(--brand);
342
+ }
343
+
344
+ input:checked + .slider-round:before {
345
+ transform: translateX(18px);
346
+ }
347
+
348
+ .css-editor {
349
+ width: 100%;
350
+ height: 140px;
351
+ font-family: var(--font-mono);
352
+ font-size: 12px;
353
+ line-height: 1.5;
354
+ padding: 8px 10px;
355
+ border: 1px solid var(--border);
356
+ border-radius: 6px;
357
+ background: #fafbfc;
358
+ color: #0f172a;
359
+ resize: vertical;
360
+ outline: none;
361
+ }
362
+
363
+ .css-editor:focus {
364
+ border-color: var(--border-focus);
365
+ background: #fff;
366
+ }
367
+
368
+ /* Syntax Cheatsheet Cards */
369
+ .syntax-card {
370
+ border: 1px solid var(--border);
371
+ border-radius: 8px;
372
+ padding: 12px;
373
+ margin-bottom: 12px;
374
+ background: #fff;
375
+ transition: border-color 0.15s;
376
+ }
377
+
378
+ .syntax-card:hover {
379
+ border-color: #cbd5e1;
380
+ }
381
+
382
+ .syntax-card-header {
383
+ display: flex;
384
+ justify-content: space-between;
385
+ align-items: center;
386
+ margin-bottom: 6px;
387
+ }
388
+
389
+ .syntax-card-title {
390
+ font-size: 13px;
391
+ font-weight: 650;
392
+ color: var(--text-main);
393
+ }
394
+
395
+ .syntax-card-badge {
396
+ font-size: 10px;
397
+ font-weight: 600;
398
+ padding: 1px 6px;
399
+ border-radius: 999px;
400
+ background: #f1f5f9;
401
+ color: var(--text-muted);
402
+ }
403
+
404
+ .syntax-card-desc {
405
+ font-size: 12px;
406
+ color: var(--text-muted);
407
+ margin-bottom: 8px;
408
+ line-height: 1.4;
409
+ }
410
+
411
+ .syntax-code-snippet {
412
+ background: #f8fafc;
413
+ border: 1px solid #e2e8f0;
414
+ border-radius: 6px;
415
+ padding: 8px 10px;
416
+ font-family: var(--font-mono);
417
+ font-size: 11px;
418
+ color: #334155;
419
+ white-space: pre-wrap;
420
+ margin-bottom: 8px;
421
+ }
422
+
423
+ .syntax-btn-insert {
424
+ width: 100%;
425
+ padding: 4px 8px;
426
+ font-size: 11px;
427
+ font-weight: 600;
428
+ border: 1px dashed var(--border);
429
+ border-radius: 4px;
430
+ background: #fafbfc;
431
+ color: var(--brand);
432
+ cursor: pointer;
433
+ }
434
+
435
+ .syntax-btn-insert:hover {
436
+ background: var(--brand-light);
437
+ border-color: var(--brand);
438
+ }
439
+
440
+ /* Middle Panel - Markdown Editor */
441
+ .editor-panel {
442
+ flex: 1;
443
+ border-right: 1px solid var(--border);
444
+ min-width: 320px;
445
+ }
446
+
447
+ .editor-toolbar {
448
+ display: flex;
449
+ gap: 8px;
450
+ align-items: center;
451
+ }
452
+
453
+ .editor-textarea {
454
+ flex: 1;
455
+ width: 100%;
456
+ border: none;
457
+ outline: none;
458
+ resize: none;
459
+ padding: 16px 20px;
460
+ font-family: var(--font-mono);
461
+ font-size: 13px;
462
+ line-height: 1.7;
463
+ color: #1e293b;
464
+ background: #ffffff;
465
+ }
466
+
467
+ .editor-footer {
468
+ padding: 6px 16px;
469
+ border-top: 1px solid var(--border);
470
+ background: #fafbfc;
471
+ font-size: 11px;
472
+ color: var(--text-muted);
473
+ display: flex;
474
+ justify-content: space-between;
475
+ }
476
+
477
+ /* Right Panel - Live WeChat Preview */
478
+ .preview-panel {
479
+ width: 480px;
480
+ flex-shrink: 0;
481
+ background: #f1f5f9;
482
+ }
483
+
484
+ .preview-container {
485
+ flex: 1;
486
+ overflow-y: auto;
487
+ display: flex;
488
+ flex-direction: column;
489
+ align-items: center;
490
+ padding: 24px 16px 48px;
491
+ }
492
+
493
+ .device-frame {
494
+ width: 430px;
495
+ min-height: 680px;
496
+ background: #ffffff;
497
+ border-radius: 18px;
498
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.05);
499
+ overflow: hidden;
500
+ display: flex;
501
+ flex-direction: column;
502
+ border: 1px solid #e2e8f0;
503
+ }
504
+
505
+ .device-notch-bar {
506
+ height: 28px;
507
+ background: #fafbfc;
508
+ border-bottom: 1px solid #f1f5f9;
509
+ display: flex;
510
+ align-items: center;
511
+ justify-content: space-between;
512
+ padding: 0 16px;
513
+ font-size: 11px;
514
+ font-weight: 600;
515
+ color: #64748b;
516
+ }
517
+
518
+ .device-screen {
519
+ flex: 1;
520
+ padding: 20px 16px 36px;
521
+ box-sizing: border-box;
522
+ overflow-y: auto;
523
+ }
524
+
525
+ /* Toast */
526
+ .toast-container {
527
+ position: fixed;
528
+ bottom: 24px;
529
+ right: 24px;
530
+ z-index: 9999;
531
+ display: flex;
532
+ flex-direction: column;
533
+ gap: 8px;
534
+ pointer-events: none;
535
+ }
536
+
537
+ .toast {
538
+ background: #1e293b;
539
+ color: #fff;
540
+ padding: 10px 16px;
541
+ border-radius: 8px;
542
+ font-size: 13px;
543
+ font-weight: 500;
544
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.15);
545
+ opacity: 0;
546
+ transform: translateY(10px);
547
+ transition: all 0.25s ease;
548
+ pointer-events: auto;
549
+ }
550
+
551
+ .toast.show {
552
+ opacity: 1;
553
+ transform: translateY(0);
554
+ }
555
+
556
+ .toast.toast-success {
557
+ background: #065f46;
558
+ border: 1px solid #10b981;
559
+ }
560
+
561
+ /* Syntax Presets */
562
+ .preset-group {
563
+ margin-bottom: 10px;
564
+ padding: 10px 12px;
565
+ background: #f8fafc;
566
+ border: 1px solid var(--border);
567
+ border-radius: var(--radius-sm);
568
+ transition: border-color 0.15s;
569
+ }
570
+
571
+ .preset-group:hover {
572
+ border-color: #cbd5e1;
573
+ }
574
+
575
+ .preset-header {
576
+ display: flex;
577
+ align-items: center;
578
+ justify-content: space-between;
579
+ margin-bottom: 6px;
580
+ }
581
+
582
+ .preset-title {
583
+ font-size: 12px;
584
+ font-weight: 650;
585
+ color: var(--text-main);
586
+ display: flex;
587
+ align-items: center;
588
+ gap: 5px;
589
+ }
590
+
591
+ .preset-select {
592
+ width: 100%;
593
+ padding: 5px 8px;
594
+ font-size: 12px;
595
+ font-weight: 500;
596
+ border: 1px solid var(--border);
597
+ border-radius: 4px;
598
+ background: #ffffff;
599
+ color: var(--text-main);
600
+ outline: none;
601
+ cursor: pointer;
602
+ transition: border-color 0.15s;
603
+ }
604
+
605
+ .preset-select:focus {
606
+ border-color: var(--brand);
607
+ }
608
+
609
+ .preset-desc {
610
+ font-size: 11px;
611
+ color: var(--text-muted);
612
+ margin-top: 5px;
613
+ line-height: 1.4;
614
+ padding-left: 2px;
615
+ }
616
+
617
+ .btn-extract-css {
618
+ padding: 2px 7px;
619
+ font-size: 11px;
620
+ font-weight: 550;
621
+ color: var(--brand);
622
+ background: #ffffff;
623
+ border: 1px solid var(--border);
624
+ border-radius: 4px;
625
+ cursor: pointer;
626
+ transition: all 0.15s ease;
627
+ white-space: nowrap;
628
+ }
629
+
630
+ .btn-extract-css:hover {
631
+ background: #f1f5f9;
632
+ border-color: var(--brand);
633
+ }
634
+
635
+ /* Hidden milkdown host used for in-browser AST parsing */
636
+ #studio-editor-host {
637
+ display: none;
638
+ }