From 79f095515fbfcc7b92f04c970cfe9b5287171e4f Mon Sep 17 00:00:00 2001 From: evanpelle Date: Thu, 29 Jan 2026 15:47:10 -0800 Subject: [PATCH] new chip --- src/client/Cosmetics.ts | 22 +++++++++++++++ src/client/components/DesktopNavBar.ts | 39 +++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/client/Cosmetics.ts b/src/client/Cosmetics.ts index d1f00e88d..0f368175c 100644 --- a/src/client/Cosmetics.ts +++ b/src/client/Cosmetics.ts @@ -30,6 +30,18 @@ export async function handlePurchase( } let __cosmetics: Promise | null = null; +let __cosmeticsHash: string | null = null; + +function simpleHash(str: string): string { + let hash = 0; + for (let i = 0; i < str.length; i++) { + const char = str.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; + } + return hash.toString(36); +} + export async function fetchCosmetics(): Promise { if (__cosmetics !== null) { return __cosmetics; @@ -46,6 +58,11 @@ export async function fetchCosmetics(): Promise { console.error(`Invalid cosmetics: ${result.error.message}`); return null; } + const patternKeys = Object.keys(result.data.patterns).sort(); + const hashInput = patternKeys + .map((k) => k + (result.data.patterns[k].product ? "sale" : "")) + .join(","); + __cosmeticsHash = simpleHash(hashInput); return result.data; } catch (error) { console.error("Error getting cosmetics:", error); @@ -55,6 +72,11 @@ export async function fetchCosmetics(): Promise { return __cosmetics; } +export async function getCosmeticsHash(): Promise { + await fetchCosmetics(); + return __cosmeticsHash; +} + export function patternRelationship( pattern: Pattern, colorPalette: { name: string; isArchived?: boolean } | null, diff --git a/src/client/components/DesktopNavBar.ts b/src/client/components/DesktopNavBar.ts index 1e13f87c1..6fbe8d398 100644 --- a/src/client/components/DesktopNavBar.ts +++ b/src/client/components/DesktopNavBar.ts @@ -1,12 +1,15 @@ 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"; @customElement("desktop-nav-bar") export class DesktopNavBar extends LitElement { @state() private _helpSeen = localStorage.getItem(HELP_SEEN_KEY) === "true"; + @state() private _hasNewCosmetics = false; createRenderRoot() { return this; @@ -23,6 +26,12 @@ 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() { @@ -46,14 +55,29 @@ 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() { return html`