Files
HokmPlay/src/components/PlayingCard.tsx
T
soroush.asadi e2d0a602b6 Build Hokm card game: offline vs-AI + online social/gamification (mock backend)
- Pure-TS Hokm engine (deal, hakem, trump, tricks, scoring, Kot) + AI bots
- Persian-luxury RTL UI (Next 16 / React 19 / Tailwind v4 / Framer Motion / Zustand)
- Online platform behind OnlineService seam (mock now, .NET SignalR later):
  auth (phone OTP + email/Google), profiles, friends, private rooms with
  partner pick, ranked matchmaking, leaderboard, shop
- Gamification: ranks/leagues, coins, XP/levels, daily rewards, achievements
- i18n fa/en, PWA manifest, engine + gamification sims

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 10:11:00 +03:30

84 lines
2.0 KiB
TypeScript

"use client";
import { cn } from "@/lib/cn";
import { Card, SUIT_IS_RED, SUIT_SYMBOL, rankLabel } from "@/lib/hokm/types";
const SIZES = {
sm: { w: 44, h: 62, rank: "text-base", pip: "text-lg", center: "text-2xl" },
md: { w: 60, h: 84, rank: "text-lg", pip: "text-xl", center: "text-3xl" },
lg: { w: 74, h: 104, rank: "text-xl", pip: "text-2xl", center: "text-4xl" },
} as const;
export type CardSize = keyof typeof SIZES;
interface Props {
card?: Card;
faceDown?: boolean;
size?: CardSize;
className?: string;
dimmed?: boolean;
}
export function PlayingCard({
card,
faceDown,
size = "md",
className,
dimmed,
}: Props) {
const s = SIZES[size];
if (faceDown || !card) {
return (
<div
className={cn("card-back rounded-lg shrink-0", className)}
style={{ width: s.w, height: s.h }}
aria-hidden
>
<div className="h-full w-full rounded-lg flex items-center justify-center">
<div className="text-gold-500/70 text-lg font-bold"></div>
</div>
</div>
);
}
const red = SUIT_IS_RED[card.suit];
const color = red ? "text-rose-600" : "text-slate-900";
const symbol = SUIT_SYMBOL[card.suit];
return (
<div
className={cn(
"card-face rounded-lg shrink-0 relative select-none transition-opacity",
dimmed && "opacity-45",
className
)}
style={{ width: s.w, height: s.h }}
>
<div className={cn("absolute top-1 left-1.5 leading-none font-bold", color, s.rank)}>
<div>{rankLabel(card.rank)}</div>
<div className={s.rank}>{symbol}</div>
</div>
<div
className={cn(
"absolute inset-0 flex items-center justify-center font-bold",
color,
s.center
)}
>
{symbol}
</div>
<div
className={cn(
"absolute bottom-1 right-1.5 leading-none font-bold rotate-180",
color,
s.rank
)}
>
<div>{rankLabel(card.rank)}</div>
<div className={s.rank}>{symbol}</div>
</div>
</div>
);
}