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", () => {