@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.
- package/README.md +30 -0
- package/dist/.vite/manifest.json +74 -37
- package/dist/adapter.d.ts +20 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +31 -0
- package/dist/adapter.js.map +1 -0
- package/dist/assets/index-B3KPjiNQ.js +13 -0
- package/dist/assets/index-B4oP0CAo.js +1 -0
- package/dist/assets/index-B7wgkGTY.js +1 -0
- package/dist/assets/index-BQQ1Mi1e.js +1 -0
- package/dist/assets/index-BQaqd7HV.js +1 -0
- package/dist/assets/index-BRMGrREe.js +7 -0
- package/dist/assets/index-BVejJ9GP.js +1 -0
- package/dist/assets/index-BXKhM-dq.js +1 -0
- package/dist/assets/index-BY_5QCeN.js +2 -0
- package/dist/assets/index-BYo4GXZ3.js +1 -0
- package/dist/assets/index-Bf_t_p3-.js +13 -0
- package/dist/assets/index-Bgyno-qy.js +1 -0
- package/dist/assets/index-BuwkzWC3.js +1 -0
- package/dist/assets/index-Bx5kysUB.js +6 -0
- package/dist/assets/index-BzdnLbE6.js +1 -0
- package/dist/assets/index-C3mqfS11.js +3 -0
- package/dist/assets/index-C77pdafO.js +1 -0
- package/dist/assets/index-C7nlezox.js +1 -0
- package/dist/assets/index-CQLZZT0S.js +1 -0
- package/dist/assets/index-CTr58p_e.js +1 -0
- package/dist/assets/index-CjIk2aLQ.js +1 -0
- package/dist/assets/index-Ct6xQ87_.js +1 -0
- package/dist/assets/index-Cvpfia2o.js +1 -0
- package/dist/assets/index-D33hrwhL.js +1 -0
- package/dist/assets/index-D55fsC0p.js +1 -0
- package/dist/assets/index-D5qCW0zl.js +1 -0
- package/dist/assets/index-DGkCtD3C.js +1 -0
- package/dist/assets/index-DIKlav_o.js +1 -0
- package/dist/assets/index-DJiXc9K-.js +1 -0
- package/dist/assets/index-DOi0-DWN.js +7 -0
- package/dist/assets/index-DkaQHRr_.js +2 -0
- package/dist/assets/index-Do3WF47E.js +1 -0
- package/dist/assets/index-Dz2Wwzwt.js +1 -0
- package/dist/assets/index-RBdLFvWq.js +1 -0
- package/dist/assets/index-YY02LYN-.js +6 -0
- package/dist/assets/index-dFTt0umM.js +1 -0
- package/dist/assets/index-iryVxUmP.js +1 -0
- package/dist/assets/index-m1bbMc0Z.js +1 -0
- package/dist/assets/index-mcj80rA1.js +3 -0
- package/dist/assets/index-qhRFP5Y0.js +1 -0
- package/dist/assets/index-z4iU21Ve.js +1 -0
- package/dist/assets/index-zXdbmld4.js +1 -0
- package/dist/assets/style-B23kjid6.css +1 -0
- package/dist/assets/style-C2UIbbzr.css +1 -0
- package/dist/assets/syntax-presets-B7ZlwXZx.js +1254 -0
- package/dist/assets/syntax-presets-Clw1Pr2j.js +1254 -0
- package/dist/editor/myno-editor.d.ts +11 -0
- package/dist/editor/myno-editor.d.ts.map +1 -1
- package/dist/editor/myno-editor.js +24 -8
- package/dist/editor/myno-editor.js.map +1 -1
- package/dist/editor-export.js +3 -0
- package/dist/src/studio/studio.html +8 -7
- package/dist/studio/editor-export.d.ts +22 -0
- package/dist/studio/editor-export.d.ts.map +1 -0
- package/dist/studio/editor-export.js +42 -0
- package/dist/studio/editor-export.js.map +1 -0
- package/dist/studio/studio-config.d.ts +32 -0
- package/dist/studio/studio-config.d.ts.map +1 -0
- package/dist/studio/studio-config.js +70 -0
- package/dist/studio/studio-config.js.map +1 -0
- package/dist/studio/studio.js +57 -36
- package/dist/studio/studio.js.map +1 -1
- package/dist/studio/themes.d.ts +1 -0
- package/dist/studio/themes.d.ts.map +1 -1
- package/dist/studio/themes.js +40 -0
- package/dist/studio/themes.js.map +1 -1
- package/dist/studio/wechat-renderer.d.ts +1 -2
- package/dist/studio/wechat-renderer.d.ts.map +1 -1
- package/dist/studio/wechat-renderer.js +2 -40
- package/dist/studio/wechat-renderer.js.map +1 -1
- package/dist/studio.js +107 -1352
- 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;
|
|
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
|
-
|
|
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":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAGxC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,2BAA2B,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5E,iDAAiD;AACjD,+CAA+C;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;
|
|
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="
|
|
8
|
-
<link rel="
|
|
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"
|
|
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":"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"}
|
package/dist/studio/studio.js
CHANGED
|
@@ -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
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
757
|
-
|
|
758
|
-
|
|
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",
|
|
844
|
-
const
|
|
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;
|