UNO-style UX rollout: Lobby, Matchmaking, Profile
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 21s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m2s
CI/CD / Deploy - local stack (db + server + web) (push) Failing after 0s

- Lobby: the two hero actions (random / create room) are now tactile press-3d
  rounded-3xl with tinted icon chips.
- Matchmaking: seat slots use the Avatar frame with a gold border when filled
  (dashed placeholder when empty + spring pop-in); cancel/start/upgrade buttons
  are tactile.
- Profile: added a level badge on the avatar (casual-game style).

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

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-05 10:07:51 +03:30
parent b661385a00
commit 6bbdbac23b
3 changed files with 24 additions and 16 deletions
+14 -8
View File
@@ -4,13 +4,13 @@ import { AnimatePresence, motion } from "framer-motion";
import { Crown, Loader2 } from "lucide-react";
import { useEffect } from "react";
import { ScreenShell } from "@/components/online/ScreenHeader";
import { Avatar } from "@/components/online/Avatar";
import { useGameStore } from "@/lib/game-store";
import { useOnlineStore } from "@/lib/online-store";
import { useSessionStore } from "@/lib/session-store";
import { useUIStore } from "@/lib/ui-store";
import { useI18n } from "@/lib/i18n";
import { getService } from "@/lib/online/service";
import { avatarEmoji } from "@/lib/online/types";
export function MatchmakingScreen() {
const { t } = useI18n();
@@ -70,7 +70,7 @@ export function MatchmakingScreen() {
<div className="mt-9 flex flex-col items-center gap-3 w-full max-w-xs">
<button
onClick={() => upgradePlan()}
className="btn-gold w-full rounded-xl py-3 flex items-center justify-center gap-2"
className="press-3d btn-gold w-full rounded-2xl py-3 flex items-center justify-center gap-2"
>
<Crown className="size-4" />
{t("queue.upgrade")}
@@ -113,7 +113,10 @@ export function MatchmakingScreen() {
return (
<div
key={i}
className="w-16 h-20 rounded-2xl glass flex flex-col items-center justify-center gap-1"
className={
"w-16 h-20 rounded-2xl flex flex-col items-center justify-center gap-1 transition " +
(p ? "glass gold-border" : "border border-dashed border-navy-700/60 bg-navy-900/30")
}
>
<AnimatePresence mode="wait">
{p ? (
@@ -121,13 +124,16 @@ export function MatchmakingScreen() {
key={p.id}
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ type: "spring", stiffness: 260, damping: 18 }}
className="flex flex-col items-center gap-0.5"
>
<span className="text-2xl">{avatarEmoji(p.avatar)}</span>
<span className="text-[9px] text-cream/70 max-w-14 truncate">
<span className="grid size-9 place-items-center rounded-xl bg-navy-900 overflow-hidden">
<Avatar id={p.avatar} size={24} />
</span>
<span className="text-[9px] text-cream/80 max-w-14 truncate">
{p.displayName}
</span>
<span className="text-[8px] text-gold-400/70">
<span className="text-[8px] text-gold-400/80">
{t("common.level")} {p.level}
</span>
</motion.div>
@@ -148,7 +154,7 @@ export function MatchmakingScreen() {
</div>
<div className="mt-10 flex gap-3">
<button onClick={cancel} className="glass rounded-xl px-6 py-3 text-cream/70 hover:text-cream">
<button onClick={cancel} className="press-3d glass rounded-2xl px-6 py-3 text-cream/70">
{t("mm.cancel")}
</button>
{ready && (
@@ -156,7 +162,7 @@ export function MatchmakingScreen() {
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
onClick={enter}
className="btn-gold rounded-xl px-8 py-3 text-lg"
className="press-3d btn-gold rounded-2xl px-8 py-3 text-lg"
>
{t("mm.start")}
</motion.button>