casino-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/README.md +213 -0
  2. package/dist/assets/assets/card-back.svg +43 -0
  3. package/dist/assets/assets/card-shoe-overlay.svg +14 -0
  4. package/dist/assets/card-back.svg +43 -0
  5. package/dist/assets/card-shoe-overlay.svg +14 -0
  6. package/dist/casino-ui.css +2 -0
  7. package/dist/components/bet-panel.d.ts +41 -0
  8. package/dist/components/bet-panel.d.ts.map +1 -0
  9. package/dist/components/bet-panel.js +37 -0
  10. package/dist/components/bet-panel.js.map +1 -0
  11. package/dist/components/button.d.ts +15 -0
  12. package/dist/components/button.d.ts.map +1 -0
  13. package/dist/components/button.js +27 -0
  14. package/dist/components/button.js.map +1 -0
  15. package/dist/components/card-score-badge.d.ts +9 -0
  16. package/dist/components/card-score-badge.d.ts.map +1 -0
  17. package/dist/components/card-score-badge.js +20 -0
  18. package/dist/components/card-score-badge.js.map +1 -0
  19. package/dist/components/card-shoe.d.ts +6 -0
  20. package/dist/components/card-shoe.d.ts.map +1 -0
  21. package/dist/components/card-shoe.js +14 -0
  22. package/dist/components/card-shoe.js.map +1 -0
  23. package/dist/components/card-table.d.ts +7 -0
  24. package/dist/components/card-table.d.ts.map +1 -0
  25. package/dist/components/card-table.js +6 -0
  26. package/dist/components/card-table.js.map +1 -0
  27. package/dist/components/chip-rack.d.ts +6 -0
  28. package/dist/components/chip-rack.d.ts.map +1 -0
  29. package/dist/components/chip-rack.js +13 -0
  30. package/dist/components/chip-rack.js.map +1 -0
  31. package/dist/components/chip.d.ts +49 -0
  32. package/dist/components/chip.d.ts.map +1 -0
  33. package/dist/components/chip.js +81 -0
  34. package/dist/components/chip.js.map +1 -0
  35. package/dist/components/game-footer.d.ts +29 -0
  36. package/dist/components/game-footer.d.ts.map +1 -0
  37. package/dist/components/game-footer.js +72 -0
  38. package/dist/components/game-footer.js.map +1 -0
  39. package/dist/components/game-info-dialog.d.ts +23 -0
  40. package/dist/components/game-info-dialog.d.ts.map +1 -0
  41. package/dist/components/game-info-dialog.js +26 -0
  42. package/dist/components/game-info-dialog.js.map +1 -0
  43. package/dist/components/icon.d.ts +10 -0
  44. package/dist/components/icon.d.ts.map +1 -0
  45. package/dist/components/icon.js +59 -0
  46. package/dist/components/icon.js.map +1 -0
  47. package/dist/components/poker-card.d.ts +15 -0
  48. package/dist/components/poker-card.d.ts.map +1 -0
  49. package/dist/components/poker-card.js +77 -0
  50. package/dist/components/poker-card.js.map +1 -0
  51. package/dist/components/result-badge.d.ts +14 -0
  52. package/dist/components/result-badge.d.ts.map +1 -0
  53. package/dist/components/result-badge.js +71 -0
  54. package/dist/components/result-badge.js.map +1 -0
  55. package/dist/components/switch-table-dialog.d.ts +10 -0
  56. package/dist/components/switch-table-dialog.d.ts.map +1 -0
  57. package/dist/components/switch-table-dialog.js +51 -0
  58. package/dist/components/switch-table-dialog.js.map +1 -0
  59. package/dist/components/toast-container.d.ts +8 -0
  60. package/dist/components/toast-container.d.ts.map +1 -0
  61. package/dist/components/toast-container.js +8 -0
  62. package/dist/components/toast-container.js.map +1 -0
  63. package/dist/components/toast-helpers.d.ts +22 -0
  64. package/dist/components/toast-helpers.d.ts.map +1 -0
  65. package/dist/components/toast-helpers.js +47 -0
  66. package/dist/components/toast-helpers.js.map +1 -0
  67. package/dist/components/toast.d.ts +26 -0
  68. package/dist/components/toast.d.ts.map +1 -0
  69. package/dist/components/toast.js +49 -0
  70. package/dist/components/toast.js.map +1 -0
  71. package/dist/components/ui/dialog.d.ts +14 -0
  72. package/dist/components/ui/dialog.d.ts.map +1 -0
  73. package/dist/components/ui/dialog.js +35 -0
  74. package/dist/components/ui/dialog.js.map +1 -0
  75. package/dist/components/ui/drawer.d.ts +14 -0
  76. package/dist/components/ui/drawer.d.ts.map +1 -0
  77. package/dist/components/ui/drawer.js +35 -0
  78. package/dist/components/ui/drawer.js.map +1 -0
  79. package/dist/components/ui/dropdown-menu.d.ts +27 -0
  80. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  81. package/dist/components/ui/dropdown-menu.js +39 -0
  82. package/dist/components/ui/dropdown-menu.js.map +1 -0
  83. package/dist/index.d.ts +23 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +25 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/lib/utils.d.ts +3 -0
  88. package/dist/lib/utils.d.ts.map +1 -0
  89. package/dist/lib/utils.js +6 -0
  90. package/dist/lib/utils.js.map +1 -0
  91. package/dist/stories/BetPanel.stories.d.ts +10 -0
  92. package/dist/stories/BetPanel.stories.d.ts.map +1 -0
  93. package/dist/stories/BetPanel.stories.js +34 -0
  94. package/dist/stories/BetPanel.stories.js.map +1 -0
  95. package/dist/stories/Button.stories.d.ts +13 -0
  96. package/dist/stories/Button.stories.d.ts.map +1 -0
  97. package/dist/stories/Button.stories.js +39 -0
  98. package/dist/stories/Button.stories.js.map +1 -0
  99. package/dist/stories/CardScoreBadge.stories.d.ts +8 -0
  100. package/dist/stories/CardScoreBadge.stories.d.ts.map +1 -0
  101. package/dist/stories/CardScoreBadge.stories.js +21 -0
  102. package/dist/stories/CardScoreBadge.stories.js.map +1 -0
  103. package/dist/stories/CardShoe.stories.d.ts +7 -0
  104. package/dist/stories/CardShoe.stories.d.ts.map +1 -0
  105. package/dist/stories/CardShoe.stories.js +8 -0
  106. package/dist/stories/CardShoe.stories.js.map +1 -0
  107. package/dist/stories/CardTable.stories.d.ts +7 -0
  108. package/dist/stories/CardTable.stories.d.ts.map +1 -0
  109. package/dist/stories/CardTable.stories.js +15 -0
  110. package/dist/stories/CardTable.stories.js.map +1 -0
  111. package/dist/stories/Chip.stories.d.ts +11 -0
  112. package/dist/stories/Chip.stories.d.ts.map +1 -0
  113. package/dist/stories/Chip.stories.js +32 -0
  114. package/dist/stories/Chip.stories.js.map +1 -0
  115. package/dist/stories/ChipRack.stories.d.ts +7 -0
  116. package/dist/stories/ChipRack.stories.d.ts.map +1 -0
  117. package/dist/stories/ChipRack.stories.js +8 -0
  118. package/dist/stories/ChipRack.stories.js.map +1 -0
  119. package/dist/stories/Dialog.stories.d.ts +6 -0
  120. package/dist/stories/Dialog.stories.d.ts.map +1 -0
  121. package/dist/stories/Dialog.stories.js +15 -0
  122. package/dist/stories/Dialog.stories.js.map +1 -0
  123. package/dist/stories/GameFooter.stories.d.ts +7 -0
  124. package/dist/stories/GameFooter.stories.d.ts.map +1 -0
  125. package/dist/stories/GameFooter.stories.js +37 -0
  126. package/dist/stories/GameFooter.stories.js.map +1 -0
  127. package/dist/stories/Icon.stories.d.ts +9 -0
  128. package/dist/stories/Icon.stories.d.ts.map +1 -0
  129. package/dist/stories/Icon.stories.js +27 -0
  130. package/dist/stories/Icon.stories.js.map +1 -0
  131. package/dist/stories/PokerCard.stories.d.ts +14 -0
  132. package/dist/stories/PokerCard.stories.d.ts.map +1 -0
  133. package/dist/stories/PokerCard.stories.js +40 -0
  134. package/dist/stories/PokerCard.stories.js.map +1 -0
  135. package/dist/stories/ResultBadge.stories.d.ts +11 -0
  136. package/dist/stories/ResultBadge.stories.d.ts.map +1 -0
  137. package/dist/stories/ResultBadge.stories.js +32 -0
  138. package/dist/stories/ResultBadge.stories.js.map +1 -0
  139. package/dist/stories/Toast.stories.d.ts +10 -0
  140. package/dist/stories/Toast.stories.d.ts.map +1 -0
  141. package/dist/stories/Toast.stories.js +34 -0
  142. package/dist/stories/Toast.stories.js.map +1 -0
  143. package/dist/styles/casino-ui-base.css +310 -0
  144. package/dist/styles/styles/casino-ui-base.css +310 -0
  145. package/dist/styles/styles/toast.css +52 -0
  146. package/dist/styles/toast.css +52 -0
  147. package/dist/toast.css +52 -0
  148. package/dist/types.d.ts +11 -0
  149. package/dist/types.d.ts.map +1 -0
  150. package/dist/types.js +2 -0
  151. package/dist/types.js.map +1 -0
  152. package/dist/utils/format-amount.d.ts +2 -0
  153. package/dist/utils/format-amount.d.ts.map +1 -0
  154. package/dist/utils/format-amount.js +31 -0
  155. package/dist/utils/format-amount.js.map +1 -0
  156. package/package.json +58 -0
  157. package/src/assets/card-back.svg +43 -0
  158. package/src/assets/card-shoe-overlay.svg +14 -0
  159. package/src/components/bet-panel.tsx +275 -0
  160. package/src/components/button.tsx +80 -0
  161. package/src/components/card-score-badge.tsx +61 -0
  162. package/src/components/card-shoe.tsx +52 -0
  163. package/src/components/card-table.tsx +182 -0
  164. package/src/components/chip-rack.tsx +55 -0
  165. package/src/components/chip.tsx +203 -0
  166. package/src/components/game-footer.tsx +356 -0
  167. package/src/components/game-info-dialog.tsx +245 -0
  168. package/src/components/icon.tsx +94 -0
  169. package/src/components/poker-card.tsx +192 -0
  170. package/src/components/result-badge.tsx +157 -0
  171. package/src/components/switch-table-dialog.tsx +211 -0
  172. package/src/components/toast-container.tsx +25 -0
  173. package/src/components/toast-helpers.ts +79 -0
  174. package/src/components/toast.tsx +282 -0
  175. package/src/components/ui/dialog.tsx +134 -0
  176. package/src/components/ui/drawer.tsx +132 -0
  177. package/src/components/ui/dropdown-menu.tsx +210 -0
  178. package/src/env.d.ts +6 -0
  179. package/src/index.ts +88 -0
  180. package/src/lib/utils.ts +6 -0
  181. package/src/stories/BetPanel.stories.tsx +113 -0
  182. package/src/stories/Button.stories.tsx +55 -0
  183. package/src/stories/CardScoreBadge.stories.tsx +34 -0
  184. package/src/stories/CardShoe.stories.tsx +12 -0
  185. package/src/stories/Chip.stories.tsx +51 -0
  186. package/src/stories/ChipRack.stories.tsx +12 -0
  187. package/src/stories/Dialog.stories.tsx +45 -0
  188. package/src/stories/GameFooter.stories.tsx +45 -0
  189. package/src/stories/Icon.stories.tsx +49 -0
  190. package/src/stories/PokerCard.stories.tsx +72 -0
  191. package/src/stories/ResultBadge.stories.tsx +51 -0
  192. package/src/stories/Toast.stories.tsx +71 -0
  193. package/src/styles/casino-ui-base.css +310 -0
  194. package/src/styles/toast.css +52 -0
  195. package/src/types.ts +11 -0
  196. package/src/utils/format-amount.ts +35 -0
