4sp-dv 1.0.21 → 1.0.24

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,7 +6,7 @@
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.20/logged-in/">
9
+ <base href="https://cdn.jsdelivr.net/npm/4sp-dv@1.0.22/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
 
@@ -171,7 +171,8 @@
171
171
  #auth-btn, #auth-btn:hover, #auth-btn:active {
172
172
  transform: none !important;
173
173
  transition: none !important;
174
- z-index: auto !important; /* Reset z-index or keep if needed, but remove scale */
174
+ background-color: transparent !important;
175
+ z-index: auto !important;
175
176
  }
176
177
 
177
178
  /* Auth Menu & Settings */
@@ -591,7 +592,7 @@
591
592
  <div class="settings-box mb-8 p-4">
592
593
  <div class="flex items-start gap-6">
593
594
  <div class="flex flex-col items-center gap-2">
594
- <div id="pfp-preview" class="w-24 h-24 rounded-full bg-gray-700 overflow-hidden border-2 border-[#333] flex items-center justify-center text-3xl font-bold text-white relative">
595
+ <div id="pfp-preview" class="w-24 h-24 rounded-[32px] bg-gray-700 overflow-hidden border-2 border-[#333] flex items-center justify-center text-3xl font-bold text-white relative">
595
596
  </div>
596
597
  <p class="text-xs text-gray-500">Preview</p>
597
598
  </div>
@@ -603,15 +604,29 @@
603
604
  </div>
604
605
 
605
606
  <div id="pfp-letter-options" class="block">
606
- <div class="grid grid-cols-6 gap-2 mb-4 max-w-xs">
607
- </div>
608
- <button id="save-letter-pfp-btn" class="btn-toolbar-style btn-primary-override">Set Letter Avatar</button>
607
+ <label class="block text-gray-400 text-xs mb-1 font-light">Custom Text (Max 3)</label>
608
+ <div class="flex gap-4 items-center mb-4">
609
+ <input type="text" id="pfp-custom-text" maxlength="3" class="input-text-style w-24 text-center uppercase" placeholder="A">
610
+ <p class="text-xs text-gray-500">Leave empty to use username initial.</p>
611
+ </div>
612
+
613
+ <label class="block text-gray-400 text-xs mb-2 font-light">Background Color</label>
614
+ <div class="grid grid-cols-5 gap-2 mb-6" id="pfp-color-grid">
615
+ <!-- Colors generated by JS -->
616
+ </div>
617
+
618
+ <button id="save-letter-pfp-btn" class="btn-toolbar-style btn-primary-override w-full justify-center">Set Letter Avatar</button>
609
619
  </div>
610
620
 
611
621
  <div id="pfp-upload-options" class="hidden">
612
- <input type="file" id="pfp-upload-input" accept="image/*" class="block w-full text-sm text-gray-400 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-[#222] file:text-white hover:file:bg-[#333] mb-4"/>
613
- <p class="text-xs text-gray-500 mb-4">Max size 2MB. Square images work best.</p>
614
- <button id="save-upload-pfp-btn" class="btn-toolbar-style btn-primary-override">Upload & Set</button>
622
+ <input type="file" id="pfp-upload-input" accept="image/*" class="hidden"/>
623
+
624
+ <button id="trigger-upload-btn" class="btn-toolbar-style mb-4 w-full justify-center">
625
+ <i class="fa-solid fa-cloud-arrow-up mr-2"></i> Choose Image...
626
+ </button>
627
+
628
+ <p class="text-xs text-gray-500 mb-4 text-center">Max size 2MB. Square images work best.</p>
629
+ <button id="save-upload-pfp-btn" class="btn-toolbar-style btn-primary-override w-full justify-center">Upload & Set</button>
615
630
  </div>
616
631
  </div>
617
632
  </div>
@@ -759,7 +774,7 @@
759
774
  const displayUsername = document.getElementById('display-username');
760
775
  const displayEmail = document.getElementById('display-email');
