From 2fd8757e6696deb2beb5b5a1fe151189c6fd0cfd Mon Sep 17 00:00:00 2001
From: FloPinguin <25036848+FloPinguin@users.noreply.github.com>
Date: Sun, 22 Feb 2026 04:15:36 +0100
Subject: [PATCH] =?UTF-8?q?Notification=20dot=20for=20new=20versions=20(+?=
=?UTF-8?q?=20mobile=20dot=20improvements)=20=E2=9C=A8=20(#3265)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Description:
- **News notification dot (desktop + mobile)**: Added a red pinging dot
on the "News" nav entry that appears when a new version is released. The
current app version is saved to localStorage (`newsSeenVersion`) on
first visit. On subsequent visits, if the version has changed, the dot
appears. Clicking "News" dismisses it by updating the stored version.
- **Mobile Store**: Replaced the static "NEW" text badge on the Store
nav item with a red pinging dot (matching the desktop navbar style). The
dot is conditionally shown based on cosmetics hash changes tracked in
localStorage, and dismissed when the user clicks Store.
- **Help dot on mobile**: Added the yellow help dot (already present on
desktop) to the mobile navbar for consistency, shown for users with
fewer than 10 games played.
### Screenshots:
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
---
resources/lang/en.json | 1 -
src/client/components/DesktopNavBar.ts | 76 ++++++----------
src/client/components/MobileNavBar.ts | 63 +++++++++----
.../components/NavNotificationsController.ts | 91 +++++++++++++++++++
4 files changed, 165 insertions(+), 66 deletions(-)
create mode 100644 src/client/components/NavNotificationsController.ts
diff --git a/resources/lang/en.json b/resources/lang/en.json
index 83160eb11..1e671caa2 100644
--- a/resources/lang/en.json
+++ b/resources/lang/en.json
@@ -42,7 +42,6 @@
"play": "Play",
"news": "News",
"store": "Store",
- "store_new_badge": "NEW",
"settings": "Settings",
"leaderboard": "Leaderboard",
"account": "Account",
diff --git a/src/client/components/DesktopNavBar.ts b/src/client/components/DesktopNavBar.ts
index 77bd1e0e6..45e1d0ea0 100644
--- a/src/client/components/DesktopNavBar.ts
+++ b/src/client/components/DesktopNavBar.ts
@@ -1,15 +1,10 @@
import { LitElement, html } from "lit";
-import { customElement, state } from "lit/decorators.js";
-import { getCosmeticsHash } from "../Cosmetics";
-import { getGamesPlayed } from "../Utils";
-
-const HELP_SEEN_KEY = "helpSeen";
-const STORE_SEEN_HASH_KEY = "storeSeenHash";
+import { customElement } from "lit/decorators.js";
+import { NavNotificationsController } from "./NavNotificationsController";
@customElement("desktop-nav-bar")
export class DesktopNavBar extends LitElement {
- @state() private _helpSeen = localStorage.getItem(HELP_SEEN_KEY) === "true";
- @state() private _hasNewCosmetics = false;
+ private _notifications = new NavNotificationsController(this);
createRenderRoot() {
return this;
@@ -26,12 +21,6 @@ export class DesktopNavBar extends LitElement {
this._updateActiveState(current);
});
}
-
- // Check if cosmetics have changed
- getCosmeticsHash().then((hash: string | null) => {
- const seenHash = localStorage.getItem(STORE_SEEN_HASH_KEY);
- this._hasNewCosmetics = hash !== null && hash !== seenHash;
- });
}
disconnectedCallback() {
@@ -54,30 +43,6 @@ export class DesktopNavBar extends LitElement {
});
}
- private showHelpDot(): boolean {
- // Only show one dot at a time to prevent
- // overwhelming users.
- return getGamesPlayed() < 10 && !this._helpSeen;
- }
-
- private showStoreDot(): boolean {
- return this._hasNewCosmetics && !this.showHelpDot();
- }
-
- private onHelpClick = () => {
- localStorage.setItem(HELP_SEEN_KEY, "true");
- this._helpSeen = true;
- };
-
- private onStoreClick = () => {
- this._hasNewCosmetics = false;
- getCosmeticsHash().then((hash: string | null) => {
- if (hash !== null) {
- localStorage.setItem(STORE_SEEN_HASH_KEY, hash);
- }
- });
- };
-
render() {
window.currentPageId ??= "page-play";
const currentPage = window.currentPageId;
@@ -142,13 +107,26 @@ export class DesktopNavBar extends LitElement {
data-i18n="main.play"
>
-
+