@@ -0,0 +1,245 @@
1
+ import {
2
+ Dialog,
3
+ DialogClose,
4
+ DialogContent,
5
+ DialogDescription,
6
+ DialogFooter,
7
+ DialogHeader,
8
+ DialogTitle,
9
+ } from "./ui/dialog";
10
+ import {
11
+ Drawer,
12
+ DrawerClose,
13
+ DrawerContent,
14
+ DrawerDescription,
15
+ DrawerFooter,
16
+ DrawerHeader,
17
+ DrawerTitle,
18
+ } from "./ui/drawer";
19
+ import { Icon } from "./icon";
20
+ import { Tabs as TabsPrimitive } from "radix-ui";
21
+ import "../styles/casino-ui-base.css";
22
+ import { cn } from "../lib/utils";
23
+ import type { CoinInfo } from "../types";
24
+
25
+ function TabTrigger({
26
+ className,
27
+ ...props
28
+ }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
29
+ return (
30
+ <TabsPrimitive.Trigger
31
+ className={cn(
32
+ "flex-1 rounded-xl px-3 py-2 text-sm font-semibold text-text-tertiary transition-all",
33
+ "data-[state=active]:bg-surface-300 data-[state=active]:text-white data-[state=active]:shadow",
34
+ className,
35
+ )}
36
+ {...props}
37
+ />
38
+ );
39
+ }
40
+
41
+ interface GameInfoBadgesProps {
42
+ badges: {
43
+ houseEdge: string;
44
+ minBet: string;
45
+ coinInfo?: CoinInfo;
46
+ };
47
+ }
48
+
49
+ function GameInfoBadges({ badges }: GameInfoBadgesProps) {
50
+ const coinInfo = badges.coinInfo;
51
+ const isUSD = coinInfo?.coinType?.toLowerCase().includes("usd") ?? false;
52
+ return (
53
+ <div className="flex gap-2 items-center h-8">
54
+ <div className="h-full flex gap-1 items-center rounded-lg bg-surface-400 p-2">
55
+ <span className="text-xs text-text-secondary text-nowrap">
56
+ House Edge
57
+ </span>
58
+ <span className="text-xs lg:text-sm font-semibold text-white">
59
+ {badges.houseEdge}%
60
+ </span>
61
+ </div>
62
+ <div className="h-full flex gap-1 items-center rounded-lg bg-surface-400 p-2">
63
+ <span className="text-xs text-text-secondary text-nowrap">
64
+ Min Bet:
65
+ </span>
66
+ <span className="text-xs lg:text-sm font-semibold text-white">
67
+ {badges.minBet}
68
+ </span>
69
+ </div>
70
+ <div className="h-full flex gap-1 items-center rounded-lg bg-surface-400 p-2">
71
+ <span className="text-xs text-text-secondary text-nowrap">
72
+ Game Coin:
73
+ </span>
74
+ {isUSD ? (
75
+ <span className="text-xs lg:text-sm font-semibold text-white">$</span>
76
+ ) : coinInfo?.image ? (
77
+ typeof coinInfo.image === "string" ? (
78
+ <img
79
+ src={coinInfo.image}
80
+ alt={coinInfo.symbol}
81
+ className="size-3 lg:size-4 object-contain rounded-[50%]"
82
+ />
83
+ ) : (
84
+ <div className="size-3 lg:size-4 object-contain rounded-[50%]">
85
+ {coinInfo.image}
86
+ </div>
87
+ )
88
+ ) : (
89
+ <span className="text-xs lg:text-sm font-semibold text-white">
90
+ {coinInfo?.symbol ?? "-"}
91
+ </span>
92
+ )}
93
+ </div>
94
+ </div>
95
+ );
96
+ }
97
+
98
+ interface GameInfoContentProps {
99
+ tabsContents: {
100
+ table: React.ReactNode;
101
+ howToPlay: React.ReactNode;
102
+ balance: React.ReactNode;
103
+ };
104
+ }
105
+
106
+ function GameInfoContent({ tabsContents }: GameInfoContentProps) {
107
+ return (
108
+ <TabsPrimitive.Root
109
+ defaultValue="table"
110
+ className="flex flex-col flex-1 max-h-118 lg:max-h-102.5 p-3 lg:py-5 lg:px-6 bg-surface-400"
111
+ >
112
+ <TabsPrimitive.List className="w-full flex gap-1 rounded-xl bg-surface-500 p-1 mb-5">
113
+ <TabTrigger
114
+ className="rounded-lg text-xs lg:text-sm text-nowrap"
115
+ value="table"
116
+ >
117
+ Table
118
+ </TabTrigger>
119
+ <TabTrigger
120
+ className="rounded-lg text-xs lg:text-sm text-nowrap"
121
+ value="how-to-play"
122
+ >
123
+ How to Play
124
+ </TabTrigger>
125
+ <TabTrigger
126
+ className="rounded-lg text-xs lg:text-sm text-nowrap"
127
+ value="balance"
128
+ >
129
+ Balance
130
+ </TabTrigger>
131
+ </TabsPrimitive.List>
132
+
133
+ <TabsPrimitive.Content
134
+ value="table"
135
+ className="flex-1 overflow-y-auto hide-scrollbar pb-24"
136
+ >
137
+ {tabsContents.table}
138
+ </TabsPrimitive.Content>
139
+ <TabsPrimitive.Content
140
+ value="how-to-play"
141
+ className="flex-1 overflow-y-auto hide-scrollbar pb-24"
142
+ >
143
+ {tabsContents.howToPlay}
144
+ </TabsPrimitive.Content>
145
+ <TabsPrimitive.Content
146
+ value="balance"
147
+ className="flex-1 overflow-y-auto hide-scrollbar pb-24"
148
+ >
149
+ {tabsContents.balance}
150
+ </TabsPrimitive.Content>
151
+ </TabsPrimitive.Root>
152
+ );
153
+ }
154
+
155
+ interface GameInfoDialogProps {
156
+ open: boolean;
157
+ onOpenChange: (open: boolean) => void;
158
+ title: string;
159
+ description: string;
160
+ badges: {
161
+ houseEdge: string;
162
+ minBet: string;
163
+ coinInfo?: CoinInfo;
164
+ };
165
+ tabsContents: {
166
+ table: React.ReactNode;
167
+ howToPlay: React.ReactNode;
168
+ balance: React.ReactNode;
169
+ };
170
+ footer?: React.ReactNode;
171
+ isMobile?: boolean;
172
+ }
173
+
174
+ function GameInfoDialog({
175
+ open,
176
+ onOpenChange,
177
+ title,
178
+ description,
179
+ badges,
180
+ tabsContents,
181
+ footer,
182
+ isMobile = false,
183
+ }: GameInfoDialogProps) {
184
+ if (isMobile) {
185
+ return (
186
+ <Drawer open={open} onOpenChange={onOpenChange}>
187
+ <DrawerContent className="bg-surface-600 overflow-clip border-none max-h-[90vh]!">
188
+ <DrawerHeader className="w-full flex flex-col gap-3 px-4 pt-5 pb-3">
189
+ <div className="w-full flex gap-6 items-start">
190
+ <div className="w-full flex flex-col gap-1">
191
+ <DrawerTitle className="text-2xl font-bold text-left">
192
+ {title}
193
+ </DrawerTitle>
194
+ <DrawerDescription className="text-left text-text-secondary font-semibold">
195
+ {description}
196
+ </DrawerDescription>
197
+ </div>
198
+ <DrawerClose className="min-w-6 cursor-pointer opacity-70 transition-opacity hover:opacity-100">
199
+ <Icon icon="x" className="size-6" />
200
+ </DrawerClose>
201
+ </div>
202
+ <GameInfoBadges badges={badges} />
203
+ </DrawerHeader>
204
+
205
+ <GameInfoContent tabsContents={tabsContents} />
206
+
207
+ {footer && (
208
+ <DrawerFooter className="sticky bottom-0 border-t border-surface-300 bg-surface-450 px-5 pt-5 pb-6">
209
+ {footer}
210
+ </DrawerFooter>
211
+ )}
212
+ </DrawerContent>
213
+ </Drawer>
214
+ );
215
+ }
216
+
217
+ return (
218
+ <Dialog open={open} onOpenChange={onOpenChange}>
219
+ <DialogContent className="w-125 rounded-xl overflow-clip bg-surface-600">
220
+ <DialogHeader className="flex flex-col gap-3 p-6">
221
+ <div className="w-full flex gap-6 items-start">
222
+ <div className="w-full flex flex-col gap-1">
223
+ <DialogTitle className="text-2xl font-bold">{title}</DialogTitle>
224
+ <DialogDescription>{description}</DialogDescription>
225
+ </div>
226
+ <DialogClose className="min-w-6 cursor-pointer opacity-70 transition-opacity hover:opacity-100">
227
+ <Icon icon="x" className="size-6" />
228
+ </DialogClose>
229
+ </div>
230
+ <GameInfoBadges badges={badges} />
231
+ </DialogHeader>
232
+
233
+ <GameInfoContent tabsContents={tabsContents} />
234
+
235
+ {footer && (
236
+ <DialogFooter className="border-t border-surface-300 bg-surface-450 px-5 pt-5 pb-6">
237
+ {footer}
238
+ </DialogFooter>
239
+ )}
240
+ </DialogContent>
241
+ </Dialog>
242
+ );
243
+ }
244
+
245
+ export default GameInfoDialog;
@@ -0,0 +1,94 @@
1
+ import React from "react";
2
+ import { cn } from "../lib/utils";
3
+
4
+ const ICONS: Record<string, string> = {
5
+ settings: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M15.0912 6.79037L13.2 6.48125C13.0893 6.10173 12.9379 5.73693 12.7485 5.39165L13.8525 3.81821C13.9417 3.69117 13.9264 3.51805 13.8166 3.40797L12.5721 2.16413C12.4611 2.05341 12.2864 2.03901 12.159 2.13085L10.6093 3.24477C10.2608 3.05213 9.89278 2.89917 9.51102 2.78813L9.1811 0.904608C9.15422 0.751648 9.02142 0.639648 8.8659 0.639648H7.1059C6.9491 0.639648 6.81534 0.753248 6.79006 0.908128L6.48414 2.78141C6.10014 2.89181 5.73151 3.04317 5.38431 3.23325L3.83871 2.12925C3.71103 2.03805 3.53726 2.05277 3.42622 2.16317L2.18238 3.40701C2.07262 3.51677 2.05727 3.68957 2.14655 3.81661L3.23423 5.37277C3.04063 5.72317 2.88638 6.09405 2.77406 6.47997L0.908145 6.79069C0.753905 6.81629 0.640625 6.95005 0.640625 7.10621V8.86621C0.640625 9.02141 0.751985 9.15421 0.904625 9.18141L2.77054 9.51229C2.88222 9.89725 3.03646 10.2681 3.2307 10.6195L2.12958 12.1596C2.0387 12.2867 2.0531 12.4611 2.1635 12.5721L3.40767 13.8172C3.51743 13.927 3.69055 13.9424 3.81759 13.8531L5.37598 12.7616C5.72574 12.9539 6.09534 13.1065 6.47838 13.2172L6.7907 15.0928C6.81598 15.2467 6.94942 15.3596 7.1059 15.3596H8.8659C9.0211 15.3596 9.1539 15.2483 9.18078 15.0956L9.51518 13.2108C9.89886 13.0979 10.2665 12.9443 10.6128 12.7516L12.1824 13.8528C12.3097 13.9427 12.4825 13.927 12.5926 13.8172L13.8368 12.5721C13.9475 12.4611 13.9619 12.286 13.8701 12.1587L12.7507 10.6044C12.9405 10.2588 13.0912 9.89341 13.2009 9.51389L15.0947 9.18141C15.248 9.15453 15.3593 9.02141 15.3593 8.86621V7.10621C15.3597 6.94941 15.2461 6.81565 15.0912 6.79037ZM7.99998 10.2396C6.76286 10.2396 5.75998 9.23677 5.75998 7.99965C5.75998 6.76253 6.76286 5.75965 7.99998 5.75965C9.2371 5.75965 10.24 6.76253 10.24 7.99965C10.24 9.23677 9.2371 10.2396 7.99998 10.2396Z" fill="currentColor"/></svg>`,
6
+ share: ` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 13.3333 13.138" fill="none"><path d="M9.80469 0L8.86198 0.942708L10.3906 2.47135H10C5.95773 2.47135 2.66667 5.76242 2.66667 9.80469V10.4714H4V9.80469C4 6.48296 6.67827 3.80469 10 3.80469H10.3906L8.86198 5.33333L9.80469 6.27604L12.9427 3.13802L9.80469 0ZM0 3.80469V4.47135V11.138C0 12.2347 0.903353 13.138 2 13.138H11.3333C12.43 13.138 13.3333 12.2347 13.3333 11.138V10.4714V9.80469H12V10.4714V11.138C12 11.5147 11.71 11.8047 11.3333 11.8047H2C1.62331 11.8047 1.33333 11.5147 1.33333 11.138V4.47135V3.80469H0Z" fill="currentColor" /></svg>`,
7
+ sit: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16.6667 16.6667" fill="none"><path d="M8.33333 0C3.73083 0 0 3.73083 0 8.33333C0 12.9358 3.73083 16.6667 8.33333 16.6667C12.9358 16.6667 16.6667 12.9358 16.6667 8.33333C16.6667 3.73083 12.9358 0 8.33333 0ZM12.5 9.16667H7.01167L8.9225 11.0775L7.74417 12.2558L3.82167 8.33333L7.74417 4.41083L8.9225 5.58917L7.01167 7.5H12.5V9.16667Z" fill="currentColor"/></svg>`,
8
+ "switch-seat": `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16.6667 15" fill="none"><path d="M13.3333 0V2.5H0V4.16667H13.3333V6.66667L16.6667 3.33333L13.3333 0ZM3.33333 8.33333L0 11.6667L3.33333 15V12.5H16.6667V10.8333H3.33333V8.33333Z" fill="currentColor"/></svg>`,
9
+ crown: `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="11" viewBox="0 0 12 11" fill="none"><path d="M1.8 11V9.77778H10.2V11H1.8ZM1.8 8.86111L1.035 3.95694C1.015 3.95694 0.9925 3.95949 0.9675 3.96458C0.9425 3.96968 0.92 3.97222 0.9 3.97222C0.65 3.97222 0.4375 3.8831 0.2625 3.70486C0.0875 3.52662 0 3.31019 0 3.05556C0 2.80093 0.0875 2.58449 0.2625 2.40625C0.4375 2.22801 0.65 2.13889 0.9 2.13889C1.15 2.13889 1.3625 2.22801 1.5375 2.40625C1.7125 2.58449 1.8 2.80093 1.8 3.05556C1.8 3.12685 1.7925 3.19306 1.7775 3.25417C1.7625 3.31528 1.745 3.3713 1.725 3.42222L3.6 4.27778L5.475 1.66528C5.365 1.5838 5.275 1.47685 5.205 1.34444C5.135 1.21204 5.1 1.06944 5.1 0.916667C5.1 0.662037 5.1875 0.445602 5.3625 0.267361C5.5375 0.0891204 5.75 0 6 0C6.25 0 6.4625 0.0891204 6.6375 0.267361C6.8125 0.445602 6.9 0.662037 6.9 0.916667C6.9 1.06944 6.865 1.21204 6.795 1.34444C6.725 1.47685 6.635 1.5838 6.525 1.66528L8.4 4.27778L10.275 3.42222C10.255 3.3713 10.2375 3.31528 10.2225 3.25417C10.2075 3.19306 10.2 3.12685 10.2 3.05556C10.2 2.80093 10.2875 2.58449 10.4625 2.40625C10.6375 2.22801 10.85 2.13889 11.1 2.13889C11.35 2.13889 11.5625 2.22801 11.7375 2.40625C11.9125 2.58449 12 2.80093 12 3.05556C12 3.31019 11.9125 3.52662 11.7375 3.70486C11.5625 3.8831 11.35 3.97222 11.1 3.97222C11.08 3.97222 11.0575 3.96968 11.0325 3.96458C11.0075 3.95949 10.985 3.95694 10.965 3.95694L10.2 8.86111H1.8ZM2.82 7.63889H9.18L9.57 5.0875L7.995 5.79028L6 2.99444L4.005 5.79028L2.43 5.0875L2.82 7.63889Z" fill="currentColor"/></svg>`,
10
+ "check-circle": `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M9.99984 1.66699C5.39984 1.66699 1.6665 5.40033 1.6665 10.0003C1.6665 14.6003 5.39984 18.3337 9.99984 18.3337C14.5998 18.3337 18.3332 14.6003 18.3332 10.0003C18.3332 5.40033 14.5998 1.66699 9.99984 1.66699ZM9.99984 16.667C6.32484 16.667 3.33317 13.6753 3.33317 10.0003C3.33317 6.32533 6.32484 3.33366 9.99984 3.33366C13.6748 3.33366 16.6665 6.32533 16.6665 10.0003C16.6665 13.6753 13.6748 16.667 9.99984 16.667ZM13.8248 6.31699L8.33317 11.8087L6.17484 9.65866L4.99984 10.8337L8.33317 14.167L14.9998 7.50033L13.8248 6.31699Z" fill="currentColor"/></svg>`,
11
+ loader: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M12 2a10 10 0 0 1 10 10h-3a7 7 0 0 0-7-7V2z" fill="currentColor"/></svg>`,
12
+ surrender: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18.0001 18.0279" fill="none"><path d="M0.984475 1.27201e-05C0.7196 0.00415314 0.467188 0.113213 0.282637 0.303257C0.0980854 0.493301 -0.00352729 0.748802 0.000100007 1.01368V11.0137V17.0137C-0.00177404 17.1462 0.0227073 17.2778 0.072121 17.4007C0.121535 17.5237 0.194895 17.6356 0.28794 17.73C0.380984 17.8244 0.491857 17.8993 0.614114 17.9504C0.736371 18.0016 0.867575 18.0279 1.0001 18.0279C1.13263 18.0279 1.26383 18.0016 1.38609 17.9504C1.50834 17.8993 1.61922 17.8244 1.71226 17.73C1.8053 17.6356 1.87867 17.5237 1.92808 17.4007C1.97749 17.2778 2.00197 17.1462 2.0001 17.0137V11.0137H8.76377C9.14277 11.0137 9.4883 11.2274 9.6583 11.5664L10.1056 12.4609C10.2746 12.7999 10.6211 13.0137 11.0001 13.0137H17.0001C17.5521 13.0137 18.0001 12.5657 18.0001 12.0137V3.01368C18.0001 2.46168 17.5521 2.01368 17.0001 2.01368H12.2364C11.8574 2.01368 11.5119 1.79995 11.3419 1.46095L10.8946 0.566419C10.7256 0.227419 10.3791 0.0136846 10.0001 0.0136846H1.1544C1.09825 0.00429949 1.0414 -0.000274395 0.984475 1.27201e-05Z" fill="currentColor"/></svg>`,
13
+ split: `<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 15 15" fill="none"><path d="M14.6567 7.3375L14.244 6.91559L12.1895 4.86109C11.9591 4.63065 11.5853 4.63065 11.3549 4.86109C11.1244 5.09154 11.1244 5.46529 11.3549 5.69573L12.4188 6.7505L9.08024 6.7505L9.08024 -2.43757e-07L7.90624 -2.95074e-07L7.90624 14.675L9.08024 14.675L9.08024 7.9245L12.4005 7.9245L11.3549 8.97009C11.1244 9.20054 11.1244 9.57429 11.3549 9.80474C11.5853 10.0352 11.9591 10.0352 12.1895 9.80474L14.6567 7.3375ZM6.73224 -3.46391e-07L5.55824 -3.97708e-07L5.55824 6.7505L2.23802 6.7505L3.30196 5.69573C3.42922 5.57191 3.49342 5.3965 3.47622 5.2188C3.45673 4.98835 3.3054 4.79116 3.08756 4.71434C2.86973 4.63638 2.62668 4.69485 2.46732 4.86109L0.412816 6.91559L8.16953e-05 7.3375L2.46732 9.80473C2.69776 10.0352 3.07151 10.0352 3.30196 9.80473C3.5324 9.57429 3.5324 9.20054 3.30196 8.97009L2.25636 7.9245L5.55824 7.9245L5.55824 14.675L6.73224 14.675L6.73224 -3.46391e-07Z" fill="currentColor"/></svg>`,
14
+ double: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M7.99986 13.1201C8.04486 13.1201 8.08736 13.1089 8.12986 13.0901L15.1699 9.89012C15.2836 9.83887 15.3599 9.72512 15.3599 9.60012L15.3599 7.68012C15.3599 7.57137 15.3011 7.46887 15.2099 7.41012C15.1186 7.35137 15.0086 7.34512 14.9099 7.39012L7.99986 10.5301L1.08986 7.39012C1.04736 7.37012 1.00486 7.36012 0.959863 7.36012C0.899863 7.36012 0.842363 7.37637 0.789863 7.41012C0.698614 7.46887 0.639863 7.57137 0.639863 7.68012L0.639864 9.60012C0.639864 9.72512 0.714863 9.83887 0.829863 9.89012L7.86986 13.0901C7.91236 13.1089 7.95486 13.1201 7.99986 13.1201ZM7.99986 8.64012C8.04486 8.64012 8.08736 8.62887 8.12986 8.61012L15.1699 5.41012C15.2836 5.35887 15.3599 5.24637 15.3599 5.12012L15.3599 3.20012C15.3599 3.09137 15.3011 2.98887 15.2099 2.93012C15.1186 2.87137 15.0086 2.86387 14.9099 2.91012L7.99986 6.05012L1.08986 2.91012C1.04736 2.89012 1.00486 2.88012 0.959863 2.88012C0.899862 2.88012 0.842362 2.89637 0.789863 2.93012C0.698613 2.98887 0.639863 3.09137 0.639863 3.20012L0.639863 5.12012C0.639863 5.24637 0.714863 5.35887 0.829863 5.41012L7.86986 8.61012C7.91236 8.62887 7.95486 8.64012 7.99986 8.64012Z" fill="currentColor"/></svg>`,
15
+ stand: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 12.2667 13.8667" fill="none"><path d="M7.2 0C6.7584 0 6.4 0.3584 6.4 0.8V5.86667H5.86667V1.86667C5.86667 1.42507 5.50827 1.06667 5.06667 1.06667C4.62507 1.06667 4.26667 1.42507 4.26667 1.86667V5.86667V7.46667V9.48021C4.26667 9.48021 2.73062 8.48653 1.95729 8.15C1.74182 8.05613 1.51681 8 1.28854 8C0.095475 8 0 9.06667 0 9.06667L2.13333 10.6667L3.84062 12.7156C4.44862 13.4452 5.34962 13.8667 6.29896 13.8667H10.1333C11.3115 13.8667 12.2667 12.9115 12.2667 11.7333V5.86667V3.46667C12.2667 3.02507 11.9083 2.66667 11.4667 2.66667C11.0251 2.66667 10.6667 3.02507 10.6667 3.46667V5.86667H10.1333V1.86667C10.1333 1.42507 9.77493 1.06667 9.33333 1.06667C8.89173 1.06667 8.53333 1.42507 8.53333 1.86667V5.86667H8V0.8C8 0.3584 7.6416 0 7.2 0Z" fill="currentColor"/></svg>`,
16
+ hit: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 11 14" fill="none"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.912 7.25265C11.0293 7.09767 11.0293 6.90233 10.912 6.74735L5.98391 0.235724C5.87228 0.0885616 5.67346 -0.000647622 5.45834 3.54045e-06C5.24404 0.000654703 5.04522 0.0911663 4.93522 0.238329L0.0861683 6.74995C-0.0287228 6.90428 -0.0287228 7.09572 0.0861683 7.25005L4.93522 13.7617C5.04522 13.9088 5.24404 13.9993 5.45834 14C5.67346 14.0006 5.87228 13.9114 5.98391 13.7643L10.912 7.25265Z" fill="currentColor"/></svg>`,
17
+ x: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3.13802 2.19531L2.19531 3.13802L7.05729 8L2.19531 12.862L3.13802 13.8047L8 8.94271L12.862 13.8047L13.8047 12.862L8.94271 8L13.8047 3.13802L12.862 2.19531L8 7.05729L3.13802 2.19531Z" fill="currentColor"/></svg>`,
18
+ check: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M13.4201 2.76046C13.2076 2.76796 13.0126 2.88046 12.9001 3.06046L6.88006 12.2705L2.98006 8.90046C2.81256 8.72671 2.56131 8.66171 2.33006 8.73421C2.10006 8.80546 1.92881 9.00046 1.88881 9.23796C1.84881 9.47671 1.94506 9.71671 2.14006 9.86046L6.60006 13.7205C6.74006 13.8392 6.92506 13.8917 7.10631 13.8655C7.28881 13.838 7.45006 13.7342 7.55006 13.5805L13.9801 3.76046C14.1176 3.55921 14.1288 3.29921 14.0101 3.08671C13.8913 2.87546 13.6626 2.74921 13.4201 2.76046Z" fill="currentColor"/></svg>`,
19
+ logout: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M5.33333 1.33301C4.59667 1.33301 4 1.92967 4 2.66634V13.333C4 14.0697 4.59667 14.6663 5.33333 14.6663H10.6667C11.4033 14.6663 12 14.0697 12 13.333V8.66634H7.33333V7.33301H12V2.66634C12 1.92967 11.4033 1.33301 10.6667 1.33301H5.33333ZM12 7.33301V8.66634H13.3333V10.6663L16 7.99967L13.3333 5.33301V7.33301H12Z" fill="currentColor"/></svg>`,
20
+ sound: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M9.16829 2.5L4.16829 7.5H2.50163C1.58079 7.5 0.834961 8.24583 0.834961 9.16667V10.8333C0.834961 11.7542 1.58079 12.5 2.50163 12.5H4.16829L9.16829 17.5V2.5ZM13.8818 5.28646L12.7035 6.46484C14.6634 8.42477 14.6632 11.5761 12.7035 13.5352L13.8818 14.7135C16.4788 12.1176 16.4786 7.8832 13.8818 5.28646ZM11.5251 7.64323L10.3467 8.82162C11.0051 9.48002 11.0051 10.52 10.3467 11.1784L11.5251 12.3584C12.82 11.0635 12.82 8.93815 11.5251 7.64323Z" fill="currentColor"/></svg>`,
21
+ eye: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M11.9999 4C5.14188 4 1.88558 9.87864 1.09558 11.5566C0.963582 11.8366 0.963582 12.1614 1.09558 12.4414C1.88558 14.1204 5.14188 20 11.9999 20C18.8339 20 22.0924 14.1629 22.8964 12.4609C23.0344 12.1679 23.0344 11.8321 22.8964 11.5391C22.0924 9.83706 18.8339 4 11.9999 4ZM11.9999 7C14.7609 7 16.9999 9.239 16.9999 12C16.9999 14.761 14.7609 17 11.9999 17C9.23888 17 6.99988 14.761 6.99988 12C6.99988 9.239 9.23888 7 11.9999 7ZM11.9999 9C11.2042 9 10.4412 9.31607 9.87856 9.87868C9.31595 10.4413 8.99988 11.2044 8.99988 12C8.99988 12.7956 9.31595 13.5587 9.87856 14.1213C10.4412 14.6839 11.2042 15 11.9999 15C12.7955 15 13.5586 14.6839 14.1212 14.1213C14.6838 13.5587 14.9999 12.7956 14.9999 12C14.9999 11.2044 14.6838 10.4413 14.1212 9.87868C13.5586 9.31607 12.7955 9 11.9999 9Z" fill="currentColor"/></svg>`,
22
+ rules: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3.33325 2C2.23661 2 1.33325 2.90335 1.33325 4V6H3.33325V12C3.33325 13.0966 4.23661 14 5.33325 14H12.6666C13.7632 14 14.6666 13.0966 14.6666 12V10H11.9999V4C11.9999 2.90335 11.0966 2 9.99992 2H3.33325ZM3.33325 3.33333H8.27726C8.18591 3.56134 7.99992 3.7411 7.99992 4V4.66667H2.66659V4C2.66659 3.62331 2.95657 3.33333 3.33325 3.33333ZM5.33325 7.33333H9.99992V8.66667H5.33325V7.33333ZM5.33325 10H9.99992V11.3333H5.33325V10ZM11.9999 11.3333H13.3333V12C13.3333 12.3767 13.0433 12.6667 12.6666 12.6667C12.2899 12.6667 11.9999 12.3767 11.9999 12V11.3333Z" fill="currentColor"/></svg>`,
23
+ copy: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 1C3.44772 1 3 1.44772 3 2V11C3 11.5523 3.44772 12 4 12H12C12.5523 12 13 11.5523 13 11V2C13 1.44772 12.5523 1 12 1H4ZM4 2.5H12V11H4V2.5ZM1 5V14C1 14.5523 1.44772 15 2 15H11V13.5H2.5V5H1Z" fill="currentColor"/></svg>`,
24
+ info: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1ZM8 2.5C11.0376 2.5 13.5 4.96243 13.5 8C13.5 11.0376 11.0376 13.5 8 13.5C4.96243 13.5 2.5 11.0376 2.5 8C2.5 4.96243 4.96243 2.5 8 2.5ZM7.25 4.5V6H8.75V4.5H7.25ZM7.25 7V11.5H8.75V7H7.25Z" fill="currentColor"/></svg>`,
25
+ user: `<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.477 2 2 6.477 2 12C2 17.523 6.477 22 12 22C17.523 22 22 17.523 22 12C22 6.477 17.523 2 12 2ZM12 4.75C13.795 4.75 15.25 6.205 15.25 8C15.25 9.795 13.795 11.25 12 11.25C10.205 11.25 8.75 9.795 8.75 8C8.75 6.205 10.205 4.75 12 4.75ZM12 20C9.23 20 6.79 18.592 5.354 16.453C6.475 14.823 10.046 14 12 14C13.954 14 17.525 14.823 18.646 16.453C17.21 18.592 14.77 20 12 20Z" fill="currentColor"/></svg>`,
26
+ wallet: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 2C2.90335 2 2 2.90335 2 4V12.6667C2 13.4033 2.59667 14 3.33333 14H12.6667C13.4033 14 14 13.4033 14 12.6667V6C14 5.26333 13.4033 4.66667 12.6667 4.66667H5.33333H4C3.62331 4.66667 3.33333 4.37669 3.33333 4C3.33333 3.62331 3.62331 3.33333 4 3.33333H13.3333V2H4ZM12 8.66667C12.368 8.66667 12.6667 8.96533 12.6667 9.33333C12.6667 9.70133 12.368 10 12 10C11.632 10 11.3333 9.70133 11.3333 9.33333C11.3333 8.96533 11.632 8.66667 12 8.66667Z" fill="currentColor"/></svg>`,
27
+ "chevron-down": `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4.23552 5L3 6.18885L8 11L13 6.18885L11.7645 5L8 8.62229L4.23552 5Z" fill="currentColor"/></svg>`,
28
+ };
29
+
30
+ const getCustomIcon = (iconName: string): string | undefined => {
31
+ return ICONS[iconName];
32
+ };
33
+
34
+ type IconProps = React.HTMLAttributes<HTMLDivElement> & {
35
+ icon: string;
36
+ width?: string | number;
37
+ height?: string | number;
38
+ color?: string;
39
+ };
40
+
41
+ const PRESERVE_COLORS_ICONS = new Set([""]);
42
+
43
+ export const Icon: React.FC<IconProps> = ({
44
+ icon,
45
+ className = "",
46
+ width,
47
+ height,
48
+ color,
49
+ ...props
50
+ }) => {
51
+ const customSvg = getCustomIcon(icon);
52
+
53
+ if (customSvg) {
54
+ const shouldPreserveColors = PRESERVE_COLORS_ICONS.has(icon);
55
+
56
+ let processedSvg = customSvg
57
+ .replace(/\swidth="[^"]*"/g, ' width="100%"')
58
+ .replace(/\sheight="[^"]*"/g, ' height="100%"')
59
+ .replace(/\sclass="[^"]*"/g, "")
60
+ .replace(/\sstyle="[^"]*"/g, "");
61
+
62
+ if (!shouldPreserveColors) {
63
+ processedSvg = processedSvg
64
+ .replace(
65
+ /fill="(?!none|url\(|currentColor)[^"]*"/g,
66
+ 'fill="currentColor"',
67
+ )
68
+ .replace(
69
+ /stroke="(?!none|url\(|currentColor)[^"]*"/g,
70
+ 'stroke="currentColor"',
71
+ );
72
+ }
73
+
74
+ return (
75
+ <div
76
+ className={cn(className)}
77
+ style={{
78
+ display: "inline-flex",
79
+ alignItems: "center",
80
+ justifyContent: "center",
81
+ minWidth: width,
82
+ minHeight: height,
83
+ width,
84
+ height,
85
+ ...(color && { color }),
86
+ }}
87
+ dangerouslySetInnerHTML={{ __html: processedSvg }}
88
+ {...props}
89
+ />
90
+ );
91
+ }
92
+
93
+ return null;
94
+ };
@@ -0,0 +1,192 @@
1
+ import { cn } from "../lib/utils";
2
+ import cardBackImg from "../assets/card-back.svg";
3
+
4
+ export type Suit = "club" | "diamond" | "heart" | "spade";
5
+ export type Rank =
6
+ | "A"
7
+ | "2"
8
+ | "3"
9
+ | "4"
10
+ | "5"
11
+ | "6"
12
+ | "7"
13
+ | "8"
14
+ | "9"
15
+ | "10"
16
+ | "J"
17
+ | "Q"
18
+ | "K";
19
+
20
+ const BADGE_COLORS = {
21
+ default: "border-card-border",
22
+ push: "border-card-border",
23
+ win: "border-[#8BB339]",
24
+ lose: "border-[#DB375E]",
25
+ bust: "border-[#DB375E]",
26
+ blackjack: "border-[#FF5C05]",
27
+ even: "border-card-border",
28
+ surrender: "border-card-border",
29
+ };
30
+
31
+ interface PokerCardProps {
32
+ suit?: Suit;
33
+ rank?: Rank;
34
+ side?: "front" | "back";
35
+ backImage?: string;
36
+ className?: string; // Can bypass to customize the card size
37
+ showShadow?: boolean;
38
+ size?: "xs" | "sm" | "md" | "lg";
39
+ type?:
40
+ | "default"
41
+ | "win"
42
+ | "lose"
43
+ | "bust"
44
+ | "blackjack"
45
+ | "push"
46
+ | "even"
47
+ | "surrender";
48
+ }
49
+
50
+ const SUIT_SVGS: Record<Suit, string> = {
51
+ heart: `<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21" fill="none"><path d="M13.8295 3.98242C12.7564 3.98242 11.7463 4.40032 10.9871 5.16052L10.4999 5.64772L10.0127 5.16052C9.2525 4.40032 8.24345 3.98242 7.17035 3.98242C4.95275 3.98242 3.1499 5.78527 3.1499 8.00287C3.1499 9.07597 3.5678 10.0861 4.328 10.8452L10.4999 17.0171L16.6718 10.8452C17.432 10.085 17.8499 9.07597 17.8499 8.00287C17.8499 5.78527 16.0471 3.98242 13.8295 3.98242ZM15.1871 9.36052L10.4999 14.0477L5.8127 9.36052C5.4494 8.99722 5.2499 8.51527 5.2499 8.00287C5.2499 6.94342 6.1109 6.08242 7.17035 6.08242C7.68275 6.08242 8.1647 6.28192 8.528 6.64522L10.4999 8.61712L12.4718 6.64522C12.8351 6.28192 13.3171 6.08242 13.8295 6.08242C14.8889 6.08242 15.7499 6.94342 15.7499 8.00287C15.7499 8.51527 15.5504 8.99722 15.1871 9.36052Z" fill="currentColor"/><path d="M15.1871 9.36052L10.4999 14.0477L5.8127 9.36052C5.4494 8.99722 5.2499 8.51527 5.2499 8.00287C5.2499 6.94342 6.1109 6.08242 7.17035 6.08242C7.68275 6.08242 8.1647 6.28192 8.528 6.64522L10.4999 8.61712L12.4718 6.64522C12.8351 6.28192 13.3171 6.08242 13.8295 6.08242C14.8889 6.08242 15.7499 6.94342 15.7499 8.00287C15.7499 8.51527 15.5504 8.99722 15.1871 9.36052Z" fill="currentColor"/></svg>`,
52
+ spade: `<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21" fill="none">
53
+ <path d="M10.4999 2.93262L4.328 9.10452C3.5678 9.86472 3.1499 10.8738 3.1499 11.9469C3.1499 14.1645 4.95275 15.9673 7.17035 15.9673C7.99775 15.9673 8.7842 15.7132 9.4499 15.2523V18.0673H11.5499V15.2523C12.2156 15.7132 13.0021 15.9673 13.8295 15.9673C16.0471 15.9673 17.8499 14.1645 17.8499 11.9469C17.8499 10.8738 17.432 9.86367 16.6718 9.10452L10.4999 2.93262ZM13.8295 13.8673C13.3171 13.8673 12.8351 13.6678 12.4718 13.3045L10.4999 11.3326L8.528 13.3045C8.1647 13.6678 7.68275 13.8673 7.17035 13.8673C6.1109 13.8673 5.2499 13.0063 5.2499 11.9469C5.2499 11.4345 5.4494 10.9525 5.8127 10.5892L10.4999 5.90202L15.1871 10.5892C15.5504 10.9525 15.7499 11.4345 15.7499 11.9469C15.7499 13.0063 14.8889 13.8673 13.8295 13.8673Z" fill="currentColor"/>
54
+ <path d="M13.8295 13.8673C13.3171 13.8673 12.8351 13.6678 12.4718 13.3045L10.4999 11.3326L8.528 13.3045C8.1647 13.6678 7.68275 13.8673 7.17035 13.8673C6.1109 13.8673 5.2499 13.0063 5.2499 11.9469C5.2499 11.4345 5.4494 10.9525 5.8127 10.5892L10.4999 5.90202L15.1871 10.5892C15.5504 10.9525 15.7499 11.4345 15.7499 11.9469C15.7499 13.0063 14.8889 13.8673 13.8295 13.8673Z" fill="currentColor"/>
55
+ </svg>`,
56
+ diamond: `<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 15 15" fill="none"><path d="M2.01221 7.50041L7.49996 13.9032L12.9877 7.50041L7.49996 1.09766L2.01221 7.50041ZM7.49996 11.5977L3.98771 7.50041L7.49996 3.40315L11.0122 7.50041L7.49996 11.5977Z" fill="currentColor"/><path d="M7.49996 11.5977L3.98771 7.50041L7.49996 3.40315L11.0122 7.50041L7.49996 11.5977Z" fill="currentColor"/></svg>`,
57
+ club: `<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21" fill="none">
58
+ <path d="M14.6978 7.48269C14.6989 7.43859 14.6999 7.39449 14.6999 7.35039C14.6999 5.03409 12.8162 3.15039 10.4999 3.15039C8.1836 3.15039 6.2999 5.03409 6.2999 7.35039C6.2999 7.39449 6.30095 7.43859 6.302 7.48269C4.4918 7.94889 3.1499 9.59634 3.1499 11.5504C3.1499 13.8667 5.0336 15.7504 7.3499 15.7504C8.11955 15.7504 8.82935 15.5236 9.4499 15.1603V17.8504H11.5499V15.1603C12.1705 15.5236 12.8803 15.7504 13.6499 15.7504C15.9662 15.7504 17.8499 13.8667 17.8499 11.5504C17.8499 9.59634 16.508 7.94889 14.6978 7.48269ZM13.6499 13.6504C12.4918 13.6504 11.5499 12.7085 11.5499 11.5504H9.4499C9.4499 12.7085 8.50805 13.6504 7.3499 13.6504C6.19175 13.6504 5.2499 12.7085 5.2499 11.5504C5.2499 10.3922 6.1907 9.45039 7.3184 9.45039L9.0803 9.56484L8.53535 8.06124C8.444 7.81029 8.3999 7.57719 8.3999 7.35039C8.3999 6.19224 9.34175 5.25039 10.4999 5.25039C11.6581 5.25039 12.5999 6.19224 12.5999 7.35039C12.5999 7.57719 12.5558 7.81029 12.4645 8.06229L11.9195 9.56589L13.5155 9.46824L13.6499 9.45039C14.8081 9.45039 15.7499 10.3922 15.7499 11.5504C15.7499 12.7085 14.8081 13.6504 13.6499 13.6504Z" fill="currentColor"/>
59
+ <path d="M13.6499 13.6504C12.4918 13.6504 11.5499 12.7085 11.5499 11.5504H9.4499C9.4499 12.7085 8.50805 13.6504 7.3499 13.6504C6.19175 13.6504 5.2499 12.7085 5.2499 11.5504C5.2499 10.3922 6.1907 9.45039 7.3184 9.45039L9.0803 9.56484L8.53535 8.06124C8.444 7.81029 8.3999 7.57719 8.3999 7.35039C8.3999 6.19224 9.34175 5.25039 10.4999 5.25039C11.6581 5.25039 12.5999 6.19224 12.5999 7.35039C12.5999 7.57719 12.5558 7.81029 12.4645 8.06229L11.9195 9.56589L13.5155 9.46824L13.6499 9.45039C14.8081 9.45039 15.7499 10.3922 15.7499 11.5504C15.7499 12.7085 14.8081 13.6504 13.6499 13.6504Z" fill="currentColor"/>
60
+ </svg>`,
61
+ };
62
+
63
+ const SUIT_CONFIG: Record<Suit, { colorClass: string }> = {
64
+ heart: { colorClass: "text-card-suit-red" },
65
+ diamond: { colorClass: "text-card-suit-red" },
66
+ spade: { colorClass: "text-card-suit-black" },
67
+ club: { colorClass: "text-card-suit-black" },
68
+ };
69
+
70
+ function SuitIcon({ suit, className }: { suit: Suit; className?: string }) {
71
+ const suitSvg = SUIT_SVGS[suit];
72
+ if (!suitSvg) {
73
+ return null;
74
+ }
75
+
76
+ const processedSvg = suitSvg
77
+ .replace(/\swidth="[^"]*"/g, ' width="100%"')
78
+ .replace(/\sheight="[^"]*"/g, ' height="100%"')
79
+ .replace(/\sclass="[^"]*"/g, "")
80
+ .replace(/\sstyle="[^"]*"/g, "");
81
+
82
+ return (
83
+ <div
84
+ className={className}
85
+ dangerouslySetInnerHTML={{
86
+ __html: processedSvg,
87
+ }}
88
+ />
89
+ );
90
+ }
91
+
92
+ export function PokerCard({
93
+ suit,
94
+ rank,
95
+ side = "front",
96
+ backImage,
97
+ className,
98
+ showShadow = true,
99
+ size = "lg",
100
+ type = "default",
101
+ }: PokerCardProps) {
102
+ const isXs = size === "xs";
103
+ const isMd = size === "md";
104
+ const isSmall = size === "sm";
105
+ const sizeClass = isXs
106
+ ? "w-6 h-8.5 rounded-[4px]"
107
+ : isSmall
108
+ ? "w-7 h-10 rounded-[4px]"
109
+ : isMd
110
+ ? "w-9 h-12.5 rounded-[4.62px]"
111
+ : "w-10 h-14 rounded-[4.62px]";
112
+ const shadow = isXs
113
+ ? "drop-shadow(0px 1px 0px #404040)"
114
+ : "drop-shadow(0px 2px 0px #404040)";
115
+ const backShadow = isXs
116
+ ? "drop-shadow(0px 1px 0px #122741)"
117
+ : "drop-shadow(0px 2px 0px #122741)";
118
+ const badgeColor = BADGE_COLORS[type];
119
+
120
+ if (side === "back") {
121
+ return (
122
+ <div
123
+ className={cn(
124
+ "relative bg-card-back-bg border overflow-clip",
125
+ badgeColor,
126
+ sizeClass,
127
+ className,
128
+ )}
129
+ style={{
130
+ filter: showShadow ? backShadow : "none",
131
+ }}
132
+ >
133
+ <div className="absolute inset-0">
134
+ <img
135
+ src={backImage ?? cardBackImg}
136
+ alt=""
137
+ className="absolute inset-0 size-full object-cover pointer-events-none"
138
+ />
139
+ </div>
140
+ </div>
141
+ );
142
+ }
143
+
144
+ if (!suit || !rank) return null;
145
+
146
+ const { colorClass } = SUIT_CONFIG[suit];
147
+
148
+ return (
149
+ <div
150
+ className={cn(
151
+ "relative bg-white border overflow-clip",
152
+ badgeColor,
153
+ sizeClass,
154
+ className,
155
+ )}
156
+ style={{
157
+ containerType: "inline-size",
158
+ filter: showShadow ? shadow : "none",
159
+ }}
160
+ >
161
+ {/* Rank text */}
162
+ <span
163
+ className={cn(
164
+ "absolute top-[2%] w-[35%] text-center font-bold leading-none",
165
+ colorClass,
166
+ rank === "10" ? "-tracking-[1.8px] left-[3%]" : "left-[10%]",
167
+ )}
168
+ style={{ fontSize: "50cqi" }}
169
+ >
170
+ {rank}
171
+ </span>
172
+
173
+ {/* Small suit icon - top right */}
174
+ <SuitIcon
175
+ suit={suit}
176
+ className={cn(
177
+ "absolute top-[8%] right-[8%] w-[37.5%] aspect-square",
178
+ colorClass,
179
+ )}
180
+ />
181
+
182
+ {/* Large suit icon - bottom left */}
183
+ <SuitIcon
184
+ suit={suit}
185
+ className={cn(
186
+ "absolute bottom-[6%] left-[3%] w-[52.5%] aspect-square",
187
+ colorClass,
188
+ )}
189
+ />
190
+ </div>
191
+ );
192
+ }