761
776
 
762
- const BASE_URL = 'https://cdn.jsdelivr.net/npm/4sp-dv@1.0.20/logged-in/';
777
+ const BASE_URL = 'https://cdn.jsdelivr.net/npm/4sp-dv@1.0.22/logged-in/';
763
778
  const STORAGE_KEY = 'local_access_code';
764
779
  const USER_DATA_KEY = 'local_user_data';
765
780
  const LAST_PAGE_KEY = 'local_last_page';
@@ -785,7 +800,9 @@
785
800
  function initAdminKeybinds(db, auth, user) {
786
801
  console.log("[Admin Keybinds] Initializing for", user.uid);
787
802
  let explicitEnabled = true;
803
+ let thirdPartyEnabled = true; // Track third party state
788
804
  let lastEnablePressTime = 0;
805
+ let lastThirdPartyEnablePressTime = 0; // Separate timer for third party
789
806
  let configUnsubscribe = null;
790
807
 
791
808
  // Visual Feedback Helper
@@ -857,9 +874,14 @@
857
874
  explicitEnabled = data.explicitEnabled;
858
875
  console.log(`[Admin Keybinds] Explicit Enabled: ${explicitEnabled}`);
859
876
  }
877
+ if (data.thirdPartyEnabled !== undefined) {
878
+ thirdPartyEnabled = data.thirdPartyEnabled;
879
+ console.log(`[Admin Keybinds] Third Party Enabled: ${thirdPartyEnabled}`);
880
+ }
860
881
  } else {
861
882
  console.log("[Admin Keybinds] Config doc missing. Defaulting to TRUE.");
862
883
  explicitEnabled = true;
884
+ thirdPartyEnabled = true;
863
885
  }
864
886
  }, (error) => console.error("Config Listen Error:", error));
865
887
  }
@@ -867,7 +889,7 @@
867
889
  // Init Listener
868
890
  subscribeToConfig();
869
891
 
870
- // EXPOSE GLOBAL TRIGGER
892
+ // EXPOSE GLOBAL TRIGGERS
871
893
  window.triggerAdminKeybind = async () => {
872
894
  console.log("[Admin Keybinds] Triggered via global function.");
873
895
  if (explicitEnabled) {
@@ -901,15 +923,53 @@
901
923
  }
902
924
  }
903
925
  };
926
+
927
+ window.triggerThirdPartyKeybind = async () => {
928
+ console.log("[Admin Keybinds] Triggered Third Party toggle.");
929
+ if (thirdPartyEnabled) {
930
+ // Disable (Immediate)
931
+ try {
932
+ await setDoc(doc(db, 'config', 'soundboard'), { thirdPartyEnabled: false }, { merge: true });
933
+ showAdminToast("Third Party Sounds: HIDDEN", "red");
934
+ lastThirdPartyEnablePressTime = 0;
935
+ } catch (err) {
936
+ console.error("[Admin Keybinds] Failed to disable:", err);
937
+ showAdminToast("Error: Check Console", "red");
938
+ }
939
+ } else {
940
+ // Enable (Double Press Safety)
941
+ const now = Date.now();
942
+ if (now - lastThirdPartyEnablePressTime < 1500) {
943
+ try {
944
+ await setDoc(doc(db, 'config', 'soundboard'), { thirdPartyEnabled: true }, { merge: true });
945
+ showAdminToast("Third Party Sounds: SHOWN", "green");
946
+ lastThirdPartyEnablePressTime = 0;
947
+ } catch (err) {
948
+ console.error("[Admin Keybinds] Failed to enable:", err);
949
+ showAdminToast("Error: Check Console", "red");
950
+ }
951
+ } else {
952
+ showAdminToast("Press Ctrl+Shift+F again to SHOW", "blue");
953
+ lastThirdPartyEnablePressTime = now;
954
+ }
955
+ }
956
+ };
904
957
 
905
958
  // Key Listener (Parent Window)
