@akairos/myno 0.2.3 → 0.3.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 (78) hide show
  1. package/README.md +30 -0
  2. package/dist/.vite/manifest.json +74 -37
  3. package/dist/adapter.d.ts +20 -0
  4. package/dist/adapter.d.ts.map +1 -0
  5. package/dist/adapter.js +31 -0
  6. package/dist/adapter.js.map +1 -0
  7. package/dist/assets/index-B3KPjiNQ.js +13 -0
  8. package/dist/assets/index-B4oP0CAo.js +1 -0
  9. package/dist/assets/index-B7wgkGTY.js +1 -0
  10. package/dist/assets/index-BQQ1Mi1e.js +1 -0
  11. package/dist/assets/index-BQaqd7HV.js +1 -0
  12. package/dist/assets/index-BRMGrREe.js +7 -0
  13. package/dist/assets/index-BVejJ9GP.js +1 -0
  14. package/dist/assets/index-BXKhM-dq.js +1 -0
  15. package/dist/assets/index-BY_5QCeN.js +2 -0
  16. package/dist/assets/index-BYo4GXZ3.js +1 -0
  17. package/dist/assets/index-Bf_t_p3-.js +13 -0
  18. package/dist/assets/index-Bgyno-qy.js +1 -0
  19. package/dist/assets/index-BuwkzWC3.js +1 -0
  20. package/dist/assets/index-Bx5kysUB.js +6 -0
  21. package/dist/assets/index-BzdnLbE6.js +1 -0
  22. package/dist/assets/index-C3mqfS11.js +3 -0
  23. package/dist/assets/index-C77pdafO.js +1 -0
  24. package/dist/assets/index-C7nlezox.js +1 -0
  25. package/dist/assets/index-CQLZZT0S.js +1 -0
  26. package/dist/assets/index-CTr58p_e.js +1 -0
  27. package/dist/assets/index-CjIk2aLQ.js +1 -0
  28. package/dist/assets/index-Ct6xQ87_.js +1 -0
  29. package/dist/assets/index-Cvpfia2o.js +1 -0
  30. package/dist/assets/index-D33hrwhL.js +1 -0
  31. package/dist/assets/index-D55fsC0p.js +1 -0
  32. package/dist/assets/index-D5qCW0zl.js +1 -0
  33. package/dist/assets/index-DGkCtD3C.js +1 -0
  34. package/dist/assets/index-DIKlav_o.js +1 -0
  35. package/dist/assets/index-DJiXc9K-.js +1 -0
  36. package/dist/assets/index-DOi0-DWN.js +7 -0
  37. package/dist/assets/index-DkaQHRr_.js +2 -0
  38. package/dist/assets/index-Do3WF47E.js +1 -0
  39. package/dist/assets/index-Dz2Wwzwt.js +1 -0
  40. package/dist/assets/index-RBdLFvWq.js +1 -0
  41. package/dist/assets/index-YY02LYN-.js +6 -0
  42. package/dist/assets/index-dFTt0umM.js +1 -0
  43. package/dist/assets/index-iryVxUmP.js +1 -0
  44. package/dist/assets/index-m1bbMc0Z.js +1 -0
  45. package/dist/assets/index-mcj80rA1.js +3 -0
  46. package/dist/assets/index-qhRFP5Y0.js +1 -0
  47. package/dist/assets/index-z4iU21Ve.js +1 -0
  48. package/dist/assets/index-zXdbmld4.js +1 -0
  49. package/dist/assets/style-B23kjid6.css +1 -0
  50. package/dist/assets/style-C2UIbbzr.css +1 -0
  51. package/dist/assets/syntax-presets-B7ZlwXZx.js +1254 -0
  52. package/dist/assets/syntax-presets-Clw1Pr2j.js +1254 -0
  53. package/dist/editor/myno-editor.d.ts +11 -0
  54. package/dist/editor/myno-editor.d.ts.map +1 -1
  55. package/dist/editor/myno-editor.js +24 -8
  56. package/dist/editor/myno-editor.js.map +1 -1
  57. package/dist/editor-export.js +3 -0
  58. package/dist/src/studio/studio.html +8 -7
  59. package/dist/studio/editor-export.d.ts +22 -0
  60. package/dist/studio/editor-export.d.ts.map +1 -0
  61. package/dist/studio/editor-export.js +42 -0
  62. package/dist/studio/editor-export.js.map +1 -0
  63. package/dist/studio/studio-config.d.ts +32 -0
  64. package/dist/studio/studio-config.d.ts.map +1 -0
  65. package/dist/studio/studio-config.js +70 -0
  66. package/dist/studio/studio-config.js.map +1 -0
  67. package/dist/studio/studio.js +57 -36
  68. package/dist/studio/studio.js.map +1 -1
  69. package/dist/studio/themes.d.ts +1 -0
  70. package/dist/studio/themes.d.ts.map +1 -1
  71. package/dist/studio/themes.js +40 -0
  72. package/dist/studio/themes.js.map +1 -1
  73. package/dist/studio/wechat-renderer.d.ts +1 -2
  74. package/dist/studio/wechat-renderer.d.ts.map +1 -1
  75. package/dist/studio/wechat-renderer.js +2 -40
  76. package/dist/studio/wechat-renderer.js.map +1 -1
  77. package/dist/studio.js +107 -1352
  78. package/package.json +6 -1
