Ignis settings tabs

This commit is contained in:
Nystik
2026-03-28 14:52:41 +01:00
parent c8da9db20f
commit fd8bf850d2
12 changed files with 300 additions and 21 deletions

View File

@@ -1,10 +1,10 @@
{
"id": "ignis-bridge",
"name": "Ignis Bridge",
"version": "1.0.0",
"minAppVersion": "1.0.0",
"description": "Upload files from your device to the vault",
"author": "Ignis",
"version": "0.6.4",
"minAppVersion": "1.12.4",
"description": "Additional Ignis specific functionality and ignis plugin management.",
"author": "Nystik",
"authorUrl": "https://github.com/Nystik-gh/ignis",
"isDesktopOnly": false
}

View File

@@ -1,17 +1,158 @@
const { Setting } = require("obsidian");
function display(containerEl) {
containerEl.createEl("h2", { text: "Ignis General Settings" });
const GITHUB_URL = "https://github.com/Nystik-gh/ignis";
const GITHUB_API_LATEST =
"https://api.github.com/repos/Nystik-gh/ignis/releases/latest";
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);
});
});
function getVersion(app) {
try {
const manifest = app.plugins.getPlugin("ignis-bridge")?.manifest;
return manifest?.version || "unknown";
} catch {
return "unknown";
}
}
async function checkForUpdate(currentVersion) {
try {
const res = await fetch(GITHUB_API_LATEST);
if (!res.ok) {
return null;
}
const data = await res.json();
const latest = data.tag_name?.replace(/^v/, "");
if (latest && latest !== currentVersion) {
return latest;
}
return null;
} catch {
return null;
}
}
function display(containerEl, app) {
const version = getVersion(app);
const header = containerEl.createDiv("ignis-header");
const logo = header.createEl("img", {
cls: "ignis-header-logo",
attr: { src: "/assets/ignis.webp", alt: "Ignis" },
});
const info = header.createDiv("ignis-header-info");
info.createEl("div", { text: "Ignis", cls: "ignis-header-title" });
info.createEl("div", {
text: "Obsidian server bridge",
cls: "ignis-header-subtitle",
});
const right = header.createDiv("ignis-header-right");
const versionCol = right.createDiv("ignis-header-version-col");
versionCol.createEl("span", {
text: `Version ${version}`,
cls: "ignis-header-version",
});
const updateIndicator = versionCol.createEl("span", {
text: "Checking...",
cls: "ignis-update-indicator",
});
const githubLink = right.createEl("a", {
cls: "ignis-github-link",
href: GITHUB_URL,
attr: { target: "_blank", "aria-label": "GitHub" },
});
const githubIcon = githubLink.createEl("img", {
cls: "ignis-github-icon",
attr: { src: "/assets/github.svg", alt: "GitHub" },
});
checkForUpdate(version).then((latestVersion) => {
if (latestVersion) {
updateIndicator.textContent = `v${latestVersion} available`;
updateIndicator.addClass("ignis-update-available");
} else {
updateIndicator.textContent = "Up to date";
}
});
addServerStatus(containerEl);
}
function getWsStatus() {
const ws = window.__ignisWs;
if (!ws) {
return "disconnected";
}
switch (ws.readyState) {
case WebSocket.CONNECTING:
return "connecting";
case WebSocket.OPEN:
return "connected";
case WebSocket.CLOSING:
case WebSocket.CLOSED:
return "disconnected";
default:
return "disconnected";
}
}
function statusLabel(status) {
switch (status) {
case "connected":
return "Connected";
case "connecting":
return "Connecting...";
case "disconnected":
return "Disconnected";
default:
return "Unknown";
}
}
function addServerStatus(containerEl) {
const status = getWsStatus();
const setting = new Setting(containerEl).setName("Server status");
const dotEl = setting.controlEl.createEl("span", {
cls: `ignis-status-dot ignis-status-${status}`,
});
const labelEl = setting.controlEl.createEl("span", {
text: statusLabel(status),
cls: "ignis-status-label",
});
const update = () => {
const s = getWsStatus();
dotEl.className = `ignis-status-dot ignis-status-${s}`;
labelEl.textContent = statusLabel(s);
};
const pollInterval = setInterval(update, 3000);
const observer = new MutationObserver(() => {
if (!containerEl.isConnected) {
clearInterval(pollInterval);
observer.disconnect();
}
});
observer.observe(containerEl.parentElement || document.body, {
childList: true,
subtree: true,
});
}
module.exports = { display };

