schoolbox web extension :)
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(plugins/changeLogo): misc errors

willow d8100848 58c229f5

+60 -22
+51 -19
src/entrypoints/plugins/changeLogo/index.ts
··· 1 1 import { browser } from "#imports"; 2 - import { dataAttr, setDataAttr } from "@/utils"; 2 + import { dataAttr, hasChanged, injectInlineStyles, setDataAttr, uninjectInlineStyles } from "@/utils"; 3 3 import { logger } from "@/utils/logger"; 4 4 import { Plugin } from "@/utils/plugin"; 5 5 import { globalSettings } from "@/utils/storage"; 6 - import type { Toggle } from "@/utils/storage"; 6 + import type { SettingsV2, Toggle } from "@/utils/storage"; 7 7 import type { StorageState } from "@/utils/storage/state.svelte"; 8 8 import schoolbox from "/schoolbox.svg?raw"; 9 9 import { flavors } from "@catppuccin/palette"; 10 + import type { Unwatch } from "wxt/utils/storage"; 10 11 11 12 const ID = "changeLogo"; 12 - let originalFavicon: string | undefined; 13 + const PLUGIN_ID = `plugin-${ID}`; 14 + 15 + let originalFavicon: string | null = null; 16 + let unwatch: Unwatch | null = null; 17 + 13 18 export const logos = buildLogos({ 14 19 schooltape: { 15 20 name: "Schooltape", ··· 56 61 logo: { id: "schooltape-rainbow" }, 57 62 }, 58 63 async (settings) => { 59 - const resolvedLogos = await logos; 60 - const logoId = (await settings.logo.get()).id; 61 - injectLogo(resolvedLogos[logoId]); 62 - if ((await settings.setAsFavicon.get()).toggle) injectFavicon(resolvedLogos[logoId]); 64 + await inject(settings); 65 + 66 + // add watcher to reload logo 67 + unwatch = globalSettings.watch((newValue, oldValue) => { 68 + if (hasChanged(newValue, oldValue, ["themeFlavour", "themeAccent"])) { 69 + uninject(); 70 + inject(settings); 71 + } 72 + }); 63 73 }, 64 74 () => { 65 - uninjectLogo(); 66 - uninjectFavicon(); 75 + uninject(); 76 + 77 + // remove watcher 78 + if (unwatch) { 79 + unwatch(); 80 + unwatch = null; 81 + } 67 82 }, 68 83 [".logo"], 69 84 ); 70 85 86 + async function inject(settings: Settings) { 87 + const resolvedLogos = await logos; 88 + const logoId = (await settings.logo.get()).id; 89 + 90 + injectLogo(resolvedLogos[logoId]); 91 + 92 + if ((await settings.setAsFavicon.get()).toggle) { 93 + injectFavicon(resolvedLogos[logoId]); 94 + } 95 + } 96 + 97 + function uninject() { 98 + uninjectLogo(); 99 + uninjectFavicon(); 100 + } 101 + 71 102 function injectLogo(logo: LogoInfo): void { 72 103 logger.info(`injecting logo: ${logo.name}`); 73 104 74 - const style = document.createElement("style"); 75 - setDataAttr(style, "logo"); 76 - 77 - style.textContent = `a.logo > img { content: url("${logo.url}"); max-width: 30%; width: 100px; }`; 78 - document.head.appendChild(style); 105 + injectInlineStyles( 106 + `a.logo > img { content: url("${logo.url}"); max-width: 30%; width: 100px; }`, 107 + `${PLUGIN_ID}-logo`, 108 + ); 79 109 } 80 110 81 111 function uninjectLogo() { 82 112 logger.info("uninjecting logo..."); 83 - for (const el of document.querySelectorAll(dataAttr("logo"))) { 84 - el.parentElement?.removeChild(el); 85 - } 113 + 114 + uninjectInlineStyles(`${PLUGIN_ID}-logo`); 86 115 } 87 116 88 117 function injectFavicon(logo: LogoInfo) { 89 118 logger.info(`injecting favicon: ${logo.name}`); 90 119 91 120 let favicon = document.querySelector("link[rel~='icon']") as HTMLLinkElement | null; 92 - 93 121 if (!favicon) { 94 122 favicon = document.createElement("link") as HTMLLinkElement; 95 123 favicon.rel = "icon"; ··· 102 130 103 131 function uninjectFavicon() { 104 132 logger.info("uninjecting favicon..."); 133 + 105 134 const favicon = document.querySelector<HTMLLinkElement>("link[rel~='icon']"); 106 - if (favicon && originalFavicon) favicon.href = originalFavicon; 135 + if (favicon && originalFavicon) { 136 + favicon.href = originalFavicon; 137 + originalFavicon = null; 138 + } 107 139 } 108 140 109 141 async function buildLogos<T extends Record<string, ImageSource>>(logos: T): Promise<Record<keyof T, LogoInfo>> {
+1 -2
src/utils/index.ts
··· 16 16 const style = document.createElement("style"); 17 17 style.textContent = styleText; 18 18 setDataAttr(style, `inline-${id}`); 19 - document.head.append(style); 20 - // logger.info(`injected styles with id ${id}`); 19 + document.head.appendChild(style); 21 20 } 22 21 23 22 export function uninjectInlineStyles(id: string) {
+8 -1
src/utils/storage/global.ts
··· 3 3 import type * as Types from "./types"; 4 4 import type { Settings as LogoSettings } from "@/entrypoints/plugins/changeLogo"; 5 5 6 + function isSettingsV1(settings: Types.SettingsV1 | Types.SettingsV2): settings is Types.SettingsV1 { 7 + return (settings as Types.SettingsV1).themeLogoAsFavicon !== undefined; 8 + } 9 + 6 10 export const globalSettings = new StorageState( 7 11 storage.defineItem<Types.SettingsV2>("local:globalSettings", { 8 12 version: 2, ··· 18 22 userSnippets: {}, 19 23 }, 20 24 migrations: { 21 - 2: async (settings: Types.SettingsV1): Promise<Types.SettingsV2> => { 25 + 2: async (settings: Types.SettingsV1 | Types.SettingsV2 | undefined) => { 26 + if (!settings || !isSettingsV1(settings)) return; 27 + 22 28 const { themeLogo, themeLogoAsFavicon, ...rest } = settings; 23 29 24 30 // dynamic import to avoid TDZ error ··· 36 42 } 37 43 s.setAsFavicon.set({ toggle: themeLogoAsFavicon }); 38 44 } 45 + 39 46 return rest; 40 47 }, 41 48 },