UX batch 2: room landscape-fit, rank vs league naming
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 3m43s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m6s
CI/CD / Deploy - local stack (db + server + web) (push) Successful in 58s

- Room: teams side-by-side in landscape so all 4 seats fit (still scrolls).
- Achievements: rename the 5 rating tiers from «لیگ» (league) to «رتبه» (rank)
  + category «رتبه» — so "league" only means the 3 playable match leagues.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-11 13:21:28 +03:30
parent 494683b63b
commit 24a2c251ad
2 changed files with 40 additions and 35 deletions
+34 -29
View File
@@ -89,36 +89,41 @@ export function RoomScreen() {
} }
/> />
{/* your team */} {/* teams: stacked on phones, side-by-side in landscape so all 4 seats fit */}
<h3 className="text-xs text-teal-300 font-bold mb-2">{t("team.us")}</h3> <div className="grid gap-x-4 landscape:grid-cols-2">
<div className="grid grid-cols-2 gap-3"> <div>
<SeatCard seat={seat(0)} role="you" onInvite={() => {}} onBot={() => {}} onClear={() => {}} /> <h3 className="text-xs text-teal-300 font-bold mb-2">{t("team.us")}</h3>
<SeatCard <div className="grid grid-cols-2 gap-3">
seat={seat(2)} <SeatCard seat={seat(0)} role="you" onInvite={() => {}} onBot={() => {}} onClear={() => {}} />
role="partner" <SeatCard
onInvite={() => setPicker({ seat: 2 })} seat={seat(2)}
onBot={() => addBot(2)} role="partner"
onClear={() => clearSeat(2)} onInvite={() => setPicker({ seat: 2 })}
/> onBot={() => addBot(2)}
</div> onClear={() => clearSeat(2)}
/>
</div>
</div>
{/* opponents */} <div className="mt-5 landscape:mt-0">
<h3 className="text-xs text-rose-300 font-bold mt-5 mb-2">{t("room.opponents")}</h3> <h3 className="text-xs text-rose-300 font-bold mb-2">{t("room.opponents")}</h3>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<SeatCard <SeatCard
seat={seat(1)} seat={seat(1)}
role="opp" role="opp"
onInvite={() => setPicker({ seat: 1 })} onInvite={() => setPicker({ seat: 1 })}
onBot={() => addBot(1)} onBot={() => addBot(1)}
onClear={() => clearSeat(1)} onClear={() => clearSeat(1)}
/> />
<SeatCard <SeatCard
seat={seat(3)} seat={seat(3)}
role="opp" role="opp"
onInvite={() => setPicker({ seat: 3 })} onInvite={() => setPicker({ seat: 3 })}
onBot={() => addBot(3)} onBot={() => addBot(3)}
onClear={() => clearSeat(3)} onClear={() => clearSeat(3)}
/> />
</div>
</div>
</div> </div>
<div className="flex gap-3 mt-7"> <div className="flex gap-3 mt-7">
+6 -6
View File
@@ -224,7 +224,7 @@ export const ACHIEVEMENT_CATEGORIES: AchievementCategoryDef[] = [
{ id: "streak", nameFa: "نوار پیروزی", nameEn: "Streaks", icon: "⚡" }, { id: "streak", nameFa: "نوار پیروزی", nameEn: "Streaks", icon: "⚡" },
{ id: "hakem", nameFa: "حاکمیت", nameEn: "Rulership", icon: "👑" }, { id: "hakem", nameFa: "حاکمیت", nameEn: "Rulership", icon: "👑" },
{ id: "level", nameFa: "سطح", nameEn: "Levels", icon: "⭐" }, { id: "level", nameFa: "سطح", nameEn: "Levels", icon: "⭐" },
{ id: "rank", nameFa: "لیگ", nameEn: "Ranks", icon: "🏅" }, { id: "rank", nameFa: "رتبه", nameEn: "Ranks", icon: "🏅" },
{ id: "veteran", nameFa: "کارنامه", nameEn: "Veterancy", icon: "🎮" }, { id: "veteran", nameFa: "کارنامه", nameEn: "Veterancy", icon: "🎮" },
]; ];
@@ -288,11 +288,11 @@ export const ACHIEVEMENTS: AchievementDef[] = [
(g) => `${g} باخت`, (g) => `${g} Losses`, (g) => `${g} باخت`, (g) => `${g} Losses`,
(g) => `با وجود ${g} باخت ادامه دهید`, (g) => `Persevere through ${g} losses`), (g) => `با وجود ${g} باخت ادامه دهید`, (g) => `Persevere through ${g} losses`),
// ranks (explicit rating floors) // ranks (explicit rating floors)
{ id: "reach_silver", category: "rank", ratingFloor: 1100, goal: 1, coinReward: 150, icon: "🥈", nameFa: "لیگ نقره", nameEn: "Reach Silver", descFa: "به لیگ نقره برسید", descEn: "Reach the Silver league" }, { id: "reach_silver", category: "rank", ratingFloor: 1100, goal: 1, coinReward: 150, icon: "🥈", nameFa: "رتبهٔ نقره", nameEn: "Reach Silver", descFa: "به رتبهٔ نقره برسید", descEn: "Reach the Silver rank" },
{ id: "reach_gold", category: "rank", ratingFloor: 1300, goal: 1, coinReward: 300, icon: "🥇", nameFa: "لیگ طلا", nameEn: "Reach Gold", descFa: "به لیگ طلا برسید", descEn: "Reach the Gold league" }, { id: "reach_gold", category: "rank", ratingFloor: 1300, goal: 1, coinReward: 300, icon: "🥇", nameFa: "رتبهٔ طلا", nameEn: "Reach Gold", descFa: "به رتبهٔ طلا برسید", descEn: "Reach the Gold rank" },
{ id: "reach_platinum", category: "rank", ratingFloor: 1500, goal: 1, coinReward: 500, icon: "🛡️", nameFa: "لیگ پلاتین", nameEn: "Reach Platinum", descFa: "به لیگ پلاتین برسید", descEn: "Reach the Platinum league" }, { id: "reach_platinum", category: "rank", ratingFloor: 1500, goal: 1, coinReward: 500, icon: "🛡️", nameFa: "رتبهٔ پلاتین", nameEn: "Reach Platinum", descFa: "به رتبهٔ پلاتین برسید", descEn: "Reach the Platinum rank" },
{ id: "reach_diamond", category: "rank", ratingFloor: 1700, goal: 1, coinReward: 900, icon: "💠", nameFa: "لیگ الماس", nameEn: "Reach Diamond", descFa: "به لیگ الماس برسید", descEn: "Reach the Diamond league" }, { id: "reach_diamond", category: "rank", ratingFloor: 1700, goal: 1, coinReward: 900, icon: "💠", nameFa: "رتبهٔ الماس", nameEn: "Reach Diamond", descFa: "به رتبهٔ الماس برسید", descEn: "Reach the Diamond rank" },
{ id: "reach_master", category: "rank", ratingFloor: 1900, goal: 1, coinReward: 1500, icon: "👑", nameFa: "لیگ استاد", nameEn: "Reach Master", descFa: "به لیگ استاد برسید", descEn: "Reach the Master league" }, { id: "reach_master", category: "rank", ratingFloor: 1900, goal: 1, coinReward: 1500, icon: "👑", nameFa: "رتبهٔ استاد", nameEn: "Reach Master", descFa: "به رتبهٔ استاد برسید", descEn: "Reach the Master rank" },
]; ];
function metricValue(metric: NonNullable<AchievementDef["metric"]>, stats: PlayerStats, level: number): number { function metricValue(metric: NonNullable<AchievementDef["metric"]>, stats: PlayerStats, level: number): number {