diff --git a/src/@types/index.d.ts b/src/@types/index.d.ts index b38ae89..1bbc083 100644 --- a/src/@types/index.d.ts +++ b/src/@types/index.d.ts @@ -30,6 +30,7 @@ export interface SlidesExtendedSettings { paneMode: "split" | "tab" | "sidebar"; themeDirectory: string; center: boolean; + preamblePath: string; } export type ChartJsOptions = { @@ -67,6 +68,7 @@ export type Options = { width: number; enableCustomControls: boolean; transition: string; + preamble: string; // biome-ignore lint/suspicious/noExplicitAny: minimal adaptation to Chart.js types [key: string]: any; }; diff --git a/src/obsidian/obsidianUtils.ts b/src/obsidian/obsidianUtils.ts index 55d71c2..d1e69ea 100644 --- a/src/obsidian/obsidianUtils.ts +++ b/src/obsidian/obsidianUtils.ts @@ -186,6 +186,23 @@ export class ObsidianUtils implements MediaCollector { return this.settings; } + async getPreamble(): Promise { + if (!this.settings.preamblePath) { + return ""; + } + try { + const preamble = await this.app.vault.adapter.read( + this.settings.preamblePath, + ); + return preamble; + } catch (_e) { + console.warn( + `Slides Extended: Preamble file not found at '${this.settings.preamblePath}'. Ignoring.`, + ); + return ""; + } + } + private getTFile(filename: string): TFile | null { if (filename.startsWith("[[") && filename.endsWith("]]")) { filename = filename.substring(2, filename.length - 2).trim(); @@ -243,6 +260,10 @@ export class ObsidianUtils implements MediaCollector { return file; } + getExportDirectory(override?: string): string { + return override ?? this.exportDir; + } + getAbsolutePath(relativePath: string): string { const markdownFile = this.getTFile(relativePath); return this.absolute(markdownFile?.path); diff --git a/src/plugin/load-mathjax.js b/src/plugin/load-mathjax.js index 5ca94dd..43484fe 100644 --- a/src/plugin/load-mathjax.js +++ b/src/plugin/load-mathjax.js @@ -29,8 +29,37 @@ window.MathJax = { }, startup: { ready: () => { + const preamblePath = window.mathJaxPreamblePath; + const preamblePromise = + preamblePath && + preamblePath.trim().length > 0 && + preamblePath.trim() !== "undefined" + ? fetch(preamblePath) + .then((response) => { + if (!response.ok) { + throw new Error( + `Failed to load preamble file: ${response.statusText}`, + ); + } + return response.text(); + }) + .catch((err) => { + console.error( + `Slides Extended: Could not load preamble file at '${preamblePath}'.`, + err, + ); + return ""; // Resolve with empty string on failure + }) + : Promise.resolve(""); + MathJax.startup.defaultReady(); - MathJax.startup.promise.then(() => { + MathJax.startup.promise.then(async () => { + const preamble = await preamblePromise; + if (preamble && preamble.trim().length > 0) { + // Process the preamble. This makes definitions available globally. + MathJax.tex2chtml(preamble); + } + console.debug("MathJax initialized and ready"); mathJaxReady = true; diff --git a/src/slidesExtended-SettingTab.ts b/src/slidesExtended-SettingTab.ts index e2b75c7..f56933e 100644 --- a/src/slidesExtended-SettingTab.ts +++ b/src/slidesExtended-SettingTab.ts @@ -259,6 +259,22 @@ export class SlidesExtendedSettingTab extends PluginSettingTab { }); }); + containerEl.createEl("h2", { text: "MathJax" }); + + new Setting(containerEl) + .setName("Preamble path") + .setDesc( + "Path to MathJax preamble file. This file will be included in your slides. (Requires reload!)", + ) + .addText((text) => + text + .setPlaceholder("preamble.sty") + .setValue(this.newSettings.preamblePath) + .onChange((value) => { + this.newSettings.preamblePath = value; + }), + ); + containerEl.createEl("h2", { text: "Plugins" }); new Setting(containerEl) diff --git a/src/slidesExtended-constants.ts b/src/slidesExtended-constants.ts index c9e29e2..2d544cd 100644 --- a/src/slidesExtended-constants.ts +++ b/src/slidesExtended-constants.ts @@ -28,10 +28,12 @@ export const DEFAULT_SETTINGS: SlidesExtendedSettings = { paneMode: "split", themeDirectory: "", center: true, + preamblePath: "preamble.sty", }; export const DEFAULTS: Options = { bg: "", center: true, + preamble: "", css: "", defaultTemplate: "", enableCustomControls: true, diff --git a/src/template/embed.html b/src/template/embed.html index a62f8c4..f830778 100644 --- a/src/template/embed.html +++ b/src/template/embed.html @@ -19,7 +19,19 @@ {{/remoteCSSPaths}} - + {{#preamblePath}} + + {{/preamblePath}} + - + {{#preamblePath}} + + {{/preamblePath}} + - + \ No newline at end of file diff --git a/test/buildValidation.unit.test.ts b/test/buildValidation.unit.test.ts index f2575f9..9d2e307 100644 --- a/test/buildValidation.unit.test.ts +++ b/test/buildValidation.unit.test.ts @@ -30,10 +30,14 @@ describe("Build Validation", () => { for (const match of matches) { const path = match[1]; - it(`should have ${path} in build output`, () => { - const fullPath = join(BUILD_DIR, path); - expect(existsSync(fullPath)).toBe(true); - }); + // The load-mathjax.js script is now loaded dynamically with a cache-busting + // timestamp, so we can't statically verify its path. + if (!path.startsWith("plugin/load-mathjax.js")) { + it(`should have ${path} in build output`, () => { + const fullPath = join(BUILD_DIR, path); + expect(existsSync(fullPath)).toBe(true); + }); + } } }); }