906
- document.addEventListener('keydown', async (e) => {
907
- // CHANGED: Trigger is Ctrl + Shift + E as requested
959
+ window.addEventListener('keydown', async (e) => {
960
+ // Trigger is Ctrl + Shift + E
908
961
  if (e.ctrlKey && e.shiftKey && (e.key.toLowerCase() === 'e' || e.code === 'KeyE')) {
909
962
  e.preventDefault();
910
963
  window.triggerAdminKeybind();
911
964
  }
912
- });
965
+ // Trigger is Ctrl + Shift + F
966
+ if (e.ctrlKey && e.shiftKey && (e.key.toLowerCase() === 'f' || e.code === 'KeyF')) {
967
+ e.preventDefault();
968
+ e.stopImmediatePropagation();
969
+ e.stopPropagation();
970
+ window.triggerThirdPartyKeybind();
971
+ }
972
+ }, { capture: true });
913
973
  }
914
974
 
915
975
  // --- ANALYTICS LOGIC (Integrated) ---
@@ -1095,6 +1155,8 @@
1095
1155
  pfpType: data.pfpType,
1096
1156
  customPfp: data.customPfp,
1097
1157
  pfpLetterBg: data.pfpLetterBg,
1158
+ letterAvatarText: data.letterAvatarText,
1159
+ letterAvatarTextColor: data.letterAvatarTextColor, // New Field
1098
1160
  navbarTheme: data.navbarTheme // Sync theme if updated remotely
1099
1161
  };
1100
1162
 
@@ -1160,12 +1222,16 @@
1160
1222
  let pfpHtml = '';
1161
1223
 
1162
1224
  if (pfpType === 'custom' && userData.customPfp) {
1163
- pfpHtml = `<img src="${userData.customPfp}" class="w-full h-full object-cover rounded-full" alt="Profile">`;
1225
+ pfpHtml = `<img src="${userData.customPfp}" class="w-full h-full object-cover rounded-[14px]" alt="Profile">`;
1164
1226
  } else {
1165
1227
  // Letter Avatar
1166
- const letter = (userData.username || 'U').charAt(0).toUpperCase();
1228
+ const initial = (userData.username || 'U').charAt(0).toUpperCase();
1229
+ const letter = userData.letterAvatarText || initial; // Use custom text or fallback
1167
1230
  const bgColor = userData.pfpLetterBg || '#3B82F6'; // Default blue
1168
- pfpHtml = `<div class="w-full h-full rounded-full flex items-center justify-center text-white font-bold text-lg" style="background-color: ${bgColor};">${letter}</div>`;
1231
+ // Adjust font size if length > 1
1232
+ const fontSizeClass = letter.length > 2 ? 'text-xs' : (letter.length > 1 ? 'text-sm' : 'text-lg');
1233
+
1234
+ pfpHtml = `<div class="w-full h-full rounded-[14px] flex items-center justify-center text-white font-bold ${fontSizeClass}" style="background-color: ${bgColor};">${letter}</div>`;
1169
1235
  }
1170
1236
 
1171
1237
  authBtn.innerHTML = pfpHtml;
@@ -1463,6 +1529,14 @@
1463
1529
  if (window.parent.triggerAdminKeybind) window.parent.triggerAdminKeybind();
1464
1530
  }
1465
1531
 
1532
+ // Forward Admin Keybind (Ctrl + Shift + F) - Third Party Check
1533
+ if (e.ctrlKey && e.shiftKey && (e.key.toLowerCase() === 'f' || e.code === 'KeyF')) {
1534
+ e.preventDefault();
1535
+ e.stopImmediatePropagation();
1536
+ e.stopPropagation();
1537
+ if (window.parent.triggerThirdPartyKeybind) window.parent.triggerThirdPartyKeybind();
1538
+ }
1539
+
1466
1540
  // Typing Sound (Standard Inputs)
1467
1541
  const target = e.target;
