4sp-dv-latest 1.0.4 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/4simpleproblems_v5_latest.html +137 -196
- package/package.json +1 -1
|
@@ -6,11 +6,14 @@
|
|
|
6
6
|
<title>4SP - VERSION 5 CLIENT</title>
|
|
7
7
|
<link rel="icon" type="image/png" href="https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo.png">
|
|
8
8
|
|
|
9
|
-
<base href="https://cdn.jsdelivr.net/npm/4sp-dv@1.0.
|
|
9
|
+
<base href="https://cdn.jsdelivr.net/npm/4sp-dv@1.0.44/logged-in/">
|
|
10
10
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap" rel="stylesheet">
|
|
12
12
|
|
|
13
13
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
|
|
14
|
+
|
|
15
|
+
<script src="https://cdn.jsdelivr.net/npm/fireworks-js@2.x/dist/index.umd.js"></script>
|
|
16
|
+
|
|
14
17
|
<style>
|
|
15
18
|
body {
|
|
16
19
|
background-color: #040404;
|
|
@@ -45,6 +48,27 @@
|
|
|
45
48
|
z-index: 60;
|
|
46
49
|
transition: background-color 0.3s ease, border-color 0.3s ease;
|
|
47
50
|
position: relative;
|
|
51
|
+
overflow: visible;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* --- FIREWORKS CONTAINER --- */
|
|
55
|
+
#fireworks-container {
|
|
56
|
+
position: absolute;
|
|
57
|
+
top: 0;
|
|
58
|
+
left: 0;
|
|
59
|
+
width: 100%;
|
|
60
|
+
height: 100%;
|
|
61
|
+
pointer-events: none; /* Let clicks pass through */
|
|
62
|
+
z-index: 1; /* Sit above background */
|
|
63
|
+
opacity: 0;
|
|
64
|
+
transition: opacity 0.5s ease;
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Ensure navbar content sits ABOVE the fireworks */
|
|
69
|
+
#navbar-container > *:not(#fireworks-container) {
|
|
70
|
+
position: relative;
|
|
71
|
+
z-index: 10;
|
|
48
72
|
}
|
|
49
73
|
|
|
50
74
|
/* --- FIXED OVERLAY LOGIC --- */
|
|
@@ -171,15 +195,15 @@
|
|
|
171
195
|
z-index: 50;
|
|
172
196
|
}
|
|
173
197
|
|
|
174
|
-
/* --- DISABLE ANIMATIONS FOR AUTH BTN --- */
|
|
175
198
|
#auth-btn, #auth-btn:hover, #auth-btn:active {
|
|
176
199
|
transform: none !important;
|
|
177
200
|
transition: none !important;
|
|
178
201
|
background-color: transparent !important;
|
|
179
|
-
z-index:
|
|
202
|
+
z-index: 65 !important;
|
|
203
|
+
cursor: pointer !important;
|
|
180
204
|
}
|
|
181
205
|
|
|
182
|
-
/* Auth Menu & Settings */
|
|
206
|
+
/* --- Auth Menu & Settings (Updated for dynamic theming) --- */
|
|
183
207
|
.auth-menu {
|
|
184
208
|
position: absolute;
|
|
185
209
|
right: 0;
|
|
@@ -192,7 +216,7 @@
|
|
|
192
216
|
display: none;
|
|
193
217
|
flex-direction: column;
|
|
194
218
|
gap: 0.5rem;
|
|
195
|
-
z-index:
|
|
219
|
+
z-index: 70;
|
|
196
220
|
box-shadow: 0 10px 30px rgba(0,0,0,0.6);
|
|
197
221
|
transform-origin: top right;
|
|
198
222
|
}
|
|
@@ -213,9 +237,10 @@
|
|
|
213
237
|
align-items: center;
|
|
214
238
|
gap: 0.75rem;
|
|
215
239
|
padding: 0.75rem 1rem;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
240
|
+
/* UPDATED: Uses variables for dynamic theme support */
|
|
241
|
+
color: var(--menu-item-text, #d1d5db);
|
|
242
|
+
background: var(--menu-item-bg, #0a0a0a);
|
|
243
|
+
border: 1px solid var(--menu-item-border, #333);
|
|
219
244
|
border-radius: 1rem;
|
|
220
245
|
text-decoration: none;
|
|
221
246
|
font-size: 0.9rem;
|
|
@@ -225,9 +250,10 @@
|
|
|
225
250
|
}
|
|
226
251
|
|
|
227
252
|
.auth-menu-item:hover {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
color: #fff;
|
|
253
|
+
/* UPDATED: Uses variables for dynamic theme support */
|
|
254
|
+
background-color: var(--menu-item-hover-bg, #000);
|
|
255
|
+
border-color: var(--menu-item-hover-border, #fff);
|
|
256
|
+
color: var(--menu-item-hover-text, #fff);
|
|
231
257
|
transform: translateY(-2px) scale(1.02);
|
|
232
258
|
box-shadow: 0 5px 15px rgba(255,255,255,0.05);
|
|
233
259
|
}
|
|
@@ -236,13 +262,6 @@
|
|
|
236
262
|
transform: translateY(0) scale(0.98);
|
|
237
263
|
}
|
|
238
264
|
|
|
239
|
-
.auth-menu-item .fa-gear, .nav-tab .fa-gear {
|
|
240
|
-
display: inline-block;
|
|
241
|
-
transform-origin: center;
|
|
242
|
-
/* Quick transition for each "click" step */
|
|
243
|
-
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
265
|
.auth-header {
|
|
247
266
|
padding: 0.5rem 1rem;
|
|
248
267
|
border-bottom: 1px solid var(--menu-divider, #333);
|
|
@@ -312,13 +331,13 @@
|
|
|
312
331
|
}
|
|
313
332
|
|
|
314
333
|
.settings-box {
|
|
315
|
-
border: 1px solid #333; border-radius:
|
|
334
|
+
border: 1px solid #333; border-radius: 1rem;
|
|
316
335
|
background-color: #000000; padding: 1.5rem; margin-bottom: 1.5rem;
|
|
317
336
|
}
|
|
318
337
|
|
|
319
338
|
.input-text-style, .input-select-style {
|
|
320
339
|
width: 100%; padding: 0.75rem; border: 1px solid #252525;
|
|
321
|
-
background-color: #111111; border-radius:
|
|
340
|
+
background-color: #111111; border-radius: 0.5rem; color: #c0c0c0; transition: all 0.2s;
|
|
322
341
|
}
|
|
323
342
|
.input-text-style:focus, .input-select-style:focus {
|
|
324
343
|
border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5);
|
|
@@ -326,24 +345,13 @@
|
|
|
326
345
|
|
|
327
346
|
.input-key-style {
|
|
328
347
|
width: 4rem; padding: 0.75rem; border: 1px solid #252525;
|
|
329
|
-
background-color: #111111; border-radius:
|
|
348
|
+
background-color: #111111; border-radius: 0.5rem; color: #c0c0c0;
|
|
330
349
|
transition: all 0.2s; font-size: 1.1rem; text-align: center;
|
|
331
350
|
font-weight: 500; text-transform: uppercase; caret-color: transparent;
|
|
332
351
|
}
|
|
333
352
|
.input-key-style:focus {
|
|
334
353
|
border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5);
|
|
335
354
|
}
|
|
336
|
-
|
|
337
|
-
/* Preference Toggles */
|
|
338
|
-
.icon-btn.off {
|
|
339
|
-
border-color: #ef4444;
|
|
340
|
-
color: #ef4444;
|
|
341
|
-
background-color: rgba(239, 68, 68, 0.05);
|
|
342
|
-
}
|
|
343
|
-
.icon-btn.off:hover {
|
|
344
|
-
background-color: rgba(239, 68, 68, 0.1);
|
|
345
|
-
border-color: #f87171;
|
|
346
|
-
}
|
|
347
355
|
.input-key-style::placeholder { font-size: 1rem; text-transform: none; }
|
|
348
356
|
|
|
349
357
|
.general-message-area { min-height: 20px; margin-top: 1rem; font-weight: 400; }
|
|
@@ -398,21 +406,8 @@
|
|
|
398
406
|
}
|
|
399
407
|
.shake-anim { animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both; }
|
|
400
408
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
body.no-animations *:hover,
|
|
404
|
-
body.no-animations *:active,
|
|
405
|
-
body.no-animations *:focus {
|
|
406
|
-
transition: none !important;
|
|
407
|
-
animation: none !important;
|
|
408
|
-
transform: none !important;
|
|
409
|
-
box-shadow: none !important;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
body.no-animations .auth-menu-item .fa-gear,
|
|
413
|
-
body.no-animations .nav-tab .fa-gear {
|
|
414
|
-
transition: none !important;
|
|
415
|
-
transform: none !important;
|
|
409
|
+
body.no-animations * {
|
|
410
|
+
transition: none !important; animation: none !important; transform: none !important;
|
|
416
411
|
}
|
|
417
412
|
|
|
418
413
|
/* Bubbly Spring Transition */
|
|
@@ -579,6 +574,8 @@
|
|
|
579
574
|
</div>
|
|
580
575
|
|
|
581
576
|
<div id="navbar-container">
|
|
577
|
+
<div id="fireworks-container"></div>
|
|
578
|
+
|
|
582
579
|
<img src="https://cdn.jsdelivr.net/npm/4sp-asset-library@latest/logo.png" id="navbar-logo" class="navbar-logo" alt="Logo">
|
|
583
580
|
|
|
584
581
|
<div class="tab-wrapper">
|
|
@@ -635,29 +632,13 @@
|
|
|
635
632
|
<h3 class="text-3xl font-bold text-white mb-6">General Settings</h3>
|
|
636
633
|
|
|
637
634
|
<div class="settings-box">
|
|
638
|
-
<h3 class="text-xl font-bold text-white mb-2">Account
|
|
639
|
-
|
|
635
|
+
<h3 class="text-xl font-bold text-white mb-2">Account Username</h3>
|
|
640
636
|
<label class="block text-gray-400 text-sm mb-2 font-light">New Username</label>
|
|
641
|
-
<div class="flex gap-2
|
|
637
|
+
<div class="flex gap-2">
|
|
642
638
|
<input type="text" id="settings-username-input" class="input-text-style" placeholder="Enter username">
|
|
643
639
|
<button id="save-username-btn" class="btn-toolbar-style btn-primary-override">Save</button>
|
|
644
640
|
</div>
|
|
645
641
|
<p id="username-msg" class="general-message-area text-sm mt-2"></p>
|
|
646
|
-
|
|
647
|
-
<div class="flex gap-8 items-center pt-4 border-t border-[#1a1a1a]">
|
|
648
|
-
<div class="flex flex-col items-center gap-2">
|
|
649
|
-
<button id="toggle-animations-btn" class="icon-btn" title="Toggle Navbar Animations">
|
|
650
|
-
<i class="fa-solid fa-wand-magic-sparkles"></i>
|
|
651
|
-
</button>
|
|
652
|
-
<span class="text-xs text-gray-500">Animations</span>
|
|
653
|
-
</div>
|
|
654
|
-
<div class="flex flex-col items-center gap-2">
|
|
655
|
-
<button id="toggle-sounds-btn" class="icon-btn" title="Toggle UI Sounds">
|
|
656
|
-
<i class="fa-solid fa-volume-high"></i>
|
|
657
|
-
</button>
|
|
658
|
-
<span class="text-xs text-gray-500">Sounds</span>
|
|
659
|
-
</div>
|
|
660
|
-
</div>
|
|
661
642
|
</div>
|
|
662
643
|
|
|
663
644
|
<h3 class="text-xl font-bold text-white mb-2 mt-6">Organization</h3>
|
|
@@ -710,8 +691,7 @@
|
|
|
710
691
|
|
|
711
692
|
<label class="block text-gray-400 text-xs mb-2 font-light">Background Color</label>
|
|
712
693
|
<div class="flex flex-wrap gap-2 mb-6" id="pfp-color-grid">
|
|
713
|
-
|
|
714
|
-
</div>
|
|
694
|
+
</div>
|
|
715
695
|
|
|
716
696
|
<button id="save-letter-pfp-btn" class="btn-toolbar-style btn-primary-override w-full justify-center">Set Letter Avatar</button>
|
|
717
697
|
</div>
|
|
@@ -732,8 +712,7 @@
|
|
|
732
712
|
|
|
733
713
|
<h3 class="text-xl font-bold text-white mb-2">Navigation Bar Theme</h3>
|
|
734
714
|
<div class="settings-box p-4">
|
|
735
|
-
<div id="theme-picker-container">
|
|
736
|
-
</div>
|
|
715
|
+
<div id="theme-picker-container"></div>
|
|
737
716
|
</div>
|
|
738
717
|
</div>
|
|
739
718
|
|
|
@@ -872,7 +851,7 @@
|
|
|
872
851
|
const displayUsername = document.getElementById('display-username');
|
|
873
852
|
const displayEmail = document.getElementById('display-email');
|
|
874
853
|
|
|
875
|
-
const BASE_URL = 'https://cdn.jsdelivr.net/npm/4sp-dv@1.0.
|
|
854
|
+
const BASE_URL = 'https://cdn.jsdelivr.net/npm/4sp-dv@1.0.44/logged-in/';
|
|
876
855
|
|
|
877
856
|
// Preload Logos
|
|
878
857
|
const preloadImgs = [
|
|
@@ -886,8 +865,10 @@
|
|
|
886
865
|
const USER_DATA_KEY = 'local_user_data';
|
|
887
866
|
const LAST_PAGE_KEY = 'local_last_page';
|
|
888
867
|
const OWNER_EMAIL = "4simpleproblems@gmail.com"; // For admin checks
|
|
868
|
+
const FIREWORKS_SETTINGS_KEY = 'fireworks_settings';
|
|
889
869
|
|
|
890
|
-
|
|
870
|
+
// RENAMED TO AVOID CONFLICTS
|
|
871
|
+
const CLIENT_PAGE_DATA = {
|
|
891
872
|
"dashboard": { "name": "Dashboard", "icon": "fa-solid fa-house-user", "url": "dashboard.html" },
|
|
892
873
|
"soundboard": { "name": "Soundboard", "icon": "fa-solid fa-volume-up", "url": "soundboard.html" },
|
|
893
874
|
"notes": { "name": "Notes", "icon": "fa-solid fa-sticky-note", "url": "notes.html" },
|
|
@@ -903,6 +884,27 @@
|
|
|
903
884
|
let currentUser = null;
|
|
904
885
|
let userDataUnsubscribe = null;
|
|
905
886
|
|
|
887
|
+
// --- FIREWORKS ENGINE INITIALIZATION ---
|
|
888
|
+
const fwContainer = document.getElementById('fireworks-container');
|
|
889
|
+
|
|
890
|
+
// HARDCODED SETTINGS AS REQUESTED
|
|
891
|
+
const fireworks = new Fireworks.default(fwContainer, {
|
|
892
|
+
autoresize: true,
|
|
893
|
+
opacity: 1.0, // Hardcoded
|
|
894
|
+
acceleration: 1.05,
|
|
895
|
+
friction: 0.97,
|
|
896
|
+
gravity: 1.5,
|
|
897
|
+
particles: 50, // Hardcoded
|
|
898
|
+
traceLength: 3,
|
|
899
|
+
traceSpeed: 10,
|
|
900
|
+
explosion: 5,
|
|
901
|
+
intensity: 5, // Hardcoded
|
|
902
|
+
flickering: 50,
|
|
903
|
+
lineStyle: 'round',
|
|
904
|
+
rocketsPoint: { min: 50, max: 50 }
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
|
|
906
908
|
// --- ADMIN KEYBINDS LOGIC (Updated to Match admin_keybinds.js exactly) ---
|
|
907
909
|
function initAdminKeybinds(db, auth, user) {
|
|
908
910
|
console.log("[Admin Keybinds] Initializing for", user.uid);
|
|
@@ -1163,7 +1165,7 @@
|
|
|
1163
1165
|
|
|
1164
1166
|
let currentPath = activePageUrl.replace(BASE_URL, '');
|
|
1165
1167
|
|
|
1166
|
-
Object.entries(
|
|
1168
|
+
Object.entries(CLIENT_PAGE_DATA).forEach(([key, page]) => {
|
|
1167
1169
|
const isAuth = page.url === currentPath;
|
|
1168
1170
|
const tab = document.createElement('a');
|
|
1169
1171
|
tab.className = `nav-tab ${isAuth ? 'active' : ''}`;
|
|
@@ -1239,7 +1241,7 @@
|
|
|
1239
1241
|
}, 50);
|
|
1240
1242
|
}
|
|
1241
1243
|
|
|
1242
|
-
// Auth Menu
|
|
1244
|
+
// Auth Menu (Wait for DOMContentLoaded equivalent in module)
|
|
1243
1245
|
if (authBtn) {
|
|
1244
1246
|
authBtn.addEventListener('click', (e) => {
|
|
1245
1247
|
e.stopPropagation();
|
|
@@ -1362,9 +1364,6 @@
|
|
|
1362
1364
|
}
|
|
1363
1365
|
|
|
1364
1366
|
authBtn.innerHTML = pfpHtml;
|
|
1365
|
-
authBtn.style.padding = '0'; // Remove padding to let avatar fill
|
|
1366
|
-
authBtn.style.overflow = 'hidden'; // Ensure roundness
|
|
1367
|
-
authBtn.style.border = '1px solid #4b5563'; // Maintain border
|
|
1368
1367
|
}
|
|
1369
1368
|
|
|
1370
1369
|
// --- Auto-Login Logic ---
|
|
@@ -1487,7 +1486,7 @@
|
|
|
1487
1486
|
|
|
1488
1487
|
// Priority: Last Page > > Default
|
|
1489
1488
|
if (lastPage) {
|
|
1490
|
-
const isValid = Object.values(
|
|
1489
|
+
const isValid = Object.values(CLIENT_PAGE_DATA).some(p => p.url === lastPage);
|
|
1491
1490
|
if (isValid) startPage = lastPage;
|
|
1492
1491
|
}
|
|
1493
1492
|
|
|
@@ -1543,7 +1542,7 @@
|
|
|
1543
1542
|
if (loader && loaderTitle && loaderBar) {
|
|
1544
1543
|
// Determine Title
|
|
1545
1544
|
let pageTitle = "Loading...";
|
|
1546
|
-
const pageEntry = Object.values(
|
|
1545
|
+
const pageEntry = Object.values(CLIENT_PAGE_DATA).find(p => p.url === cleanPageName || p.url.includes(lookupName));
|
|
1547
1546
|
if (pageEntry) pageTitle = pageEntry.name;
|
|
1548
1547
|
|
|
1549
1548
|
loaderTitle.textContent = pageTitle;
|
|
@@ -2148,8 +2147,42 @@
|
|
|
2148
2147
|
if (!res.ok) return;
|
|
2149
2148
|
let themes = await res.json();
|
|
2150
2149
|
|
|
2150
|
+
// --- INJECT CUSTOM "THE NEW YEAR" THEME & REMOVE ROYAL ---
|
|
2151
|
+
// 1. Filter out Royal
|
|
2152
|
+
themes = themes.filter(t => t.name !== 'Royal');
|
|
2153
|
+
|
|
2154
|
+
// 2. Inject The New Year (Deep Blue)
|
|
2155
|
+
const newYearTheme = {
|
|
2156
|
+
"name": "The New Year",
|
|
2157
|
+
"navbar-bg": "#020617", // Very deep blue (Slate-950)
|
|
2158
|
+
"navbar-border": "#1e293b",
|
|
2159
|
+
"navbar-text": "#e2e8f0",
|
|
2160
|
+
"tab-text": "#94a3b8",
|
|
2161
|
+
"tab-hover-text": "#ffffff",
|
|
2162
|
+
"tab-hover-bg": "rgba(255, 255, 255, 0.1)",
|
|
2163
|
+
"tab-active-text": "#fcd34d", // Gold accent for festive feel
|
|
2164
|
+
"tab-active-bg": "rgba(252, 211, 77, 0.15)",
|
|
2165
|
+
"tab-active-border": "#fcd34d",
|
|
2166
|
+
"accent-color": "#fcd34d",
|
|
2167
|
+
"logo-src": "https://cdn.jsdelivr.net/npm/4sp-asset-library@latest/logo.png",
|
|
2168
|
+
|
|
2169
|
+
// --- UPDATED: AUTH MENU SPECIFIC THEME COLORS ---
|
|
2170
|
+
"menu-bg": "#020617",
|
|
2171
|
+
"menu-border": "#fcd34d", // Gold border for menu
|
|
2172
|
+
"menu-divider": "#1e293b",
|
|
2173
|
+
"menu-username-text": "#fcd34d", // Gold Username
|
|
2174
|
+
"menu-email-text": "#94a3b8",
|
|
2175
|
+
"menu-item-bg": "#0f172a", // Dark Slate for items
|
|
2176
|
+
"menu-item-text": "#cbd5e1",
|
|
2177
|
+
"menu-item-hover-bg": "rgba(252, 211, 77, 0.1)", // Gold tint on hover
|
|
2178
|
+
"menu-item-hover-text": "#fcd34d"
|
|
2179
|
+
};
|
|
2180
|
+
|
|
2181
|
+
themes.push(newYearTheme);
|
|
2182
|
+
// --------------------------------------------------------
|
|
2183
|
+
|
|
2151
2184
|
// --- Sorting Logic from settings.js ---
|
|
2152
|
-
const orderedThemeNames = ['Dark', 'Light', 'Christmas'];
|
|
2185
|
+
const orderedThemeNames = ['Dark', 'Light', 'Christmas', 'The New Year']; // Prioritize New Year
|
|
2153
2186
|
const sortedThemes = [];
|
|
2154
2187
|
|
|
2155
2188
|
orderedThemeNames.forEach(name => {
|
|
@@ -2214,22 +2247,33 @@
|
|
|
2214
2247
|
function applyTheme(theme) {
|
|
2215
2248
|
const root = document.documentElement;
|
|
2216
2249
|
|
|
2250
|
+
// --- FIREWORKS LOGIC ---
|
|
2251
|
+
if (theme.name === 'The New Year') {
|
|
2252
|
+
document.getElementById('fireworks-container').style.opacity = '1';
|
|
2253
|
+
fireworks.start();
|
|
2254
|
+
} else {
|
|
2255
|
+
document.getElementById('fireworks-container').style.opacity = '0';
|
|
2256
|
+
fireworks.stop();
|
|
2257
|
+
}
|
|
2258
|
+
// -----------------------
|
|
2259
|
+
|
|
2217
2260
|
// --- Logo Path Modification ---
|
|
2218
2261
|
let logoSrc;
|
|
2219
2262
|
const isLightTheme = lightThemeNames.includes(theme.name);
|
|
2220
2263
|
|
|
2221
2264
|
if (isLightTheme) {
|
|
2222
2265
|
logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo-dark.png';
|
|
2223
|
-
|
|
2224
|
-
root.style.setProperty('--menu-
|
|
2266
|
+
// Default light theme variables if not specified in theme
|
|
2267
|
+
if(!theme['menu-username-text']) root.style.setProperty('--menu-username-text', '#000000');
|
|
2268
|
+
if(!theme['menu-email-text']) root.style.setProperty('--menu-email-text', '#444444');
|
|
2225
2269
|
} else if (theme.name === 'Christmas') {
|
|
2226
2270
|
logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo-christmas.png';
|
|
2227
|
-
root.style.setProperty('--menu-username-text', 'white');
|
|
2228
|
-
root.style.setProperty('--menu-email-text', '#9ca3af');
|
|
2271
|
+
if(!theme['menu-username-text']) root.style.setProperty('--menu-username-text', 'white');
|
|
2272
|
+
if(!theme['menu-email-text']) root.style.setProperty('--menu-email-text', '#9ca3af');
|
|
2229
2273
|
} else {
|
|
2230
2274
|
logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-asset-library@latest/logo.png';
|
|
2231
|
-
root.style.setProperty('--menu-username-text', 'white');
|
|
2232
|
-
root.style.setProperty('--menu-email-text', '#9ca3af');
|
|
2275
|
+
if(!theme['menu-username-text']) root.style.setProperty('--menu-username-text', 'white');
|
|
2276
|
+
if(!theme['menu-email-text']) root.style.setProperty('--menu-email-text', '#9ca3af');
|
|
2233
2277
|
}
|
|
2234
2278
|
|
|
2235
2279
|
// Apply CSS Variables from theme object (overrides defaults if present)
|
|
@@ -2278,7 +2322,8 @@
|
|
|
2278
2322
|
localStorage.setItem('user-navbar-theme', JSON.stringify(theme));
|
|
2279
2323
|
|
|
2280
2324
|
// Apply Glide Button Color Sync
|
|
2281
|
-
|
|
2325
|
+
const glideColor = theme['tab-active-text'] || theme['accent-color'] || '#ffffff';
|
|
2326
|
+
root.style.setProperty('--glide-btn-color', glideColor);
|
|
2282
2327
|
|
|
2283
2328
|
// Also update user doc if logged in
|
|
2284
2329
|
if (currentUser) {
|
|
@@ -2542,41 +2587,6 @@
|
|
|
2542
2587
|
|
|
2543
2588
|
loadThemes();
|
|
2544
2589
|
loadPanicKeys();
|
|
2545
|
-
|
|
2546
|
-
// --- App Preference Toggles Init ---
|
|
2547
|
-
const animBtn = document.getElementById('toggle-animations-btn');
|
|
2548
|
-
const soundBtn = document.getElementById('toggle-sounds-btn');
|
|
2549
|
-
|
|
2550
|
-
const updateToggleUI = () => {
|
|
2551
|
-
const isEnabled = window.areAnimationsEnabled;
|
|
2552
|
-
animBtn.classList.toggle('off', !isEnabled);
|
|
2553
|
-
animBtn.innerHTML = isEnabled ? '<i class="fa-solid fa-wand-magic-sparkles"></i>' : '<i class="fa-solid fa-wand-magic"></i>';
|
|
2554
|
-
|
|
2555
|
-
// Apply to body
|
|
2556
|
-
if (isEnabled) document.body.classList.remove('no-animations');
|
|
2557
|
-
else document.body.classList.add('no-animations');
|
|
2558
|
-
|
|
2559
|
-
soundBtn.classList.toggle('off', window.isMuted);
|
|
2560
|
-
soundBtn.innerHTML = window.isMuted ? '<i class="fa-solid fa-volume-xmark"></i>' : '<i class="fa-solid fa-volume-high"></i>';
|
|
2561
|
-
};
|
|
2562
|
-
|
|
2563
|
-
if (animBtn) {
|
|
2564
|
-
animBtn.onclick = () => {
|
|
2565
|
-
window.areAnimationsEnabled = !window.areAnimationsEnabled;
|
|
2566
|
-
localStorage.setItem('app_animations_enabled', window.areAnimationsEnabled);
|
|
2567
|
-
updateToggleUI();
|
|
2568
|
-
};
|
|
2569
|
-
}
|
|
2570
|
-
|
|
2571
|
-
if (soundBtn) {
|
|
2572
|
-
soundBtn.onclick = () => {
|
|
2573
|
-
window.isMuted = !window.isMuted;
|
|
2574
|
-
localStorage.setItem('app_is_muted', window.isMuted);
|
|
2575
|
-
updateToggleUI();
|
|
2576
|
-
};
|
|
2577
|
-
}
|
|
2578
|
-
|
|
2579
|
-
updateToggleUI();
|
|
2580
2590
|
}
|
|
2581
2591
|
|
|
2582
2592
|
checkAutoLogin();
|
|
@@ -2588,26 +2598,14 @@
|
|
|
2588
2598
|
<script>
|
|
2589
2599
|
// --- Sound & Notification Logic ---
|
|
2590
2600
|
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
Object.defineProperty(window, 'isMuted', {
|
|
2594
|
-
get: () => localStorage.getItem('app_is_muted') === 'true',
|
|
2595
|
-
set: (v) => localStorage.setItem('app_is_muted', v)
|
|
2596
|
-
});
|
|
2597
|
-
|
|
2598
|
-
Object.defineProperty(window, 'areAnimationsEnabled', {
|
|
2599
|
-
get: () => localStorage.getItem('app_animations_enabled') !== 'false',
|
|
2600
|
-
set: (v) => localStorage.setItem('app_animations_enabled', v)
|
|
2601
|
-
});
|
|
2602
|
-
|
|
2603
|
-
// Initial Class Set
|
|
2604
|
-
if (!window.areAnimationsEnabled) document.body.classList.add('no-animations');
|
|
2601
|
+
let isMuted = false;
|
|
2602
|
+
let areAnimationsEnabled = true;
|
|
2605
2603
|
|
|
2606
2604
|
// EXPOSE PlayTypeSound GLOBALLY
|
|
2607
2605
|
// Debounce to prevent rapid-fire stuttering if called too fast
|
|
2608
2606
|
let typeSoundTimeout = null;
|
|
2609
2607
|
window.playTypeSound = function() {
|
|
2610
|
-
if (
|
|
2608
|
+
if (isMuted) return;
|
|
2611
2609
|
if (audioCtx.state === 'suspended') audioCtx.resume();
|
|
2612
2610
|
|
|
2613
2611
|
// Small debounce
|
|
@@ -2648,7 +2646,7 @@
|
|
|
2648
2646
|
};
|
|
2649
2647
|
|
|
2650
2648
|
function playClickSound() {
|
|
2651
|
-
if (
|
|
2649
|
+
if (isMuted) return;
|
|
2652
2650
|
if (audioCtx.state === 'suspended') audioCtx.resume();
|
|
2653
2651
|
|
|
2654
2652
|
const osc = audioCtx.createOscillator();
|
|
@@ -2663,12 +2661,8 @@
|
|
|
2663
2661
|
osc.stop(audioCtx.currentTime + 0.015);
|
|
2664
2662
|
}
|
|
2665
2663
|
|
|
2666
|
-
// --- App Preferences State ---
|
|
2667
|
-
window.isMuted = localStorage.getItem('app_is_muted') === 'true';
|
|
2668
|
-
window.areAnimationsEnabled = localStorage.getItem('app_animations_enabled') !== 'false'; // Default true
|
|
2669
|
-
|
|
2670
2664
|
window.playMechClick = function(isReverse = false) {
|
|
2671
|
-
if (
|
|
2665
|
+
if (isMuted) return;
|
|
2672
2666
|
if (audioCtx.state === 'suspended') audioCtx.resume();
|
|
2673
2667
|
const now = audioCtx.currentTime;
|
|
2674
2668
|
|
|
@@ -2709,60 +2703,7 @@
|
|
|
2709
2703
|
osc.stop(now + 0.02);
|
|
2710
2704
|
};
|
|
2711
2705
|
|
|
2712
|
-
// Gear
|
|
2713
|
-
let gearHoverStartTime = 0;
|
|
2714
|
-
let currentGearRotation = 0;
|
|
2715
|
-
let currentAnimatingGear = null;
|
|
2716
|
-
const gearClickDelays = [0, 120, 240, 360]; // Adjusted for 0.5s total
|
|
2717
|
-
|
|
2718
|
-
const handleGearMouseOver = (e) => {
|
|
2719
|
-
const target = e.target.closest('#auth-settings-btn, #nav-settings-tab');
|
|
2720
|
-
if (target && currentAnimatingGear !== target) {
|
|
2721
|
-
currentAnimatingGear = target;
|
|
2722
|
-
const icon = target.querySelector('.fa-gear');
|
|
2723
|
-
if (!icon) return;
|
|
2724
|
-
|
|
2725
|
-
gearHoverStartTime = Date.now();
|
|
2726
|
-
gearClickDelays.forEach((delay, index) => {
|
|
2727
|
-
setTimeout(() => {
|
|
2728
|
-
if (target.matches(':hover')) {
|
|
2729
|
-
if (window.areAnimationsEnabled) {
|
|
2730
|
-
currentGearRotation = (index + 1) * 45;
|
|
2731
|
-
icon.style.transform = `rotate(${currentGearRotation}deg)`;
|
|
2732
|
-
}
|
|
2733
|
-
window.playMechClick(false);
|
|
2734
|
-
}
|
|
2735
|
-
}, delay);
|
|
2736
|
-
});
|
|
2737
|
-
}
|
|
2738
|
-
};
|
|
2739
|
-
|
|
2740
|
-
const handleGearMouseOut = (e) => {
|
|
2741
|
-
const target = e.target.closest('#auth-settings-btn, #nav-settings-tab');
|
|
2742
|
-
if (target && !target.contains(e.relatedTarget)) {
|
|
2743
|
-
currentAnimatingGear = null;
|
|
2744
|
-
const icon = target.querySelector('.fa-gear');
|
|
2745
|
-
if (!icon) return;
|
|
2746
|
-
|
|
2747
|
-
const elapsed = Date.now() - gearHoverStartTime;
|
|
2748
|
-
const clickCount = gearClickDelays.filter(d => d <= elapsed).length;
|
|
2749
|
-
|
|
2750
|
-
for (let i = 0; i < clickCount; i++) {
|
|
2751
|
-
setTimeout(() => {
|
|
2752
|
-
if (!target.matches(':hover')) {
|
|
2753
|
-
if (window.areAnimationsEnabled) {
|
|
2754
|
-
currentGearRotation -= 45;
|
|
2755
|
-
icon.style.transform = `rotate(${currentGearRotation}deg)`;
|
|
2756
|
-
}
|
|
2757
|
-
window.playMechClick(true);
|
|
2758
|
-
}
|
|
2759
|
-
}, gearClickDelays[i]);
|
|
2760
|
-
}
|
|
2761
|
-
}
|
|
2762
|
-
};
|
|
2763
|
-
|
|
2764
|
-
document.addEventListener('mouseover', handleGearMouseOver);
|
|
2765
|
-
document.addEventListener('mouseout', handleGearMouseOut);
|
|
2706
|
+
// Removed Gear Animation Logic
|
|
2766
2707
|
|
|
2767
2708
|
const notificationContainer = document.getElementById('notification-container');
|
|
2768
2709
|
function showNotification(message, iconClass = 'fa-solid fa-info-circle', type = 'info') {
|