View File

@@ -41,30 +41,44 @@ function createTab(id, name, displayFn, app) {
return tab;
}
function injectIgnisSettings(setting, app) {
function createGroup(name) {
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";
title.textContent = name;
group.appendChild(title);
const items = document.createElement("div");
items.className = "vertical-tab-header-group-items";
group.appendChild(items);
return { group, items };
}
function injectIgnisSettings(setting, app) {
const ignis = createGroup("Ignis");
const tabs = [
createTab("ignis-general", "General", generalTab.display, app),
createTab("ignis-server-plugins", "Server Plugins", serverPluginsTab.display, app),
createTab(
"ignis-core-plugins",
"Core plugins",
serverPluginsTab.display,
app,
),
];
for (const tab of tabs) {
tab.navEl = createNavEl(tab, setting);
items.appendChild(tab.navEl);
ignis.items.appendChild(tab.navEl);
}
setting.tabHeadersEl.appendChild(group);
setting.tabHeadersEl.appendChild(ignis.group);
const corePlugins = createGroup("Ignis Core Plugins");
setting.tabHeadersEl.appendChild(corePlugins.group);
}
function patchSettingsModal(plugin) {

View File

@@ -48,7 +48,14 @@ async function activateBundledPlugin(bundledPluginId, enable, app) {
}
function display(containerEl, app) {
containerEl.createEl("h2", { text: "Server Plugins" });
containerEl.createEl("h2", { text: "Ignis Core Plugins" });
const descEl = containerEl.createEl("p", {
text:
"Ignis plugins extend server functionality and run alongside your vaults. " +
"They are separate from Obsidian's built-in plugins.",
cls: "ignis-plugins-description",
});
const loadingEl = containerEl.createEl("p", { text: "Loading plugins..." });

113
plugin/styles.css Normal file
View File

@@ -0,0 +1,113 @@
.ignis-header {
display: flex;
align-items: center;
gap: 16px;
padding: 16px 0 12px;
margin-bottom: 12px;
border-bottom: 1px solid var(--background-modifier-border);
}
.ignis-header-logo {
width: 48px;
height: 48px;
flex-shrink: 0;
}
.ignis-header-info {
flex: 1;
min-width: 0;
}
.ignis-header-title {
font-size: var(--font-ui-large);
font-weight: var(--font-semibold);
line-height: 1.2;
margin: 0;
}
.ignis-header-subtitle {
font-size: var(--font-ui-small);
color: var(--text-muted);
line-height: 1.2;
margin: 4px 0 0;
}
.ignis-header-right {
display: flex;
align-items: center;
gap: 12px;
flex-shrink: 0;
}
.ignis-header-version-col {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 2px;
}
.ignis-header-version {
font-size: var(--font-ui-small);
color: var(--text-muted);
}
.ignis-update-indicator {
font-size: var(--font-ui-smaller);
color: var(--text-faint);
}
.ignis-update-indicator.ignis-update-available {
color: var(--text-accent);
}
.ignis-github-link {
color: var(--text-muted);
display: flex;
align-items: center;
}
.ignis-github-link:hover {
color: var(--text-normal);
}
.ignis-github-link:hover .ignis-github-icon {
opacity: 1;
}
.ignis-github-icon {
width: 32px;
height: 32px;
opacity: 0.6;
}
.ignis-status-dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
}
.ignis-status-connected {
background-color: var(--color-green);
}
.ignis-status-connecting {
background-color: var(--color-yellow);
}
.ignis-status-disconnected {
background-color: var(--color-red);
}
.ignis-status-label {
font-size: var(--font-ui-small);
color: var(--text-muted);
}
.ignis-plugins-description {
padding: 0 16px;
color: var(--text-muted);
font-size: var(--font-ui-small);
margin-bottom: 16px;
}