diff --git a/index.html b/index.html index a3d09f6..2dc586f 100644 --- a/index.html +++ b/index.html @@ -242,12 +242,18 @@

4

+ + diff --git a/src/clicker/clicker.js b/src/clicker/clicker.js index 56f805e..6129528 100644 --- a/src/clicker/clicker.js +++ b/src/clicker/clicker.js @@ -110,7 +110,14 @@ try { ui.view("settings/code"); return; } - await auth.sync(true, updateCode); + await auth.sync(true, updateCode) + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ clicker.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); } init(); @@ -441,7 +448,14 @@ try { text: `Use ${input}`, class: 'submit-button', onclick: async () => { - if (storage.get("code") !== input) await auth.clearBulkLoad(); + if (storage.get("code") !== input) await auth.clearBulkLoad() + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ clicker.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); storage.set("code", input); init(); // Close all modals @@ -458,7 +472,14 @@ try { } else { // Close all modals ui.view(""); - if (storage.get("code") !== input) await auth.clearBulkLoad(); + if (storage.get("code") !== input) await auth.clearBulkLoad() + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ clicker.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); storage.set("code", input); init(); // Update URL parameters with seat code @@ -570,7 +591,14 @@ try { ]); } // Render Theme Store - themes.renderStore(); + themes.renderStore() + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ clicker.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); } // Show multiple choice card diff --git a/src/design.css b/src/design.css index 6eba639..f1ab91e 100644 --- a/src/design.css +++ b/src/design.css @@ -45,7 +45,7 @@ body { min-height: 100%; - padding: 50px 7.5% 25px 7.5%; + padding: 50px 7.5% 125px 7.5%; color: var(--text-color); background-color: var(--background-color); font: @@ -66,6 +66,10 @@ body.enable-transitions { --easing: cubic-bezier(0.32, 0, 0.67, 0); } +body:has(#header) > *:not([id]):not(dialog) { + position: fixed; +} + h1 { font-size: 1.75rem; } diff --git a/src/layout.css b/src/layout.css index f5059f8..afa8aef 100644 --- a/src/layout.css +++ b/src/layout.css @@ -229,6 +229,34 @@ div.spacer { align-self: center; position: fixed; bottom: 25px; + padding-left: 5px; + transition: 0.5s; +} + +#controls-container:hover { + border-radius: 0 100vh 100vh 0; + transition: 0.5s; +} + +#controls-container::before { + content: attr(checks); + position: absolute; + bottom: 0; + right: 75%; + height: 100%; + width: fit-content; + background-color: var(--surface-color); + color: var(--accent-text-color); + padding: 7.5px 12.5px 7.5px 17.5px; + border-radius: 50vh 0 0 50vh; + z-index: -1; + transition: 0.5s; +} + +#controls-container:hover::before { + right: 100%; + background-color: var(--accent-color); + transition: 0.5s; } #symbols-grid { @@ -281,6 +309,10 @@ div.spacer { margin-top: 10px; } +dialog:has(.history-feed) > button { + margin-top: 5px; +} + #history-feed { overflow-y: auto; height: 400px; diff --git a/src/main.js b/src/main.js index b810ce4..7c5847f 100644 --- a/src/main.js +++ b/src/main.js @@ -55,6 +55,10 @@ try { storage.set("developer", true); updateVersionString(true); } + + window.onerror = function (error, url, line) { + ui.reportBugModal(null, `${String(error)} at ${url} line ${line}`); + } } catch (error) { if (storage.get("developer")) { alert(`Error @ main.js: ${error.message}`); diff --git a/src/modules/auth.js b/src/modules/auth.js index b761964..c16fe6d 100644 --- a/src/modules/auth.js +++ b/src/modules/auth.js @@ -183,7 +183,14 @@ export async function sync(hideWelcome = true, returnFunction = null) { Object.entries(r.settings).forEach(([key, value]) => { if (key !== "password" && key !== "code" && key !== "usr" && key !== "pwd" && key !== "history" && key !== "questionsAnswered" && key !== "developer" && key !== "cache" && key !== "lastBulkLoad" && key !== "adminCache" && key !== "lastAdminBulkLoad") storage.set(key, value); }); - await themes.syncTheme(); + await themes.syncTheme() + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ auth.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); if (document.getElementById('clicker')) document.getElementById('clicker').classList = r.settings['layout'] || ''; } window.location.reload(); @@ -591,7 +598,14 @@ export async function bulkLoad(fields = [], usr = null, pwd = null, isAdmin = fa } if (fields.includes('courses') ? (!(await storage.idbGet((isAdmin || isTA) ? "adminCache" : "cache") || {})?.['courses']?.length && !fetchedBulkLoad?.courses?.length) : false) { console.log('🔴 Bulk load out of sync, reloading'); - await clearBulkLoad(); + await clearBulkLoad() + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ auth.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); location.reload(); return false; } diff --git a/src/modules/ui.css b/src/modules/ui.css index 3928cd5..75875dd 100644 --- a/src/modules/ui.css +++ b/src/modules/ui.css @@ -623,19 +623,6 @@ body:has(.topbar) { margin-left: -20px; } -#controls-container .pill::before { - content: attr(checks); - position: absolute; - bottom: 100%; - left: 50%; - transform: translateX(-50%); - min-width: 100%; - background: var(--accent-color); - color: var(--accent-text-color); - padding: 7.5px 17.5px 2.5px 17.5px; - border-radius: 50vh 50vh 0 0; -} - [data-manual-reset-cache] { margin-top: 10px; } diff --git a/src/themes/themes.js b/src/themes/themes.js index 7c94c27..fd84709 100644 --- a/src/themes/themes.js +++ b/src/themes/themes.js @@ -193,13 +193,27 @@ export async function renderStore() { await storage.idbReady; var initialTheme = storage.get("theme") || "default"; var checks = (await storage.idbGet("cache"))?.checksCount || 0; - document.querySelector('#controls-container .pill')?.setAttribute('checks', checks); + document.getElementById("controls-container")?.setAttribute('checks', checks); var ownedThemes = (await storage.idbGet("cache"))?.ownedThemes || []; if (document.body.getAttribute('data-theme') && !ownedThemes.includes(document.body.getAttribute('data-theme')) && themes.find(theme => theme[0] === document.body.getAttribute('data-theme'))?.[3]) { resetTheme(); ui.toast("Applied theme is not owned.", 2000, "error", "bi bi-exclamation-triangle-fill"); - await auth.syncPush("theme"); - renderStore(); + await auth.syncPush("theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); + renderStore() + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); return; } var featuredTheme = themes.filter(t => t[3] && (t[0] !== document.body.getAttribute('data-theme')))[Math.floor(Math.random() * themes.filter(t => t[3] && (t[0] !== document.body.getAttribute('data-theme'))).length)]; @@ -244,7 +258,14 @@ export async function renderStore() { Array.from(store.querySelectorAll('.theme-item button')).forEach(btn => { btn.textContent = btn.parentElement.classList.contains('selected') ? "Applied" : (ownedThemes.includes(btn.parentElement.getAttribute('data-theme')) ? "Owned" : "Preview"); }); - await auth.syncPush("theme"); + await auth.syncPush("theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); ui.toast(`Applied ${featuredTheme[1] || featuredTheme[0]} theme.`, 2000, "success", "bi bi-check2-circle"); } else { if (featuredTheme[4] && featuredTheme[4].length && !featuredTheme[4].some(t => ownedThemes.includes(t))) { @@ -270,7 +291,14 @@ export async function renderStore() { icon: 'bi-bag-check-fill', class: 'submit-button', onclick: async () => { - await auth.buyTheme(featuredTheme[0], featuredTheme[3]); + await auth.buyTheme(featuredTheme[0], featuredTheme[3]) + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); ownedThemes.push(featuredTheme[0]); const cache = await storage.idbGet("cache") || {}; cache.ownedThemes = ownedThemes; @@ -283,7 +311,14 @@ export async function renderStore() { checksText.innerHTML = ` You've got ${cache.checksCount} Check${(cache.checksCount == 1) ? '' : 's'} available to spend!`; storage.set("theme", featuredTheme[0]); document.body.setAttribute('data-theme', featuredTheme[0]); - await auth.syncPush("theme"); + await auth.syncPush("theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); ui.toast(`Purchased and applied ${featuredTheme[1] || featuredTheme[0]} theme.`, 2000, "success", "bi bi-bag-check-fill"); }, close: true, @@ -346,7 +381,14 @@ export async function renderStore() { Array.from(store.querySelectorAll('.theme-item button')).forEach(btn => { btn.textContent = btn.parentElement.classList.contains('selected') ? "Applied" : (ownedThemes.includes(btn.parentElement.getAttribute('data-theme')) ? "Owned" : "Preview"); }); - await auth.syncPush("theme"); + await auth.syncPush("theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); ui.toast(`Applied ${name} theme.`, 2000, "success", "bi bi-check2-circle"); } else { if (theme[4] && theme[4].length && !theme[4].some(t => ownedThemes.includes(t))) { @@ -372,7 +414,14 @@ export async function renderStore() { icon: 'bi-bag-check-fill', class: 'submit-button', onclick: async () => { - await auth.buyTheme(theme[0], theme[3]); + await auth.buyTheme(theme[0], theme[3]) + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); ownedThemes.push(theme[0]); const cache = await storage.idbGet("cache") || {}; cache.ownedThemes = ownedThemes; @@ -385,7 +434,14 @@ export async function renderStore() { checksText.innerHTML = ` You've got ${cache.checksCount} Check${(cache.checksCount == 1) ? '' : 's'} available to spend!`; storage.set("theme", theme[0]); document.body.setAttribute('data-theme', theme[0]); - await auth.syncPush("theme"); + await auth.syncPush("theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); ui.toast(`Purchased and applied ${name} theme.`, 2000, "success", "bi bi-bag-check-fill"); }, close: true, @@ -461,8 +517,22 @@ try { storage.set("theme", value); // Update developer theme input if (document.getElementById("theme-debug")) document.getElementById("theme-debug").value = value; - await auth.syncPush("theme"); - await auth.syncPush("custom-theme"); + await auth.syncPush("theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); + await auth.syncPush("custom-theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); }); document.getElementById("theme-reset")?.addEventListener("click", resetTheme); @@ -477,8 +547,22 @@ try { storage.set("custom-theme", customTheme); storage.set("theme", "custom"); applyCustomTheme(); - await auth.syncPush("custom-theme"); - await auth.syncPush("theme"); + await auth.syncPush("custom-theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); + await auth.syncPush("theme") + .catch(error => { + if (storage.get("developer")) { + alert(`Error @ themes.js: ${error.message}`); + } else { + ui.reportBugModal(null, String(error.stack)); + } + }); }); document.getElementById("editor-reset")?.addEventListener("click", () => {