import { preferences, defaultPreferences, preferencesSchema, cache } from "@/utils/storage"; 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 }; 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 = !values[_.setting].enabled; values[_.setting].enabled = state; 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 = await 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[data.setting][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[data.setting][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); } async function getState(name: string): Promise { const state = values[name] ?? (defaultPreferences as preferencesSchema)[name]; if (!state) return null; return state.enabled; } 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"); }