word-waltz / commit
added notification button
cspell.json | 2 ++ src/index.html | 2 ++ src/main.ts | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/styles/main.css | 25 +++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/cspell.json b/cspell.json index f2f9255..71a9877 100644 --- a/cspell.json +++ b/cspell.json @@ -3,6 +3,8 @@ "version": "0.2", "language": "en", "words": [ + "notif", + "Notif", "ASDFGHJKL", "ciphertext", "ENTERZCVBNM", diff --git a/src/index.html b/src/index.html index c02748b..df57278 100644 --- a/src/index.html +++ b/src/index.html @@ -19,6 +19,8 @@ <span class="header__title">Word Waltz</span> </a> <nav class="header__links"> + <button id="notif-btn" class="header__notif-btn" type="button" aria-label="Notification settings" + title="Enable notifications">๐</button> <a href="https://www.flaticon.com/search?author_id=296&style_id=1001&type=standard" target="_blank" rel="noopener" title="Icons by Freepik on Flaticon">Icons</a> <a href="https://gitlab.com/PavelSafronov/word-waltz" target="_blank" rel="noopener" diff --git a/src/main.ts b/src/main.ts index c99d796..4087c2b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -794,3 +794,73 @@ bootstrap().catch((err: unknown) => { if (app) showError(app, 'Something went wrong loading the game. Please refresh.'); }); +// --------------------------------------------------------------------------- +// Notification status button โ always visible in the header +// --------------------------------------------------------------------------- + +function initNotifButton(): void { + const btn = document.getElementById('notif-btn') as HTMLButtonElement | null; + if (!btn) return; + + if (!('Notification' in window)) { + btn.hidden = true; + return; + } + + function updateBtn(): void { + const perm = Notification.permission; + if (perm === 'granted') { + btn!.textContent = '๐'; + btn!.title = 'Notifications enabled โ click to test'; + btn!.classList.add('header__notif-btn--on'); + btn!.classList.remove('header__notif-btn--blocked'); + } else if (perm === 'denied') { + btn!.textContent = '๐'; + btn!.title = 'Notifications blocked'; + btn!.classList.remove('header__notif-btn--on'); + btn!.classList.add('header__notif-btn--blocked'); + } else { + btn!.textContent = '๐'; + btn!.title = 'Enable notifications'; + btn!.classList.remove('header__notif-btn--on', 'header__notif-btn--blocked'); + } + } + + async function showTestNotification(): Promise<void> { + const reg = await registerServiceWorker(); + if (reg) { + await reg.showNotification('Word Waltz', { + body: "Notifications are working! You'll be alerted when it's your turn.", + icon: `${import.meta.env.BASE_URL}apple-touch-icon.png`, + tag: 'word-waltz-test', + }); + } + } + + updateBtn(); + + btn.addEventListener('click', async () => { + const perm = Notification.permission; + + if (perm === 'denied') { + alert("Notifications are blocked. To enable them, click the lock/info icon in your browser's address bar, find Notifications, and set it to Allow."); + return; + } + + if (perm === 'granted') { + await showTestNotification(); + return; + } + + // 'default' โ request permission + await registerServiceWorker(); + const result = await Notification.requestPermission(); + updateBtn(); + if (result === 'granted') { + await showTestNotification(); + } + }); +} + +initNotifButton(); + diff --git a/src/styles/main.css b/src/styles/main.css index 0da06f2..615a19a 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -109,6 +109,31 @@ header { text-decoration: underline; } +.header__notif-btn { + background: none; + border: none; + cursor: pointer; + font-size: 1rem; + padding: 2px 4px; + border-radius: 4px; + line-height: 1; + opacity: 0.35; + transition: opacity 0.15s; +} + +.header__notif-btn:hover { + opacity: 0.8; +} + +.header__notif-btn--on { + opacity: 1; +} + +.header__notif-btn--blocked { + opacity: 0.3; + cursor: default; +} + /* --- App container ---------------------------------------- */ #app { flex: 1;