From 47cf768e26b650cc4a9c1637539b64434b7cef95 Mon Sep 17 00:00:00 2001 From: Nystik <236107-Nystik@users.noreply.gitlab.com> Date: Fri, 27 Mar 2026 19:53:19 +0100 Subject: [PATCH] refactor plugin, split into modules --- build.js | 12 + plugin/main.js | 406 ++++++++++------------ plugin/src/file-actions.js | 95 +++++ plugin/src/main.js | 34 ++ plugin/src/settings/general-tab.js | 17 + plugin/src/settings/inject.js | 86 +++++ plugin/src/settings/server-plugins-tab.js | 14 + 7 files changed, 448 insertions(+), 216 deletions(-) create mode 100644 plugin/src/file-actions.js create mode 100644 plugin/src/main.js create mode 100644 plugin/src/settings/general-tab.js create mode 100644 plugin/src/settings/inject.js create mode 100644 plugin/src/settings/server-plugins-tab.js diff --git a/build.js b/build.js index 789a4f0..290f0ad 100644 --- a/build.js +++ b/build.js @@ -31,4 +31,16 @@ Promise.all([ plugins: [sveltePlugin({ compilerOptions: { css: "injected" } })], logLevel: "info", }), + + // Build ignis-bridge plugin + esbuild.build({ + entryPoints: [path.join(__dirname, "plugin", "src", "main.js")], + bundle: true, + outfile: path.join(__dirname, "plugin", "main.js"), + format: "cjs", + platform: "browser", + target: ["chrome90"], + external: ["obsidian"], + logLevel: "info", + }), ]).catch(() => process.exit(1)); diff --git a/plugin/main.js b/plugin/main.js index bdffe75..fbc10b8 100644 --- a/plugin/main.js +++ b/plugin/main.js @@ -1,233 +1,207 @@ -const { Plugin, Setting, Notice, TFile, TFolder } = require("obsidian"); +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +// plugin/src/file-actions.js +var require_file_actions = __commonJS({ + "plugin/src/file-actions.js"(exports2, module2) { + var { Notice, TFile: TFile2, TFolder: TFolder2 } = require("obsidian"); + function getVaultId() { + return window.__currentVaultId || ""; + } + function triggerDownload(endpoint, filePath, downloadName) { + const vaultId = getVaultId(); + const url = `/api/fs/${endpoint}?vault=${encodeURIComponent(vaultId)}&path=${encodeURIComponent(filePath)}`; + const a = document.createElement("a"); + a.href = url; + a.download = downloadName; + a.click(); + } + function showFilePicker2(app, targetFolder = null) { + const input = document.createElement("input"); + input.type = "file"; + input.multiple = true; + input.style.display = "none"; + input.addEventListener("change", async () => { + const files = Array.from(input.files || []); + if (files.length === 0) + return; + const folder = targetFolder || app.vault.getRoot(); + const folderPath = folder.path; + new Notice(`Uploading ${files.length} file(s)...`); + let successCount = 0; + let errorCount = 0; + for (const file of files) { + try { + const arrayBuffer = await file.arrayBuffer(); + const targetPath = folderPath ? `${folderPath}/${file.name}` : file.name; + await app.vault.createBinary(targetPath, arrayBuffer); + successCount++; + } catch (e) { + console.error("[ignis-bridge] Upload failed:", file.name, e); + errorCount++; + } + } + if (successCount > 0) { + new Notice(`Uploaded ${successCount} file(s) successfully`); + } + if (errorCount > 0) { + new Notice(`Failed to upload ${errorCount} file(s)`, 5e3); + } + input.remove(); + }); + document.body.appendChild(input); + input.click(); + } + function addFileMenuItems2(menu, file) { + menu.addItem((item) => { + item.setTitle("Download").setIcon("download").onClick(() => triggerDownload("download", file.path, file.name)); + }); + } + function addFolderMenuItems2(menu, folder, app) { + menu.addItem((item) => { + item.setTitle("Download as ZIP").setIcon("download").onClick( + () => triggerDownload("download-zip", folder.path, `${folder.name}.zip`) + ); + }); + menu.addItem((item) => { + item.setTitle("Upload file").setIcon("upload").onClick(() => showFilePicker2(app, folder)); + }); + } + module2.exports = { showFilePicker: showFilePicker2, addFileMenuItems: addFileMenuItems2, addFolderMenuItems: addFolderMenuItems2 }; + } +}); + +// plugin/src/settings/general-tab.js +var require_general_tab = __commonJS({ + "plugin/src/settings/general-tab.js"(exports2, module2) { + var { Setting } = require("obsidian"); + function display(containerEl) { + containerEl.createEl("h2", { text: "Ignis General Settings" }); + new Setting(containerEl).setName("Example toggle").setDesc("This is a test toggle to prove the Setting API works.").addToggle((toggle) => { + toggle.setValue(false); + toggle.onChange((value) => { + console.log("[ignis] Toggle:", value); + }); + }); + } + module2.exports = { display }; + } +}); + +// plugin/src/settings/server-plugins-tab.js +var require_server_plugins_tab = __commonJS({ + "plugin/src/settings/server-plugins-tab.js"(exports2, module2) { + var { Setting } = require("obsidian"); + function display(containerEl) { + containerEl.createEl("h2", { text: "Server Plugins" }); + new Setting(containerEl).setName("Example text input").setDesc("This is a test input to prove a second tab works.").addText((text) => { + text.setPlaceholder("Type something..."); + }); + } + module2.exports = { display }; + } +}); + +// plugin/src/settings/inject.js +var require_inject = __commonJS({ + "plugin/src/settings/inject.js"(exports2, module2) { + var generalTab = require_general_tab(); + var serverPluginsTab = require_server_plugins_tab(); + function createNavEl(tab, setting) { + const nav = document.createElement("div"); + nav.className = "vertical-tab-nav-item tappable"; + const title = document.createElement("div"); + title.className = "vertical-tab-nav-item-title"; + title.textContent = tab.name; + nav.appendChild(title); + const chevron = document.createElement("div"); + chevron.className = "vertical-tab-nav-item-chevron"; + nav.appendChild(chevron); + nav.addEventListener("click", () => { + setting.openTab(tab); + }); + return nav; + } + function createTab(id, name, displayFn) { + const tab = { + id, + name, + containerEl: createDiv("vertical-tab-content"), + navEl: null, + display() { + this.containerEl.empty(); + displayFn(this.containerEl); + }, + hide() { + this.containerEl.empty(); + } + }; + return tab; + } + function injectIgnisSettings(setting) { + const group = document.createElement("div"); + group.className = "vertical-tab-header-group"; + const title = document.createElement("div"); + title.className = "vertical-tab-header-group-title"; + title.textContent = "Ignis"; + group.appendChild(title); + const items = document.createElement("div"); + items.className = "vertical-tab-header-group-items"; + group.appendChild(items); + const tabs = [ + createTab("ignis-general", "General", generalTab.display), + createTab("ignis-server-plugins", "Server Plugins", serverPluginsTab.display) + ]; + for (const tab of tabs) { + tab.navEl = createNavEl(tab, setting); + items.appendChild(tab.navEl); + } + setting.tabHeadersEl.appendChild(group); + } + function patchSettingsModal2(plugin) { + const original = plugin.app.setting.onOpen; + plugin._originalOnOpen = original; + plugin.app.setting.onOpen = function() { + original.call(this); + injectIgnisSettings(this); + }; + } + function unpatchSettingsModal2(plugin) { + if (plugin._originalOnOpen) { + plugin.app.setting.onOpen = plugin._originalOnOpen; + } + } + module2.exports = { patchSettingsModal: patchSettingsModal2, unpatchSettingsModal: unpatchSettingsModal2 }; + } +}); + +// plugin/src/main.js +var { Plugin, TFile, TFolder } = require("obsidian"); +var { showFilePicker, addFileMenuItems, addFolderMenuItems } = require_file_actions(); +var { patchSettingsModal, unpatchSettingsModal } = require_inject(); window.__obsidianAPI = require("obsidian"); - -function getVaultId() { - return window.__currentVaultId || ""; -} - -function triggerDownload(endpoint, filePath, downloadName) { - const vaultId = getVaultId(); - const url = - `/api/fs/${endpoint}` + - `?vault=${encodeURIComponent(vaultId)}` + - `&path=${encodeURIComponent(filePath)}`; - - const a = document.createElement("a"); - a.href = url; - a.download = downloadName; - a.click(); -} - -function createNavEl(tab, setting) { - const nav = document.createElement("div"); - nav.className = "vertical-tab-nav-item tappable"; - - const title = document.createElement("div"); - title.className = "vertical-tab-nav-item-title"; - title.textContent = tab.name; - nav.appendChild(title); - - const chevron = document.createElement("div"); - chevron.className = "vertical-tab-nav-item-chevron"; - nav.appendChild(chevron); - - nav.addEventListener("click", () => { - setting.openTab(tab); - }); - - return nav; -} - -function createIgnisTab(id, name, displayFn) { - const tab = { - id, - name, - containerEl: createDiv("vertical-tab-content"), - navEl: null, - - display() { - this.containerEl.empty(); - displayFn(this.containerEl); - }, - - hide() { - this.containerEl.empty(); - }, - }; - - return tab; -} - -class IgnisBridgePlugin extends Plugin { +var IgnisBridgePlugin = class extends Plugin { async onload() { console.log("[ignis-bridge] Plugin loaded"); - - this.patchSettingsModal(); - + patchSettingsModal(this); this.addRibbonIcon("upload", "Upload file", () => { - this.showFilePicker(); + showFilePicker(this.app); }); - this.registerEvent( this.app.workspace.on("file-menu", (menu, file) => { if (file instanceof TFile) { - this.addFileMenuItems(menu, file); + addFileMenuItems(menu, file); } else if (file instanceof TFolder) { - this.addFolderMenuItems(menu, file); + addFolderMenuItems(menu, file, this.app); } - }), + }) ); } - - patchSettingsModal() { - const original = this.app.setting.onOpen; - const self = this; - this._originalOnOpen = original; - - this.app.setting.onOpen = function () { - original.call(this); - self.injectIgnisSettings(this); - }; - } - - injectIgnisSettings(setting) { - const group = document.createElement("div"); - group.className = "vertical-tab-header-group"; - - const title = document.createElement("div"); - title.className = "vertical-tab-header-group-title"; - title.textContent = "Ignis"; - group.appendChild(title); - - const items = document.createElement("div"); - items.className = "vertical-tab-header-group-items"; - group.appendChild(items); - - const generalTab = createIgnisTab( - "ignis-general", - "General", - (containerEl) => { - containerEl.createEl("h2", { text: "Ignis General Settings" }); - - new Setting(containerEl) - .setName("Example toggle") - .setDesc("This is a test toggle to prove the Setting API works.") - .addToggle((toggle) => { - toggle.setValue(false); - toggle.onChange((value) => { - console.log("[ignis] Toggle:", value); - }); - }); - }, - ); - - const pluginsTab = createIgnisTab( - "ignis-server-plugins", - "Server Plugins", - (containerEl) => { - containerEl.createEl("h2", { text: "Server Plugins" }); - - new Setting(containerEl) - .setName("Example text input") - .setDesc("This is a test input to prove a second tab works.") - .addText((text) => { - text.setPlaceholder("Type something..."); - }); - }, - ); - - generalTab.navEl = createNavEl(generalTab, setting); - pluginsTab.navEl = createNavEl(pluginsTab, setting); - - items.appendChild(generalTab.navEl); - items.appendChild(pluginsTab.navEl); - - setting.tabHeadersEl.appendChild(group); - } - - addFileMenuItems(menu, file) { - menu.addItem((item) => { - item - .setTitle("Download") - .setIcon("download") - .onClick(() => triggerDownload("download", file.path, file.name)); - }); - } - - addFolderMenuItems(menu, folder) { - menu.addItem((item) => { - item - .setTitle("Download as ZIP") - .setIcon("download") - .onClick(() => - triggerDownload("download-zip", folder.path, `${folder.name}.zip`), - ); - }); - - menu.addItem((item) => { - item - .setTitle("Upload file") - .setIcon("upload") - .onClick(() => this.showFilePicker(folder)); - }); - } - - showFilePicker(targetFolder = null) { - const input = document.createElement("input"); - input.type = "file"; - input.multiple = true; - input.style.display = "none"; - - input.addEventListener("change", async () => { - const files = Array.from(input.files || []); - if (files.length === 0) return; - - const folder = targetFolder || this.app.vault.getRoot(); - const folderPath = folder.path; - - new Notice(`Uploading ${files.length} file(s)...`); - - let successCount = 0; - let errorCount = 0; - - for (const file of files) { - try { - const arrayBuffer = await file.arrayBuffer(); - const targetPath = folderPath - ? `${folderPath}/${file.name}` - : file.name; - - await this.app.vault.createBinary(targetPath, arrayBuffer); - successCount++; - } catch (e) { - console.error("[ignis-bridge] Upload failed:", file.name, e); - errorCount++; - } - } - - if (successCount > 0) { - new Notice(`Uploaded ${successCount} file(s) successfully`); - } - - if (errorCount > 0) { - new Notice(`Failed to upload ${errorCount} file(s)`, 5000); - } - - input.remove(); - }); - - document.body.appendChild(input); - input.click(); - } - onunload() { - if (this._originalOnOpen) { - this.app.setting.onOpen = this._originalOnOpen; - } - + unpatchSettingsModal(this); console.log("[ignis-bridge] Plugin unloaded"); } -} - +}; module.exports = IgnisBridgePlugin; diff --git a/plugin/src/file-actions.js b/plugin/src/file-actions.js new file mode 100644 index 0000000..7624ac3 --- /dev/null +++ b/plugin/src/file-actions.js @@ -0,0 +1,95 @@ +const { Notice, TFile, TFolder } = require("obsidian"); + +function getVaultId() { + return window.__currentVaultId || ""; +} + +function triggerDownload(endpoint, filePath, downloadName) { + const vaultId = getVaultId(); + const url = + `/api/fs/${endpoint}` + + `?vault=${encodeURIComponent(vaultId)}` + + `&path=${encodeURIComponent(filePath)}`; + + const a = document.createElement("a"); + a.href = url; + a.download = downloadName; + a.click(); +} + +function showFilePicker(app, targetFolder = null) { + const input = document.createElement("input"); + input.type = "file"; + input.multiple = true; + input.style.display = "none"; + + input.addEventListener("change", async () => { + const files = Array.from(input.files || []); + if (files.length === 0) return; + + const folder = targetFolder || app.vault.getRoot(); + const folderPath = folder.path; + + new Notice(`Uploading ${files.length} file(s)...`); + + let successCount = 0; + let errorCount = 0; + + for (const file of files) { + try { + const arrayBuffer = await file.arrayBuffer(); + const targetPath = folderPath + ? `${folderPath}/${file.name}` + : file.name; + + await app.vault.createBinary(targetPath, arrayBuffer); + successCount++; + } catch (e) { + console.error("[ignis-bridge] Upload failed:", file.name, e); + errorCount++; + } + } + + if (successCount > 0) { + new Notice(`Uploaded ${successCount} file(s) successfully`); + } + + if (errorCount > 0) { + new Notice(`Failed to upload ${errorCount} file(s)`, 5000); + } + + input.remove(); + }); + + document.body.appendChild(input); + input.click(); +} + +function addFileMenuItems(menu, file) { + menu.addItem((item) => { + item + .setTitle("Download") + .setIcon("download") + .onClick(() => triggerDownload("download", file.path, file.name)); + }); +} + +function addFolderMenuItems(menu, folder, app) { + menu.addItem((item) => { + item + .setTitle("Download as ZIP") + .setIcon("download") + .onClick(() => + triggerDownload("download-zip", folder.path, `${folder.name}.zip`), + ); + }); + + menu.addItem((item) => { + item + .setTitle("Upload file") + .setIcon("upload") + .onClick(() => showFilePicker(app, folder)); + }); +} + +module.exports = { showFilePicker, addFileMenuItems, addFolderMenuItems }; diff --git a/plugin/src/main.js b/plugin/src/main.js new file mode 100644 index 0000000..4cd1d35 --- /dev/null +++ b/plugin/src/main.js @@ -0,0 +1,34 @@ +const { Plugin, TFile, TFolder } = require("obsidian"); +const { showFilePicker, addFileMenuItems, addFolderMenuItems } = require("./file-actions"); +const { patchSettingsModal, unpatchSettingsModal } = require("./settings/inject"); + +window.__obsidianAPI = require("obsidian"); + +class IgnisBridgePlugin extends Plugin { + async onload() { + console.log("[ignis-bridge] Plugin loaded"); + + patchSettingsModal(this); + + this.addRibbonIcon("upload", "Upload file", () => { + showFilePicker(this.app); + }); + + this.registerEvent( + this.app.workspace.on("file-menu", (menu, file) => { + if (file instanceof TFile) { + addFileMenuItems(menu, file); + } else if (file instanceof TFolder) { + addFolderMenuItems(menu, file, this.app); + } + }), + ); + } + + onunload() { + unpatchSettingsModal(this); + console.log("[ignis-bridge] Plugin unloaded"); + } +} + +module.exports = IgnisBridgePlugin; diff --git a/plugin/src/settings/general-tab.js b/plugin/src/settings/general-tab.js new file mode 100644 index 0000000..9f2498d --- /dev/null +++ b/plugin/src/settings/general-tab.js @@ -0,0 +1,17 @@ +const { Setting } = require("obsidian"); + +function display(containerEl) { + containerEl.createEl("h2", { text: "Ignis General Settings" }); + + new Setting(containerEl) + .setName("Example toggle") + .setDesc("This is a test toggle to prove the Setting API works.") + .addToggle((toggle) => { + toggle.setValue(false); + toggle.onChange((value) => { + console.log("[ignis] Toggle:", value); + }); + }); +} + +module.exports = { display }; diff --git a/plugin/src/settings/inject.js b/plugin/src/settings/inject.js new file mode 100644 index 0000000..bc8f514 --- /dev/null +++ b/plugin/src/settings/inject.js @@ -0,0 +1,86 @@ +const generalTab = require("./general-tab"); +const serverPluginsTab = require("./server-plugins-tab"); + +function createNavEl(tab, setting) { + const nav = document.createElement("div"); + nav.className = "vertical-tab-nav-item tappable"; + + const title = document.createElement("div"); + title.className = "vertical-tab-nav-item-title"; + title.textContent = tab.name; + nav.appendChild(title); + + const chevron = document.createElement("div"); + chevron.className = "vertical-tab-nav-item-chevron"; + nav.appendChild(chevron); + + nav.addEventListener("click", () => { + setting.openTab(tab); + }); + + return nav; +} + +function createTab(id, name, displayFn) { + const tab = { + id, + name, + containerEl: createDiv("vertical-tab-content"), + navEl: null, + + display() { + this.containerEl.empty(); + displayFn(this.containerEl); + }, + + hide() { + this.containerEl.empty(); + }, + }; + + return tab; +} + +function injectIgnisSettings(setting) { + const group = document.createElement("div"); + group.className = "vertical-tab-header-group"; + + const title = document.createElement("div"); + title.className = "vertical-tab-header-group-title"; + title.textContent = "Ignis"; + group.appendChild(title); + + const items = document.createElement("div"); + items.className = "vertical-tab-header-group-items"; + group.appendChild(items); + + const tabs = [ + createTab("ignis-general", "General", generalTab.display), + createTab("ignis-server-plugins", "Server Plugins", serverPluginsTab.display), + ]; + + for (const tab of tabs) { + tab.navEl = createNavEl(tab, setting); + items.appendChild(tab.navEl); + } + + setting.tabHeadersEl.appendChild(group); +} + +function patchSettingsModal(plugin) { + const original = plugin.app.setting.onOpen; + plugin._originalOnOpen = original; + + plugin.app.setting.onOpen = function () { + original.call(this); + injectIgnisSettings(this); + }; +} + +function unpatchSettingsModal(plugin) { + if (plugin._originalOnOpen) { + plugin.app.setting.onOpen = plugin._originalOnOpen; + } +} + +module.exports = { patchSettingsModal, unpatchSettingsModal }; diff --git a/plugin/src/settings/server-plugins-tab.js b/plugin/src/settings/server-plugins-tab.js new file mode 100644 index 0000000..a45cb06 --- /dev/null +++ b/plugin/src/settings/server-plugins-tab.js @@ -0,0 +1,14 @@ +const { Setting } = require("obsidian"); + +function display(containerEl) { + containerEl.createEl("h2", { text: "Server Plugins" }); + + new Setting(containerEl) + .setName("Example text input") + .setDesc("This is a test input to prove a second tab works.") + .addText((text) => { + text.setPlaceholder("Type something..."); + }); +} + +module.exports = { display };