1468
1542
  const isInput = target.tagName === 'INPUT' || target.tagName === 'TEXTAREA';
@@ -1474,7 +1548,7 @@
1474
1548
  if ((isInput || isContentEditable) && validKey && !e.repeat) {
1475
1549
  notifyParentTyping();
1476
1550
  }
1477
- });
1551
+ }, { capture: true });
1478
1552
 
1479
1553
  // Fallback 'input' listener for weird edge cases
1480
1554
  window.addEventListener('input', function(e) {
@@ -1609,13 +1683,19 @@
1609
1683
 
1610
1684
  // --- 2. Personalization ---
1611
1685
  // Letter Avatar Setup
1612
- const letterColors = ['EF4444', 'F97316', 'F59E0B', '84CC16', '10B981', '06B6D4', '3B82F6', '6366F1', '8B5CF6', 'EC4899', '6B7280'];
1686
+ // Removed last color (Grey) to make 10 colors (5x2 grid)
1687
+ const letterColors = ['EF4444', 'F97316', 'F59E0B', '84CC16', '10B981', '06B6D4', '3B82F6', '6366F1', '8B5CF6', 'EC4899'];
1613
1688
  const pfpModeBtns = document.querySelectorAll('.pfp-mode-btn');
1614
1689
  const pfpLetterOptions = document.getElementById('pfp-letter-options');
1615
1690
  const pfpUploadOptions = document.getElementById('pfp-upload-options');
1616
1691
  const pfpPreview = document.getElementById('pfp-preview');
1617
1692
  const saveLetterPfpBtn = document.getElementById('save-letter-pfp-btn');
1618
1693
 
1694
+ // New Inputs
1695
+ const pfpCustomText = document.getElementById('pfp-custom-text');
1696
+ const pfpCustomColor = document.getElementById('pfp-custom-color');
1697
+ const triggerUploadBtn = document.getElementById('trigger-upload-btn');
1698
+
1619
1699
  let pfpState = { mode: 'letter', letterColor: '#3B82F6' };
1620
1700
 
1621
1701
  pfpModeBtns.forEach(btn => {
@@ -1633,16 +1713,18 @@
1633
1713
  } else {
1634
1714
  pfpLetterOptions.classList.add('hidden');
1635
1715
  pfpUploadOptions.classList.remove('hidden');
1716
+ updatePfpPreview(); // Ensure preview switches if needed
1636
1717
  }
1637
1718
  });
1638
1719
  });
1639
1720
 
1640
1721
  // Render Color Grid
