feat: add global theme toggle

This commit is contained in:
SethBurkart123
2025-03-30 08:49:13 +11:00
parent 6147e96cc9
commit 3ecd7205ed
14 changed files with 145 additions and 141 deletions
+13 -4
View File
@@ -6,7 +6,7 @@ import browser from 'webextension-polyfill';
function createSEQTAAPI(): SEQTAAPI {
return {
onMount: (selector, callback) => {
eventManager.register(
return eventManager.register(
`${selector}Added`,
{
customCheck: (element) => element.matches(selector),
@@ -22,11 +22,20 @@ function createSEQTAAPI(): SEQTAAPI {
return path.split('/')[0];
},
onPageChange: (callback) => {
window.addEventListener('hashchange', () => {
const handler = () => {
const page = window.location.hash.split('?page=/')[1] || '';
callback(page.split('/')[0]);
});
},
};
window.addEventListener('hashchange', handler);
// Return an unregister function
return {
unregister: () => {
window.removeEventListener('hashchange', handler);
}
};
}
};
}
+69 -1
View File
@@ -1,5 +1,16 @@
import type { Plugin, PluginSettings } from './types';
import { createPluginAPI } from './createAPI';
import browser from 'webextension-polyfill';
interface PluginSettingsStorage {
enabled?: boolean;
[key: string]: any;
}
interface StorageChange<T = any> {
oldValue?: T;
newValue?: T;
}
export class PluginManager {
private static instance: PluginManager;
@@ -9,7 +20,9 @@ export class PluginManager {
private cleanupFunctions: Map<string, () => void> = new Map();
private listeners: Map<string, Set<(...args: any[]) => void>> = new Map();
private constructor() {}
private constructor() {
this.setupPluginStateListener();
}
public static getInstance(): PluginManager {
if (!PluginManager.instance) {
@@ -66,6 +79,17 @@ export class PluginManager {
try {
const api = createPluginAPI(plugin);
// Check if plugin is enabled before starting
if (plugin.disableToggle) {
const settings = await browser.storage.local.get(`plugin.${pluginId}.settings`);
const pluginSettings = settings[`plugin.${pluginId}.settings`] as PluginSettingsStorage | undefined;
const enabled = pluginSettings?.enabled ?? true;
if (!enabled) {
console.info(`Plugin "${pluginId}" is disabled, skipping initialization`);
return;
}
}
// Wait for both settings and storage to be loaded before starting the plugin
await Promise.all([
(api.settings as any).loaded,
@@ -145,9 +169,21 @@ export class PluginManager {
}];
});
if (plugin.disableToggle) {
settingsEntries.push([
'enabled', {
id: 'enabled',
title: plugin.name,
description: plugin.description,
type: 'boolean',
default: true
}
])
}
return {
pluginId: id,
name: plugin.name,
description: plugin.description,
settings: Object.fromEntries(settingsEntries)
};
});
@@ -177,4 +213,36 @@ export class PluginManager {
listeners.delete(callback);
}
}
// Add handler for plugin enable/disable state changes
private async handlePluginStateChange(pluginId: string, enabled: boolean): Promise<void> {
if (enabled) {
await this.startPlugin(pluginId);
} else {
await this.stopPlugin(pluginId);
}
}
// Add listener for plugin settings changes
private setupPluginStateListener(): void {
browser.storage.onChanged.addListener((changes: { [key: string]: StorageChange }, area: string) => {
if (area !== 'local') return;
for (const [key, change] of Object.entries(changes)) {
const match = key.match(/^plugin\.(.+)\.settings$/);
if (!match) continue;
const pluginId = match[1];
const plugin = this.plugins.get(pluginId);
if (!plugin?.disableToggle) continue;
const enabled = (change.newValue as PluginSettingsStorage)?.enabled ?? true;
const wasEnabled = (change.oldValue as PluginSettingsStorage)?.enabled ?? true;
if (enabled !== wasEnabled) {
this.handlePluginStateChange(pluginId, enabled);
}
}
});
}
}
+4 -3
View File
@@ -56,10 +56,10 @@ export type SettingsAPI<T extends PluginSettings> = {
}
export interface SEQTAAPI {
onMount: (selector: string, callback: (element: Element) => void) => void;
onMount: (selector: string, callback: (element: Element) => void) => { unregister: () => void };
getFiber: (selector: string) => ReactFiber;
getCurrentPage: () => string;
onPageChange: (callback: (page: string) => void) => void;
onPageChange: (callback: (page: string) => void) => { unregister: () => void };
}
export interface StorageAPI<T = any> {
@@ -101,5 +101,6 @@ export interface Plugin<T extends PluginSettings = PluginSettings, S = any> {
description: string;
version: string;
settings: T;
run: (api: PluginAPI<T, S>) => void | Promise<void> | (() => void) | Promise<() => void>;
disableToggle?: boolean; // Optional flag to show/hide the plugin's enable/disable toggle in settings
run: (api: PluginAPI<T, S>) => void | Promise<void> | (() => void) | Promise<(() => void)>;
}