import { defaultPreferences, preferences, preferencesSchema, } from "@/utils/storage"; import config from "@/utils/config.json"; import data from "@/public/preferences.json"; declare global { interface Window { polyplus: Record; } } let values: preferencesSchema; let activeTag: Tags = "all"; type Tags = | "all" | "utility" | "social" | "economy" | "development" | "customization"; type SettingData = { name: string; desc: string; setting: string; notes?: Array; config?: Array<{ type: "select" | "check"; subsetting: string; label?: string; values?: Record; }>; tags: Array; }; export default defineUnlistedScript(() => { for ( const src of [ "/css/polytoria.css", "/css/preferences.css", ] ) { const css = browser.runtime.getURL(src as any); const link = document.createElement("link"); link.rel = "stylesheet"; link.href = css; document.head.appendChild(link); } console.log("Static Settings Data:", data); const saveBtn = document.getElementById("save")!; const searchInput = document.getElementById("search")! as HTMLInputElement; const allTags = [ ...new Set( //@ts-ignore: I do not want to deal with stupid type errors for working code right now data.reduce((acc: Tags[], setting: SettingData) => { if (setting.tags && Array.isArray(setting.tags)) { return acc.concat(setting.tags); } return acc; }, [] as Tags[]), ) as Set, ]; createTag("all"); for (const tag of allTags) { createTag(tag); } preferences.getPreferences() .then(async (preferenceValues) => { values = preferenceValues; window.polyplus = { preferences: preferenceValues, static: data, config: config, }; console.log("Loaded preferences: ", preferenceValues); for (const _ of data as SettingData[]) { const container = await createContainer(_); container.getElementsByClassName("toggle-btn")[0].addEventListener( "click", async () => { saveBtn.removeAttribute("disabled"); const state = getState(_.setting); if (state) { values.enabled = values.enabled.filter((item) => item !== _.setting ); } else { values.enabled.push(_.setting); } updateState(container, !state); }, ); } }); saveBtn.addEventListener("click", async () => { saveBtn.setAttribute("disabled", "true"); preferences.setValue(values); }); searchInput.addEventListener("input", () => { querySettings(searchInput.value, activeTag); }); }); async function createContainer(data: SettingData): Promise { const noteClasses = { "?": "note", "!": "warning", "-": "secondary", }; const state = getState(data.setting); const container = document.createElement("div"); container.id = data.setting; container.classList.add("setting-container"); container.classList.add(state ? "enabled" : "disabled"); container.innerHTML = `   ${data.name}

${data.desc} ${ (data.notes || []).map((note) => { const noteType = note.charAt(0) as keyof typeof noteClasses; return `* ${note.slice(1)}`; }).join("") } `; document.getElementById("settings")!.appendChild(container); if (data.config) { try { createConfig(container, data); } catch (e) {} } return container; } function createConfig(div: HTMLDivElement, data: SettingData) { for (const subsetting of data.config!) { if (subsetting.type === "select") { const select = document.createElement("select"); select.classList.add("form-select", "form-select-sm", "mb-2"); select.setAttribute("style", "width: 350px;"); for (const [key, value] of Object.entries(subsetting.values!)) { const option = document.createElement("option"); option.value = key; option.innerText = value; select.appendChild(option); } select.addEventListener("change", function () { document.getElementById("save")!.removeAttribute("disabled"); (values.config[data.setting as keyof typeof values.config] as Record< string, any >)[subsetting.subsetting] = select.options[select.selectedIndex].value; }); div.appendChild(select); } else if (subsetting.type === "check") { const check = document.createElement("span"); check.classList.add("form-check", "form-switch"); check.innerHTML = ` `; const checkbox = check.getElementsByClassName( "form-check-input", )[0] as HTMLInputElement; checkbox.checked = values[data.setting][subsetting.subsetting]; check.getElementsByClassName("form-check-input")[0].addEventListener( "change", () => { document.getElementById("save")!.removeAttribute("disabled"); (values.config[data.setting as keyof typeof values.config] as Record< string, any >)[subsetting.subsetting] = checkbox.checked; }, ); div.appendChild(check); } } } function updateState(div: HTMLDivElement, state: boolean) { const toggleBtn = div.getElementsByClassName("toggle-btn")[0]; div.classList.toggle("enabled", state); div.classList.toggle("disabled", !state); toggleBtn.classList.toggle("btn-success", !state); toggleBtn.classList.toggle("btn-danger", state); } function getState(name: string) { if (values.enabled.includes(name)) { return true; } return (defaultPreferences as preferencesSchema).enabled.includes(name); } function createTag(name: Tags) { const tag = document.createElement("div"); tag.classList.add("col-auto"); tag.style.minWidth = "150px"; tag.innerHTML = ` `; tag.children[0].addEventListener("click", function () { activeTag = name; querySettings( (document.getElementById("search")! as HTMLInputElement).value, name, ); }); document.getElementById("discovery")!.appendChild(tag); return tag; } function querySettings(query: string, tag: Tags) { console.time("querySettings"); const meetsConditions = function (data: SettingData) { let result = false; if (data.name.toLowerCase().includes(query)) result = true; if (query.length > 4 && data.desc.toLowerCase().includes(query)) { result = true; } if (!data.tags.includes(tag) && tag != "all") result = false; return result; }; let results = 0; for ( const container of Array.from(document.getElementById("settings")!.children) ) { const setting = data.find((setting) => setting.setting == container.id); const match = meetsConditions(setting as SettingData); if (match) { results++; (container as HTMLDivElement).style.display = "block"; } else { (container as HTMLDivElement).style.display = "none"; } } console.log("Found " + results + " result(s)"); console.timeEnd("querySettings"); }