1641
- const gridContainer = pfpLetterOptions.querySelector('.grid');
1642
- gridContainer.innerHTML = ''; // Clear prev to avoid dups on re-run
1722
+ const gridContainer = document.getElementById('pfp-color-grid');
1723
+ gridContainer.innerHTML = '';
1724
+
1643
1725
  letterColors.forEach(color => {
1644
1726
  const div = document.createElement('div');
1645
- div.className = 'w-8 h-8 rounded-full cursor-pointer hover:scale-110 transition border-2 border-transparent';
1727
+ div.className = 'w-10 h-10 rounded-lg cursor-pointer hover:scale-110 transition border-2 border-transparent';
1646
1728
  div.style.backgroundColor = '#' + color;
1647
1729
  div.onclick = () => {
1648
1730
  pfpState.letterColor = '#' + color;
@@ -1651,25 +1733,69 @@
1651
1733
  gridContainer.appendChild(div);
1652
1734
  });
1653
1735
 
1736
+ // Listeners for new inputs
1737
+ pfpCustomText.addEventListener('input', () => updatePfpPreview());
1738
+
1739
+ // Removed old pfpCustomColor logic
1740
+
1741
+ if (triggerUploadBtn) {
1742
+ triggerUploadBtn.addEventListener('click', () => {
1743
+ document.getElementById('pfp-upload-input').click();
1744
+ });
1745
+ }
1746
+
1654
1747
  function updatePfpPreview() {
1655
1748
  if (pfpState.mode === 'letter') {
1656
- const initial = currentUser ? (currentUser.username || "U").charAt(0).toUpperCase() : "U";
1749
+ const usernameChar = currentUser ? (currentUser.username || "U").charAt(0).toUpperCase() : "U";
1750
+ // Prefer input value, fallback to saved text, fallback to username char
1751
+ let displayText = pfpCustomText.value.trim().toUpperCase();
1752
+
1753
+ if (!displayText) displayText = usernameChar;
1754
+
1657
1755
  pfpPreview.style.backgroundImage = 'none';
1658
1756
  pfpPreview.style.backgroundColor = pfpState.letterColor;
1659
- pfpPreview.innerText = initial;
1757
+ pfpPreview.style.color = '#FFFFFF';
1758
+ pfpPreview.innerText = displayText;
1759
+ // Dynamic font size
1760
+ if (displayText.length > 2) pfpPreview.style.fontSize = '1.5rem';
1761
+ else if (displayText.length > 1) pfpPreview.style.fontSize = '2rem';
1762
+ else pfpPreview.style.fontSize = '3rem';
1763
+
1764
+ } else if (pfpState.mode === 'upload') {
1765
+ // ... (Existing logic)
1766
+ if (currentUser && currentUser.customPfp && currentUser.pfpType === 'custom') {
1767
+ pfpPreview.style.backgroundImage = `url('${currentUser.customPfp}')`;
1768
+ pfpPreview.style.backgroundColor = "transparent";
1769
+ pfpPreview.style.backgroundSize = "cover";
1770
+ pfpPreview.innerText = "";
1771
+ } else {
1772
+ const initial = currentUser ? (currentUser.username || "U").charAt(0).toUpperCase() : "U";
1773
+ pfpPreview.style.backgroundImage = 'none';
1774
+ pfpPreview.style.backgroundColor = '#333';
1775
+ pfpPreview.style.color = '#FFFFFF';
1776
+ pfpPreview.innerText = initial;
1777
+ pfpPreview.style.fontSize = '3rem';
1778
+ }
1660
1779
  }
1661
1780
  }
1662
1781
 
1663
1782
  saveLetterPfpBtn.addEventListener('click', async () => {
1664
1783
  if (!currentUser) return;
1784
+
1785
+ const textVal = pfpCustomText.value.trim().toUpperCase();
1786
+ if (/[<>/\\\\]/.test(textVal)) {
1787
+ alert("Invalid characters in avatar text.");
1788
+ return;
1789
+ }
1790
+
1665
1791
  saveLetterPfpBtn.innerText = "Saving...";
1666
1792
  try {
1667
1793
  await updateDoc(doc(db, "users", currentUser.uid), {
1668
1794
  pfpType: 'letter',
1669
1795
  pfpLetterBg: pfpState.letterColor,
1670
- letterAvatarColor: pfpState.letterColor // Legacy support
1796
+ letterAvatarColor: pfpState.letterColor,
1797
+ letterAvatarText: textVal
1671
1798
  });
1672
- // Local update handled by snapshot
1673
1799
  saveLetterPfpBtn.innerText = "Saved!";
1674
1800
  setTimeout(() => saveLetterPfpBtn.innerText = "Set Letter Avatar", 2000);
1675
1801
  } catch(e) {
@@ -1944,15 +2070,23 @@
1944
2070
 
1945
2071
  // --- Logo Path Modification ---
1946
2072
  let logoSrc;
1947
- if (lightThemeNames.includes(theme.name)) {
2073
+ const isLightTheme = lightThemeNames.includes(theme.name);
2074
+
2075
+ if (isLightTheme) {
1948
2076
  logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo-dark.png';
2077
+ root.style.setProperty('--menu-username-text', '#000000');
2078
+ root.style.setProperty('--menu-email-text', '#444444');
1949
2079
  } else if (theme.name === 'Christmas') {
1950
2080
  logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo-christmas.png';
2081
+ root.style.setProperty('--menu-username-text', 'white');
2082
+ root.style.setProperty('--menu-email-text', '#9ca3af');
1951
2083
  } else {
1952
2084
  logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-asset-library@latest/logo.png';
2085
+ root.style.setProperty('--menu-username-text', 'white');
2086
+ root.style.setProperty('--menu-email-text', '#9ca3af');
1953
2087
  }
1954
2088
 
1955
- // Apply CSS Variables
2089
+ // Apply CSS Variables from theme object (overrides defaults if present)
1956
2090
  for (const [key, value] of Object.entries(theme)) {
1957
2091
  if (key !== 'logo-src' && key !== 'name') {
1958
2092
  root.style.setProperty(`--${key}`, value);
@@ -2211,11 +2345,34 @@
2211
2345
  function loadSettingsData() {
2212
2346
  if (currentUser) {
2213
2347
  settingsUsernameInput.value = currentUser.username || "";
2348
+
2349
+ // PFP State Init
2214
2350
  pfpState.letterColor = currentUser.pfpLetterBg || '#3B82F6';
2351
+ pfpState.mode = currentUser.pfpType === 'custom' ? 'upload' : 'letter';
2352
+
2353
+ // Populate Inputs
2354
+ pfpCustomText.value = currentUser.letterAvatarText || "";
2355
+
2356
+ // Update UI Buttons to reflect current mode
2357
+ pfpModeBtns.forEach(btn => {
2358
+ if (btn.dataset.mode === pfpState.mode) {
2359
+ btn.classList.add('active', 'bg-[#222]');
2360
+ if (pfpState.mode === 'letter') {
2361
+ pfpLetterOptions.classList.remove('hidden');
2362
+ pfpUploadOptions.classList.add('hidden');
2363
+ } else {
2364
+ pfpLetterOptions.classList.add('hidden');
2365
+ pfpUploadOptions.classList.remove('hidden');
2366
+ }
2367
+ } else {
2368
+ btn.classList.remove('active', 'bg-[#222]');
2369
+ }
2370
+ });
2371
+
2215
2372
  updatePfpPreview();
2216
2373
  }
2217
2374
  loadThemes();
2218
- loadPanicKeys(); // Refresh inputs when settings open
2375
+ loadPanicKeys();
2219
2376
  }
2220
2377
 
2221
2378
  checkAutoLogin();
@@ -274,10 +274,6 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
274
274
 
275
275
  </head>
276
276
  <body class="min-h-screen">
277
-
278
- <div id="loading-screen" class="fixed inset-0 bg-[#040404] flex items-center justify-center z-50">
279
- <i class="fa-solid fa-spinner fa-spin fa-2x text-white"></i>
280
- </div>
281
277
 
282
278
  <div id="page-content" class="hidden">
283
279
 
@@ -298,12 +294,14 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
298
294
  />
299
295
  <i class="fa-solid fa-magnifying-glass absolute left-5 top-1/2 transform -translate-y-1/2 text-gray-500"></i>
300
296
 
301
- <button
302
- id="search-button"
303
- class="btn-toolbar-style btn-primary-override absolute right-2 top-1/2 transform -translate-y-1/2 h-10 px-4"
304
- title="Search">
305
- <i class="fa-solid fa-arrow-right"></i>
306
- </button>
297
+ <div class="absolute right-2 top-1/2 transform -translate-y-1/2">
298
+ <button
299
+ id="search-button"
300
+ class="btn-toolbar-style btn-primary-override h-10 px-4"
301
+ title="Search">
302
+ <i class="fa-solid fa-arrow-right"></i>
303
+ </button>
304
+ </div>
307
305
  </div>
308
306
 
309
307
  <div id="definition-output" class="dictionary-content-box">
@@ -322,6 +320,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
322
320
  import { firebaseConfig } from "../firebase-config.js";
323
321
 
324
322
  // --- CONFIGURATION ---
323
+ // Hardcoded API keys as requested
325
324
  const DICT_KEY = 'e9433acb-a413-4034-b379-c04f65ba4728';
326
325
  const THES_KEY = '14361996-c9fa-4e29-ac53-bb70eb0647e7';
327
326
 
@@ -332,7 +331,6 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
332
331
 
333
332
  // --- DOM Elements ---
334
333
  const pageContent = document.getElementById('page-content');
335
- const loadingScreen = document.getElementById('loading-screen');
336
334
  const searchInput = document.getElementById('search-input');
337
335
  const searchButton = document.getElementById('search-button');
338
336
  const definitionOutput = document.getElementById('definition-output');
@@ -628,12 +626,8 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
628
626
 
629
627
  onAuthStateChanged(auth, (user) => {
630
628
  if (user || window._LOCAL_MODE) {
631
- loadingScreen.classList.add('fade-out');
632
- setTimeout(() => {
633
- loadingScreen.style.display = 'none';
634
- pageContent.classList.remove('hidden');
635
- pageContent.classList.add('fade-in');
636
- }, 500);
629
+ pageContent.classList.remove('hidden');
630
+ pageContent.classList.add('fade-in');
637
631
  } else if (!window._LOCAL_MODE) {
638
632
  window.location.href = '../index.html';
639
633
  }
@@ -686,4 +680,4 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
686
680
  </script>
687
681
 
688
682
  </body>
689
- </html>
683
+ </html>
@@ -341,7 +341,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
341
341
  <div id="explicitSoundsContainer" class="sound-grid"></div>
342
342
  </div>
343
343
 
344
- <div class="mb-10">
344
+ <div class="mb-10" id="thirdPartySectionWrapper">
345
345
  <h2 class="section-header text-blue-400/80 border-blue-900/30">Third Party Sounds</h2>
346
346
  <div id="thirdPartySoundsContainer" class="sound-grid">
347
347
  <div class="text-gray-500 italic col-span-full text-center p-10">Loading sounds from CDN...</div>
@@ -429,6 +429,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
429
429
  const explicitSoundsContainer = document.getElementById('explicitSoundsContainer');
430
430
  const thirdPartySoundsContainer = document.getElementById('thirdPartySoundsContainer');
431
431
  const explicitSectionWrapper = document.getElementById('explicitSectionWrapper');
432
+ const thirdPartySectionWrapper = document.getElementById('thirdPartySectionWrapper');
432
433
 
433
434
  // --- Soundboard Logic State ---
434
435
  let playingAudios = [];
@@ -466,14 +467,25 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
466
467
  // Optional: Ensure any "explicit" sounds stop playing if they were active?
467
468
  // For now we just hide the section as per typical admin toggle logic
468
469
  }
470
+
471
+ // Admin toggle logic for "thirdPartyEnabled". Default to true.
472
+ const isThirdPartyEnabled = data.thirdPartyEnabled !== false;
473
+
474
+ if (isThirdPartyEnabled) {
475
+ thirdPartySectionWrapper.style.display = 'block';
476
+ } else {
477
+ thirdPartySectionWrapper.style.display = 'none';
478
+ }
469
479
  } else {
470
480
  // Doc doesn't exist? Default to true.
471
481
  explicitSectionWrapper.style.display = 'block';
482
+ thirdPartySectionWrapper.style.display = 'block';
472
483
  }
473
484
  }, (error) => {
474
485
  console.warn("Config listener error:", error);
475
486
  // Fallback to visible on error
476
487
  explicitSectionWrapper.style.display = 'block';
488
+ thirdPartySectionWrapper.style.display = 'block';
477
489
  });
478
490
  }
479
491
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "4sp-dv",
3
- "version": "1.0.21",
3
+ "version": "1.0.24",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/v5-4simpleproblems/v5-4simpleproblems-dv#readme",