@@ -19,6 +19,15 @@ export interface MynoEditorOptions {
19
19
  featureConfigs?: CrepeConfig["featureConfigs"];
20
20
  /** create 完成后的逃生舱(可拿到 Crepe 实例做进一步定制)。 */
21
21
  onCreated?: (crepe: Crepe) => void | Promise<void>;
22
+ /**
23
+ * 排版 config(studio 导出的那套 JSON 的核心字段):选中预设替换默认、主题变量覆盖观感。
24
+ * 结构上兼容 parseStyleConfig 的结果——多余字段忽略;运行时更新用 applyStyleConfig()。
25
+ */
26
+ styleConfig?: {
27
+ editorVars?: Record<string, string>;
28
+ exportTheme?: Record<string, string | undefined>;
29
+ syntaxPresets?: Record<string, string>;
30
+ };
22
31
  }
23
32
  export declare class MynoEditor {
24
33
  private crepe;
@@ -26,6 +35,8 @@ export declare class MynoEditor {
26
35
  private isDestroyed;
27
36
  constructor(options: MynoEditorOptions);
28
37
  create(): Promise<Crepe>;
38
+ /** 运行时更新排版样式(config 异步加载完成后调用;undefined = 回到出厂默认)。 */
39
+ applyStyleConfig(styleConfig?: MynoEditorOptions["styleConfig"]): void;
29
40
  getMarkdown(): string;
30
41
  setMarkdown(markdown: string): void;
31
42
  setReadonly(readonly: boolean): void;
@@ -1 +1 @@
1
- {"version":3,"file":"myno-editor.d.ts","sourceRoot":"","sources":["../../src/editor/myno-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAgBxD,OAAO,wCAAwC,CAAC;AAChD,OAAO,iCAAiC,CAAC;AACzC,OAAO,oDAAoD,CAAC;AAC5D,OAAO,6CAA6C,CAAC;AAErD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,kDAAkD;IAClD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,sDAAsD;IACtD,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,6CAA6C;IAC7C,cAAc,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC/C,0CAA0C;IAC1C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,iBAAiB;IAIhC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC;IAiF9B,WAAW,IAAI,MAAM;IAKrB,WAAW,CAAC,QAAQ,EAAE,MAAM;IAc5B,WAAW,CAAC,QAAQ,EAAE,OAAO;IAI7B,QAAQ,IAAI,KAAK,GAAG,IAAI;IAIlB,OAAO;CAOd"}
1
+ {"version":3,"file":"myno-editor.d.ts","sourceRoot":"","sources":["../../src/editor/myno-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAiBxD,OAAO,wCAAwC,CAAC;AAChD,OAAO,iCAAiC,CAAC;AACzC,OAAO,oDAAoD,CAAC;AAC5D,OAAO,6CAA6C,CAAC;AAErD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,kDAAkD;IAClD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,sDAAsD;IACtD,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,6CAA6C;IAC7C,cAAc,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC/C,0CAA0C;IAC1C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD;;;OAGG;IACH,WAAW,CAAC,EAAE;QACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;QACjD,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACxC,CAAC;CACH;AAID,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,iBAAiB;IAIhC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC;IA2E9B,sDAAsD;IACtD,gBAAgB,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC,aAAa,CAAC;IAuB/D,WAAW,IAAI,MAAM;IAKrB,WAAW,CAAC,QAAQ,EAAE,MAAM;IAc5B,WAAW,CAAC,QAAQ,EAAE,OAAO;IAI7B,QAAQ,IAAI,KAAK,GAAG,IAAI;IAIlB,OAAO;CAOd"}
@@ -7,10 +7,12 @@ import { createDataImageUploadPlugin, dataImageFile } from "./image-upload";
7
7
  // 各语法类目的默认预设(h2 呼吸柱、引用样式等)是 myno 的默认观感,随编辑器一起生效;
8
8
  // studio 等宿主若在运行时注入自己的预设 CSS,后注入者按文档顺序覆盖这里的默认。
9
9
  import { buildCombinedPresetsCss } from "../studio/syntax-presets";
10
+ import { buildWechatThemeCss, getWechatPreviewTheme } from "../studio/themes";
10
11
  import "@milkdown/crepe/theme/common/style.css";
11
12
  import "@milkdown/crepe/theme/frame.css";
12
13
  import "@akairos/milkdown-article-style/tokens-default.css";
13
14
  import "@akairos/milkdown-article-style/article.css";
15
+ const PRESET_STYLE_ID = "myno-editor-preset-css";
14
16
  export class MynoEditor {
15
17
  crepe = null;
16
18
  options;
@@ -19,14 +21,8 @@ export class MynoEditor {
19
21
  this.options = options;
20
22
  }
21
23
  async create() {
22
- const { root, defaultValue = "", readonly = false, placeholder = "输入内容,或输入 / 快速插入文章组件...", uploadImage, plugins, featureConfigs, onCreated } = this.options;
23
- let presetStyle = document.getElementById("myno-editor-preset-css");
24
- if (!presetStyle) {
25
- presetStyle = document.createElement("style");
26
- presetStyle.id = "myno-editor-preset-css";
27
- document.head.appendChild(presetStyle);
28
- }
29
- presetStyle.textContent = buildCombinedPresetsCss({});
24
+ const { root, defaultValue = "", readonly = false, placeholder = "输入内容,或输入 / 快速插入文章组件...", uploadImage, plugins, featureConfigs, onCreated, styleConfig } = this.options;
25
+ this.applyStyleConfig(styleConfig);
30
26
  const crepe = new Crepe({
31
27
  root,
32
28
  defaultValue,
@@ -89,6 +85,26 @@ export class MynoEditor {
89
85
  this.crepe = crepe;
90
86
  return crepe;
91
87
  }
88
+ /** 运行时更新排版样式(config 异步加载完成后调用;undefined = 回到出厂默认)。 */
89
+ applyStyleConfig(styleConfig) {
90
+ let styleTag = document.getElementById(PRESET_STYLE_ID);
91
+ if (!styleTag) {
92
+ styleTag = document.createElement("style");
93
+ styleTag.id = PRESET_STYLE_ID;
94
+ document.head.appendChild(styleTag);
95
+ }
96
+ const presets = buildCombinedPresetsCss(styleConfig?.syntaxPresets ?? {});
97
+ const hasTheme = styleConfig && (Object.keys(styleConfig.editorVars ?? {}).length > 0
98
+ || Object.keys(styleConfig.exportTheme ?? {}).filter(k => styleConfig.exportTheme[k] != null).length > 0);
99
+ // 导出主题的 Partial 字段合并到默认主题底上,编辑器内即所见即所得
100
+ const themeCss = hasTheme
101
+ ? buildWechatThemeCss(styleConfig.editorVars ?? {}, getWechatPreviewTheme("default", {
102
+ editorVars: styleConfig.editorVars,
103
+ exportTheme: styleConfig.exportTheme,
104
+ }).exportTheme)
105
+ : "";
106
+ styleTag.textContent = `${presets}\n${themeCss}`;
107
+ }
92
108
  getMarkdown() {
93
109
  if (!this.crepe)
94
110
  return this.options.defaultValue || "";
@@ -1 +1 @@
1
- {"version":3,"file":"myno-editor.js","sourceRoot":"","sources":["../../src/editor/myno-editor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"myno-editor.js","sourceRoot":"","sources":["../../src/editor/myno-editor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import{E as c,r as m,d,c as _,g as l,a as u,b as w,e as f,f as g,h}from"./assets/syntax-presets-B7ZlwXZx.js";async function C(){const t=window.__ZZHUB_WECHAT_PAYLOAD__,s=c.make().config(e=>{e.set(m,document.getElementById("editor-host")),e.set(d,t.markdown)}).use(_).use(l).use(u());try{await s.create();const e=new DOMParser().parseFromString(s.action(w()),"text/html");for(const n of e.querySelectorAll("img")){const r=n.getAttribute("src")||"";if(r&&!/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(r)){const o=new URL(r,t.assetBaseUrl);n.src=o.protocol==="file:"?decodeURIComponent(o.pathname):o.href}}const a=e.body.innerHTML,i=await f({semanticHtml:a,baseCss:h,customCss:[g(t.syntaxPresets??{}),t.customCss].filter(Boolean).join(`
2
+
3
+ `),structure:t.structure,editorVars:t.editorVars,theme:t.exportTheme});window.__ZZHUB_SET_RESULT__({status:"success",html:i,semanticHtml:a})}catch(e){window.__ZZHUB_SET_RESULT__({status:"error",error:e instanceof Error?e.message:String(e)})}finally{await s.destroy()}}C().catch(t=>window.__ZZHUB_SET_RESULT__({status:"error",error:String(t)}));
@@ -4,8 +4,9 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>myno — 微信公众号排版工作台</title>
7
- <script type="module" crossorigin src="/studio.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/style-Cif_gYUW.css">
7
+ <script type="module" crossorigin src="../../studio.js"></script>
8
+ <link rel="modulepreload" crossorigin href="../../assets/syntax-presets-B7ZlwXZx.js">
9
+ <link rel="stylesheet" crossorigin href="../../assets/style-B23kjid6.css">
9
10
  </head>
10
11
  <body>
11
12
  <!-- Header -->
@@ -21,14 +22,14 @@
21
22
  <span class="brand-title">myno</span>
22
23
  <span class="brand-subtitle">WeChat Visual Studio</span>
23
24
  </div>
24
- <span id="config-mode-badge" class="badge badge-subtle">账号配置</span>
25
+ <span id="config-mode-badge" class="badge badge-subtle">本地模式</span>
25
26
  </div>
26
27
 
27
28
  <!-- Center Config Selector -->
28
29
  <div class="header-center">
29
30
  <div class="config-selector-group">
30
- <label for="account-select" class="selector-label">目标配置:</label>
31
- <select id="account-select" class="select-control">
31
+ <label for="account-select" class="selector-label" hidden>目标配置:</label>
32
+ <select id="account-select" class="select-control" hidden>
32
33
  <option value="default">默认账号 (default)</option>
33
34
  </select>
34
35
  <button id="btn-import-config" class="btn btn-ghost btn-sm" title="导入已有 wechat-style.json 排版配置">
@@ -47,7 +48,7 @@
47
48
  <span>🔄 重置</span>
48
49
  </button>
49
50
 
50
- <button id="btn-save" class="btn btn-primary btn-sm" title="保存当前调整至本地 config.json 的当前账号">
51
+ <button id="btn-save" class="btn btn-primary btn-sm" title="保存当前调整至本地 config.json 的当前账号" hidden>
51
52
  <span>💾 保存至账号</span>
52
53
  </button>
53
54
 
@@ -55,7 +56,7 @@
55
56
  <span>📋 一键复制到公众号</span>
56
57
  </button>
57
58
 
58
- <a href="/" class="btn btn-ghost btn-sm" title="查看最近渲染记录">
59
+ <a id="history-link" href="/" class="btn btn-ghost btn-sm" title="查看最近渲染记录" hidden>
59
60
  <span>📜 历史记录</span>
60
61
  </a>
61
62
  </div>
@@ -0,0 +1,22 @@
1
+ import { type ArticleStructure } from "./wechat-renderer";
2
+ import type { WechatExportTheme } from "./themes";
3
+ declare global {
4
+ interface Window {
5
+ __ZZHUB_WECHAT_PAYLOAD__: {
6
+ markdown: string;
7
+ assetBaseUrl: string;
8
+ editorVars: Record<string, string>;
9
+ exportTheme: WechatExportTheme;
10
+ syntaxPresets?: Record<string, string>;
11
+ structure?: ArticleStructure;
12
+ customCss?: string;
13
+ };
14
+ __ZZHUB_SET_RESULT__: (result: {
15
+ status: "success" | "error";
16
+ html?: string;
17
+ semanticHtml?: string;
18
+ error?: string;
19
+ }) => void;
20
+ }
21
+ }
22
+ //# sourceMappingURL=editor-export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor-export.d.ts","sourceRoot":"","sources":["../../src/studio/editor-export.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,wBAAwB,EAAE;YACxB,QAAQ,EAAE,MAAM,CAAC;YACjB,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACnC,WAAW,EAAE,iBAAiB,CAAC;YAC/B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACvC,SAAS,CAAC,EAAE,gBAAgB,CAAC;YAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;QACF,oBAAoB,EAAE,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,YAAY,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,KAAK,IAAI,CAAC;KAC/H;CACF"}
@@ -0,0 +1,42 @@
1
+ import { defaultValueCtx, Editor, rootCtx } from "@milkdown/kit/core";
2
+ import { commonmark } from "@milkdown/kit/preset/commonmark";
3
+ import { gfm } from "@milkdown/kit/preset/gfm";
4
+ import { getHTML } from "@milkdown/kit/utils";
5
+ import articleCss from "@akairos/milkdown-article-style/article.css?raw";
6
+ import { getCombinedMilkdownPlugins } from "@akairos/milkdown-article-plugins";
7
+ import { renderWechatHtml } from "./wechat-renderer";
8
+ import { buildCombinedPresetsCss } from "./syntax-presets";
9
+ /** 无交互导出入口,与 Studio 共用 myno 的语法、预设和微信渲染器。 */
10
+ async function main() {
11
+ const payload = window.__ZZHUB_WECHAT_PAYLOAD__;
12
+ const editor = Editor.make().config(ctx => {
13
+ ctx.set(rootCtx, document.getElementById("editor-host"));
14
+ ctx.set(defaultValueCtx, payload.markdown);
15
+ }).use(commonmark).use(gfm).use(getCombinedMilkdownPlugins());
16
+ try {
17
+ await editor.create();
18
+ const semantic = new DOMParser().parseFromString(editor.action(getHTML()), "text/html");
19
+ for (const image of semantic.querySelectorAll("img")) {
20
+ const src = image.getAttribute("src") || "";
21
+ if (src && !/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(src)) {
22
+ const url = new URL(src, payload.assetBaseUrl);
23
+ image.src = url.protocol === "file:" ? decodeURIComponent(url.pathname) : url.href;
24
+ }
25
+ }
26
+ const semanticHtml = semantic.body.innerHTML;
27
+ const html = await renderWechatHtml({
28
+ semanticHtml, baseCss: articleCss,
29
+ customCss: [buildCombinedPresetsCss(payload.syntaxPresets ?? {}), payload.customCss].filter(Boolean).join("\n\n"),
30
+ structure: payload.structure, editorVars: payload.editorVars, theme: payload.exportTheme,
31
+ });
32
+ window.__ZZHUB_SET_RESULT__({ status: "success", html, semanticHtml });
33
+ }
34
+ catch (error) {
35
+ window.__ZZHUB_SET_RESULT__({ status: "error", error: error instanceof Error ? error.message : String(error) });
36
+ }
37
+ finally {
38
+ await editor.destroy();
39
+ }
40
+ }
41
+ void main().catch(error => window.__ZZHUB_SET_RESULT__({ status: "error", error: String(error) }));
42
+ //# sourceMappingURL=editor-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor-export.js","sourceRoot":"","sources":["../../src/studio/editor-export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { type WechatPluginDoc } from "@akairos/milkdown-article-plugins";
2
+ import { type WechatExportTheme } from "./themes";
3
+ import type { ArticleStructure } from "./wechat-renderer";
4
+ export interface AccountData {
5
+ name: string;
6
+ customCssPath: string | null;
7
+ customCssContent: string;
8
+ theme: {
9
+ editorVars: Record<string, string>;
10
+ exportTheme: Partial<WechatExportTheme>;
11
+ syntaxPresets?: Record<string, string>;
12
+ structure?: ArticleStructure;
13
+ };
14
+ articleThemeCss?: string;
15
+ articleTheme?: string | null;
16
+ articleThemeStandalone?: boolean;
17
+ }
18
+ export interface StudioConfigResponse {
19
+ defaultAccount: string;
20
+ accounts: Record<string, AccountData>;
21
+ plugins: WechatPluginDoc[];
22
+ sampleMarkdown: string;
23
+ }
24
+ /** 独立工作台使用本包主题和语法示例,不带发布账号的署名。 */
25
+ export declare function createLocalStudioConfig(): StudioConfigResponse;
26
+ /** 宿主配置优先;接口缺失或失败时保留完整的本地工作台。 */
27
+ export declare function loadStudioConfig(fetchConfig?: (input: string, init: RequestInit) => Promise<Response>): Promise<{
28
+ config: StudioConfigResponse;
29
+ source: "local" | "pipeline";
30
+ error?: string;
31
+ }>;
32
+ //# sourceMappingURL=studio-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-config.d.ts","sourceRoot":"","sources":["../../src/studio/studio-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE;QACL,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,WAAW,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACxC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACvC,SAAS,CAAC,EAAE,gBAAgB,CAAC;KAC9B,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,kCAAkC;AAClC,wBAAgB,uBAAuB,IAAI,oBAAoB,CA4B9D;AAED,iCAAiC;AACjC,wBAAsB,gBAAgB,CAAC,WAAW,GAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAS,GAAG,OAAO,CAAC;IAC5H,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,OAAO,GAAG,UAAU,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA+BD"}
@@ -0,0 +1,70 @@
1
+ import { getPluginDocs } from "@akairos/milkdown-article-plugins";
2
+ import { getWechatPreviewTheme } from "./themes";
3
+ /** 独立工作台使用本包主题和语法示例,不带发布账号的署名。 */
4
+ export function createLocalStudioConfig() {
5
+ const theme = getWechatPreviewTheme("default", { exportTheme: { footerText: "" } });
6
+ const plugins = getPluginDocs();
7
+ return {
8
+ defaultAccount: "default",
9
+ accounts: {
10
+ default: {
11
+ name: "本地默认",
12
+ customCssPath: null,
13
+ customCssContent: "",
14
+ theme: { editorVars: { ...theme.editorVars }, exportTheme: { ...theme.exportTheme } },
15
+ },
16
+ },
17
+ plugins,
18
+ sampleMarkdown: [
19
+ "# 微信排版示例",
20
+ "## 从一段文字开始",
21
+ "在这里写下你的内容,调整左侧样式后,可一键复制到公众号,或导出配置供下次使用。",
22
+ "这段正文包含 **加粗**、*斜体*、[链接](https://example.com) 和 `行内代码`。",
23
+ "> 引用可以补充背景,也可以呈现一段值得记住的话。",
24
+ "### 列表与表格",
25
+ "- 写作\n- 调整样式\n- 复制或导出",
26
+ "| 项目 | 说明 |\n| --- | --- |\n| 正文 | 调整字号与行距 |\n| 配置 | 导出为 JSON |",
27
+ "```ts\nconst message = 'Hello, myno';\n```",
28
+ "---",
29
+ ...plugins.map(plugin => `### ${plugin.name}\n\n${plugin.sampleMarkdown}`),
30
+ ].join("\n\n"),
31
+ };
32
+ }
33
+ /** 宿主配置优先;接口缺失或失败时保留完整的本地工作台。 */
34
+ export async function loadStudioConfig(fetchConfig = fetch) {
35
+ const local = createLocalStudioConfig();
36
+ try {
37
+ const response = await fetchConfig("/api/studio/config", { signal: AbortSignal.timeout(3000) });
38
+ if (response.status === 404)
39
+ return { config: local, source: "local" };
40
+ if (!response.ok)
41
+ throw new Error(`HTTP ${response.status}`);
42
+ const data = await response.json();
43
+ if (!data?.accounts || typeof data.accounts !== "object" || Array.isArray(data.accounts) || !data.accounts[data.defaultAccount]?.theme) {
44
+ throw new Error("工作台配置缺少有效的默认账号");
45
+ }
46
+ const accounts = {};
47
+ for (const [key, account] of Object.entries(data.accounts)) {
48
+ if (!account?.theme)
49
+ throw new Error(`账号 ${key} 缺少主题配置`);
50
+ const theme = getWechatPreviewTheme("default", {
51
+ editorVars: account.theme.editorVars,
52
+ exportTheme: { footerText: "", ...account.theme.exportTheme },
53
+ });
54
+ accounts[key] = {
55
+ ...local.accounts.default,
56
+ ...account,
57
+ name: account.name || key,
58
+ theme: { ...account.theme, editorVars: { ...theme.editorVars }, exportTheme: { ...theme.exportTheme } },
59
+ };
60
+ }
61
+ return {
62
+ source: "pipeline",
63
+ config: { ...data, accounts, plugins: data.plugins ?? local.plugins, sampleMarkdown: data.sampleMarkdown || local.sampleMarkdown },
64
+ };
65
+ }
66
+ catch (error) {
67
+ return { config: local, source: "local", error: error instanceof Error ? error.message : String(error) };
68
+ }
69
+ }
70
+ //# sourceMappingURL=studio-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-config.js","sourceRoot":"","sources":["../../src/studio/studio-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAwB,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,qBAAqB,EAA0B,MAAM,UAAU,CAAC;AAyBzE,kCAAkC;AAClC,MAAM,UAAU,uBAAuB;IACrC,MAAM,KAAK,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACpF,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,OAAO;QACL,cAAc,EAAE,SAAS;QACzB,QAAQ,EAAE;YACR,OAAO,EAAE;gBACP,IAAI,EAAE,MAAM;gBACZ,aAAa,EAAE,IAAI;gBACnB,gBAAgB,EAAE,EAAE;gBACpB,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,EAAE,WAAW,EAAE,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,EAAE;aACtF;SACF;QACD,OAAO;QACP,cAAc,EAAE;YACd,UAAU;YACV,YAAY;YACZ,yCAAyC;YACzC,wDAAwD;YACxD,2BAA2B;YAC3B,WAAW;YACX,uBAAuB;YACvB,iEAAiE;YACjE,4CAA4C;YAC5C,KAAK;YACL,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,cAAc,EAAE,CAAC;SAC3E,CAAC,IAAI,CAAC,MAAM,CAAC;KACf,CAAC;AACJ,CAAC;AAED,iCAAiC;AACjC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,cAAuE,KAAK;IAKjH,MAAM,KAAK,GAAG,uBAAuB,EAAE,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QACvE,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA0B,CAAC;QAC3D,IAAI,CAAC,IAAI,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,CAAC;YACvI,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;QACD,MAAM,QAAQ,GAAgC,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,OAAO,EAAE,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;YACzD,MAAM,KAAK,GAAG,qBAAqB,CAAC,SAAS,EAAE;gBAC7C,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU;gBACpC,WAAW,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE;aAC9D,CAAC,CAAC;YACH,QAAQ,CAAC,GAAG,CAAC,GAAG;gBACd,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO;gBACzB,GAAG,OAAO;gBACV,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,GAAG;gBACzB,KAAK,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,EAAE,WAAW,EAAE,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,EAAE;aACxG,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,cAAc,EAAE;SACnI,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IAC3G,CAAC;AACH,CAAC"}
@@ -9,10 +9,14 @@ import { STYLE_PACKS } from "./style-packs";
9
9
  import { SYNTAX_CATEGORIES, buildCombinedPresetsCss } from "./syntax-presets";
10
10
  import { COLOR_PALETTES } from "./color-palettes";
11
11
  import { parseStyleConfig, exportStyleConfigBlob } from "./config-manager";
12
- import { renderWechatHtml, buildWechatThemeCss } from "./wechat-renderer";
13
- let accounts = {};
14
- let currentAccount = "default";
15
- let pluginsList = [];
12
+ import { renderWechatHtml } from "./wechat-renderer";
13
+ import { buildWechatThemeCss } from "./themes";
14
+ import { createLocalStudioConfig, loadStudioConfig } from "./studio-config";
15
+ // 本地默认数据始终可用,宿主加载失败不会中断编辑器初始化。
16
+ let studioConfig = createLocalStudioConfig();
17
+ let accounts = studioConfig.accounts;
18
+ let currentAccount = studioConfig.defaultAccount;
19
+ let pipelineConnected = false;
16
20
  let latestWechatHtml = "";
17
21
  let debounceTimer = null;
18
22
  let showingHtmlSource = false;
@@ -70,6 +74,8 @@ const btnCopy = document.getElementById("btn-copy");
70
74
  const btnToggleView = document.getElementById("btn-toggle-view");
71
75
  const btnLoadSample = document.getElementById("btn-load-sample");
72
76
  const btnClearMd = document.getElementById("btn-clear-md");
77
+ const historyLink = document.getElementById("history-link");
78
+ const accountLabel = document.querySelector('label[for="account-select"]');
73
79
  // ── Toast System ────────────────────────────────────────────────────────
74
80
  function showToast(message, type = "info") {
75
81
  if (!toastContainer)
@@ -619,8 +625,12 @@ function applyAccountConfig(accountKey) {
619
625
  if (!account)
620
626
  return;
621
627
  const standalone = Boolean(account.articleThemeStandalone);
622
- configModeBadge.textContent = standalone ? "独立排版文件" : "账号默认配置";
628
+ standaloneThemeName = "";
629
+ configModeBadge.textContent = !pipelineConnected ? "本地模式" : standalone ? "独立排版文件" : "账号默认配置";
623
630
  configModeBadge.className = `badge ${standalone ? "badge-primary" : "badge-subtle"}`;
631
+ accountSelect.hidden = accountLabel.hidden = !pipelineConnected;
632
+ btnSave.hidden = historyLink.hidden = !pipelineConnected;
633
+ btnReset.title = pipelineConnected ? "恢复当前账号默认样式" : "恢复本地默认样式";
624
634
  btnSave.disabled = Boolean(account.articleThemeStandalone);
625
635
  btnSave.title = account.articleThemeStandalone
626
636
  ? "当前账号引用独立配置,请通过「导出配置」保存调整后替换原文件"
@@ -717,45 +727,58 @@ async function initStudio() {
717
727
  bindColorPair(pickerH3Color, hexH3Color, () => scheduleRender(20));
718
728
  bindColorPair(pickerQuoteColor, hexQuoteColor, () => scheduleRender(20));
719
729
  bindColorPair(pickerDividerColor, hexDividerColor, () => scheduleRender(20));
730
+ const localMarkdown = studioConfig.sampleMarkdown;
731
+ editorMarkdown.value = localMarkdown;
732
+ const configRequest = loadStudioConfig();
733
+ let initialMarkdown = localMarkdown;
720
734
  try {
721
- const res = await fetch("/api/studio/config");
722
- if (!res.ok)
723
- throw new Error(`HTTP ${res.status}`);
724
- const data = (await res.json());
725
- accounts = data.accounts || {};
726
- currentAccount = data.defaultAccount || "default";
727
- pluginsList = data.plugins || [];
728
- // Account selector
729
- accountSelect.innerHTML = "";
730
- for (const [key, acc] of Object.entries(accounts)) {
731
- const opt = document.createElement("option");
732
- opt.value = key;
733
- opt.textContent = `${acc.name || key} (${key})`;
734
- if (key === currentAccount)
735
- opt.selected = true;
736
- accountSelect.appendChild(opt);
737
- }
738
- const initialMd = data.sampleMarkdown || "# 微信排版标题\n\n欢迎使用 myno 微信排版工作台!";
739
- editorMarkdown.value = initialMd;
740
- // Mount MynoEditor (Milkdown Crepe)
735
+ // 编辑器先用本地默认值创建,配置接口不是启动前提。
741
736
  if (milkdownEditorRoot) {
742
737
  mynoEditor = new MynoEditor({
743
738
  root: milkdownEditorRoot,
744
- defaultValue: initialMd,
739
+ defaultValue: localMarkdown,
745
740
  onMarkdownChange: (md) => {
746
741
  editorMarkdown.value = md;
747
742
  scheduleRender(40);
748
743
  },
749
744
  });
750
745
  await mynoEditor.create();
746
+ initialMarkdown = mynoEditor.getMarkdown();
751
747
  }
752
- renderSyntaxCards(pluginsList);
753
748
  applyAccountConfig(currentAccount);
749
+ renderSyntaxCards(studioConfig.plugins);
754
750
  }
755
751
  catch (err) {
756
- console.error("Failed to load studio config:", err);
757
- showToast("无法加载服务器配置,使用本地默认设置", "error");
758
- scheduleRender(20);
752
+ console.error("Failed to initialize editor:", err);
753
+ await mynoEditor?.destroy();
754
+ mynoEditor = null;
755
+ showToast("编辑器初始化失败,可切换 Markdown 源码模式继续编辑", "error");
756
+ }
757
+ const result = await configRequest;
758
+ if (result.source === "pipeline") {
759
+ studioConfig = result.config;
760
+ accounts = studioConfig.accounts;
761
+ currentAccount = studioConfig.defaultAccount;
762
+ pipelineConnected = true;
763
+ accountSelect.innerHTML = "";
764
+ for (const [key, account] of Object.entries(accounts)) {
765
+ const option = document.createElement("option");
766
+ option.value = key;
767
+ option.textContent = `${account.name} (${key})`;
768
+ option.selected = key === currentAccount;
769
+ accountSelect.appendChild(option);
770
+ }
771
+ // 只替换尚未编辑的示例正文,迟到的配置不能覆盖用户输入。
772
+ if (getActiveMarkdown() === initialMarkdown) {
773
+ editorMarkdown.value = studioConfig.sampleMarkdown;
774
+ mynoEditor?.setMarkdown(studioConfig.sampleMarkdown);
775
+ }
776
+ applyAccountConfig(currentAccount);
777
+ renderSyntaxCards(studioConfig.plugins);
778
+ }
779
+ else if (result.error) {
780
+ configModeBadge.textContent = "本地模式 · 配置未加载";
781
+ showToast("未能加载 pipeline 配置,当前使用本地默认配置;可正常编辑和导出", "info");
759
782
  }
760
783
  }
761
784
  // ── Event Handlers ──────────────────────────────────────────────────────
@@ -840,10 +863,8 @@ tabBtnSyntax?.addEventListener("click", () => {
840
863
  tabContentSyntax.style.display = "block";
841
864
  });
842
865
  // Load sample / clear
843
- btnLoadSample?.addEventListener("click", async () => {
844
- const res = await fetch("/api/studio/config");
845
- const data = (await res.json());
846
- const sample = data.sampleMarkdown || "";
866
+ btnLoadSample?.addEventListener("click", () => {
867
+ const sample = studioConfig.sampleMarkdown;
847
868
  editorMarkdown.value = sample;
848
869
  if (mynoEditor)
849
870
  mynoEditor.setMarkdown(sample);
@@ -871,12 +892,12 @@ btnToggleView?.addEventListener("click", () => {
871
892
  // Reset
872
893
  btnReset?.addEventListener("click", () => {
873
894
  applyAccountConfig(currentAccount);
874
- showToast("已重置为当前账号默认样式", "info");
895
+ showToast(pipelineConnected ? "已重置为当前账号默认样式" : "已重置为本地默认样式", "info");
875
896
  });
876
897
  // Save to config.json
877
898
  btnSave?.addEventListener("click", async () => {
878
899
  const account = accounts[currentAccount];
879
- if (!account)
900
+ if (!pipelineConnected || !account || account.articleThemeStandalone)
880
901
  return;
881
902
  const { structure, ...theme } = readStyleControls();
882
903
  const { headerImageUrl: _headerImageUrl, ...savedStructure } = structure;