fix(topbar): coin balance was clipped — compact large numbers + shrink bar
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 50s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m4s
CI/CD / Deploy - local stack (db + server + web) (push) Failing after 2m22s

The Home top bar overflowed on narrow screens; in RTL the coins pill is the
far-left item so its leading digits got clipped (showed "04,240" for 104,240).
- CoinsPill: compact big balances (104,240 → 104K, 1.2M), shrink-0 +
  whitespace-nowrap; exact value in the tooltip.
- TopBar: tighter gaps, profile pill min-w-0 (shrinks/truncates first), icon+coins
  group shrink-0 so it never gets squeezed.

Verified: tsc + next build clean; web rebuilt on :1500.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-07 06:57:45 +03:30
parent 1fba9c2f96
commit 3e0c0ed876
2 changed files with 16 additions and 9 deletions
+10 -3
View File
@@ -6,6 +6,13 @@ import { useUIStore } from "@/lib/ui-store";
import { useI18n } from "@/lib/i18n";
import { cn } from "@/lib/cn";
/** Compact balance so big numbers don't overflow tight headers (104,240 → 104K). */
function fmtCoins(n: number): string {
if (n < 10_000) return n.toLocaleString();
if (n < 1_000_000) return `${(n / 1000).toFixed(n < 100_000 ? 1 : 0)}K`.replace(".0K", "K");
return `${(n / 1_000_000).toFixed(1)}M`.replace(".0M", "M");
}
/**
* The coin balance, as a button that opens the buy-coins store. Use it anywhere
* coins are shown so tapping the balance always leads to topping up.
@@ -17,15 +24,15 @@ export function CoinsPill({ className }: { className?: string }) {
return (
<button
onClick={() => go("buycoins")}
title={t("buy.title")}
title={`${coins.toLocaleString()}${t("buy.title")}`}
aria-label={t("buy.title")}
className={cn(
"glass rounded-full ltr:pl-3 rtl:pr-3 ltr:pr-1 rtl:pl-1 py-1 flex items-center gap-1.5 hover:bg-navy-800/80 active:scale-95 transition",
"glass rounded-full ltr:pl-3 rtl:pr-3 ltr:pr-1 rtl:pl-1 py-1 flex items-center gap-1.5 shrink-0 hover:bg-navy-800/80 active:scale-95 transition",
className
)}
>
<Coins className="size-3.5 text-gold-400 shrink-0" />
<span className="text-xs font-bold text-gold-300 tabular-nums">{coins.toLocaleString()}</span>
<span className="text-xs font-bold text-gold-300 tabular-nums whitespace-nowrap">{fmtCoins(coins)}</span>
<span className="grid size-5 place-items-center rounded-full btn-gold shrink-0">
<Plus className="size-3" strokeWidth={3.5} />
</span>
+6 -6
View File
@@ -22,16 +22,16 @@ export function TopBar() {
const xpPct = maxed ? 100 : Math.min(100, Math.max(0, Math.round((profile.xp / xpNeed) * 100)));
return (
<div className="flex items-center justify-between gap-3">
<div className="flex items-center justify-between gap-2">
<button
onClick={() => go("profile")}
className="glass rounded-full ltr:pr-4 rtl:pl-4 ltr:pl-1.5 rtl:pr-1.5 py-1.5 flex items-center gap-2 hover:bg-navy-800/80 transition"
className="glass rounded-full ltr:pr-4 rtl:pl-4 ltr:pl-1.5 rtl:pr-1.5 py-1.5 flex items-center gap-2 min-w-0 hover:bg-navy-800/80 transition"
>
<span className="relative size-9 rounded-full bg-navy-900 gold-border flex items-center justify-center overflow-hidden">
<span className="relative size-9 shrink-0 rounded-full bg-navy-900 gold-border flex items-center justify-center overflow-hidden">
<Avatar id={profile.avatar} image={profile.avatarImage} size={profile.avatarImage ? 36 : 26} />
</span>
<span className="text-start leading-tight min-w-[96px]">
<span className="flex items-center gap-1 text-sm font-bold text-cream max-w-28 truncate">
<span className="text-start leading-tight min-w-0 w-[88px] sm:w-24">
<span className="flex items-center gap-1 text-sm font-bold text-cream truncate">
{profile.displayName}
{profile.plan === "pro" && <Crown className="size-3 text-gold-400 fill-gold-500 shrink-0" />}
</span>
@@ -48,7 +48,7 @@ export function TopBar() {
</span>
</button>
<div className="flex items-center gap-2">
<div className="flex items-center gap-1.5 shrink-0">
<button
onClick={() => go("notifications")}
className="glass rounded-full p-2 hover:bg-navy-800/80 transition relative"