feat: 将主题令牌接入 DOCX 动态模板

This commit is contained in:
SkyJourney
2026-07-31 08:43:26 +08:00
parent 459a079f3b
commit 6e40374200
33 changed files with 1478 additions and 56 deletions
@@ -3,6 +3,7 @@ import http from "node:http";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { createApplicationService } from "@md-to-pdf/application";
import { defaultExportConfig } from "@md-to-pdf/core";
import {
DOCX_STYLE_SLOT_NAMES,
createDocxThemeStyleCaptureScript,
@@ -120,8 +121,17 @@ try {
const tokenSets = [];
for (const theme of bundledThemes) {
console.error(`[Electron DOCX theme styles] capturing ${theme.id}`);
const themeCss = await application.getThemeCss(theme.id);
assert(themeCss !== undefined, `主题 ${theme.id} 缺少 CSS`);
const prepared = await application.prepareDocxExport({
markdown: `# ${theme.name}`,
fileName: `${theme.id}.md`,
language: "zh-CN",
exportConfig: {
...defaultExportConfig,
themeId: theme.id
}
});
const themeCss = prepared.theme.css;
const manifest = prepared.theme.manifest;
const themeFingerprint =
await createDocxThemeStyleFingerprint(theme.id, themeCss);
const request = {
@@ -150,7 +160,7 @@ try {
tokenSets.push(
resolveDocxThemeTokens({
snapshot,
config: normalizeDocxThemeMappingConfig(theme)
config: normalizeDocxThemeMappingConfig(manifest)
})
);
}
@@ -17,6 +17,7 @@ import {
import path from "node:path";
import {
DocxExportService,
DocxThemeTokenService,
MAXIMUM_MARKDOWN_LENGTH,
readDocxExportRuntimeLimits,
type ApplicationService
@@ -159,6 +160,9 @@ export class DesktopApplicationController {
const pandocRuntime = new PandocRuntime({
desktopResourcesPath: options.desktopResourcesPath
});
this.#docxMediaEngine = new ElectronDocxMediaEngine({
renderUrl: options.docxRenderUrl
});
this.#docxExportService = new DocxExportService({
application: this.#applicationService,
runtime: pandocRuntime,
@@ -169,11 +173,11 @@ export class DesktopApplicationController {
import.meta.url
)
}),
themeTokens: new DocxThemeTokenService(
this.#docxMediaEngine
),
limits: readDocxExportRuntimeLimits()
});
this.#docxMediaEngine = new ElectronDocxMediaEngine({
renderUrl: options.docxRenderUrl
});
}
async initialize() {
@@ -21,6 +21,7 @@ export interface ElectronDocxMediaEngineOptions {
export class ElectronDocxMediaEngine
implements DocxMediaCaptureAdapter, DocxThemeStyleCaptureAdapter
{
readonly themeStyleBaseUrl: string;
private readonly renderUrl: string;
private windowPromise: Promise<BrowserWindow> | undefined;
private queue = Promise.resolve();
@@ -28,6 +29,7 @@ export class ElectronDocxMediaEngine
constructor(options: ElectronDocxMediaEngineOptions) {
this.renderUrl = options.renderUrl;
this.themeStyleBaseUrl = this.renderUrl;
}
capture(