type MermaidApi = typeof import("mermaid").default;

export class MermaidPreviewRenderer {
    private initialized = false;
    private mermaidModule: Promise<MermaidApi> | null = null;
    private nextDiagramId = 0;

    public render(
        language: string,
        content: string,
        applyPreview: (value: null | string | HTMLElement) => void,
    ): void | null {
        if (!this.isMermaidLanguage(language)) {
            return null;
        }

        const diagram = content.trim();
        if (!diagram) {
            applyPreview(this.createMessage("请输入 Mermaid 图表内容"));
            return;
        }

        this.nextDiagramId += 1;
        void this.renderDiagram(
            `auth-markdown-mermaid-${this.nextDiagramId}`,
            diagram,
            applyPreview,
        );
    }

    private async renderDiagram(
        diagramId: string,
        diagram: string,
        applyPreview: (value: null | string | HTMLElement) => void,
    ): Promise<void> {
        try {
            const mermaid = await this.getMermaid();
            this.ensureInitialized(mermaid);
            const { svg } = await mermaid.render(diagramId, diagram);
            applyPreview(svg);
        } catch (error: unknown) {
            applyPreview(this.createMessage(this.getErrorMessage(error)));
        }
    }

    private getMermaid(): Promise<MermaidApi> {
        this.mermaidModule ??= import("mermaid").then((module) => module.default);
        return this.mermaidModule;
    }

    private ensureInitialized(mermaid: MermaidApi): void {
        if (this.initialized) {
            return;
        }

        mermaid.initialize({
            startOnLoad: false,
            securityLevel: "strict",
            theme: "dark",
            fontFamily: "JetBrains Mono, Microsoft YaHei UI, sans-serif",
            themeVariables: {
                background: "#0f172a",
                darkMode: true,
                fontFamily: "JetBrains Mono, Microsoft YaHei UI, sans-serif",
                primaryColor: "#1e293b",
                primaryTextColor: "#f8fafc",
                primaryBorderColor: "#5eead4",
                lineColor: "#67e8f9",
                secondaryColor: "#0f766e",
                tertiaryColor: "#334155",
            },
        });
        this.initialized = true;
    }

    private isMermaidLanguage(language: string): boolean {
        const normalized = language.trim().toLowerCase();
        return normalized === "mermaid" || normalized === "mmd";
    }

    private createMessage(message: string): HTMLElement {
        const element = document.createElement("div");
        element.className = "markdown-mermaid-message";
        element.textContent = message;
        return element;
    }

    private getErrorMessage(error: unknown): string {
        if (error instanceof Error) {
            return `Mermaid 渲染失败:${error.message}`;
        }

        return "Mermaid 渲染失败,请检查图表语法";
    }
}
评论加载中...