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.
@@ -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.45/logged-in/">
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: auto !important;
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: 50;
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
- color: var(--menu-text, #d1d5db);
217
- background: #0a0a0a;
218
- border: 1px solid #333;
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
- background-color: #000;
229
- border-color: #fff;
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: 1.5rem;
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: 1rem; color: #c0c0c0; transition: all 0.2s;
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: 1rem; color: #c0c0c0;
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
- /* Animation Control */
402
- body.no-animations *,
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 Details & Preferences</h3>
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 mb-6">
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
- <!-- Colors generated by JS -->
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.45/logged-in/';
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
- const PAGE_DATA = {
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(PAGE_DATA).forEach(([key, page]) => {
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(PAGE_DATA).some(p => p.url === lastPage);
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(PAGE_DATA).find(p => p.url === cleanPageName || p.url.includes(lookupName));
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
- root.style.setProperty('--menu-username-text', '#000000');
2224
- root.style.setProperty('--menu-email-text', '#444444');
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
- root.style.setProperty('--glide-btn-color', 'var(--tab-text)');
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
- // Sync with global state
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 (window.isMuted) return;
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 (window.isMuted) return;
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 (window.isMuted || !window.areAnimationsEnabled) return;
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 Clicking Sequence
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') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "4sp-dv-latest",
3
- "version": "1.0.4",
3
+ "version": "1.0.7",
4
4
  "description": "The latest HTML file of the 4SP Version 5 Client.",
5
5
  "license": "ISC",
6
6
  "author": "",