diff --git a/components/iframe_forms/iframe-application-form.html b/components/iframe_forms/iframe-application-form.html index b580c2e2..cfe91fa9 100644 --- a/components/iframe_forms/iframe-application-form.html +++ b/components/iframe_forms/iframe-application-form.html @@ -112,16 +112,19 @@ height: 8px; } ::-webkit-scrollbar-track { - background: transparent; + background: rgba(255, 255, 255, 0.1); } ::-webkit-scrollbar-thumb { - background-color: #3b82f6; + background-color: rgba(255, 255, 255, 0.3); border-radius: 4px; } + ::-webkit-scrollbar-thumb:hover { + background-color: rgba(255, 255, 255, 0.4); + } /* Custom Scrollbar styling for Firefox */ * { scrollbar-width: thin; - scrollbar-color: #3b82f6 transparent; + scrollbar-color: rgba(255, 255, 255, 0.3) transparent; } diff --git a/components/iframe_forms/iframe-bug-fix-form.html b/components/iframe_forms/iframe-bug-fix-form.html index f8a186bf..017d7b84 100644 --- a/components/iframe_forms/iframe-bug-fix-form.html +++ b/components/iframe_forms/iframe-bug-fix-form.html @@ -112,16 +112,19 @@ height: 8px; } ::-webkit-scrollbar-track { - background: transparent; + background: rgba(255, 255, 255, 0.1); } ::-webkit-scrollbar-thumb { - background-color: #3b82f6; + background-color: rgba(255, 255, 255, 0.3); border-radius: 4px; } + ::-webkit-scrollbar-thumb:hover { + background-color: rgba(255, 255, 255, 0.4); + } /* Custom Scrollbar styling for Firefox */ * { scrollbar-width: thin; - scrollbar-color: #3b82f6 transparent; + scrollbar-color: rgba(255, 255, 255, 0.3) transparent; } diff --git a/components/iframe_forms/iframe-content-appeals-form.html b/components/iframe_forms/iframe-content-appeals-form.html index 5ae9e782..c7f94194 100644 --- a/components/iframe_forms/iframe-content-appeals-form.html +++ b/components/iframe_forms/iframe-content-appeals-form.html @@ -105,16 +105,19 @@ height: 8px; } ::-webkit-scrollbar-track { - background: transparent; + background: rgba(255, 255, 255, 0.1); } ::-webkit-scrollbar-thumb { - background-color: #3b82f6; + background-color: rgba(255, 255, 255, 0.3); border-radius: 4px; } + ::-webkit-scrollbar-thumb:hover { + background-color: rgba(255, 255, 255, 0.4); + } /* Custom Scrollbar styling for Firefox */ * { scrollbar-width: thin; - scrollbar-color: #3b82f6 transparent; + scrollbar-color: rgba(255, 255, 255, 0.3) transparent; } diff --git a/components/iframe_forms/iframe-feedback-form.html b/components/iframe_forms/iframe-feedback-form.html index ad787fc8..8bc564c9 100644 --- a/components/iframe_forms/iframe-feedback-form.html +++ b/components/iframe_forms/iframe-feedback-form.html @@ -119,16 +119,19 @@ height: 8px; } ::-webkit-scrollbar-track { - background: transparent; + background: rgba(255, 255, 255, 0.1); } ::-webkit-scrollbar-thumb { - background-color: #3b82f6; + background-color: rgba(255, 255, 255, 0.3); border-radius: 4px; } + ::-webkit-scrollbar-thumb:hover { + background-color: rgba(255, 255, 255, 0.4); + } /* Custom Scrollbar styling for Firefox */ * { scrollbar-width: thin; - scrollbar-color: #3b82f6 transparent; + scrollbar-color: rgba(255, 255, 255, 0.3) transparent; } diff --git a/components/iframe_forms/iframe-request-form.html b/components/iframe_forms/iframe-request-form.html index a706157f..23ce8ff4 100644 --- a/components/iframe_forms/iframe-request-form.html +++ b/components/iframe_forms/iframe-request-form.html @@ -112,15 +112,18 @@ height: 8px; } ::-webkit-scrollbar-track { - background: transparent; + background: rgba(255, 255, 255, 0.1); } ::-webkit-scrollbar-thumb { - background-color: #3b82f6; + background-color: rgba(255, 255, 255, 0.3); border-radius: 4px; } + ::-webkit-scrollbar-thumb:hover { + background-color: rgba(255, 255, 255, 0.4); + } * { scrollbar-width: thin; - scrollbar-color: #3b82f6 transparent; + scrollbar-color: rgba(255, 255, 255, 0.3) transparent; } diff --git a/css/style.css b/css/style.css index cde5e9ea..0c967619 100644 --- a/css/style.css +++ b/css/style.css @@ -10,6 +10,34 @@ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1); --modal-motion-duration: 160ms; + --scrollbar-width: 8px; + --scrollbar-track: rgba(255, 255, 255, 0.1); + --scrollbar-thumb: rgba(255, 255, 255, 0.3); + --scrollbar-thumb-hover: rgba(255, 255, 255, 0.4); +} + +/* Global scrollbar styling */ +* { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-thumb) transparent; +} + +*::-webkit-scrollbar { + width: var(--scrollbar-width); + height: var(--scrollbar-width); +} + +*::-webkit-scrollbar-track { + background: var(--scrollbar-track); +} + +*::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border-radius: 4px; +} + +*::-webkit-scrollbar-thumb:hover { + background: var(--scrollbar-thumb-hover); } /* Core Styles */ @@ -312,24 +340,6 @@ header img { } } -/* Custom Scrollbar */ -.video-info::-webkit-scrollbar { - width: 8px; -} - -.video-info::-webkit-scrollbar-track { - background: rgba(255, 255, 255, 0.1); -} - -.video-info::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.3); - border-radius: 4px; -} - -.video-info::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.4); -} - /* Progress Bars */ .progress-bar { width: 100%; @@ -468,24 +478,6 @@ footer a:hover { overflow-y: auto; } -/* Disclaimer Modal Scrollbar */ -#disclaimerModal .modal-scroll::-webkit-scrollbar { - width: 8px; -} - -#disclaimerModal .modal-scroll::-webkit-scrollbar-track { - background: rgba(255, 255, 255, 0.1); -} - -#disclaimerModal .modal-scroll::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.3); - border-radius: 4px; -} - -#disclaimerModal .modal-scroll::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.4); -} - /* Disclaimer Modal Button Container */ #disclaimerModal .button-container { padding: 1rem 1.5rem; diff --git a/js/app.js b/js/app.js index e7c5bb9b..c3cac2fc 100644 --- a/js/app.js +++ b/js/app.js @@ -3229,7 +3229,22 @@ class bitvidApp { // 6) NIP-07 button inside the login modal => call the extension & login const nip07Button = document.getElementById("loginNIP07"); if (nip07Button) { + const originalLabel = nip07Button.textContent; + const setLoadingState = (isLoading) => { + nip07Button.disabled = isLoading; + nip07Button.dataset.loading = isLoading ? "true" : "false"; + nip07Button.setAttribute("aria-busy", isLoading ? "true" : "false"); + nip07Button.textContent = isLoading + ? "Connecting to NIP-07 extension..." + : originalLabel; + }; + nip07Button.addEventListener("click", async () => { + if (nip07Button.dataset.loading === "true") { + return; + } + + setLoadingState(true); console.log( "[app.js] loginNIP07 clicked! Attempting extension login..." ); @@ -3245,7 +3260,13 @@ class bitvidApp { } } catch (err) { console.error("[NIP-07 login error]", err); - this.showError("Failed to login with NIP-07. Please try again."); + const message = + err && typeof err.message === "string" && err.message.trim() + ? err.message.trim() + : "Failed to login with NIP-07. Please try again."; + this.showError(message); + } finally { + setLoadingState(false); } }); } diff --git a/js/nostr.js b/js/nostr.js index 10a290a9..ecc6fb3b 100644 --- a/js/nostr.js +++ b/js/nostr.js @@ -20,6 +20,7 @@ const RELAY_URLS = [ const EVENTS_CACHE_STORAGE_KEY = "bitvid:eventsCache:v1"; const LEGACY_EVENTS_STORAGE_KEY = "bitvidEvents"; const EVENTS_CACHE_TTL_MS = 10 * 60 * 1000; // 10 minutes +const NIP07_LOGIN_TIMEOUT_MS = 15_000; // 15 seconds // To limit error spam let errorLogCount = 0; @@ -492,13 +493,57 @@ class NostrClient { */ async login() { try { - if (!window.nostr) { + const extension = window.nostr; + if (!extension) { console.log("No Nostr extension found"); throw new Error( "Please install a Nostr extension (Alby, nos2x, etc.)." ); } - const pubkey = await window.nostr.getPublicKey(); + + if (typeof extension.getPublicKey !== "function") { + throw new Error( + "This NIP-07 extension is missing getPublicKey support. Please update the extension." + ); + } + + if (typeof extension.enable === "function") { + if (isDevMode) { + console.log("Requesting permissions from NIP-07 extension..."); + } + try { + await extension.enable(); + } catch (enableErr) { + throw new Error( + enableErr && enableErr.message + ? enableErr.message + : "The NIP-07 extension denied the permission request." + ); + } + } + + let timeoutId; + const pubkey = await Promise.race([ + extension.getPublicKey(), + new Promise((_, reject) => { + timeoutId = setTimeout(() => { + reject( + new Error( + "Timed out waiting for the NIP-07 extension. Check the extension prompt and try again." + ) + ); + }, NIP07_LOGIN_TIMEOUT_MS); + }), + ]).finally(() => { + if (timeoutId) { + clearTimeout(timeoutId); + } + }); + if (!pubkey || typeof pubkey !== "string") { + throw new Error( + "The NIP-07 extension did not return a public key. Please try again." + ); + } const npub = window.NostrTools.nip19.npubEncode(pubkey); if (isDevMode) {