@zhuweiyou/dsh-holdem 0.1.0 → 0.1.2

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.
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["ZH: Record<string, string>","EN: Record<string, string>","translator: Translate","name","seatTokens: string[]","name","state: ClientState","socket: WebSocket | null","pollTimer: ReturnType<typeof setInterval> | undefined","reconnectTimer: ReturnType<typeof setTimeout> | undefined","toastTimer: ReturnType<typeof setTimeout> | undefined","ws: WebSocket","session: Awaited<ReturnType<typeof api.session>> | null","HOSTING_OPTIONS: HostingOption[]","name","css","state","name","css","css","lines: string[]","presets: { label: string; value: number }[]","css","css","SUIT_SYMBOL: Record<string, string>","css","css","css","state","css","state","css"],"sources":["../src/invariant.ts","../src/client/i18n.ts","../src/client/api.ts","../src/client/presence.ts","../src/client/store.ts","../src/client/backends.ts","../src/client/ui.ts","../src/client/CloudflarePanel.tsx","../src/client/Lobby.tsx","../src/client/Settlement.tsx","../src/client/ActionBar.tsx","../src/client/InviteSheet.tsx","../src/client/CardView.tsx","../src/client/SeatPod.tsx","../src/client/SideRail.tsx","../src/client/Table.tsx","../src/client/HoldemPanel.tsx","../src/client/PanelIcon.tsx","../src/client/slots.tsx","../src/client/index.tsx"],"sourcesContent":["/** 全局常量:协议、上限、时间与筹码档位。 */\n\nexport const PACKAGE_NAME = '@zhuweiyou/dsh-holdem'\nexport const CLIENT_ID = '@zhuweiyou/dsh-holdem'\nexport const PANEL_KEY = 'holdem'\nexport const SUBPROTOCOL = 'holdem.v1'\nexport const ROUTE_PREFIX = '/holdem'\n\nexport const MAX_SEATS = 6\nexport const MAX_SPECTATORS = 16\nexport const MAX_ROOMS = 8\nexport const MAX_TITLE = 24\nexport const MAX_DISPLAY_NAME = 16\nexport const MAX_CHAT = 80\nexport const MAX_CHAT_LINES = 80\nexport const MAX_HISTORY_HANDS = 50\nexport const MAX_CACHED_ACTIONS = 64\nexport const MAX_BODY_BYTES = 64 * 1024\nexport const MAX_FRAME_BYTES = 64 * 1024\n\nexport const TICK_MS = 250\nexport const WS_TICKET_TTL_MS = 60_000\nexport const SESSION_TTL_MS = 24 * 60 * 60 * 1000\nexport const HEARTBEAT_MS = 15_000\nexport const DISCONNECT_AFTER_MS = 45_000\nexport const LOBBY_KICK_IDLE_MS = 10 * 60 * 1000\nexport const CHAT_COOLDOWN_MS = 1200\nexport const ACTION_RATE_WINDOW_MS = 10_000\nexport const ACTION_RATE_MAX = 30\n\nexport const BUY_IN_BB = 100\nexport const ALL_IN_RUNOUT_MS = 1200\nexport const HAND_OVER_MIN_MS = 2500\n\nexport const BLIND_LEVELS = [\n { id: '10/20', sb: 10, bb: 20 },\n { id: '25/50', sb: 25, bb: 50 },\n { id: '100/200', sb: 100, bb: 200 },\n] as const\n\nexport type BlindLevelId = (typeof BLIND_LEVELS)[number]['id']\n\nexport function blindsFor(id: string): { id: BlindLevelId; sb: number; bb: number } {\n const found = BLIND_LEVELS.find((level) => level.id === id)\n const level = found ?? BLIND_LEVELS[1]!\n return { id: level.id, sb: level.sb, bb: level.bb }\n}\n\nexport function buyInFor(bb: number): number {\n return bb * BUY_IN_BB\n}\n","export type Translate = (key: string, params?: Record<string, string | number>) => string\n\nconst ZH: Record<string, string> = {\n 'panel.title': '德州扑克',\n 'panel.subtitle': '房主即服务端 · 娱乐筹码',\n 'common.loading': '正在准备牌桌…',\n 'common.cancel': '取消',\n 'common.confirm': '确定',\n 'common.copy': '复制',\n 'common.copied': '已复制',\n 'common.close': '关闭',\n 'common.name': '昵称',\n 'common.retry': '重试',\n 'common.back': '返回大厅',\n 'common.leave': '离开',\n 'common.players': '{n} 人',\n 'common.spectators': '观战 {n}',\n 'lobby.create': '创建房间',\n 'lobby.join': '加入房间',\n 'host.label': '开桌位置',\n 'host.local': '本机',\n 'host.localHint': '跑在你自己的 dsh 里;同一 Wi-Fi 的朋友用局域网链接加入,不需要公网。',\n 'host.cloudflare': '公网 · Cloudflare',\n 'host.cloudflareHint': '牌桌跑在 Cloudflare Worker 上,关掉你的电脑也能玩;点一下授权 → 自动部署,之后建房直接用。',\n 'host.needCloudflare': '先授权并部署 Cloudflare,再开桌',\n 'cf.needAuth': '还没授权 Cloudflare',\n 'cf.waiting': '等待浏览器授权…',\n 'cf.cancel': '取消授权',\n 'cf.authorized': '已授权 {account}',\n 'cf.authorize': '授权 Cloudflare',\n 'cf.deploy': '部署到 Cloudflare',\n 'cf.redeploy': '重新部署',\n 'cf.deploying': '部署中…',\n 'cf.switchAccount': '换账号',\n 'cf.address': '云端地址',\n 'cf.authHint': '浏览器没有自动打开时(授权页一般会自动弹),复制这个链接到浏览器:',\n 'cf.unreachable': '拿不到 Cloudflare 状态(插件可能刚重载)',\n 'lobby.title': '房间名',\n 'lobby.titlePlaceholder': '例如 周五晚场',\n 'lobby.blinds': '盲注',\n 'lobby.namePlaceholder': '你的昵称',\n 'lobby.createAction': '开一桌',\n 'lobby.linkOnly': '邀请链接',\n 'lobby.linkOnlyPlaceholder': '粘贴房主发来的邀请链接',\n 'lobby.needLink': '粘贴房主发来的邀请链接(只认链接,没有房号)',\n 'lobby.joinFailed': '加入失败({where}):{message}',\n 'lobby.linkHint': '链接里已经带着这桌在哪儿(本机 / 局域网 / Cloudflare),所以不用填房号。',\n 'lobby.enter': '进入牌桌',\n 'lobby.preview': '查看房间',\n 'lobby.sit': '入座',\n 'lobby.watch': '观战',\n 'lobby.invited': '你被邀请加入房间 {code}',\n 'lobby.full': '座位已满,会以观战身份进入',\n 'lobby.needCode': '请输入 6 位房号',\n 'lobby.needName': '请先填昵称',\n 'lobby.hintPrefix': '开桌时可选 Cloudflare(公网牌桌,关掉电脑也能玩)或本机(同一 Wi-Fi 内分享);把邀请链接发过去,对方用浏览器打开就能加入。想自己开桌再装 ',\n 'lobby.hintSuffix': '。',\n 'lobby.seated': '已在座 {n}/6',\n 'lobby.phase.lobby': '等待开局',\n 'lobby.phase.hand': '正在打牌',\n 'table.room': '房号 {code}',\n 'table.hand': '第 {n} 手',\n 'table.blinds': '{sb}/{bb} · 带入 {buyIn}',\n 'table.copyInvite': '复制邀请链接',\n 'table.invite': '邀请好友',\n 'table.copyCode': '复制房号',\n 'invite.title': '邀请好友入桌',\n 'invite.copy': '复制',\n 'invite.copied': '已复制',\n 'invite.copyCode': '复制房号',\n 'table.pause': '暂停',\n 'table.dissolve': '解散并结算',\n 'table.dissolveConfirm': '解散房间并生成总结算?',\n 'table.waiting': '等待房主开局',\n 'table.waitingReady': '等待其他玩家准备',\n 'table.ready': '准备',\n 'table.unready': '取消准备',\n 'table.start': '开始',\n 'table.hideRail': '收起侧栏',\n 'table.showRail': '侧栏',\n 'table.kick': '踢出',\n 'table.kickConfirm': '把 {name} 请出房间?',\n 'table.stand': '离座',\n 'table.sitDown': '入座',\n 'table.spectating': '观战中',\n 'table.you': '你',\n 'table.host': '房主',\n 'table.dealer': 'D',\n 'table.sb': 'SB',\n 'table.bb': 'BB',\n 'table.emptySeats': '还有 {n} 个空位',\n 'table.folded': '已弃牌',\n 'table.allin': '全下',\n 'table.offline': '离线',\n 'table.autofold': '托管',\n 'table.sittingOut': '暂离',\n 'table.pot': '底池 {amount}',\n 'table.potMain': '主池',\n 'table.potSide': '边池 {n}',\n 'table.street.preflop': '翻牌前',\n 'table.street.flop': '翻牌',\n 'table.street.turn': '转牌',\n 'table.street.river': '河牌',\n 'table.street.showdown': '摊牌',\n 'table.yourTurn': '轮到你了',\n 'table.waitTurn': '等待 {name} 行动',\n 'table.fold': '弃牌',\n 'table.check': '过牌',\n 'table.call': '跟注 {amount}',\n 'table.raise': '加注',\n 'table.bet': '下注',\n 'table.raiseTo': '加注到 {amount}',\n 'table.allinAction': '全下',\n 'table.halfPot': '1/2 池',\n 'table.twoThirds': '2/3 池',\n 'table.potBet': '一池',\n 'table.min': '最小',\n 'table.max': '最大',\n 'table.timer': '{s} 秒',\n 'table.spectatorHint': '观战模式:看不到任何未亮出的底牌,有人离座后可以补位。',\n 'table.noSeat': '你还没有入座',\n 'table.winner': '{name} 赢得 {amount}',\n 'table.foldWin': '其余玩家弃牌',\n 'table.nextHand': '{s} 秒后开始下一手',\n 'table.paused': '已暂停,等待房主开始',\n 'rail.leaderboard': '排行榜',\n 'rail.history': '最近手牌',\n 'rail.chat': '桌边聊天',\n 'rail.spectators': '观战席',\n 'rail.empty': '还没有记录',\n 'rail.hands': '{n} 手',\n 'rail.net': '净赢',\n 'rail.wins': '胜',\n 'rail.chatPlaceholder': '说点什么…',\n 'rail.send': '发送',\n 'rail.chatOff': '本桌已关闭聊天',\n 'rail.noSpectators': '暂时没有人观战',\n 'settle.title': '本场结算',\n 'settle.dissolved': '房主已解散房间',\n 'settle.idle': '房主长时间无响应,房间自动解散',\n 'settle.rank': '名次',\n 'settle.player': '玩家',\n 'settle.hands': '手数',\n 'settle.wins': '胜局',\n 'settle.net': '净赢',\n 'settle.bb100': 'BB/100',\n 'settle.showdown': '摊牌胜率',\n 'settle.duration': '时长 {m} 分钟 · 共 {hands} 手',\n 'settle.copy': '复制战绩',\n 'settle.download': '下载 JSON',\n 'settle.again': '再来一局',\n 'settle.backHome': '返回大厅(可重新开房)',\n 'settle.empty': '这一场还没有打完任何一手。',\n 'error.generic': '出了点问题',\n 'error.connection': '与房主的连接中断,正在重连…',\n 'error.stale': '状态已更新,已为你刷新',\n 'error.notYourTurn': '还没轮到你',\n 'error.roomGone': '房间已解散',\n 'error.noSeatCookie': '浏览器没有保存牌桌凭证(cookie 被拦或没带上),刷新页面后再试',\n 'error.kicked': '你被房主请出了房间',\n 'toast.joined': '已进入房间 {code}',\n 'toast.created': '房间已创建:{code}',\n 'toast.duplicate': '操作已生效',\n 'toast.switched': '已切换到房间 {code}',\n 'toast.left': '已离开房间',\n 'toast.settlement': '本场已结算',\n}\n\nconst EN: Record<string, string> = {\n 'panel.title': \"Hold'em\",\n 'panel.subtitle': 'Host is the server · play chips',\n 'common.loading': 'Preparing the table…',\n 'common.cancel': 'Cancel',\n 'common.confirm': 'Confirm',\n 'common.copy': 'Copy',\n 'common.copied': 'Copied',\n 'common.close': 'Close',\n 'common.name': 'Name',\n 'common.retry': 'Retry',\n 'common.back': 'Back to lobby',\n 'common.leave': 'Leave',\n 'common.players': '{n} players',\n 'common.spectators': '{n} watching',\n 'lobby.create': 'Create room',\n 'lobby.join': 'Join room',\n 'host.label': 'Where to host',\n 'host.local': 'This machine',\n 'host.localHint': 'Runs inside your own dsh: friends on the same Wi-Fi join through the LAN link; nothing is exposed publicly.',\n 'host.cloudflare': 'Public · Cloudflare',\n 'host.cloudflareHint': 'Rooms run on a Cloudflare Worker — play even with your laptop off. Authorize once, deploy automatically.',\n 'host.needCloudflare': 'Authorize and deploy Cloudflare first',\n 'cf.needAuth': 'Cloudflare not connected',\n 'cf.waiting': 'Waiting for the browser…',\n 'cf.cancel': 'Cancel',\n 'cf.authorized': 'Connected as {account}',\n 'cf.authorize': 'Authorize Cloudflare',\n 'cf.deploy': 'Deploy to Cloudflare',\n 'cf.redeploy': 'Redeploy',\n 'cf.deploying': 'Deploying…',\n 'cf.switchAccount': 'Switch account',\n 'cf.address': 'Worker address',\n 'cf.authHint': 'If the authorization page did not open by itself, copy this link:',\n 'cf.unreachable': 'Cannot read Cloudflare status yet',\n 'lobby.title': 'Room name',\n 'lobby.titlePlaceholder': 'Friday night',\n 'lobby.blinds': 'Blinds',\n 'lobby.namePlaceholder': 'Your name',\n 'lobby.createAction': 'Create',\n 'lobby.code': 'Room code',\n 'lobby.codePlaceholder': '6-digit code',\n 'lobby.preview': 'Preview',\n 'lobby.sit': 'Take a seat',\n 'lobby.watch': 'Watch',\n 'lobby.invited': 'You are invited to room {code}',\n 'lobby.full': 'Seats are full — you will join as a spectator',\n 'lobby.needCode': 'Enter the 6-digit room code',\n 'lobby.needName': 'Enter a name first',\n 'lobby.hintPrefix': 'Host on Cloudflare for a public table that stays up with your laptop off, or on this machine for same-Wi-Fi play. Send the invite link and friends join in a browser. Install ',\n 'lobby.hintSuffix': ' only if you want to host your own table.',\n 'lobby.seated': 'Seated {n}/6',\n 'lobby.phase.lobby': 'Waiting',\n 'lobby.phase.hand': 'In hand',\n 'table.room': 'Room {code}',\n 'table.hand': 'Hand #{n}',\n 'table.blinds': '{sb}/{bb} · buy-in {buyIn}',\n 'table.copyInvite': 'Copy invite link',\n 'table.invite': 'Invite',\n 'table.copyCode': 'Copy code',\n 'invite.title': 'Invite to the table',\n 'invite.copy': 'Copy',\n 'invite.copied': 'Copied',\n 'invite.copyCode': 'Copy code',\n 'table.pause': 'Pause',\n 'table.dissolve': 'Dissolve & settle',\n 'table.dissolveConfirm': 'Dissolve the room and show the final settlement?',\n 'table.waiting': 'Waiting for the host to start',\n 'table.waitingReady': 'Waiting for other players to ready up',\n 'table.ready': 'Ready',\n 'table.unready': 'Not ready',\n 'table.start': 'Start',\n 'table.hideRail': 'Hide panel',\n 'table.showRail': 'Panel',\n 'table.kick': 'Kick',\n 'table.kickConfirm': 'Kick {name} out of the room?',\n 'table.stand': 'Stand up',\n 'table.sitDown': 'Sit down',\n 'table.spectating': 'Spectating',\n 'table.you': 'You',\n 'table.host': 'Host',\n 'table.dealer': 'D',\n 'table.sb': 'SB',\n 'table.bb': 'BB',\n 'table.emptySeats': '{n} seats open',\n 'table.folded': 'Folded',\n 'table.allin': 'All in',\n 'table.offline': 'Offline',\n 'table.autofold': 'Auto',\n 'table.sittingOut': 'Sitting out',\n 'table.pot': 'Pot {amount}',\n 'table.potMain': 'Main pot',\n 'table.potSide': 'Side pot {n}',\n 'table.street.preflop': 'Pre-flop',\n 'table.street.flop': 'Flop',\n 'table.street.turn': 'Turn',\n 'table.street.river': 'River',\n 'table.street.showdown': 'Showdown',\n 'table.yourTurn': 'Your turn',\n 'table.waitTurn': '{name} to act',\n 'table.fold': 'Fold',\n 'table.check': 'Check',\n 'table.call': 'Call {amount}',\n 'table.raise': 'Raise',\n 'table.bet': 'Bet',\n 'table.raiseTo': 'Raise to {amount}',\n 'table.allinAction': 'All in',\n 'table.halfPot': '1/2 pot',\n 'table.twoThirds': '2/3 pot',\n 'table.potBet': 'Pot',\n 'table.min': 'Min',\n 'table.max': 'Max',\n 'table.timer': '{s}s',\n 'table.spectatorHint': 'Spectating: hole cards stay hidden. You can take a freed seat.',\n 'table.noSeat': 'You are not seated',\n 'table.winner': '{name} wins {amount}',\n 'table.foldWin': 'Everyone else folded',\n 'table.nextHand': 'Next hand in {s}s',\n 'table.paused': 'Paused — waiting for the host',\n 'rail.leaderboard': 'Leaderboard',\n 'rail.history': 'Recent hands',\n 'rail.chat': 'Table chat',\n 'rail.spectators': 'Spectators',\n 'rail.empty': 'Nothing yet',\n 'rail.hands': '{n} hands',\n 'rail.net': 'Net',\n 'rail.wins': 'W',\n 'rail.chatPlaceholder': 'Say something…',\n 'rail.send': 'Send',\n 'rail.chatOff': 'Chat is off at this table',\n 'rail.noSpectators': 'No spectators yet',\n 'settle.title': 'Session settlement',\n 'settle.dissolved': 'The host dissolved the room',\n 'settle.idle': 'The host went idle, so the room was settled automatically',\n 'settle.rank': '#',\n 'settle.player': 'Player',\n 'settle.hands': 'Hands',\n 'settle.wins': 'Wins',\n 'settle.net': 'Net',\n 'settle.bb100': 'BB/100',\n 'settle.showdown': 'Showdown',\n 'settle.duration': '{m} min · {hands} hands',\n 'settle.copy': 'Copy results',\n 'settle.download': 'Download JSON',\n 'settle.again': 'Play again',\n 'settle.backHome': 'Back to lobby',\n 'settle.empty': 'No hand finished in this session.',\n 'error.generic': 'Something went wrong',\n 'error.connection': 'Lost the host connection — reconnecting…',\n 'error.stale': 'State changed; refreshed for you',\n 'error.notYourTurn': 'Not your turn',\n 'error.roomGone': 'The room is gone',\n 'error.noSeatCookie': 'The browser did not keep the seat cookie — refresh the page and try again',\n 'error.kicked': 'The host removed you from the room',\n 'toast.joined': 'Joined room {code}',\n 'toast.created': 'Room created: {code}',\n 'toast.duplicate': 'Already applied',\n 'toast.switched': 'Switched to room {code}',\n 'toast.left': 'Left the room',\n 'toast.settlement': 'Session settled',\n}\n\nexport const DICTS = { zh: ZH, en: EN }\n\nlet translator: Translate = createTranslator('zh')\n\nexport function setTranslator(locale: string): void {\n translator = createTranslator(locale)\n}\n\nexport function t(key: string, params?: Record<string, string | number>): string {\n return translator(key, params)\n}\n\nexport function createTranslator(locale: string): Translate {\n const dict = locale.toLowerCase().startsWith('en') ? EN : ZH\n return (key, params) => {\n const template = dict[key] ?? ZH[key] ?? key\n if (!params) return template\n return template.replace(/\\{(\\w+)\\}/g, (_match, name: string) => String(params[name] ?? `{${name}}`))\n }\n}\n","import type { ClientCommand, PlayerView, RoomPreview, SessionSummary } from '../types.ts'\n\nexport const PREFIX = '/holdem'\nconst HEADERS = {\n 'content-type': 'application/json',\n 'x-requested-with': '@zhuweiyou/dsh-holdem',\n}\n\n/** 后端基址:'' = 当前 DSH 进程;也可以指到 Cloudflare Worker 上。 */\nlet apiBase = ''\n\nexport function setApiBase(base: string): void {\n const trimmed = base.trim().replace(/\\/+$/, '')\n apiBase = trimmed === '' ? '' : trimmed\n}\n\nexport function getApiBase(): string {\n return apiBase\n}\n\n/** 座位 token 走请求头,不依赖浏览器是否保留 cookie。 */\nlet seatTokens: string[] = []\n\nexport function setSeatTokens(tokens: string[]): void {\n seatTokens = [...new Set(tokens.filter((token) => token !== ''))]\n}\n\nexport class ApiError extends Error {\n readonly code: string\n readonly status: number\n readonly view: PlayerView | undefined\n\n constructor(code: string, message: string, status: number, view?: PlayerView) {\n super(message)\n this.name = 'ApiError'\n this.code = code\n this.status = status\n this.view = view\n }\n}\n\nasync function request<T>(path: string, init: RequestInit = {}): Promise<T> {\n const response = await fetch(`${apiBase}${PREFIX}${path}`, {\n credentials: apiBase === '' ? 'same-origin' : 'omit',\n ...init,\n headers: {\n ...HEADERS,\n ...(seatTokens.length > 0 ? { 'x-holdem-seat': seatTokens.join(',') } : {}),\n ...(init.headers as Record<string, string> | undefined),\n },\n })\n const text = await response.text()\n const body = (text ? JSON.parse(text) : {}) as T & { error?: string; message?: string; view?: PlayerView }\n if (!response.ok) {\n throw new ApiError(body.error ?? `http-${response.status}`, body.message ?? response.statusText, response.status, body.view)\n }\n return body\n}\n\nexport interface CreateRoomResponse {\n roomId: string\n roomCode: string\n hostPlayerId: string\n joinUrl: string\n wsTicket: string\n sessionToken: string\n view: PlayerView\n}\n\nexport interface JoinResponse {\n playerId: string\n roomId: string\n seat: number | null\n wsTicket: string\n sessionToken: string\n view: PlayerView\n}\n\nexport interface CloudflareStatus {\n authorized: boolean\n account: string\n workerUrl: string\n pending: boolean\n deploying: boolean\n authorizeUrl: string\n error: string\n log: string\n}\n\nexport interface SessionResponse {\n inRoom: boolean\n roomId?: string\n view?: PlayerView\n /** 浏览器实际带上来几个座位凭证(0 说明 cookie 没存/被拦)。 */\n seatCookies?: number\n}\n\nexport interface StateResponse {\n seq: number\n view: PlayerView\n}\n\nexport const api = {\n createRoom(input: { title?: string | undefined; blindLevel?: string | undefined; displayName?: string | undefined; browserId?: string | undefined }) {\n return request<CreateRoomResponse>('/api/rooms', { method: 'POST', body: JSON.stringify(input) })\n },\n preview(input: { code: string; invite?: string | undefined; role?: 'sit' | 'watch' | undefined; browserId?: string | undefined }) {\n const query = new URLSearchParams({ code: input.code })\n if (input.invite) query.set('invite', input.invite)\n if (input.role) query.set('role', input.role)\n if (input.browserId) query.set('browser', input.browserId)\n return request<RoomPreview>(`/api/preview?${query.toString()}`)\n },\n join(input: { roomCode: string; invite?: string | undefined; displayName: string; role: 'sit' | 'watch'; browserId?: string | undefined }) {\n return request<JoinResponse>('/api/join', { method: 'POST', body: JSON.stringify(input) })\n },\n session(roomId?: string) {\n const query = roomId ? `?roomId=${encodeURIComponent(roomId)}` : ''\n return request<SessionResponse>(`/api/session${query}`)\n },\n state(roomId: string) {\n return request<StateResponse>(`/api/rooms/${encodeURIComponent(roomId)}/state`)\n },\n action(roomId: string, input: { actionId: string; baseSeq: number; command: ClientCommand }) {\n return request<{ seq: number; view: PlayerView; duplicate: boolean }>(\n `/api/rooms/${encodeURIComponent(roomId)}/action`,\n { method: 'POST', body: JSON.stringify(input) },\n )\n },\n leave(roomId?: string) {\n return request<{ ok: boolean }>('/api/leave', {\n method: 'POST',\n body: JSON.stringify(roomId ? { roomId } : {}),\n keepalive: true,\n })\n },\n wsTicket(roomId?: string) {\n return request<{ wsTicket: string }>('/api/ws-ticket', {\n method: 'POST',\n body: JSON.stringify(roomId ? { roomId } : {}),\n })\n },\n history(roomId: string) {\n return request<{ summary: SessionSummary | null }>(`/api/rooms/${encodeURIComponent(roomId)}/history`)\n },\n cloudflare() {\n return request<CloudflareStatus>('/api/cloudflare')\n },\n cloudflareAction(action: 'login' | 'deploy' | 'cancel' | 'logout') {\n return request<CloudflareStatus>(`/api/cloudflare?action=${action}`, { method: 'POST', body: '{}' })\n },\n}\n\nexport function newActionId(): string {\n const cryptoObject = globalThis.crypto\n if (cryptoObject?.randomUUID) return cryptoObject.randomUUID()\n return `a${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`\n}\n","const BROWSER_KEY = 'dsh-holdem.browser'\nconst NAME_KEY = 'dsh-holdem.name'\nconst ID_RE = /^[A-Za-z0-9_-]{8,64}$/\n\nlet cached = ''\n\nfunction storage(): Storage | undefined {\n try {\n return globalThis.localStorage\n } catch {\n return undefined\n }\n}\n\n/** 同一浏览器(同源)稳定 id,用于「这个浏览器已经在这个房间里」判定。 */\nexport function browserId(): string {\n if (cached) return cached\n const store = storage()\n if (!store) return ''\n try {\n const existing = store.getItem(BROWSER_KEY)\n if (existing && ID_RE.test(existing)) {\n cached = existing\n return cached\n }\n const next = (globalThis.crypto?.randomUUID?.() ?? `b${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`)\n .replace(/[^A-Za-z0-9_-]/g, '')\n .slice(0, 64)\n if (!ID_RE.test(next)) return ''\n store.setItem(BROWSER_KEY, next)\n cached = next\n return cached\n } catch {\n return ''\n }\n}\n\nexport function rememberedName(): string {\n try {\n return storage()?.getItem(NAME_KEY) ?? ''\n } catch {\n return ''\n }\n}\n\nexport function rememberName(name: string): void {\n try {\n storage()?.setItem(NAME_KEY, name)\n } catch {\n // ignore\n }\n}\n\nexport interface DeepLink {\n code: string\n invite: string\n role: 'sit' | 'watch'\n}\n\n/** 读取 `/?dsh-panel=holdem&code=...&invite=...&role=...`(也兼容 hash 内的查询串)。 */\nexport function parseDeepLink(): DeepLink | null {\n if (typeof location === 'undefined') return null\n const search = new URLSearchParams(location.search)\n const hash = location.hash.includes('?') ? new URLSearchParams(location.hash.slice(location.hash.indexOf('?') + 1)) : null\n const code = search.get('code') ?? hash?.get('code') ?? ''\n const panel = search.get('dsh-panel') ?? hash?.get('dsh-panel') ?? ''\n if (!code || (panel !== 'holdem' && !search.has('code'))) return null\n return {\n code: code.replace(/\\D/g, '').slice(0, 6),\n invite: search.get('invite') ?? hash?.get('invite') ?? '',\n role: (search.get('role') ?? hash?.get('role')) === 'watch' ? 'watch' : 'sit',\n }\n}\n\nexport function clearDeepLink(): void {\n try {\n const url = new URL(location.href)\n for (const key of ['code', 'invite', 'role', 'dsh-panel']) url.searchParams.delete(key)\n const query = url.searchParams.toString()\n history.replaceState(null, '', `${url.pathname}${query ? `?${query}` : ''}${url.hash.includes('dsh-panel') ? '#/' : url.hash}`)\n } catch {\n // ignore\n }\n}\n","import { useSyncExternalStore } from 'react'\nimport type { ClientCommand, PlayerView, ServerEvent } from '../types.ts'\nimport { ApiError, api, getApiBase, newActionId, setApiBase, setSeatTokens } from './api.ts'\nimport { browserId } from './presence.ts'\nimport { t } from './i18n.ts'\n\nexport type Connection = 'idle' | 'connecting' | 'live' | 'polling' | 'offline'\n\nexport interface Toast {\n id: number\n text: string\n kind: 'info' | 'error'\n}\n\nexport interface ClientState {\n booted: boolean\n busy: boolean\n connection: Connection\n view: PlayerView | null\n notice: string | null\n toast: Toast | null\n /** 刚开完房:面板会自动把邀请弹窗打开一次,免得房主不知道怎么叫人。 */\n autoInvite: boolean\n}\n\nlet state: ClientState = {\n booted: false,\n busy: false,\n connection: 'idle',\n view: null,\n notice: null,\n toast: null,\n autoInvite: false,\n}\n\nconst listeners = new Set<() => void>()\nlet socket: WebSocket | null = null\nlet pollTimer: ReturnType<typeof setInterval> | undefined\nlet reconnectTimer: ReturnType<typeof setTimeout> | undefined\nlet toastTimer: ReturnType<typeof setTimeout> | undefined\nlet toastSeq = 0\nlet disposed = false\n\nrestoreBackend()\nsyncSeatTokens()\n\nconst ROOM_KEY = 'holdem:room'\nconst SEATS_KEY = 'holdem:seats'\n\n/** 每个标签页自己保存每个房间的座位 token,并同步到请求头。 */\nfunction readSeats(): Record<string, string> {\n try {\n const raw = sessionStorage.getItem(SEATS_KEY)\n return raw ? (JSON.parse(raw) as Record<string, string>) : {}\n } catch {\n return {}\n }\n}\n\nfunction syncSeatTokens(): void {\n setSeatTokens(Object.values(readSeats()))\n}\n\nfunction rememberSeat(roomId: string, token: string): void {\n const seats = readSeats()\n seats[roomId] = token\n const ids = Object.keys(seats)\n for (const stale of ids.slice(0, Math.max(0, ids.length - 5))) delete seats[stale]\n try {\n sessionStorage.setItem(SEATS_KEY, JSON.stringify(seats))\n } catch {\n // 隐私模式忽略\n }\n syncSeatTokens()\n}\n\n/** 每个标签页记住自己在哪个房间,刷新后不会跑到同一浏览器里最新开的那个房间。 */\nfunction rememberRoom(roomId: string | null): void {\n try {\n if (roomId) sessionStorage.setItem(ROOM_KEY, roomId)\n else sessionStorage.removeItem(ROOM_KEY)\n } catch {\n // 隐私模式下忽略\n }\n}\n\nfunction rememberedRoom(): string | null {\n try {\n return sessionStorage.getItem(ROOM_KEY)\n } catch {\n return null\n }\n}\n\nfunction set(patch: Partial<ClientState>): void {\n state = { ...state, ...patch }\n for (const listener of listeners) listener()\n}\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n}\n\nexport function useClientState(): ClientState {\n return useSyncExternalStore(subscribe, getState, getState)\n}\n\nexport function getState(): ClientState {\n return state\n}\n\nexport function toast(text: string, kind: 'info' | 'error' = 'info'): void {\n toastSeq += 1\n set({ toast: { id: toastSeq, text, kind } })\n if (toastTimer) clearTimeout(toastTimer)\n toastTimer = setTimeout(() => {\n set({ toast: null })\n }, kind === 'error' ? 4200 : 2600)\n}\n\n/** 邀请弹窗已经自动弹过一次了。 */\nexport function consumeAutoInvite(): void {\n if (state.autoInvite) set({ autoInvite: false })\n}\n\nexport function clearToast(): void {\n if (toastTimer) clearTimeout(toastTimer)\n set({ toast: null })\n}\n\n// ------------------------------------------------------------------ 通道\n\nconst BASE_KEY = 'holdem:api-base'\n\nfunction wsUrl(ticket: string): string {\n const base = getApiBase()\n const url = base === '' ? new URL(location.href) : new URL(base)\n const protocol = url.protocol === 'https:' ? 'wss' : 'ws'\n return `${protocol}://${url.host}/holdem/ws?ticket=${encodeURIComponent(ticket)}`\n}\n\n/** 切换后端(本机 / Cloudflare Worker),下一轮刷新也能回到同一处。 */\nexport function useBackend(base: string): void {\n setApiBase(base)\n try {\n if (base === '') sessionStorage.removeItem(BASE_KEY)\n else sessionStorage.setItem(BASE_KEY, base)\n } catch {\n // 忽略\n }\n}\n\nexport function restoreBackend(): void {\n try {\n const saved = sessionStorage.getItem(BASE_KEY)\n if (saved) setApiBase(saved)\n } catch {\n // 忽略\n }\n}\n\nfunction stopPolling(): void {\n if (pollTimer) clearInterval(pollTimer)\n pollTimer = undefined\n}\n\nfunction startPolling(roomId: string): void {\n if (pollTimer || disposed) return\n pollTimer = setInterval(() => {\n void refresh(roomId).catch(() => undefined)\n }, 1000)\n}\n\nfunction scheduleReconnect(roomId: string): void {\n if (reconnectTimer || disposed) return\n reconnectTimer = setTimeout(() => {\n reconnectTimer = undefined\n void reissueTicket(roomId)\n }, 3000)\n}\n\nasync function reissueTicket(roomId: string): Promise<void> {\n if (disposed) return\n try {\n const { wsTicket } = await api.wsTicket(roomId)\n connectChannel(roomId, wsTicket)\n } catch {\n scheduleReconnect(roomId)\n }\n}\n\nfunction closeChannel(): void {\n stopPolling()\n if (reconnectTimer) clearTimeout(reconnectTimer)\n reconnectTimer = undefined\n if (socket) {\n socket.onclose = null\n socket.close()\n }\n socket = null\n}\n\nfunction connectChannel(roomId: string, ticket: string): void {\n closeChannel()\n if (disposed) return\n set({ connection: 'connecting' })\n let ws: WebSocket\n try {\n ws = new WebSocket(wsUrl(ticket), 'holdem.v1')\n } catch {\n set({ connection: 'polling' })\n startPolling(roomId)\n scheduleReconnect(roomId)\n return\n }\n socket = ws\n ws.onopen = () => {\n set({ connection: 'live' })\n stopPolling()\n }\n ws.onmessage = (event) => {\n try {\n handleEvent(JSON.parse(String(event.data)) as ServerEvent)\n } catch {\n // ignore malformed frames\n }\n }\n ws.onclose = () => {\n if (socket === ws) socket = null\n if (disposed) return\n set({ connection: 'polling' })\n const room = state.view?.room.roomId\n if (room) {\n startPolling(room)\n scheduleReconnect(room)\n }\n }\n ws.onerror = () => {\n ws.close()\n }\n}\n\nfunction handleEvent(event: ServerEvent): void {\n if (event.type === 'snapshot') {\n if (!state.view || state.view.room.roomId === event.view.room.roomId) set({ view: event.view })\n return\n }\n if (event.type === 'settled') {\n toast(t('toast.settlement'))\n const room = state.view?.room.roomId\n if (room) void refresh(room)\n return\n }\n if (event.type === 'kicked') {\n closeChannel()\n set({ view: null, notice: t('error.kicked'), connection: 'idle' })\n return\n }\n if (event.type === 'left') {\n closeChannel()\n set({ view: null, notice: event.reason, connection: 'idle' })\n return\n }\n if (event.type === 'reject') {\n toast(event.reason, 'error')\n }\n}\n\nasync function refresh(roomId: string): Promise<void> {\n if (!roomId) return\n try {\n const response = await api.state(roomId)\n set({ view: response.view })\n } catch (error) {\n if (error instanceof ApiError && (error.status === 403 || error.status === 404)) {\n await recoverSession(roomId)\n } else {\n throw error\n }\n }\n}\n\n/**\n * 状态接口说「不在这个房间」时,先确认浏览器现在到底在哪个房间:\n * 同一个浏览器可能有多个标签页各自在别的房间,cookie 还在就别把用户踢回大厅。\n */\nasync function recoverSession(roomId: string): Promise<void> {\n let session: Awaited<ReturnType<typeof api.session>> | null = null\n try {\n session = await api.session()\n } catch {\n session = null\n }\n if (session?.inRoom && session.view) {\n const next = session.view.room.roomId\n rememberRoom(next)\n set({ view: session.view, notice: null })\n if (next !== roomId) toast(t('toast.switched', { code: session.view.room.roomCode }))\n try {\n const { wsTicket } = await api.wsTicket(next)\n connectChannel(next, wsTicket)\n } catch {\n set({ connection: 'polling' })\n startPolling(next)\n scheduleReconnect(next)\n }\n return\n }\n rememberRoom(null)\n closeChannel()\n const noCookie = session !== null && !session.inRoom && (session.seatCookies ?? 1) === 0\n set({ view: null, connection: 'idle', notice: noCookie ? t('error.noSeatCookie') : t('error.roomGone') })\n}\n\n// ------------------------------------------------------------------ 生命周期\n\nexport async function bootstrap(): Promise<void> {\n // 插件热重载会先 dispose 再重新挂载:此时状态已清空,直接重来一次\n if (disposed) disposed = false\n else if (state.booted) return\n try {\n syncSeatTokens()\n const session = await api.session(rememberedRoom() ?? undefined)\n if (session.inRoom && session.view) {\n rememberRoom(session.view.room.roomId)\n set({ view: session.view })\n try {\n const { wsTicket } = await api.wsTicket(session.view.room.roomId)\n connectChannel(session.view.room.roomId, wsTicket)\n } catch {\n set({ connection: 'polling' })\n startPolling(session.view.room.roomId)\n }\n }\n } catch {\n // 没有会话时保持大厅\n } finally {\n set({ booted: true })\n }\n}\n\nexport function dispose(): void {\n disposed = true\n closeChannel()\n if (toastTimer) clearTimeout(toastTimer)\n toastTimer = undefined\n listeners.clear()\n socket = null\n state = { booted: false, busy: false, connection: 'idle', view: null, notice: null, toast: null, autoInvite: false }\n}\n\nexport async function createRoom(\n input: { title?: string | undefined; blindLevel: string; displayName: string },\n base = '',\n): Promise<void> {\n set({ busy: true })\n if (base !== '') useBackend(base)\n try {\n const created = await api.createRoom({ ...input, browserId: browserId() })\n rememberRoom(created.view.room.roomId)\n rememberSeat(created.view.room.roomId, created.sessionToken)\n set({ view: created.view, busy: false, notice: null, autoInvite: true })\n toast(t('toast.created', { code: created.roomCode }))\n connectChannel(created.view.room.roomId, created.wsTicket)\n } catch (error) {\n set({ busy: false })\n if (base !== '') useBackend('')\n toast(errorText(error), 'error')\n throw error\n }\n}\n\nexport async function joinRoom(input: {\n roomCode: string\n invite?: string | undefined\n displayName: string\n role: 'sit' | 'watch'\n}, base = ''): Promise<void> {\n set({ busy: true })\n if (base !== '') useBackend(base)\n try {\n const joined = await api.join({ ...input, browserId: browserId() })\n rememberRoom(joined.view.room.roomId)\n rememberSeat(joined.view.room.roomId, joined.sessionToken)\n set({ view: joined.view, busy: false, notice: null })\n toast(t('toast.joined', { code: joined.view.room.roomCode }))\n connectChannel(joined.view.room.roomId, joined.wsTicket)\n } catch (error) {\n set({ busy: false })\n if (base !== '') useBackend('')\n toast(errorText(error), 'error')\n throw error\n }\n}\n\nexport async function leaveRoom(): Promise<void> {\n try {\n await api.leave(state.view?.room.roomId)\n } catch {\n // 房间可能已解散\n }\n rememberRoom(null)\n closeChannel()\n set({ view: null, connection: 'idle', notice: null })\n toast(t('toast.left'))\n}\n\nexport async function runCommand(command: ClientCommand): Promise<void> {\n const view = state.view\n if (!view) return\n set({ busy: true })\n try {\n const response = await api.action(view.room.roomId, {\n actionId: newActionId(),\n baseSeq: view.room.seq,\n command,\n })\n set({ view: response.view, busy: false })\n if (response.duplicate) toast(t('toast.duplicate'))\n } catch (error) {\n set({ busy: false })\n if (error instanceof ApiError) {\n if (error.code === 'stale' && error.view) {\n set({ view: error.view })\n toast(t('error.stale'))\n return\n }\n if (error.code === 'not-your-turn') {\n toast(t('error.notYourTurn'), 'error')\n } else {\n toast(error.message || t('error.generic'), 'error')\n }\n const roomId = state.view?.room.roomId\n if (roomId) void refresh(roomId).catch(() => undefined)\n return\n }\n toast(errorText(error), 'error')\n }\n}\n\nexport function errorText(error: unknown): string {\n if (error instanceof ApiError) return error.message || t('error.generic')\n if (error instanceof Error) return error.message\n return t('error.generic')\n}\n","import { t } from './i18n.ts'\n\n/**\n * 开桌位置的抽象:每个方案只描述「在哪儿开、需要填什么、请求打到哪个基址」。\n * 以后加 ngrok / Tailscale / 自建 VPS,只要再加一个条目。\n */\nexport interface HostingOption {\n id: string\n label: () => string\n hint: () => string\n /** 需要额外填一个地址(例如 Worker 的 URL) */\n needsUrl: boolean\n /** 地址输入框的占位符 */\n urlPlaceholder?: () => string\n /** 请求应该打到哪儿('' = 当前 DSH 进程) */\n resolveBase: (context: { url: string }) => string\n}\n\nexport const HOSTING_OPTIONS: HostingOption[] = [\n {\n id: 'local',\n label: () => t('host.local'),\n hint: () => t('host.localHint'),\n needsUrl: false,\n resolveBase: () => '',\n },\n {\n id: 'cloudflare',\n label: () => t('host.cloudflare'),\n hint: () => t('host.cloudflareHint'),\n needsUrl: false,\n resolveBase: (context) => context.url.trim().replace(/\\/+$/, ''),\n },\n]\n\nexport function hostingOption(id: string): HostingOption {\n return HOSTING_OPTIONS.find((option) => option.id === id) ?? HOSTING_OPTIONS[0]!\n}\n","import type { CSSProperties } from 'react'\n\nexport function cx(...values: (string | false | null | undefined)[]): string {\n return values.filter((value): value is string => typeof value === 'string' && value.length > 0).join(' ')\n}\n\nconst chipsFormat = new Intl.NumberFormat('en-US')\n\nexport function formatChips(value: number): string {\n return chipsFormat.format(Math.round(value))\n}\n\nexport function signedChips(value: number): string {\n if (value === 0) return '0'\n return `${value > 0 ? '+' : '−'}${formatChips(Math.abs(value))}`\n}\n\nexport function formatBb(bb: number, netChips: number, handsPlayed: number): string {\n if (handsPlayed <= 0 || bb <= 0) return '—'\n const value = (netChips / bb / handsPlayed) * 100\n return `${value >= 0 ? '+' : '−'}${Math.abs(value).toFixed(1)}`\n}\n\nexport function formatDuration(ms: number): number {\n return Math.max(0, Math.round(ms / 60_000))\n}\n\nexport function avatarStyle(playerId: string): CSSProperties {\n const hue = hashHue(playerId)\n return {\n background: `linear-gradient(150deg, hsl(${hue} 46% 44%), hsl(${(hue + 38) % 360} 42% 28%))`,\n }\n}\n\nexport function initialOf(name: string | null | undefined): string {\n const text = (name ?? '?').trim()\n if (!text) return '?'\n const chars = [...text]\n return (chars[0] ?? '?').toUpperCase()\n}\n\nfunction hashHue(value: string): number {\n let hash = 0\n for (let i = 0; i < value.length; i += 1) hash = (hash * 31 + value.charCodeAt(i)) >>> 0\n return hash % 360\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n if (max < min) return min\n return Math.min(max, Math.max(min, value))\n}\n\nexport async function copyText(text: string): Promise<boolean> {\n try {\n await navigator.clipboard.writeText(text)\n return true\n } catch {\n return false\n }\n}\n\nexport function downloadJson(filename: string, value: unknown): void {\n const blob = new Blob([JSON.stringify(value, null, 2)], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = filename\n anchor.click()\n setTimeout(() => URL.revokeObjectURL(url), 2000)\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { api, type CloudflareStatus } from './api.ts'\nimport { t } from './i18n.ts'\nimport { copyText, cx } from './ui.ts'\nimport css from './styles.module.css'\n\nexport interface CloudflarePanelProps {\n /** Worker 地址变化时通知外层(建房要用它当后端基址) */\n onWorkerUrl: (url: string) => void\n}\n\n/**\n * Cloudflare 授权 + 部署面板:点一下开浏览器授权,授权完直接部署,\n * 部署成功自动拿到 workers.dev 地址,用户不用自己填域名。\n */\nexport function CloudflarePanel({ onWorkerUrl }: CloudflarePanelProps) {\n const [status, setStatus] = useState<CloudflareStatus | null>(null)\n const [busy, setBusy] = useState(false)\n const [copied, setCopied] = useState(false)\n const [failure, setFailure] = useState('')\n const reported = useRef('')\n\n useEffect(() => {\n let alive = true\n const load = async (): Promise<void> => {\n try {\n const next = await api.cloudflare()\n if (!alive) return\n setStatus(next)\n if (next.workerUrl && reported.current !== next.workerUrl) {\n reported.current = next.workerUrl\n onWorkerUrl(next.workerUrl)\n }\n } catch {\n if (alive) setFailure(t('cf.unreachable'))\n }\n }\n void load()\n const timer = setInterval(() => {\n void load()\n }, 1500)\n return () => {\n alive = false\n clearInterval(timer)\n }\n }, [onWorkerUrl])\n\n const act = async (action: 'login' | 'deploy' | 'cancel' | 'logout'): Promise<void> => {\n setFailure('')\n setBusy(true)\n try {\n const next = await api.cloudflareAction(action)\n setStatus(next)\n if (action === 'logout') {\n reported.current = ''\n onWorkerUrl('')\n }\n } catch (error) {\n setFailure(error instanceof Error ? error.message : String(error))\n } finally {\n setBusy(false)\n }\n }\n\n const copyUrl = async (): Promise<void> => {\n if (!status?.authorizeUrl) return\n if (await copyText(status.authorizeUrl)) {\n setCopied(true)\n setTimeout(() => setCopied(false), 1600)\n }\n }\n\n const authorized = status?.authorized === true\n const workerUrl = status?.workerUrl ?? ''\n\n return (\n <div className={css.cfPanel}>\n <div className={css.cfRow}>\n {authorized ? (\n <span className={cx(css.cfBadge, css.cfBadgeOn)}>{t('cf.authorized', { account: status?.account || 'Cloudflare' })}</span>\n ) : (\n <span className={cx(css.cfBadge, status?.pending && css.cfBadgeWait)}>\n {status?.pending ? t('cf.waiting') : t('cf.needAuth')}\n </span>\n )}\n <span className={css.grow} />\n {authorized ? (\n <>\n <button type=\"button\" className={cx(css.btn, css.btnChip)} disabled={busy || status?.deploying} onClick={() => void act('deploy')}>\n {status?.deploying ? t('cf.deploying') : workerUrl ? t('cf.redeploy') : t('cf.deploy')}\n </button>\n <button type=\"button\" className={cx(css.btn, css.btnChip)} disabled={busy} onClick={() => void act('logout')}>\n {t('cf.switchAccount')}\n </button>\n </>\n ) : status?.pending ? (\n <>\n <span className={css.cfWaiting}>{t('cf.waiting')}</span>\n <button type=\"button\" className={cx(css.btn, css.btnChip)} disabled={busy} onClick={() => void act('cancel')}>\n {t('cf.cancel')}\n </button>\n </>\n ) : (\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} disabled={busy} onClick={() => void act('login')}>\n {t('cf.authorize')}\n </button>\n )}\n </div>\n\n {workerUrl ? (\n <div className={css.cfRow}>\n <span className={css.cfLabel}>{t('cf.address')}</span>\n <code className={css.urlText}>{workerUrl}</code>\n </div>\n ) : null}\n\n {status?.authorizeUrl && !authorized ? (\n <div className={css.cfAuthBox}>\n <p className={css.cfAuthHint}>{t('cf.authHint')}</p>\n <div className={css.cfRow}>\n <code className={css.urlText} title={status.authorizeUrl}>\n {status.authorizeUrl}\n </code>\n <button type=\"button\" className={cx(css.btn, css.btnChip)} onClick={() => void copyUrl()}>\n {copied ? t('invite.copied') : t('invite.copy')}\n </button>\n </div>\n </div>\n ) : null}\n\n {failure || status?.error ? <p className={css.cfError}>{failure || status?.error}</p> : null}\n {status?.log ? <pre className={css.cfLog}>{status.log.slice(-600)}</pre> : null}\n </div>\n )\n}\n","import { useState } from 'react'\nimport { BLIND_LEVELS } from '../invariant.ts'\nimport { t } from './i18n.ts'\nimport { createRoom, joinRoom, useClientState } from './store.ts'\nimport { HOSTING_OPTIONS, hostingOption } from './backends.ts'\nimport { CloudflarePanel } from './CloudflarePanel.tsx'\nimport { clearDeepLink, parseDeepLink, rememberName, rememberedName } from './presence.ts'\nimport { cx, formatChips } from './ui.ts'\nimport css from './styles.module.css'\n\nconst NPM_URL = 'https://www.npmjs.com/package/@zhuweiyou/dsh-holdem'\n\ninterface JoinLink {\n /** 请求要打到哪个 origin('' = 当前 DSH 进程) */\n base: string\n code: string\n invite: string\n}\n\n/** 加入只认邀请链接:里面带着房号、邀请 token,以及这桌跑在哪台机器/Worker 上。 */\nfunction parseJoinLink(text: string): JoinLink | null {\n const trimmed = text.trim()\n if (!/^https?:\\/\\//i.test(trimmed)) return null\n try {\n const url = new URL(trimmed)\n const code = (url.searchParams.get('code') ?? '').replace(/\\D/g, '').slice(0, 6)\n if (code.length !== 6) return null\n const sameOrigin = typeof location !== 'undefined' && url.origin === location.origin\n return { base: sameOrigin ? '' : url.origin, code, invite: url.searchParams.get('invite') ?? '' }\n } catch {\n return null\n }\n}\n\nfunction readPref(key: string, fallback: string): string {\n try {\n return localStorage.getItem(`holdem:${key}`) ?? fallback\n } catch {\n return fallback\n }\n}\n\nfunction writePref(key: string, value: string): void {\n try {\n localStorage.setItem(`holdem:${key}`, value)\n } catch {\n // 忽略\n }\n}\n\nfunction buildLabel(): string {\n const raw = typeof __HOLDEM_BUILD__ === 'string' ? __HOLDEM_BUILD__ : ''\n const date = raw ? new Date(raw) : null\n const stamp = date && !Number.isNaN(date.getTime())\n ? date.toLocaleTimeString(undefined, { hour12: false }).slice(0, 5)\n : ''\n return stamp ? `@zhuweiyou/dsh-holdem · build ${stamp}` : '@zhuweiyou/dsh-holdem · dev'\n}\n\nexport function Lobby() {\n const state = useClientState()\n const deepLink = parseDeepLink()\n const [tab, setTab] = useState<'create' | 'join'>(deepLink ? 'join' : 'create')\n const [name, setName] = useState(() => rememberedName())\n const [title, setTitle] = useState('')\n const [blindLevel, setBlindLevel] = useState<string>('25/50')\n const [hosting, setHosting] = useState<string>(() => readPref('hosting', 'cloudflare'))\n const [workerUrl, setWorkerUrl] = useState<string>(() => readPref('worker-url', ''))\n const [joinText, setJoinText] = useState(() => {\n if (!deepLink) return ''\n const query = new URLSearchParams({ code: deepLink.code, role: 'auto' })\n if (deepLink.invite) query.set('invite', deepLink.invite)\n const origin = typeof location === 'undefined' ? '' : location.origin\n return `${origin}/holdem/play?${query.toString()}`\n })\n const [error, setError] = useState<string | null>(null)\n\n const submitCreate = async (): Promise<void> => {\n setError(null)\n if (!name.trim()) {\n setError(t('lobby.needName'))\n return\n }\n rememberName(name.trim())\n const option = hostingOption(hosting)\n if (hosting === 'cloudflare' && workerUrl.trim() === '') {\n setError(t('host.needCloudflare'))\n return\n }\n writePref('hosting', hosting)\n try {\n await createRoom(\n { title: title.trim() || undefined, blindLevel, displayName: name.trim() },\n option.resolveBase({ url: workerUrl }),\n )\n } catch (reason) {\n setError(reason instanceof Error ? reason.message : t('error.generic'))\n }\n }\n\n /** 加入只用邀请链接:链接里带着房号、邀请 token 和「在哪儿」(本机 / 局域网 / Cloudflare)。 */\n const submitJoin = async (role: 'sit' | 'watch'): Promise<void> => {\n setError(null)\n if (!name.trim()) {\n setError(t('lobby.needName'))\n return\n }\n const parsed = parseJoinLink(joinText)\n if (!parsed) {\n setError(t('lobby.needLink'))\n return\n }\n rememberName(name.trim())\n try {\n await joinRoom(\n { roomCode: parsed.code, invite: parsed.invite, displayName: name.trim(), role },\n parsed.base,\n )\n clearDeepLink()\n } catch (reason) {\n const where = parsed.base === '' ? (typeof location === 'undefined' ? '本机' : location.host) : new URL(parsed.base).host\n const message = reason instanceof Error ? reason.message : t('error.generic')\n setError(t('lobby.joinFailed', { where, message }))\n }\n }\n\n return (\n <div className={css.lobby}>\n <div className={css.lobbyHead}>\n <h1 className={css.lobbyTitle}>{t('panel.title')}</h1>\n <p className={css.lobbySubtitle}>{t('panel.subtitle')}</p>\n </div>\n\n {state.notice ? <div className={css.notice}>{state.notice}</div> : null}\n {error ? <div className={css.noticeError}>{error}</div> : null}\n\n <div className={css.tabs}>\n <button\n type=\"button\"\n className={cx(css.tab, tab === 'create' && css.tabActive)}\n onClick={() => setTab('create')}\n >\n {t('lobby.create')}\n </button>\n <button\n type=\"button\"\n className={cx(css.tab, tab === 'join' && css.tabActive)}\n onClick={() => setTab('join')}\n >\n {t('lobby.join')}\n </button>\n </div>\n\n <div className={css.lobbyBody}>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('common.name')}</span>\n <input\n className={css.input}\n value={name}\n maxLength={16}\n placeholder={t('lobby.namePlaceholder')}\n onChange={(event) => setName(event.target.value)}\n />\n </label>\n\n {tab === 'create' ? (\n <>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('lobby.title')}</span>\n <input\n className={css.input}\n value={title}\n maxLength={24}\n placeholder={t('lobby.titlePlaceholder')}\n onChange={(event) => setTitle(event.target.value)}\n />\n </label>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('lobby.blinds')}</span>\n <select className={css.input} value={blindLevel} onChange={(event) => setBlindLevel(event.target.value)}>\n {BLIND_LEVELS.map((level) => (\n <option key={level.id} value={level.id}>\n {level.id} · {t('table.blinds', { sb: level.sb, bb: level.bb, buyIn: formatChips(level.bb * 100) })}\n </option>\n ))}\n </select>\n </label>\n <div className={css.field}>\n <span className={css.fieldLabel}>{t('host.label')}</span>\n <div className={css.hostRow}>\n {HOSTING_OPTIONS.map((option) => (\n <button\n key={option.id}\n type=\"button\"\n className={cx(css.btn, css.btnChip, hosting === option.id && css.hostActive)}\n onClick={() => setHosting(option.id)}\n >\n {option.label()}\n </button>\n ))}\n </div>\n <p className={css.hint}>{hostingOption(hosting).hint()}</p>\n {hosting === 'cloudflare' ? <CloudflarePanel onWorkerUrl={setWorkerUrl} /> : null}\n </div>\n <button type=\"button\" className={cx(css.btn, css.btnPrimary, css.btnWide)} disabled={state.busy} onClick={() => void submitCreate()}>\n {t('lobby.createAction')}\n </button>\n <p className={css.hint}>6 人桌 · 每手 100BB · 超出座位自动观战</p>\n </>\n ) : (\n <>\n {deepLink ? <div className={css.inviteBanner}>{t('lobby.invited', { code: deepLink.code })}</div> : null}\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('lobby.linkOnly')}</span>\n <input\n className={css.input}\n value={joinText}\n placeholder={t('lobby.linkOnlyPlaceholder')}\n onChange={(event) => setJoinText(event.target.value)}\n />\n </label>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnPrimary, css.btnWide)}\n disabled={state.busy}\n onClick={() => void submitJoin('sit')}\n >\n {t('lobby.enter')}\n </button>\n <p className={css.hint}>{t('lobby.linkHint')}</p>\n </>\n )}\n </div>\n\n <p className={css.hint}>\n {t('lobby.hintPrefix')}\n <a className={css.hintLink} href={NPM_URL} target=\"_blank\" rel=\"noreferrer\">\n @zhuweiyou/dsh-holdem\n </a>\n {t('lobby.hintSuffix')}\n </p>\n <p className={css.buildTag}>{buildLabel()}</p>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { PlayerView } from '../types.ts'\nimport { t } from './i18n.ts'\nimport { createRoom, leaveRoom } from './store.ts'\nimport { copyText, cx, downloadJson, formatBb, formatChips, formatDuration, signedChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport function Settlement({ view }: { view: PlayerView }) {\n const summary = view.settlement\n const [copied, setCopied] = useState(false)\n if (!summary) {\n return (\n <div className={css.settle}>\n <p className={css.railEmpty}>{t('settle.empty')}</p>\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} onClick={() => void leaveRoom()}>\n {t('common.back')}\n </button>\n </div>\n )\n }\n\n const isHost = view.room.hostPlayerId === view.you.playerId\n const markdown = buildMarkdown(view)\n const fileName = `holdem-${summary.roomCode}-${summary.sessionId.slice(-6)}.json`\n\n const again = async (): Promise<void> => {\n const title = summary.title\n const blindLevel = view.room.settings.blindLevel\n const displayName = view.you.displayName\n await leaveRoom()\n await createRoom({ title, blindLevel, displayName })\n }\n\n return (\n <div className={css.settle}>\n <div className={css.settleHead}>\n <div>\n <h1 className={css.settleTitle}>{t('settle.title')}</h1>\n <p className={css.settleMeta}>\n {summary.reason === 'host-idle' ? t('settle.idle') : t('settle.dissolved')}\n {' · '}\n {t('settle.duration', { m: formatDuration(summary.durationMs), hands: summary.handsPlayed })}\n {' · '}\n {summary.title} #{summary.roomCode}\n </p>\n </div>\n <div className={css.settleActions}>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnGhost)}\n onClick={() => {\n void copyText(markdown).then((ok) => setCopied(ok))\n }}\n >\n {copied ? t('common.copied') : t('settle.copy')}\n </button>\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} onClick={() => downloadJson(fileName, summary)}>\n {t('settle.download')}\n </button>\n {isHost ? (\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} onClick={() => void again()}>\n {t('settle.again')}\n </button>\n ) : null}\n <button type=\"button\" className={cx(css.btn, isHost ? css.btnOutline : css.btnPrimary)} onClick={() => void leaveRoom()}>\n {t('settle.backHome')}\n </button>\n </div>\n </div>\n\n {summary.players.length === 0 ? (\n <p className={css.railEmpty}>{t('settle.empty')}</p>\n ) : (\n <div className={css.settleTable}>\n <div className={cx(css.settleRow, css.settleRowHead)}>\n <span>{t('settle.rank')}</span>\n <span>{t('settle.player')}</span>\n <span>{t('settle.hands')}</span>\n <span>{t('settle.wins')}</span>\n <span>{t('settle.net')}</span>\n <span>{t('settle.bb100')}</span>\n <span>{t('settle.showdown')}</span>\n </div>\n {summary.players.map((player) => (\n <div key={player.playerId} className={cx(css.settleRow, player.rank === 1 && css.settleRowFirst)}>\n <span className={css.settleRank}>{medal(player.rank)}</span>\n <span className={css.settlePlayer}>{player.displayName}</span>\n <span>{player.handsPlayed}</span>\n <span>{player.handsWon}</span>\n <span className={player.netChips > 0 ? css.netUp : player.netChips < 0 ? css.netDown : css.netFlat}>\n {signedChips(player.netChips)}\n </span>\n <span>{formatBb(view.room.settings.bb, player.netChips, player.handsPlayed)}</span>\n <span>\n {player.showdownsPlayed === 0\n ? '—'\n : `${player.showdownsWon}/${player.showdownsPlayed}`}\n </span>\n </div>\n ))}\n </div>\n )}\n\n <div className={css.settleHistory}>\n <h3 className={css.railTitle}>{t('rail.history')}</h3>\n <div className={css.historyScroll}>\n {summary.history.length === 0 ? <p className={css.railEmpty}>{t('settle.empty')}</p> : null}\n {[...summary.history].reverse().map((hand) => (\n <div key={hand.handNo} className={css.settleHandRow}>\n <span className={css.historyNo}>#{hand.handNo}</span>\n <span className={css.historyBoard}>\n {hand.board.map((card) => (\n <span key={card} className={css.historyCard}>{card}</span>\n ))}\n </span>\n <span className={css.settleHandPot}>{formatChips(hand.pots.reduce((sum, pot) => sum + pot.amount, 0))}</span>\n <span className={css.settleHandWinners}>\n {hand.winners\n .map((seat) => hand.deltas.find((delta) => delta.seat === seat)?.displayName ?? '')\n .join(' · ')}\n </span>\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n\nfunction medal(rank: number): string {\n if (rank === 1) return '🥇'\n if (rank === 2) return '🥈'\n if (rank === 3) return '🥉'\n return String(rank)\n}\n\nfunction buildMarkdown(view: PlayerView): string {\n const summary = view.settlement!\n const lines: string[] = []\n lines.push(`# 德州扑克战绩 · ${summary.roomCode}`)\n lines.push('')\n lines.push(`${summary.title} · ${summary.handsPlayed} 手 · ${new Date(summary.startedAt).toLocaleString()} → ${new Date(summary.endedAt).toLocaleString()}`)\n lines.push('')\n lines.push('| 名次 | 玩家 | 手数 | 胜局 | 净赢 | BB/100 | 摊牌 |')\n lines.push('| --- | --- | --- | --- | --- | --- | --- |')\n for (const player of summary.players) {\n lines.push(\n `| ${player.rank} | ${player.displayName} | ${player.handsPlayed} | ${player.handsWon} | ${signedChips(player.netChips)} | ${formatBb(view.room.settings.bb, player.netChips, player.handsPlayed)} | ${player.showdownsWon}/${player.showdownsPlayed} |`,\n )\n }\n lines.push('')\n lines.push('> 娱乐筹码,与 DeepSeek 余额无关。')\n return lines.join('\\n')\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type { LegalActions, TableAction } from '../types.ts'\nimport { t } from './i18n.ts'\nimport { clamp, cx, formatChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport interface ActionBarProps {\n legal: LegalActions\n potTotal: number\n bigBlind: number\n busy: boolean\n secondsLeft: number | null\n onAction: (action: TableAction) => void\n}\n\nexport function ActionBar({ legal, potTotal, bigBlind, busy, secondsLeft, onAction }: ActionBarProps) {\n const [raiseTo, setRaiseTo] = useState(legal.minRaiseTo)\n const lastLegal = useRef(`${legal.minRaiseTo}:${legal.maxRaiseTo}:${legal.canRaise}`)\n\n useEffect(() => {\n const key = `${legal.minRaiseTo}:${legal.maxRaiseTo}:${legal.canRaise}`\n if (lastLegal.current !== key) {\n lastLegal.current = key\n setRaiseTo(legal.minRaiseTo)\n }\n }, [legal.minRaiseTo, legal.maxRaiseTo, legal.canRaise])\n\n const step = Math.max(1, Math.round(bigBlind / 2))\n const raiseDisabled = !legal.canRaise || busy\n const presets: { label: string; value: number }[] = legal.canRaise\n ? [\n { label: t('table.halfPot'), value: presetTo(legal, potTotal, 0.5) },\n { label: t('table.twoThirds'), value: presetTo(legal, potTotal, 0.66) },\n { label: t('table.potBet'), value: presetTo(legal, potTotal, 1) },\n ]\n : []\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent): void => {\n const target = event.target as HTMLElement | null\n if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)) return\n const key = event.key.toLowerCase()\n if (key === 'f' && legal.canFold) onAction({ type: 'fold' })\n else if (key === 'c' && (legal.canCheck || legal.canCall)) onAction(legal.canCheck ? { type: 'check' } : { type: 'call' })\n else if (key === 'r' && legal.canRaise) onAction({ type: 'raise', to: clamp(raiseTo, legal.minRaiseTo, legal.maxRaiseTo) })\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [legal, onAction, raiseTo])\n\n const isAllIn = legal.canRaise && raiseTo >= legal.maxRaiseTo\n\n return (\n <div className={css.actionBar}>\n <div className={css.actionTimer}>\n <span className={css.actionTimerLabel}>{t('table.yourTurn')}</span>\n {secondsLeft !== null ? <span className={css.actionTimerValue}>{t('table.timer', { s: secondsLeft })}</span> : null}\n </div>\n <div className={css.actionRow}>\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} disabled={!legal.canFold || busy} onClick={() => onAction({ type: 'fold' })}>\n {t('table.fold')}\n </button>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnCall)}\n disabled={busy || (!legal.canCheck && !legal.canCall)}\n onClick={() => onAction(legal.canCheck ? { type: 'check' } : { type: 'call' })}\n >\n {legal.canCheck ? t('table.check') : t('table.call', { amount: formatChips(legal.callAmount) })}\n </button>\n {legal.canRaise ? (\n <div className={css.raiseGroup}>\n <div className={css.raiseHead}>\n <span className={css.raiseValue}>{isAllIn ? t('table.allinAction') : formatChips(raiseTo)}</span>\n <div className={css.presetRow}>\n {presets.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className={cx(css.btn, css.btnChip)}\n disabled={raiseDisabled}\n onClick={() => setRaiseTo(clamp(preset.value, legal.minRaiseTo, legal.maxRaiseTo))}\n >\n {preset.label}\n </button>\n ))}\n <button\n type=\"button\"\n className={cx(css.btn, css.btnChip)}\n disabled={raiseDisabled}\n onClick={() => setRaiseTo(legal.maxRaiseTo)}\n >\n {t('table.max')}\n </button>\n </div>\n </div>\n <input\n className={css.slider}\n type=\"range\"\n min={legal.minRaiseTo}\n max={legal.maxRaiseTo}\n step={step}\n value={clamp(raiseTo, legal.minRaiseTo, legal.maxRaiseTo)}\n disabled={raiseDisabled}\n onChange={(event) => setRaiseTo(Number(event.target.value))}\n />\n <button\n type=\"button\"\n className={cx(css.btn, css.btnRaise)}\n disabled={raiseDisabled}\n onClick={() => onAction({ type: 'raise', to: clamp(raiseTo, legal.minRaiseTo, legal.maxRaiseTo) })}\n >\n {isAllIn\n ? t('table.allinAction')\n : t('table.raiseTo', { amount: formatChips(clamp(raiseTo, legal.minRaiseTo, legal.maxRaiseTo)) })}\n </button>\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nfunction presetTo(legal: LegalActions, pot: number, fraction: number): number {\n const target = legal.minRaiseTo + Math.round(Math.max(pot, legal.minRaiseTo) * fraction)\n return clamp(target, legal.minRaiseTo, legal.maxRaiseTo)\n}\n","import { useState } from 'react'\nimport type { PlayerView } from '../types.ts'\nimport { getApiBase } from './api.ts'\nimport { t } from './i18n.ts'\nimport { copyText, cx } from './ui.ts'\nimport css from './styles.module.css'\n\n/** 邀请面板:一条链接 + 复制。远端(Cloudflare / 别人机器)用 joinUrl,本机优先局域网地址。 */\nexport function InviteSheet({ view, onClose }: { view: PlayerView; onClose: () => void }) {\n const room = view.room\n const [copied, setCopied] = useState(false)\n const remote = getApiBase() !== ''\n const link = remote ? room.joinUrl : room.lanUrl || room.joinUrl\n\n const copy = async (): Promise<void> => {\n if (!(await copyText(link))) return\n setCopied(true)\n setTimeout(() => setCopied(false), 1600)\n }\n\n return (\n <div className={css.sheetBackdrop} onClick={onClose} role=\"presentation\">\n <div className={css.sheet} role=\"dialog\" aria-label={t('invite.title')} onClick={(event) => event.stopPropagation()}>\n <header className={css.sheetHead}>\n <h2 className={css.sheetTitle}>{t('invite.title')}</h2>\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} onClick={onClose}>\n {t('common.close')}\n </button>\n </header>\n <div className={css.inviteLinkRow}>\n <input\n className={css.inviteLinkInput}\n value={link}\n readOnly\n spellCheck={false}\n onFocus={(event) => event.currentTarget.select()}\n />\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} onClick={() => void copy()}>\n {copied ? t('invite.copied') : t('invite.copy')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n","import type { Card } from '../types.ts'\nimport { cx } from './ui.ts'\nimport css from './styles.module.css'\n\nconst SUIT_SYMBOL: Record<string, string> = { s: '♠', h: '♥', d: '♦', c: '♣' }\nconst RED_SUITS = new Set(['h', 'd'])\n\nexport function suitOfCard(card: string): string {\n return card[1] ?? 's'\n}\n\nexport function rankOfCard(card: string): string {\n const char = card[0] ?? '?'\n return char === 'T' ? '10' : char\n}\n\nexport function isRedCard(card: string): boolean {\n return RED_SUITS.has(suitOfCard(card))\n}\n\nexport function CardView({ card, size = 'md', dim = false }: { card: Card; size?: 'sm' | 'md' | 'lg'; dim?: boolean }) {\n return (\n <div className={cx(css.card, css[`card_${size}`], isRedCard(card) ? css.cardRed : css.cardBlack, dim && css.cardDim)}>\n <span className={css.cardRank}>{rankOfCard(card)}</span>\n <span className={css.cardSuit}>{SUIT_SYMBOL[suitOfCard(card)] ?? '♠'}</span>\n </div>\n )\n}\n\nexport function CardBack({ size = 'sm' }: { size?: 'sm' | 'md' | 'lg' }) {\n return <div className={cx(css.card, css.cardBack, css[`card_${size}`])} aria-hidden=\"true\" />\n}\n\nexport function CardSlot({ filled, size = 'md', card }: { filled: boolean; size?: 'sm' | 'md' | 'lg'; card?: Card | undefined }) {\n if (filled && card) return <CardView card={card} size={size} />\n return <div className={cx(css.card, css.cardSlot, css[`card_${size}`])} aria-hidden=\"true\" />\n}\n","import type { SeatView, ShownHandView } from '../types.ts'\nimport { CardBack, CardView } from './CardView.tsx'\nimport { t } from './i18n.ts'\nimport { avatarStyle, cx, formatChips, initialOf, signedChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport interface SeatPodProps {\n seat: SeatView\n isYou: boolean\n isActor: boolean\n secondsLeft: number | null\n isDealer: boolean\n blind: 'sb' | 'bb' | null\n shown: ShownHandView | null\n className?: string | undefined\n canSit?: boolean | undefined\n onSit?: (() => void) | undefined\n onKick?: (() => void) | undefined\n}\n\nexport function SeatPod({\n seat,\n isYou,\n isActor,\n secondsLeft,\n isDealer,\n blind,\n shown,\n className,\n canSit,\n onSit,\n onKick,\n}: SeatPodProps) {\n if (!seat.playerId) {\n return (\n <div className={cx(css.seat, css.seatEmpty, className)}>\n <div className={css.seatEmptyText}>{t('table.sitDown')}</div>\n {canSit ? (\n <button type=\"button\" className={cx(css.btn, css.btnChip)} onClick={onSit}>\n {t('table.sitDown')}\n </button>\n ) : null}\n </div>\n )\n }\n\n const out = seat.folded || seat.sittingOut\n return (\n <div\n className={cx(\n css.seat,\n isYou && css.seatYou,\n isActor && css.seatActor,\n out && css.seatOut,\n !seat.connected && css.seatOffline,\n className,\n )}\n >\n <div className={css.seatTop}>\n <div className={css.avatar} style={avatarStyle(seat.playerId)}>\n {initialOf(seat.displayName)}\n {isActor && secondsLeft !== null ? (\n <span\n className={css.timerRing}\n style={{ '--progress': `${Math.max(0, Math.min(1, secondsLeft / 30)) * 360}deg` } as React.CSSProperties}\n aria-hidden=\"true\"\n />\n ) : null}\n </div>\n <div className={css.seatMeta}>\n <div className={css.seatName}>\n <span className={css.nameText}>{seat.displayName}</span>\n {isDealer ? <span className={cx(css.badge, css.badgeDealer)}>{t('table.dealer')}</span> : null}\n {blind === 'sb' ? <span className={cx(css.badge, css.badgeBlind)}>{t('table.sb')}</span> : null}\n {blind === 'bb' ? <span className={cx(css.badge, css.badgeBlind)}>{t('table.bb')}</span> : null}\n {isYou ? <span className={cx(css.badge, css.badgeYou)}>{t('table.you')}</span> : null}\n {seat.host ? <span className={cx(css.badge, css.badgeHost)}>{t('table.host')}</span> : null}\n </div>\n <div className={css.seatStack}>\n {formatChips(seat.stack)}\n {seat.handNet !== 0 ? (\n <span className={seat.handNet > 0 ? css.netUp : css.netDown}> {signedChips(seat.handNet)}</span>\n ) : null}\n </div>\n <div className={css.seatStatus}>\n {seat.allIn ? <span className={css.statusAllIn}>{t('table.allin')}</span> : null}\n {seat.folded ? <span className={css.statusFolded}>{t('table.folded')}</span> : null}\n {seat.sittingOut && !seat.autoFold ? <span className={css.statusMuted}>{t('table.sittingOut')}</span> : null}\n {seat.autoFold ? <span className={css.statusMuted}>{t('table.autofold')}</span> : null}\n {!seat.connected ? <span className={css.statusMuted}>{t('table.offline')}</span> : null}\n {seat.lastAction && !seat.folded ? <span className={css.statusAction}>{seat.lastAction}</span> : null}\n </div>\n </div>\n </div>\n\n {shown || seat.holeCount > 0 ? (\n <div className={css.seatCards}>\n {shown\n ? shown.cards.map((card) => <CardView key={card} card={card} size=\"sm\" dim={out} />)\n : Array.from({ length: seat.holeCount }, (_, index) => (\n <CardBack key={index} size=\"sm\" />\n ))}\n </div>\n ) : null}\n\n {onKick ? (\n <button type=\"button\" className={css.kickBtn} title={t('table.kick')} onClick={onKick}>\n ✕\n </button>\n ) : null}\n {seat.committed > 0 ? <div className={css.betChip}>{formatChips(seat.committed)}</div> : null}\n {shown ? <div className={css.handName}>{shown.name}</div> : null}\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { PlayerView } from '../types.ts'\nimport { t } from './i18n.ts'\nimport { runCommand } from './store.ts'\nimport { cx, formatBb, formatChips, signedChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport interface SideRailProps {\n view: PlayerView\n onChat: (text: string) => void\n busy: boolean\n}\n\nexport function SideRail({ view, onChat, busy }: SideRailProps) {\n const isHost = view.room.hostPlayerId === view.you.playerId\n const [draft, setDraft] = useState('')\n const send = (): void => {\n const text = draft.trim()\n if (!text) return\n setDraft('')\n onChat(text.slice(0, 80))\n }\n\n return (\n <aside className={css.rail}>\n <section className={css.railSection}>\n <h3 className={css.railTitle}>{t('rail.leaderboard')}</h3>\n <div className={css.leaderList}>\n {view.leaderboard.length === 0 ? <p className={css.railEmpty}>{t('rail.empty')}</p> : null}\n {view.leaderboard.map((entry, index) => (\n <div key={entry.playerId} className={cx(css.leaderRow, entry.playerId === view.you.playerId && css.leaderRowYou)}>\n <span className={css.leaderRank}>{index + 1}</span>\n <span className={css.leaderName}>{entry.displayName}</span>\n <span className={css.leaderHands}>{t('rail.hands', { n: entry.handsPlayed })}</span>\n <span className={entry.netChips > 0 ? css.netUp : entry.netChips < 0 ? css.netDown : css.netFlat}>\n {signedChips(entry.netChips)}\n </span>\n </div>\n ))}\n </div>\n </section>\n\n <section className={css.railSection}>\n <h3 className={css.railTitle}>{t('rail.history')}</h3>\n <div className={css.historyList}>\n {!view.lastHand ? <p className={css.railEmpty}>{t('rail.empty')}</p> : null}\n {view.lastHand ? (\n <div className={css.historyRow}>\n <span className={css.historyNo}>#{view.lastHand.handNo}</span>\n <span className={css.historyBoard}>\n {view.lastHand.board.map((card) => (\n <span key={card} className={css.historyCard}>{card}</span>\n ))}\n </span>\n <span className={css.historyPot}>{formatChips(view.lastHand.pots.reduce((sum, pot) => sum + pot.amount, 0))}</span>\n </div>\n ) : null}\n </div>\n </section>\n\n <section className={css.railSection}>\n <h3 className={css.railTitle}>{t('rail.spectators')}</h3>\n {view.spectators.length === 0 ? <p className={css.railEmpty}>{t('rail.noSpectators')}</p> : null}\n <div className={css.spectatorList}>\n {view.spectators.map((entry) => (\n <span key={entry.playerId} className={css.spectatorChip}>\n {entry.displayName}\n {isHost ? (\n <button\n type=\"button\"\n className={css.spectatorKick}\n title={t('table.kick')}\n onClick={() => {\n if (window.confirm(t('table.kickConfirm', { name: entry.displayName }))) {\n void runCommand({ type: 'hostKick', playerId: entry.playerId })\n }\n }}\n >\n ✕\n </button>\n ) : null}\n </span>\n ))}\n </div>\n </section>\n\n <section className={cx(css.railSection, css.railChat)}>\n <h3 className={css.railTitle}>{t('rail.chat')}</h3>\n <div className={css.chatList}>\n {view.chat.length === 0 ? <p className={css.railEmpty}>{t('rail.empty')}</p> : null}\n {view.chat.map((line, index) => (\n <div key={`${line.ts}-${index}`} className={css.chatLine}>\n <span className={css.chatName}>{line.displayName}</span>\n <span className={css.chatText}>{line.text}</span>\n </div>\n ))}\n </div>\n {view.room.settings.chatEnabled ? (\n <div className={css.chatComposer}>\n <input\n className={css.chatInput}\n value={draft}\n maxLength={80}\n placeholder={t('rail.chatPlaceholder')}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') send()\n }}\n />\n <button type=\"button\" className={cx(css.btn, css.btnChip)} disabled={busy || draft.trim().length === 0} onClick={send}>\n {t('rail.send')}\n </button>\n </div>\n ) : (\n <p className={css.railEmpty}>{t('rail.chatOff')}</p>\n )}\n </section>\n\n <div className={css.railFooter}>\n {t('rail.net')}: <strong>{signedChips(view.you.netChips)}</strong> · BB/100{' '}\n {formatBb(view.room.settings.bb, view.you.netChips, view.you.handsPlayed)}\n </div>\n </aside>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { PlayerView, SeatView, TableAction } from '../types.ts'\nimport { ActionBar } from './ActionBar.tsx'\nimport { InviteSheet } from './InviteSheet.tsx'\nimport { CardBack, CardSlot, CardView } from './CardView.tsx'\nimport { SeatPod } from './SeatPod.tsx'\nimport { SideRail } from './SideRail.tsx'\nimport { t } from './i18n.ts'\nimport { consumeAutoInvite, leaveRoom, runCommand, useClientState } from './store.ts'\nimport { cx, formatChips, signedChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport function Table({ view }: { view: PlayerView }) {\n const state = useClientState()\n const [railOpen, setRailOpen] = useState(() => readRailPref())\n const narrow = useNarrow()\n const hand = view.hand\n const room = view.room\n const youSeat = view.you.seat\n const actor = view.you.canAct && view.you.legal ? t('table.yourTurn') : actorLabel(view)\n\n const secondsLeft = useCountdown(hand?.deadlineAt ?? null)\n const nextHandSeconds = useCountdown(room.nextHandAt)\n const isHost = room.hostPlayerId === view.you.playerId\n const base = youSeat ?? 0\n const [inviteOpen, setInviteOpen] = useState(false)\n const [copied, setCopied] = useState(false)\n\n useEffect(() => {\n if (!copied) return undefined\n const timer = setTimeout(() => setCopied(false), 1600)\n return () => clearTimeout(timer)\n }, [copied])\n\n // 刚开完房:自动打开一次邀请面板,房主不用找入口\n useEffect(() => {\n if (!state.autoInvite) return\n setInviteOpen(true)\n consumeAutoInvite()\n }, [state.autoInvite])\n\n const act = (action: TableAction): void => {\n void runCommand({ type: 'action', action })\n }\n\n const seatedView = youSeat === null ? null : room.seats.find((seat) => seat.seat === youSeat) ?? null\n const emptySeats = room.seats.filter((seat) => seat.playerId === null).length\n\n return (\n <div className={css.table}>\n <header className={css.header}>\n <div className={css.headerMain}>\n <div className={css.titleRow}>\n <h1 className={css.roomTitle}>{room.title}</h1>\n <button type=\"button\" className={cx(css.btn, css.inviteBtn)} onClick={() => setInviteOpen(true)}>\n {t('table.invite')}\n </button>\n <span className={cx(css.phasePill, room.phase === 'hand' ? css.phasePillHand : css.phasePillLobby)}>\n {room.phase === 'hand' ? t('lobby.phase.hand') : t('lobby.phase.lobby')}\n </span>\n </div>\n <div className={css.metaRow}>\n <span>{t('table.blinds', { sb: room.settings.sb, bb: room.settings.bb, buyIn: formatChips(room.settings.buyIn) })}</span>\n <span>{t('table.hand', { n: room.handNo })}</span>\n <span className={cx(css.conn, state.connection === 'live' ? css.connLive : state.connection === 'polling' ? css.connPolling : css.connOffline)}>\n {state.connection === 'live' ? '●' : state.connection === 'polling' ? '◐' : '○'}\n </span>\n <span className={css.spectatorCount}>{t('common.spectators', { n: view.spectators.length })}</span>\n </div>\n </div>\n <div className={css.headerActions}>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnChip)}\n onClick={() => {\n setRailOpen((open) => {\n writeRailPref(!open)\n return !open\n })\n }}\n >\n {railOpen ? t('table.hideRail') : t('table.showRail')}\n </button>\n {isHost && room.phase !== 'hand' ? (\n <button type=\"button\" className={cx(css.btn, css.btnChip)} onClick={() => void runCommand({ type: 'hostPause' })}>\n {t('table.pause')}\n </button>\n ) : null}\n {isHost ? (\n <button\n type=\"button\"\n className={cx(css.btn, css.btnDanger)}\n onClick={() => {\n if (window.confirm(t('table.dissolveConfirm'))) void runCommand({ type: 'hostDissolve' })\n }}\n >\n {t('table.dissolve')}\n </button>\n ) : null}\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} onClick={() => void leaveRoom()}>\n {t('common.leave')}\n </button>\n </div>\n </header>\n\n <div className={css.tableBody}>\n <div className={css.feltArea}>\n <div className={css.felt}>\n {narrow ? (\n <div className={css.narrowList}>\n {room.seats\n .filter((seat) => seat.playerId !== null)\n .map((seat) => (\n <SeatRow key={seat.seat} seat={seat} view={view} />\n ))}\n {emptySeats > 0 ? <div className={css.narrowEmpty}>{t('table.emptySeats', { n: emptySeats })}</div> : null}\n </div>\n ) : (\n <div className={css.seatsLayer}>\n {room.seats.map((seat) => {\n const rel = (seat.seat - base + 6) % 6\n const shown = hand?.shownHands.find((entry) => entry.seat === seat.seat) ?? null\n const emptySeat = !seat.playerId\n return (\n <SeatPod\n key={seat.seat}\n seat={seat}\n isYou={seat.seat === youSeat}\n isActor={hand?.toActSeat === seat.seat && room.phase === 'hand'}\n secondsLeft={hand?.toActSeat === seat.seat ? secondsLeft : null}\n isDealer={hand?.button === seat.seat}\n blind={hand?.sbSeat === seat.seat ? 'sb' : hand?.bbSeat === seat.seat ? 'bb' : null}\n shown={shown}\n className={css[`pos${rel}`]}\n canSit={emptySeat && room.phase === 'lobby' && view.you.spectator}\n onSit={() => void runCommand({ type: 'sit' })}\n onKick={\n isHost && room.phase === 'lobby' && seat.playerId !== null && seat.playerId !== view.you.playerId\n ? () => {\n if (window.confirm(t('table.kickConfirm', { name: seat.displayName ?? '' }))) {\n void runCommand({ type: 'hostKick', playerId: seat.playerId as never })\n }\n }\n : undefined\n }\n />\n )\n })}\n </div>\n )}\n\n <div className={css.center}>\n <div className={css.streetLabel}>{t(`table.street.${hand?.street ?? 'preflop'}`)}</div>\n <div className={css.boardRow}>\n {Array.from({ length: 5 }, (_, index) => {\n const card = hand?.board[index]\n return <CardSlot key={card ?? `slot-${index}`} filled={Boolean(card)} card={card} size=\"md\" />\n })}\n </div>\n {hand && hand.potTotal > 0 ? (\n <div className={css.potRow}>\n <span className={css.potChips} aria-hidden=\"true\" />\n <span className={css.potAmount}>{t('table.pot', { amount: formatChips(hand.potTotal) })}</span>\n {hand.pots.length > 1 ? (\n <span className={css.sidePots}>\n {hand.pots.map((pot, index) => (\n <span key={index} className={css.sidePot}>\n {index === 0 ? t('table.potMain') : t('table.potSide', { n: index })} {formatChips(pot.amount)}\n </span>\n ))}\n </span>\n ) : null}\n </div>\n ) : null}\n {room.phase === 'lobby' ? (\n <div className={css.lobbyCenter}>\n <div className={css.centerTitle}>{t('table.waiting')}</div>\n <div className={css.centerHint}>\n {seatedView?.ready ? t('table.waitingReady') : null}\n </div>\n <div className={css.centerActions}>\n {isHost ? (\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} disabled={state.busy} onClick={() => void runCommand({ type: 'start' })}>\n {t('table.start')}\n </button>\n ) : null}\n {youSeat !== null ? (\n <button\n type=\"button\"\n className={cx(css.btn, css.btnOutline)}\n disabled={state.busy}\n onClick={() => void runCommand({ type: 'ready', ready: !view.you.ready })}\n >\n {view.you.ready ? t('table.unready') : t('table.ready')}\n </button>\n ) : null}\n </div>\n </div>\n ) : null}\n {room.phase === 'handOver' && view.lastHand ? (\n <div className={css.handOverBanner}>\n <div className={css.bannerTitle}>\n {bannerTitle(view)}\n </div>\n <div className={css.bannerDeltas}>\n {view.lastHand.deltas\n .filter((delta) => delta.net !== 0)\n .map((delta) => (\n <span key={delta.seat} className={delta.net > 0 ? css.netUp : css.netDown}>\n {delta.displayName} {signedChips(delta.net)}\n </span>\n ))}\n </div>\n {nextHandSeconds !== null ? (\n <div className={css.bannerNext}>{t('table.nextHand', { s: nextHandSeconds })}</div>\n ) : null}\n </div>\n ) : null}\n </div>\n </div>\n\n <div className={css.ownArea}>\n {view.you.spectator ? (\n <div className={css.ownHint}>\n <span>{t('table.spectatorHint')}</span>\n {room.phase === 'lobby' ? (\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} disabled={state.busy} onClick={() => void runCommand({ type: 'sit' })}>\n {t('table.sitDown')}\n </button>\n ) : null}\n </div>\n ) : (\n <>\n <div className={css.ownCards}>\n {view.you.holeCards.length > 0\n ? view.you.holeCards.map((card) => <CardView key={card} card={card} size=\"lg\" />)\n : room.phase === 'hand'\n ? [0, 1].map((index) => <CardBack key={index} size=\"lg\" />)\n : null}\n <div className={css.ownMeta}>\n <span className={css.ownName}>{seatedView?.displayName ?? view.you.displayName}</span>\n <span className={css.ownStack}>{formatChips(seatedView?.stack ?? 0)}</span>\n <span className={view.you.netChips >= 0 ? css.netUp : css.netDown}>{signedChips(view.you.netChips)}</span>\n </div>\n </div>\n {view.you.canAct && view.you.legal ? (\n <ActionBar\n legal={view.you.legal}\n potTotal={hand?.potTotal ?? 0}\n bigBlind={room.settings.bb}\n busy={state.busy}\n secondsLeft={secondsLeft}\n onAction={act}\n />\n ) : (\n <div className={css.ownHint}>\n <span>\n {room.phase === 'hand' && hand\n ? actor\n : room.phase === 'handOver'\n ? t('table.paused')\n : t('table.waiting')}\n </span>\n {room.phase === 'lobby' ? (\n <div className={css.ownButtons}>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnOutline)}\n disabled={state.busy}\n onClick={() => void runCommand({ type: 'ready', ready: !view.you.ready })}\n >\n {view.you.ready ? t('table.unready') : t('table.ready')}\n </button>\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} disabled={state.busy} onClick={() => void runCommand({ type: 'stand' })}>\n {t('table.stand')}\n </button>\n </div>\n ) : null}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n\n {inviteOpen ? <InviteSheet view={view} onClose={() => setInviteOpen(false)} /> : null}\n\n {railOpen ? (\n <div className={css.railWrap}>\n <SideRail view={view} busy={state.busy} onChat={(text) => void runCommand({ type: 'chat', text })} />\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nconst RAIL_KEY = 'holdem:rail'\n\nfunction readRailPref(): boolean {\n try {\n return localStorage.getItem(RAIL_KEY) !== 'closed'\n } catch {\n return true\n }\n}\n\nfunction writeRailPref(open: boolean): void {\n try {\n localStorage.setItem(RAIL_KEY, open ? 'open' : 'closed')\n } catch {\n // 忽略\n }\n}\n\nfunction actorLabel(view: PlayerView): string {\n const seat = view.hand?.toActSeat\n if (seat === undefined || seat === null) return t('table.waiting')\n const name = view.room.seats.find((entry) => entry.seat === seat)?.displayName ?? '—'\n return t('table.waitTurn', { name })\n}\n\nfunction bannerTitle(view: PlayerView): string {\n const last = view.lastHand\n if (!last) return ''\n if (last.foldedWin) return t('table.foldWin')\n const names = last.winners\n .map((seat) => view.room.seats.find((entry) => entry.seat === seat)?.displayName ?? '—')\n .join(' · ')\n const amount = last.pots.reduce((sum, pot) => sum + pot.amount, 0)\n return t('table.winner', { name: names, amount: formatChips(amount) })\n}\n\nfunction SeatRow({ seat, view }: { seat: SeatView; view: PlayerView }) {\n const shown = view.hand?.shownHands.find((entry) => entry.seat === seat.seat) ?? null\n return (\n <div className={cx(css.narrowRow, seat.seat === view.you.seat && css.narrowRowYou, seat.folded && css.seatOut)}>\n <span className={css.narrowName}>{seat.displayName ?? '—'}</span>\n <span className={css.narrowStack}>{formatChips(seat.stack)}</span>\n <span className={css.narrowCards}>\n {shown\n ? shown.cards.map((card) => <CardView key={card} card={card} size=\"sm\" />)\n : Array.from({ length: seat.holeCount }, (_, index) => <CardBack key={index} size=\"sm\" />)}\n </span>\n <span className={css.narrowStatus}>\n {seat.folded ? t('table.folded') : seat.allIn ? t('table.allin') : seat.lastAction ?? ''}\n </span>\n </div>\n )\n}\n\nfunction useCountdown(target: string | null): number | null {\n const [now, setNow] = useState(() => Date.now())\n useEffect(() => {\n if (!target) return undefined\n const timer = setInterval(() => setNow(Date.now()), 250)\n return () => clearInterval(timer)\n }, [target])\n if (!target) return null\n const remaining = Date.parse(target) - now\n if (!Number.isFinite(remaining)) return null\n return Math.max(0, Math.ceil(remaining / 1000))\n}\n\nfunction useNarrow(): boolean {\n const [narrow, setNarrow] = useState(() => typeof window !== 'undefined' && window.innerWidth < 900)\n useEffect(() => {\n const media = window.matchMedia('(max-width: 899px)')\n const update = (): void => setNarrow(media.matches)\n update()\n media.addEventListener('change', update)\n return () => media.removeEventListener('change', update)\n }, [])\n return narrow\n}\n","import { useEffect } from 'react'\nimport { Lobby } from './Lobby.tsx'\nimport { Settlement } from './Settlement.tsx'\nimport { Table } from './Table.tsx'\nimport { t } from './i18n.ts'\nimport { bootstrap, clearToast, useClientState } from './store.ts'\nimport { cx } from './ui.ts'\nimport css from './styles.module.css'\n\nexport function HoldemPanel() {\n const state = useClientState()\n\n useEffect(() => {\n void bootstrap()\n }, [])\n\n const closed = state.view?.room.phase === 'closed' && state.view.settlement !== null\n\n return (\n <div className={css.panel}>\n {!state.booted ? (\n <div className={css.loading}>\n <div className={css.loadingMark} aria-hidden=\"true\" />\n <p>{t('common.loading')}</p>\n </div>\n ) : state.view ? (\n closed ? <Settlement view={state.view} /> : <Table view={state.view} />\n ) : (\n <Lobby />\n )}\n {state.toast ? (\n <button\n type=\"button\"\n className={cx(css.toast, state.toast.kind === 'error' && css.toastError)}\n onClick={clearToast}\n >\n {state.toast.text}\n </button>\n ) : null}\n </div>\n )\n}\n","import type { PanelIconProps } from '@deepseek-ai/dsh-client-ui-slots'\n\n/** 侧栏面板图标:一只筹码叠着两张牌。 */\nexport function PanelIcon({ size = 20, active = false }: PanelIconProps) {\n const accent = active ? 'var(--dsw-alias-brand-primary)' : 'currentColor'\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <rect x=\"4.5\" y=\"3.5\" width=\"9\" height=\"13\" rx=\"2\" stroke={accent} strokeWidth=\"1.4\" transform=\"rotate(-12 9 10)\" />\n <rect x=\"9\" y=\"6\" width=\"9\" height=\"13\" rx=\"2\" stroke={accent} strokeWidth=\"1.4\" transform=\"rotate(9 13.5 12.5)\" />\n <circle cx=\"7.2\" cy=\"17.4\" r=\"4.1\" stroke={accent} strokeWidth=\"1.4\" />\n <circle cx=\"7.2\" cy=\"17.4\" r=\"1.7\" stroke={accent} strokeWidth=\"1.2\" strokeDasharray=\"1.5 1.8\" />\n </svg>\n )\n}\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { PanelIconProps } from '@deepseek-ai/dsh-client-ui-slots'\nimport { PANEL_KEY } from '../invariant.ts'\nimport { HoldemPanel } from './HoldemPanel.tsx'\nimport { PanelIcon } from './PanelIcon.tsx'\nimport { t } from './i18n.ts'\n\nexport { PANEL_KEY }\n\nexport function registerClientSlots(ctx: ClientContext): void {\n ctx.slots.inject('sidebar.panellist', () => ctx.slots.register({\n name: 'sidebar.panellist',\n id: PANEL_KEY,\n order: 30,\n label: () => t('panel.title'),\n }, function HoldemIcon(props: PanelIconProps) {\n return (\n <span\n onClick={() => ctx.layout.selectPanel(PANEL_KEY)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') ctx.layout.selectPanel(PANEL_KEY)\n }}\n role=\"presentation\"\n >\n <PanelIcon {...props} />\n </span>\n )\n }))\n\n ctx.slots.inject('main', () => ctx.slots.register({\n name: 'main',\n key: PANEL_KEY,\n }, HoldemPanel))\n}\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { PANEL_KEY } from '../invariant.ts'\nimport { DICTS, setTranslator } from './i18n.ts'\nimport { registerClientSlots } from './slots.tsx'\nimport { dispose } from './store.ts'\n\nexport const name = '@zhuweiyou/dsh-holdem-client'\nexport const inject = ['slots', 'layout', 'locale']\n\nconst NS = 'holdem'\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n const offZh = ctx.locale.register(NS, 'zh', DICTS.zh)\n const offEn = ctx.locale.register(NS, 'en', DICTS.en)\n const sync = (): void => setTranslator(ctx.locale.getLocale().id ?? 'zh')\n sync()\n const offLocale = ctx.locale.subscribe(sync)\n return () => {\n offZh()\n offEn()\n offLocale()\n }\n }, 'holdem: locale')\n\n ctx.effect(() => {\n registerClientSlots(ctx)\n // 邀请深链:/ ?dsh-panel=holdem&code=...&invite=...\n try {\n const params = new URLSearchParams(location.search)\n if (params.get('dsh-panel') === PANEL_KEY) ctx.layout.selectPanel(PANEL_KEY)\n } catch {\n // ignore\n }\n }, 'holdem: slots')\n\n ctx.effect(() => () => dispose(), 'holdem: dispose')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["ZH: Record<string, string>","EN: Record<string, string>","translator: Translate","name","seatTokens: string[]","name","state: ClientState","socket: WebSocket | null","pollTimer: ReturnType<typeof setInterval> | undefined","reconnectTimer: ReturnType<typeof setTimeout> | undefined","toastTimer: ReturnType<typeof setTimeout> | undefined","ws: WebSocket","session: Awaited<ReturnType<typeof api.session>> | null","HOSTING_OPTIONS: HostingOption[]","name","css","state","name","css","css","lines: string[]","presets: { label: string; value: number }[]","css","css","SUIT_SYMBOL: Record<string, string>","css","css","css","state","css","state","css"],"sources":["../src/invariant.ts","../src/client/i18n.ts","../src/client/api.ts","../src/client/presence.ts","../src/client/store.ts","../src/client/backends.ts","../src/client/ui.ts","../src/client/CloudflarePanel.tsx","../src/client/Lobby.tsx","../src/client/Settlement.tsx","../src/client/ActionBar.tsx","../src/client/InviteSheet.tsx","../src/client/CardView.tsx","../src/client/SeatPod.tsx","../src/client/SideRail.tsx","../src/client/Table.tsx","../src/client/HoldemPanel.tsx","../src/client/PanelIcon.tsx","../src/client/slots.tsx","../src/client/index.tsx"],"sourcesContent":["/** 全局常量:协议、上限、时间与筹码档位。 */\n\nexport const PACKAGE_NAME = '@zhuweiyou/dsh-holdem'\nexport const CLIENT_ID = '@zhuweiyou/dsh-holdem'\nexport const PANEL_KEY = 'holdem'\nexport const SUBPROTOCOL = 'holdem.v1'\nexport const ROUTE_PREFIX = '/holdem'\n\nexport const MAX_SEATS = 6\nexport const MAX_SPECTATORS = 16\nexport const MAX_ROOMS = 8\nexport const MAX_TITLE = 24\nexport const MAX_DISPLAY_NAME = 16\nexport const MAX_CHAT = 80\nexport const MAX_CHAT_LINES = 80\nexport const MAX_HISTORY_HANDS = 50\nexport const MAX_CACHED_ACTIONS = 64\nexport const MAX_BODY_BYTES = 64 * 1024\nexport const MAX_FRAME_BYTES = 64 * 1024\n\nexport const TICK_MS = 250\nexport const WS_TICKET_TTL_MS = 60_000\nexport const SESSION_TTL_MS = 24 * 60 * 60 * 1000\nexport const HEARTBEAT_MS = 15_000\nexport const DISCONNECT_AFTER_MS = 45_000\nexport const LOBBY_KICK_IDLE_MS = 10 * 60 * 1000\nexport const CHAT_COOLDOWN_MS = 1200\nexport const ACTION_RATE_WINDOW_MS = 10_000\nexport const ACTION_RATE_MAX = 30\n\nexport const BUY_IN_BB = 100\nexport const ALL_IN_RUNOUT_MS = 1200\nexport const HAND_OVER_MIN_MS = 2500\n\nexport const BLIND_LEVELS = [\n { id: '10/20', sb: 10, bb: 20 },\n { id: '25/50', sb: 25, bb: 50 },\n { id: '100/200', sb: 100, bb: 200 },\n] as const\n\nexport type BlindLevelId = (typeof BLIND_LEVELS)[number]['id']\n\nexport function blindsFor(id: string): { id: BlindLevelId; sb: number; bb: number } {\n const found = BLIND_LEVELS.find((level) => level.id === id)\n const level = found ?? BLIND_LEVELS[1]!\n return { id: level.id, sb: level.sb, bb: level.bb }\n}\n\nexport function buyInFor(bb: number): number {\n return bb * BUY_IN_BB\n}\n","export type Translate = (key: string, params?: Record<string, string | number>) => string\n\nconst ZH: Record<string, string> = {\n 'panel.title': '德州扑克',\n 'panel.subtitle': '房主即服务端 · 娱乐筹码',\n 'common.loading': '正在准备牌桌…',\n 'common.cancel': '取消',\n 'common.confirm': '确定',\n 'common.copy': '复制',\n 'common.copied': '已复制',\n 'common.close': '关闭',\n 'common.name': '昵称',\n 'common.retry': '重试',\n 'common.back': '返回大厅',\n 'common.leave': '离开',\n 'common.players': '{n} 人',\n 'common.spectators': '观战 {n}',\n 'lobby.create': '创建房间',\n 'lobby.join': '加入房间',\n 'host.label': '开桌位置',\n 'host.local': '本机',\n 'host.localHint': '跑在你自己的 dsh 里;同一 Wi-Fi 的朋友用局域网链接加入,不需要公网。',\n 'host.cloudflare': '公网 · Cloudflare',\n 'host.cloudflareHint': '牌桌跑在 Cloudflare Worker 上,关掉你的电脑也能玩;点一下授权 → 自动部署,之后建房直接用。',\n 'host.needCloudflare': '先授权并部署 Cloudflare,再开桌',\n 'cf.needAuth': '还没授权 Cloudflare',\n 'cf.waiting': '等待浏览器授权…',\n 'cf.cancel': '取消授权',\n 'cf.authorized': '已授权 {account}',\n 'cf.authorize': '授权 Cloudflare',\n 'cf.deploy': '部署到 Cloudflare',\n 'cf.redeploy': '重新部署',\n 'cf.deploying': '部署中…',\n 'cf.switchAccount': '换账号',\n 'cf.address': '云端地址',\n 'cf.authHint': '浏览器没有自动打开时(授权页一般会自动弹),复制这个链接到浏览器:',\n 'cf.unreachable': '拿不到 Cloudflare 状态(插件可能刚重载)',\n 'lobby.title': '房间名',\n 'lobby.titlePlaceholder': '例如 周五晚场',\n 'lobby.blinds': '盲注',\n 'lobby.namePlaceholder': '你的昵称',\n 'lobby.createAction': '开一桌',\n 'lobby.linkOnly': '邀请链接',\n 'lobby.linkOnlyPlaceholder': '粘贴房主发来的邀请链接',\n 'lobby.needLink': '粘贴房主发来的邀请链接(只认链接,没有房号)',\n 'lobby.joinFailed': '加入失败({where}):{message}',\n 'lobby.linkHint': '链接里已经带着这桌在哪儿(本机 / 局域网 / Cloudflare),所以不用填房号。',\n 'lobby.enter': '进入牌桌',\n 'lobby.preview': '查看房间',\n 'lobby.sit': '入座',\n 'lobby.watch': '观战',\n 'lobby.invited': '你被邀请加入房间 {code}',\n 'lobby.full': '座位已满,会以观战身份进入',\n 'lobby.needCode': '请输入 6 位房号',\n 'lobby.needName': '请先填昵称',\n 'lobby.hintPrefix': '开桌时可选 Cloudflare(公网牌桌,关掉电脑也能玩)或本机(同一 Wi-Fi 内分享);把邀请链接发过去,对方用浏览器打开就能加入。想自己开桌再装 ',\n 'lobby.hintSuffix': '。',\n 'lobby.seated': '已在座 {n}/6',\n 'lobby.phase.lobby': '等待开局',\n 'lobby.phase.hand': '正在打牌',\n 'table.room': '房号 {code}',\n 'table.hand': '第 {n} 手',\n 'table.blinds': '{sb}/{bb} · 带入 {buyIn}',\n 'table.copyInvite': '复制邀请链接',\n 'table.invite': '邀请好友',\n 'table.copyCode': '复制房号',\n 'invite.title': '邀请好友入桌',\n 'invite.copy': '复制',\n 'invite.copied': '已复制',\n 'invite.copyCode': '复制房号',\n 'table.pause': '暂停',\n 'table.dissolve': '解散并结算',\n 'table.dissolveConfirm': '解散房间并生成总结算?',\n 'table.waiting': '等待房主开局',\n 'table.waitingReady': '等待其他玩家准备',\n 'table.ready': '准备',\n 'table.unready': '取消准备',\n 'table.start': '开始',\n 'table.hideRail': '收起侧栏',\n 'table.showRail': '侧栏',\n 'table.kick': '踢出',\n 'table.kickConfirm': '把 {name} 请出房间?',\n 'table.stand': '离座',\n 'table.sitDown': '入座',\n 'table.spectating': '观战中',\n 'table.you': '你',\n 'table.host': '房主',\n 'table.dealer': 'D',\n 'table.sb': 'SB',\n 'table.bb': 'BB',\n 'table.emptySeats': '还有 {n} 个空位',\n 'table.folded': '已弃牌',\n 'table.allin': '全下',\n 'table.offline': '离线',\n 'table.autofold': '托管',\n 'table.sittingOut': '暂离',\n 'table.pot': '底池 {amount}',\n 'table.potMain': '主池',\n 'table.potSide': '边池 {n}',\n 'table.street.preflop': '翻牌前',\n 'table.street.flop': '翻牌',\n 'table.street.turn': '转牌',\n 'table.street.river': '河牌',\n 'table.street.showdown': '摊牌',\n 'table.yourTurn': '轮到你了',\n 'table.waitTurn': '等待 {name} 行动',\n 'table.fold': '弃牌',\n 'table.check': '过牌',\n 'table.call': '跟注 {amount}',\n 'table.raise': '加注',\n 'table.bet': '下注',\n 'table.raiseTo': '加注到 {amount}',\n 'table.allinAction': '全下',\n 'table.halfPot': '1/2 池',\n 'table.twoThirds': '2/3 池',\n 'table.potBet': '一池',\n 'table.min': '最小',\n 'table.max': '最大',\n 'table.timer': '{s} 秒',\n 'table.spectatorHint': '观战模式:看不到任何未亮出的底牌,有人离座后可以补位。',\n 'table.noSeat': '你还没有入座',\n 'table.winner': '{name} 赢得 {amount}',\n 'table.foldWin': '其余玩家弃牌',\n 'table.nextHand': '{s} 秒后开始下一手',\n 'table.paused': '已暂停,等待房主开始',\n 'rail.leaderboard': '排行榜',\n 'rail.history': '最近手牌',\n 'rail.chat': '桌边聊天',\n 'rail.spectators': '观战席',\n 'rail.empty': '还没有记录',\n 'rail.hands': '{n} 手',\n 'rail.net': '净赢',\n 'rail.wins': '胜',\n 'rail.chatPlaceholder': '说点什么…',\n 'rail.send': '发送',\n 'rail.chatOff': '本桌已关闭聊天',\n 'rail.noSpectators': '暂时没有人观战',\n 'settle.title': '本场结算',\n 'settle.dissolved': '房主已解散房间',\n 'settle.idle': '房主长时间无响应,房间自动解散',\n 'settle.rank': '名次',\n 'settle.player': '玩家',\n 'settle.hands': '手数',\n 'settle.wins': '胜局',\n 'settle.net': '净赢',\n 'settle.bb100': 'BB/100',\n 'settle.showdown': '摊牌胜率',\n 'settle.duration': '时长 {m} 分钟 · 共 {hands} 手',\n 'settle.copy': '复制战绩',\n 'settle.download': '下载 JSON',\n 'settle.again': '再来一局',\n 'settle.backHome': '返回大厅(可重新开房)',\n 'settle.empty': '这一场还没有打完任何一手。',\n 'error.generic': '出了点问题',\n 'error.connection': '与房主的连接中断,正在重连…',\n 'error.stale': '状态已更新,已为你刷新',\n 'error.notYourTurn': '还没轮到你',\n 'error.roomGone': '房间已解散',\n 'error.noSeatCookie': '浏览器没有保存牌桌凭证(cookie 被拦或没带上),刷新页面后再试',\n 'error.kicked': '你被房主请出了房间',\n 'toast.joined': '已进入房间 {code}',\n 'toast.created': '房间已创建:{code}',\n 'toast.duplicate': '操作已生效',\n 'toast.switched': '已切换到房间 {code}',\n 'toast.left': '已离开房间',\n 'toast.settlement': '本场已结算',\n}\n\nconst EN: Record<string, string> = {\n 'panel.title': \"Hold'em\",\n 'panel.subtitle': 'Host is the server · play chips',\n 'common.loading': 'Preparing the table…',\n 'common.cancel': 'Cancel',\n 'common.confirm': 'Confirm',\n 'common.copy': 'Copy',\n 'common.copied': 'Copied',\n 'common.close': 'Close',\n 'common.name': 'Name',\n 'common.retry': 'Retry',\n 'common.back': 'Back to lobby',\n 'common.leave': 'Leave',\n 'common.players': '{n} players',\n 'common.spectators': '{n} watching',\n 'lobby.create': 'Create room',\n 'lobby.join': 'Join room',\n 'host.label': 'Where to host',\n 'host.local': 'This machine',\n 'host.localHint': 'Runs inside your own dsh: friends on the same Wi-Fi join through the LAN link; nothing is exposed publicly.',\n 'host.cloudflare': 'Public · Cloudflare',\n 'host.cloudflareHint': 'Rooms run on a Cloudflare Worker — play even with your laptop off. Authorize once, deploy automatically.',\n 'host.needCloudflare': 'Authorize and deploy Cloudflare first',\n 'cf.needAuth': 'Cloudflare not connected',\n 'cf.waiting': 'Waiting for the browser…',\n 'cf.cancel': 'Cancel',\n 'cf.authorized': 'Connected as {account}',\n 'cf.authorize': 'Authorize Cloudflare',\n 'cf.deploy': 'Deploy to Cloudflare',\n 'cf.redeploy': 'Redeploy',\n 'cf.deploying': 'Deploying…',\n 'cf.switchAccount': 'Switch account',\n 'cf.address': 'Worker address',\n 'cf.authHint': 'If the authorization page did not open by itself, copy this link:',\n 'cf.unreachable': 'Cannot read Cloudflare status yet',\n 'lobby.title': 'Room name',\n 'lobby.titlePlaceholder': 'Friday night',\n 'lobby.blinds': 'Blinds',\n 'lobby.namePlaceholder': 'Your name',\n 'lobby.createAction': 'Create',\n 'lobby.code': 'Room code',\n 'lobby.codePlaceholder': '6-digit code',\n 'lobby.preview': 'Preview',\n 'lobby.sit': 'Take a seat',\n 'lobby.watch': 'Watch',\n 'lobby.invited': 'You are invited to room {code}',\n 'lobby.full': 'Seats are full — you will join as a spectator',\n 'lobby.needCode': 'Enter the 6-digit room code',\n 'lobby.needName': 'Enter a name first',\n 'lobby.hintPrefix': 'Host on Cloudflare for a public table that stays up with your laptop off, or on this machine for same-Wi-Fi play. Send the invite link and friends join in a browser. Install ',\n 'lobby.hintSuffix': ' only if you want to host your own table.',\n 'lobby.seated': 'Seated {n}/6',\n 'lobby.phase.lobby': 'Waiting',\n 'lobby.phase.hand': 'In hand',\n 'table.room': 'Room {code}',\n 'table.hand': 'Hand #{n}',\n 'table.blinds': '{sb}/{bb} · buy-in {buyIn}',\n 'table.copyInvite': 'Copy invite link',\n 'table.invite': 'Invite',\n 'table.copyCode': 'Copy code',\n 'invite.title': 'Invite to the table',\n 'invite.copy': 'Copy',\n 'invite.copied': 'Copied',\n 'invite.copyCode': 'Copy code',\n 'table.pause': 'Pause',\n 'table.dissolve': 'Dissolve & settle',\n 'table.dissolveConfirm': 'Dissolve the room and show the final settlement?',\n 'table.waiting': 'Waiting for the host to start',\n 'table.waitingReady': 'Waiting for other players to ready up',\n 'table.ready': 'Ready',\n 'table.unready': 'Not ready',\n 'table.start': 'Start',\n 'table.hideRail': 'Hide panel',\n 'table.showRail': 'Panel',\n 'table.kick': 'Kick',\n 'table.kickConfirm': 'Kick {name} out of the room?',\n 'table.stand': 'Stand up',\n 'table.sitDown': 'Sit down',\n 'table.spectating': 'Spectating',\n 'table.you': 'You',\n 'table.host': 'Host',\n 'table.dealer': 'D',\n 'table.sb': 'SB',\n 'table.bb': 'BB',\n 'table.emptySeats': '{n} seats open',\n 'table.folded': 'Folded',\n 'table.allin': 'All in',\n 'table.offline': 'Offline',\n 'table.autofold': 'Auto',\n 'table.sittingOut': 'Sitting out',\n 'table.pot': 'Pot {amount}',\n 'table.potMain': 'Main pot',\n 'table.potSide': 'Side pot {n}',\n 'table.street.preflop': 'Pre-flop',\n 'table.street.flop': 'Flop',\n 'table.street.turn': 'Turn',\n 'table.street.river': 'River',\n 'table.street.showdown': 'Showdown',\n 'table.yourTurn': 'Your turn',\n 'table.waitTurn': '{name} to act',\n 'table.fold': 'Fold',\n 'table.check': 'Check',\n 'table.call': 'Call {amount}',\n 'table.raise': 'Raise',\n 'table.bet': 'Bet',\n 'table.raiseTo': 'Raise to {amount}',\n 'table.allinAction': 'All in',\n 'table.halfPot': '1/2 pot',\n 'table.twoThirds': '2/3 pot',\n 'table.potBet': 'Pot',\n 'table.min': 'Min',\n 'table.max': 'Max',\n 'table.timer': '{s}s',\n 'table.spectatorHint': 'Spectating: hole cards stay hidden. You can take a freed seat.',\n 'table.noSeat': 'You are not seated',\n 'table.winner': '{name} wins {amount}',\n 'table.foldWin': 'Everyone else folded',\n 'table.nextHand': 'Next hand in {s}s',\n 'table.paused': 'Paused — waiting for the host',\n 'rail.leaderboard': 'Leaderboard',\n 'rail.history': 'Recent hands',\n 'rail.chat': 'Table chat',\n 'rail.spectators': 'Spectators',\n 'rail.empty': 'Nothing yet',\n 'rail.hands': '{n} hands',\n 'rail.net': 'Net',\n 'rail.wins': 'W',\n 'rail.chatPlaceholder': 'Say something…',\n 'rail.send': 'Send',\n 'rail.chatOff': 'Chat is off at this table',\n 'rail.noSpectators': 'No spectators yet',\n 'settle.title': 'Session settlement',\n 'settle.dissolved': 'The host dissolved the room',\n 'settle.idle': 'The host went idle, so the room was settled automatically',\n 'settle.rank': '#',\n 'settle.player': 'Player',\n 'settle.hands': 'Hands',\n 'settle.wins': 'Wins',\n 'settle.net': 'Net',\n 'settle.bb100': 'BB/100',\n 'settle.showdown': 'Showdown',\n 'settle.duration': '{m} min · {hands} hands',\n 'settle.copy': 'Copy results',\n 'settle.download': 'Download JSON',\n 'settle.again': 'Play again',\n 'settle.backHome': 'Back to lobby',\n 'settle.empty': 'No hand finished in this session.',\n 'error.generic': 'Something went wrong',\n 'error.connection': 'Lost the host connection — reconnecting…',\n 'error.stale': 'State changed; refreshed for you',\n 'error.notYourTurn': 'Not your turn',\n 'error.roomGone': 'The room is gone',\n 'error.noSeatCookie': 'The browser did not keep the seat cookie — refresh the page and try again',\n 'error.kicked': 'The host removed you from the room',\n 'toast.joined': 'Joined room {code}',\n 'toast.created': 'Room created: {code}',\n 'toast.duplicate': 'Already applied',\n 'toast.switched': 'Switched to room {code}',\n 'toast.left': 'Left the room',\n 'toast.settlement': 'Session settled',\n}\n\nexport const DICTS = { zh: ZH, en: EN }\n\nlet translator: Translate = createTranslator('zh')\n\nexport function setTranslator(locale: string): void {\n translator = createTranslator(locale)\n}\n\nexport function t(key: string, params?: Record<string, string | number>): string {\n return translator(key, params)\n}\n\nexport function createTranslator(locale: string): Translate {\n const dict = locale.toLowerCase().startsWith('en') ? EN : ZH\n return (key, params) => {\n const template = dict[key] ?? ZH[key] ?? key\n if (!params) return template\n return template.replace(/\\{(\\w+)\\}/g, (_match, name: string) => String(params[name] ?? `{${name}}`))\n }\n}\n","import type { ClientCommand, PlayerView, RoomPreview, SessionSummary } from '../types.ts'\n\nexport const PREFIX = '/holdem'\nconst HEADERS = {\n 'content-type': 'application/json',\n 'x-requested-with': '@zhuweiyou/dsh-holdem',\n}\n\n/** 后端基址:'' = 当前 DSH 进程;也可以指到 Cloudflare Worker 上。 */\nlet apiBase = ''\n\nexport function setApiBase(base: string): void {\n const trimmed = base.trim().replace(/\\/+$/, '')\n apiBase = trimmed === '' ? '' : trimmed\n}\n\nexport function getApiBase(): string {\n return apiBase\n}\n\n/** 座位 token 走请求头,不依赖浏览器是否保留 cookie。 */\nlet seatTokens: string[] = []\n\nexport function setSeatTokens(tokens: string[]): void {\n seatTokens = [...new Set(tokens.filter((token) => token !== ''))]\n}\n\nexport class ApiError extends Error {\n readonly code: string\n readonly status: number\n readonly view: PlayerView | undefined\n\n constructor(code: string, message: string, status: number, view?: PlayerView) {\n super(message)\n this.name = 'ApiError'\n this.code = code\n this.status = status\n this.view = view\n }\n}\n\nasync function request<T>(path: string, init: RequestInit = {}, base: string = apiBase): Promise<T> {\n const response = await fetch(`${base}${PREFIX}${path}`, {\n credentials: base === '' ? 'same-origin' : 'omit',\n ...init,\n headers: {\n ...HEADERS,\n ...(seatTokens.length > 0 ? { 'x-holdem-seat': seatTokens.join(',') } : {}),\n ...(init.headers as Record<string, string> | undefined),\n },\n })\n const text = await response.text()\n const body = (text ? JSON.parse(text) : {}) as T & { error?: string; message?: string; view?: PlayerView }\n if (!response.ok) {\n throw new ApiError(body.error ?? `http-${response.status}`, body.message ?? response.statusText, response.status, body.view)\n }\n return body\n}\n\n/**\n * 本机特权请求:Cloudflare 授权/部署跑在 dsh 进程里,只认回环地址。\n * 当前会话可能指向 Worker(创建过公网房间后 apiBase 不是 ''),所以这里强制打到本机。\n */\nfunction localRequest<T>(path: string, init: RequestInit = {}): Promise<T> {\n return request<T>(path, init, '')\n}\n\nexport interface CreateRoomResponse {\n roomId: string\n roomCode: string\n hostPlayerId: string\n joinUrl: string\n wsTicket: string\n sessionToken: string\n view: PlayerView\n}\n\nexport interface JoinResponse {\n playerId: string\n roomId: string\n seat: number | null\n wsTicket: string\n sessionToken: string\n view: PlayerView\n}\n\nexport interface CloudflareStatus {\n authorized: boolean\n account: string\n workerUrl: string\n pending: boolean\n deploying: boolean\n authorizeUrl: string\n error: string\n log: string\n}\n\nexport interface SessionResponse {\n inRoom: boolean\n roomId?: string\n view?: PlayerView\n /** 浏览器实际带上来几个座位凭证(0 说明 cookie 没存/被拦)。 */\n seatCookies?: number\n}\n\nexport interface StateResponse {\n seq: number\n view: PlayerView\n}\n\nexport const api = {\n createRoom(input: { title?: string | undefined; blindLevel?: string | undefined; displayName?: string | undefined; browserId?: string | undefined }) {\n return request<CreateRoomResponse>('/api/rooms', { method: 'POST', body: JSON.stringify(input) })\n },\n preview(input: { code: string; invite?: string | undefined; role?: 'sit' | 'watch' | undefined; browserId?: string | undefined }) {\n const query = new URLSearchParams({ code: input.code })\n if (input.invite) query.set('invite', input.invite)\n if (input.role) query.set('role', input.role)\n if (input.browserId) query.set('browser', input.browserId)\n return request<RoomPreview>(`/api/preview?${query.toString()}`)\n },\n join(input: { roomCode: string; invite?: string | undefined; displayName: string; role: 'sit' | 'watch'; browserId?: string | undefined }) {\n return request<JoinResponse>('/api/join', { method: 'POST', body: JSON.stringify(input) })\n },\n session(roomId?: string) {\n const query = roomId ? `?roomId=${encodeURIComponent(roomId)}` : ''\n return request<SessionResponse>(`/api/session${query}`)\n },\n state(roomId: string) {\n return request<StateResponse>(`/api/rooms/${encodeURIComponent(roomId)}/state`)\n },\n action(roomId: string, input: { actionId: string; baseSeq: number; command: ClientCommand }) {\n return request<{ seq: number; view: PlayerView; duplicate: boolean }>(\n `/api/rooms/${encodeURIComponent(roomId)}/action`,\n { method: 'POST', body: JSON.stringify(input) },\n )\n },\n leave(roomId?: string) {\n return request<{ ok: boolean }>('/api/leave', {\n method: 'POST',\n body: JSON.stringify(roomId ? { roomId } : {}),\n keepalive: true,\n })\n },\n wsTicket(roomId?: string) {\n return request<{ wsTicket: string }>('/api/ws-ticket', {\n method: 'POST',\n body: JSON.stringify(roomId ? { roomId } : {}),\n })\n },\n history(roomId: string) {\n return request<{ summary: SessionSummary | null }>(`/api/rooms/${encodeURIComponent(roomId)}/history`)\n },\n cloudflare() {\n return localRequest<CloudflareStatus>('/api/cloudflare')\n },\n cloudflareAction(action: 'login' | 'deploy' | 'cancel' | 'logout') {\n return localRequest<CloudflareStatus>(`/api/cloudflare?action=${action}`, { method: 'POST', body: '{}' })\n },\n}\n\nexport function newActionId(): string {\n const cryptoObject = globalThis.crypto\n if (cryptoObject?.randomUUID) return cryptoObject.randomUUID()\n return `a${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`\n}\n","const BROWSER_KEY = 'dsh-holdem.browser'\nconst NAME_KEY = 'dsh-holdem.name'\nconst ID_RE = /^[A-Za-z0-9_-]{8,64}$/\n\nlet cached = ''\n\nfunction storage(): Storage | undefined {\n try {\n return globalThis.localStorage\n } catch {\n return undefined\n }\n}\n\n/** 同一浏览器(同源)稳定 id,用于「这个浏览器已经在这个房间里」判定。 */\nexport function browserId(): string {\n if (cached) return cached\n const store = storage()\n if (!store) return ''\n try {\n const existing = store.getItem(BROWSER_KEY)\n if (existing && ID_RE.test(existing)) {\n cached = existing\n return cached\n }\n const next = (globalThis.crypto?.randomUUID?.() ?? `b${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`)\n .replace(/[^A-Za-z0-9_-]/g, '')\n .slice(0, 64)\n if (!ID_RE.test(next)) return ''\n store.setItem(BROWSER_KEY, next)\n cached = next\n return cached\n } catch {\n return ''\n }\n}\n\nexport function rememberedName(): string {\n try {\n return storage()?.getItem(NAME_KEY) ?? ''\n } catch {\n return ''\n }\n}\n\nexport function rememberName(name: string): void {\n try {\n storage()?.setItem(NAME_KEY, name)\n } catch {\n // ignore\n }\n}\n\nexport interface DeepLink {\n code: string\n invite: string\n role: 'sit' | 'watch'\n}\n\n/** 读取 `/?dsh-panel=holdem&code=...&invite=...&role=...`(也兼容 hash 内的查询串)。 */\nexport function parseDeepLink(): DeepLink | null {\n if (typeof location === 'undefined') return null\n const search = new URLSearchParams(location.search)\n const hash = location.hash.includes('?') ? new URLSearchParams(location.hash.slice(location.hash.indexOf('?') + 1)) : null\n const code = search.get('code') ?? hash?.get('code') ?? ''\n const panel = search.get('dsh-panel') ?? hash?.get('dsh-panel') ?? ''\n if (!code || (panel !== 'holdem' && !search.has('code'))) return null\n return {\n code: code.replace(/\\D/g, '').slice(0, 6),\n invite: search.get('invite') ?? hash?.get('invite') ?? '',\n role: (search.get('role') ?? hash?.get('role')) === 'watch' ? 'watch' : 'sit',\n }\n}\n\nexport function clearDeepLink(): void {\n try {\n const url = new URL(location.href)\n for (const key of ['code', 'invite', 'role', 'dsh-panel']) url.searchParams.delete(key)\n const query = url.searchParams.toString()\n history.replaceState(null, '', `${url.pathname}${query ? `?${query}` : ''}${url.hash.includes('dsh-panel') ? '#/' : url.hash}`)\n } catch {\n // ignore\n }\n}\n","import { useSyncExternalStore } from 'react'\nimport type { ClientCommand, PlayerView, ServerEvent } from '../types.ts'\nimport { ApiError, api, getApiBase, newActionId, setApiBase, setSeatTokens } from './api.ts'\nimport { browserId } from './presence.ts'\nimport { t } from './i18n.ts'\n\nexport type Connection = 'idle' | 'connecting' | 'live' | 'polling' | 'offline'\n\nexport interface Toast {\n id: number\n text: string\n kind: 'info' | 'error'\n}\n\nexport interface ClientState {\n booted: boolean\n busy: boolean\n connection: Connection\n view: PlayerView | null\n notice: string | null\n toast: Toast | null\n /** 刚开完房:面板会自动把邀请弹窗打开一次,免得房主不知道怎么叫人。 */\n autoInvite: boolean\n}\n\nlet state: ClientState = {\n booted: false,\n busy: false,\n connection: 'idle',\n view: null,\n notice: null,\n toast: null,\n autoInvite: false,\n}\n\nconst listeners = new Set<() => void>()\nlet socket: WebSocket | null = null\nlet pollTimer: ReturnType<typeof setInterval> | undefined\nlet reconnectTimer: ReturnType<typeof setTimeout> | undefined\nlet toastTimer: ReturnType<typeof setTimeout> | undefined\nlet toastSeq = 0\nlet disposed = false\n\nrestoreBackend()\nsyncSeatTokens()\n\nconst ROOM_KEY = 'holdem:room'\nconst SEATS_KEY = 'holdem:seats'\n\n/** 每个标签页自己保存每个房间的座位 token,并同步到请求头。 */\nfunction readSeats(): Record<string, string> {\n try {\n const raw = sessionStorage.getItem(SEATS_KEY)\n return raw ? (JSON.parse(raw) as Record<string, string>) : {}\n } catch {\n return {}\n }\n}\n\nfunction syncSeatTokens(): void {\n setSeatTokens(Object.values(readSeats()))\n}\n\nfunction rememberSeat(roomId: string, token: string): void {\n const seats = readSeats()\n seats[roomId] = token\n const ids = Object.keys(seats)\n for (const stale of ids.slice(0, Math.max(0, ids.length - 5))) delete seats[stale]\n try {\n sessionStorage.setItem(SEATS_KEY, JSON.stringify(seats))\n } catch {\n // 隐私模式忽略\n }\n syncSeatTokens()\n}\n\n/** 每个标签页记住自己在哪个房间,刷新后不会跑到同一浏览器里最新开的那个房间。 */\nfunction rememberRoom(roomId: string | null): void {\n try {\n if (roomId) sessionStorage.setItem(ROOM_KEY, roomId)\n else sessionStorage.removeItem(ROOM_KEY)\n } catch {\n // 隐私模式下忽略\n }\n}\n\nfunction rememberedRoom(): string | null {\n try {\n return sessionStorage.getItem(ROOM_KEY)\n } catch {\n return null\n }\n}\n\nfunction set(patch: Partial<ClientState>): void {\n state = { ...state, ...patch }\n for (const listener of listeners) listener()\n}\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n}\n\nexport function useClientState(): ClientState {\n return useSyncExternalStore(subscribe, getState, getState)\n}\n\nexport function getState(): ClientState {\n return state\n}\n\nexport function toast(text: string, kind: 'info' | 'error' = 'info'): void {\n toastSeq += 1\n set({ toast: { id: toastSeq, text, kind } })\n if (toastTimer) clearTimeout(toastTimer)\n toastTimer = setTimeout(() => {\n set({ toast: null })\n }, kind === 'error' ? 4200 : 2600)\n}\n\n/** 邀请弹窗已经自动弹过一次了。 */\nexport function consumeAutoInvite(): void {\n if (state.autoInvite) set({ autoInvite: false })\n}\n\nexport function clearToast(): void {\n if (toastTimer) clearTimeout(toastTimer)\n set({ toast: null })\n}\n\n// ------------------------------------------------------------------ 通道\n\nconst BASE_KEY = 'holdem:api-base'\n\nfunction wsUrl(ticket: string): string {\n const base = getApiBase()\n const url = base === '' ? new URL(location.href) : new URL(base)\n const protocol = url.protocol === 'https:' ? 'wss' : 'ws'\n return `${protocol}://${url.host}/holdem/ws?ticket=${encodeURIComponent(ticket)}`\n}\n\n/** 切换后端(本机 / Cloudflare Worker),下一轮刷新也能回到同一处。 */\nexport function useBackend(base: string): void {\n setApiBase(base)\n try {\n if (base === '') sessionStorage.removeItem(BASE_KEY)\n else sessionStorage.setItem(BASE_KEY, base)\n } catch {\n // 忽略\n }\n}\n\nexport function restoreBackend(): void {\n try {\n const saved = sessionStorage.getItem(BASE_KEY)\n if (saved) setApiBase(saved)\n } catch {\n // 忽略\n }\n}\n\nfunction stopPolling(): void {\n if (pollTimer) clearInterval(pollTimer)\n pollTimer = undefined\n}\n\nfunction startPolling(roomId: string): void {\n if (pollTimer || disposed) return\n pollTimer = setInterval(() => {\n void refresh(roomId).catch(() => undefined)\n }, 1000)\n}\n\nfunction scheduleReconnect(roomId: string): void {\n if (reconnectTimer || disposed) return\n reconnectTimer = setTimeout(() => {\n reconnectTimer = undefined\n void reissueTicket(roomId)\n }, 3000)\n}\n\nasync function reissueTicket(roomId: string): Promise<void> {\n if (disposed) return\n try {\n const { wsTicket } = await api.wsTicket(roomId)\n connectChannel(roomId, wsTicket)\n } catch {\n scheduleReconnect(roomId)\n }\n}\n\nfunction closeChannel(): void {\n stopPolling()\n if (reconnectTimer) clearTimeout(reconnectTimer)\n reconnectTimer = undefined\n if (socket) {\n socket.onclose = null\n socket.close()\n }\n socket = null\n}\n\nfunction connectChannel(roomId: string, ticket: string): void {\n closeChannel()\n if (disposed) return\n set({ connection: 'connecting' })\n let ws: WebSocket\n try {\n ws = new WebSocket(wsUrl(ticket), 'holdem.v1')\n } catch {\n set({ connection: 'polling' })\n startPolling(roomId)\n scheduleReconnect(roomId)\n return\n }\n socket = ws\n ws.onopen = () => {\n set({ connection: 'live' })\n stopPolling()\n }\n ws.onmessage = (event) => {\n try {\n handleEvent(JSON.parse(String(event.data)) as ServerEvent)\n } catch {\n // ignore malformed frames\n }\n }\n ws.onclose = () => {\n if (socket === ws) socket = null\n if (disposed) return\n set({ connection: 'polling' })\n const room = state.view?.room.roomId\n if (room) {\n startPolling(room)\n scheduleReconnect(room)\n }\n }\n ws.onerror = () => {\n ws.close()\n }\n}\n\nfunction handleEvent(event: ServerEvent): void {\n if (event.type === 'snapshot') {\n if (!state.view || state.view.room.roomId === event.view.room.roomId) set({ view: event.view })\n return\n }\n if (event.type === 'settled') {\n toast(t('toast.settlement'))\n const room = state.view?.room.roomId\n if (room) void refresh(room)\n return\n }\n if (event.type === 'kicked') {\n closeChannel()\n useBackend('')\n set({ view: null, notice: t('error.kicked'), connection: 'idle' })\n return\n }\n if (event.type === 'left') {\n closeChannel()\n useBackend('')\n set({ view: null, notice: event.reason, connection: 'idle' })\n return\n }\n if (event.type === 'reject') {\n toast(event.reason, 'error')\n }\n}\n\nasync function refresh(roomId: string): Promise<void> {\n if (!roomId) return\n try {\n const response = await api.state(roomId)\n set({ view: response.view })\n } catch (error) {\n if (error instanceof ApiError && (error.status === 403 || error.status === 404)) {\n await recoverSession(roomId)\n } else {\n throw error\n }\n }\n}\n\n/**\n * 状态接口说「不在这个房间」时,先确认浏览器现在到底在哪个房间:\n * 同一个浏览器可能有多个标签页各自在别的房间,cookie 还在就别把用户踢回大厅。\n */\nasync function recoverSession(roomId: string): Promise<void> {\n let session: Awaited<ReturnType<typeof api.session>> | null = null\n try {\n session = await api.session()\n } catch {\n session = null\n }\n if (session?.inRoom && session.view) {\n const next = session.view.room.roomId\n rememberRoom(next)\n set({ view: session.view, notice: null })\n if (next !== roomId) toast(t('toast.switched', { code: session.view.room.roomCode }))\n try {\n const { wsTicket } = await api.wsTicket(next)\n connectChannel(next, wsTicket)\n } catch {\n set({ connection: 'polling' })\n startPolling(next)\n scheduleReconnect(next)\n }\n return\n }\n rememberRoom(null)\n closeChannel()\n useBackend('')\n const noCookie = session !== null && !session.inRoom && (session.seatCookies ?? 1) === 0\n set({ view: null, connection: 'idle', notice: noCookie ? t('error.noSeatCookie') : t('error.roomGone') })\n}\n\n// ------------------------------------------------------------------ 生命周期\n\nexport async function bootstrap(): Promise<void> {\n // 插件热重载会先 dispose 再重新挂载:此时状态已清空,直接重来一次\n if (disposed) disposed = false\n else if (state.booted) return\n try {\n syncSeatTokens()\n const session = await api.session(rememberedRoom() ?? undefined)\n if (session.inRoom && session.view) {\n rememberRoom(session.view.room.roomId)\n set({ view: session.view })\n try {\n const { wsTicket } = await api.wsTicket(session.view.room.roomId)\n connectChannel(session.view.room.roomId, wsTicket)\n } catch {\n set({ connection: 'polling' })\n startPolling(session.view.room.roomId)\n }\n } else {\n // 没在房间里就别继续指着远端:大厅的授权面板、入座都要回到本机\n useBackend('')\n }\n } catch {\n // 没有会话时保持大厅\n } finally {\n set({ booted: true })\n }\n}\n\nexport function dispose(): void {\n disposed = true\n closeChannel()\n if (toastTimer) clearTimeout(toastTimer)\n toastTimer = undefined\n listeners.clear()\n socket = null\n state = { booted: false, busy: false, connection: 'idle', view: null, notice: null, toast: null, autoInvite: false }\n}\n\nexport async function createRoom(\n input: { title?: string | undefined; blindLevel: string; displayName: string },\n base = '',\n): Promise<void> {\n set({ busy: true })\n if (base !== '') useBackend(base)\n try {\n const created = await api.createRoom({ ...input, browserId: browserId() })\n rememberRoom(created.view.room.roomId)\n rememberSeat(created.view.room.roomId, created.sessionToken)\n set({ view: created.view, busy: false, notice: null, autoInvite: true })\n toast(t('toast.created', { code: created.roomCode }))\n connectChannel(created.view.room.roomId, created.wsTicket)\n } catch (error) {\n set({ busy: false })\n if (base !== '') useBackend('')\n toast(errorText(error), 'error')\n throw error\n }\n}\n\nexport async function joinRoom(input: {\n roomCode: string\n invite?: string | undefined\n displayName: string\n role: 'sit' | 'watch'\n}, base = ''): Promise<void> {\n set({ busy: true })\n if (base !== '') useBackend(base)\n try {\n const joined = await api.join({ ...input, browserId: browserId() })\n rememberRoom(joined.view.room.roomId)\n rememberSeat(joined.view.room.roomId, joined.sessionToken)\n set({ view: joined.view, busy: false, notice: null })\n toast(t('toast.joined', { code: joined.view.room.roomCode }))\n connectChannel(joined.view.room.roomId, joined.wsTicket)\n } catch (error) {\n set({ busy: false })\n if (base !== '') useBackend('')\n toast(errorText(error), 'error')\n throw error\n }\n}\n\nexport async function leaveRoom(): Promise<void> {\n try {\n await api.leave(state.view?.room.roomId)\n } catch {\n // 房间可能已解散\n }\n rememberRoom(null)\n closeChannel()\n useBackend('')\n set({ view: null, connection: 'idle', notice: null })\n toast(t('toast.left'))\n}\n\nexport async function runCommand(command: ClientCommand): Promise<void> {\n const view = state.view\n if (!view) return\n set({ busy: true })\n try {\n const response = await api.action(view.room.roomId, {\n actionId: newActionId(),\n baseSeq: view.room.seq,\n command,\n })\n set({ view: response.view, busy: false })\n if (response.duplicate) toast(t('toast.duplicate'))\n } catch (error) {\n set({ busy: false })\n if (error instanceof ApiError) {\n if (error.code === 'stale' && error.view) {\n set({ view: error.view })\n toast(t('error.stale'))\n return\n }\n if (error.code === 'not-your-turn') {\n toast(t('error.notYourTurn'), 'error')\n } else {\n toast(error.message || t('error.generic'), 'error')\n }\n const roomId = state.view?.room.roomId\n if (roomId) void refresh(roomId).catch(() => undefined)\n return\n }\n toast(errorText(error), 'error')\n }\n}\n\nexport function errorText(error: unknown): string {\n if (error instanceof ApiError) return error.message || t('error.generic')\n if (error instanceof Error) return error.message\n return t('error.generic')\n}\n","import { t } from './i18n.ts'\n\n/**\n * 开桌位置的抽象:每个方案只描述「在哪儿开、需要填什么、请求打到哪个基址」。\n * 以后加 ngrok / Tailscale / 自建 VPS,只要再加一个条目。\n */\nexport interface HostingOption {\n id: string\n label: () => string\n hint: () => string\n /** 需要额外填一个地址(例如 Worker 的 URL) */\n needsUrl: boolean\n /** 地址输入框的占位符 */\n urlPlaceholder?: () => string\n /** 请求应该打到哪儿('' = 当前 DSH 进程) */\n resolveBase: (context: { url: string }) => string\n}\n\nexport const HOSTING_OPTIONS: HostingOption[] = [\n {\n id: 'local',\n label: () => t('host.local'),\n hint: () => t('host.localHint'),\n needsUrl: false,\n resolveBase: () => '',\n },\n {\n id: 'cloudflare',\n label: () => t('host.cloudflare'),\n hint: () => t('host.cloudflareHint'),\n needsUrl: false,\n resolveBase: (context) => context.url.trim().replace(/\\/+$/, ''),\n },\n]\n\nexport function hostingOption(id: string): HostingOption {\n return HOSTING_OPTIONS.find((option) => option.id === id) ?? HOSTING_OPTIONS[0]!\n}\n","import type { CSSProperties } from 'react'\n\nexport function cx(...values: (string | false | null | undefined)[]): string {\n return values.filter((value): value is string => typeof value === 'string' && value.length > 0).join(' ')\n}\n\nconst chipsFormat = new Intl.NumberFormat('en-US')\n\nexport function formatChips(value: number): string {\n return chipsFormat.format(Math.round(value))\n}\n\nexport function signedChips(value: number): string {\n if (value === 0) return '0'\n return `${value > 0 ? '+' : '−'}${formatChips(Math.abs(value))}`\n}\n\nexport function formatBb(bb: number, netChips: number, handsPlayed: number): string {\n if (handsPlayed <= 0 || bb <= 0) return '—'\n const value = (netChips / bb / handsPlayed) * 100\n return `${value >= 0 ? '+' : '−'}${Math.abs(value).toFixed(1)}`\n}\n\nexport function formatDuration(ms: number): number {\n return Math.max(0, Math.round(ms / 60_000))\n}\n\nexport function avatarStyle(playerId: string): CSSProperties {\n const hue = hashHue(playerId)\n return {\n background: `linear-gradient(150deg, hsl(${hue} 46% 44%), hsl(${(hue + 38) % 360} 42% 28%))`,\n }\n}\n\nexport function initialOf(name: string | null | undefined): string {\n const text = (name ?? '?').trim()\n if (!text) return '?'\n const chars = [...text]\n return (chars[0] ?? '?').toUpperCase()\n}\n\nfunction hashHue(value: string): number {\n let hash = 0\n for (let i = 0; i < value.length; i += 1) hash = (hash * 31 + value.charCodeAt(i)) >>> 0\n return hash % 360\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n if (max < min) return min\n return Math.min(max, Math.max(min, value))\n}\n\nexport async function copyText(text: string): Promise<boolean> {\n try {\n await navigator.clipboard.writeText(text)\n return true\n } catch {\n return false\n }\n}\n\nexport function downloadJson(filename: string, value: unknown): void {\n const blob = new Blob([JSON.stringify(value, null, 2)], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = filename\n anchor.click()\n setTimeout(() => URL.revokeObjectURL(url), 2000)\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { api, type CloudflareStatus } from './api.ts'\nimport { t } from './i18n.ts'\nimport { copyText, cx } from './ui.ts'\nimport css from './styles.module.css'\n\nexport interface CloudflarePanelProps {\n /** Worker 地址变化时通知外层(建房要用它当后端基址) */\n onWorkerUrl: (url: string) => void\n}\n\n/**\n * Cloudflare 授权 + 部署面板:点一下开浏览器授权,授权完直接部署,\n * 部署成功自动拿到 workers.dev 地址,用户不用自己填域名。\n */\nexport function CloudflarePanel({ onWorkerUrl }: CloudflarePanelProps) {\n const [status, setStatus] = useState<CloudflareStatus | null>(null)\n const [busy, setBusy] = useState(false)\n const [copied, setCopied] = useState(false)\n const [failure, setFailure] = useState('')\n const reported = useRef('')\n\n useEffect(() => {\n let alive = true\n const load = async (): Promise<void> => {\n try {\n const next = await api.cloudflare()\n if (!alive) return\n setStatus(next)\n if (next.workerUrl && reported.current !== next.workerUrl) {\n reported.current = next.workerUrl\n onWorkerUrl(next.workerUrl)\n }\n } catch {\n if (alive) setFailure(t('cf.unreachable'))\n }\n }\n void load()\n const timer = setInterval(() => {\n void load()\n }, 1500)\n return () => {\n alive = false\n clearInterval(timer)\n }\n }, [onWorkerUrl])\n\n const act = async (action: 'login' | 'deploy' | 'cancel' | 'logout'): Promise<void> => {\n setFailure('')\n setBusy(true)\n try {\n const next = await api.cloudflareAction(action)\n setStatus(next)\n if (action === 'logout') {\n reported.current = ''\n onWorkerUrl('')\n }\n } catch (error) {\n setFailure(error instanceof Error ? error.message : String(error))\n } finally {\n setBusy(false)\n }\n }\n\n const copyUrl = async (): Promise<void> => {\n if (!status?.authorizeUrl) return\n if (await copyText(status.authorizeUrl)) {\n setCopied(true)\n setTimeout(() => setCopied(false), 1600)\n }\n }\n\n const authorized = status?.authorized === true\n const workerUrl = status?.workerUrl ?? ''\n\n return (\n <div className={css.cfPanel}>\n <div className={css.cfRow}>\n {authorized ? (\n <span className={cx(css.cfBadge, css.cfBadgeOn)}>{t('cf.authorized', { account: status?.account || 'Cloudflare' })}</span>\n ) : (\n <span className={cx(css.cfBadge, status?.pending && css.cfBadgeWait)}>\n {status?.pending ? t('cf.waiting') : t('cf.needAuth')}\n </span>\n )}\n <span className={css.grow} />\n {authorized ? (\n <>\n <button type=\"button\" className={cx(css.btn, css.btnChip)} disabled={busy || status?.deploying} onClick={() => void act('deploy')}>\n {status?.deploying ? t('cf.deploying') : workerUrl ? t('cf.redeploy') : t('cf.deploy')}\n </button>\n <button type=\"button\" className={cx(css.btn, css.btnChip)} disabled={busy} onClick={() => void act('logout')}>\n {t('cf.switchAccount')}\n </button>\n </>\n ) : status?.pending ? (\n <>\n <span className={css.cfWaiting}>{t('cf.waiting')}</span>\n <button type=\"button\" className={cx(css.btn, css.btnChip)} disabled={busy} onClick={() => void act('cancel')}>\n {t('cf.cancel')}\n </button>\n </>\n ) : (\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} disabled={busy} onClick={() => void act('login')}>\n {t('cf.authorize')}\n </button>\n )}\n </div>\n\n {workerUrl ? (\n <div className={css.cfRow}>\n <span className={css.cfLabel}>{t('cf.address')}</span>\n <code className={css.urlText}>{workerUrl}</code>\n </div>\n ) : null}\n\n {status?.authorizeUrl && !authorized ? (\n <div className={css.cfAuthBox}>\n <p className={css.cfAuthHint}>{t('cf.authHint')}</p>\n <div className={css.cfRow}>\n <code className={css.urlText} title={status.authorizeUrl}>\n {status.authorizeUrl}\n </code>\n <button type=\"button\" className={cx(css.btn, css.btnChip)} onClick={() => void copyUrl()}>\n {copied ? t('invite.copied') : t('invite.copy')}\n </button>\n </div>\n </div>\n ) : null}\n\n {failure || status?.error ? <p className={css.cfError}>{failure || status?.error}</p> : null}\n {status?.log ? <pre className={css.cfLog}>{status.log.slice(-600)}</pre> : null}\n </div>\n )\n}\n","import { useState } from 'react'\nimport { BLIND_LEVELS } from '../invariant.ts'\nimport { t } from './i18n.ts'\nimport { createRoom, joinRoom, useClientState } from './store.ts'\nimport { HOSTING_OPTIONS, hostingOption } from './backends.ts'\nimport { CloudflarePanel } from './CloudflarePanel.tsx'\nimport { clearDeepLink, parseDeepLink, rememberName, rememberedName } from './presence.ts'\nimport { cx, formatChips } from './ui.ts'\nimport css from './styles.module.css'\n\nconst NPM_URL = 'https://www.npmjs.com/package/@zhuweiyou/dsh-holdem'\n\ninterface JoinLink {\n /** 请求要打到哪个 origin('' = 当前 DSH 进程) */\n base: string\n code: string\n invite: string\n}\n\n/** 加入只认邀请链接:里面带着房号、邀请 token,以及这桌跑在哪台机器/Worker 上。 */\nfunction parseJoinLink(text: string): JoinLink | null {\n const trimmed = text.trim()\n if (!/^https?:\\/\\//i.test(trimmed)) return null\n try {\n const url = new URL(trimmed)\n const code = (url.searchParams.get('code') ?? '').replace(/\\D/g, '').slice(0, 6)\n if (code.length !== 6) return null\n const sameOrigin = typeof location !== 'undefined' && url.origin === location.origin\n return { base: sameOrigin ? '' : url.origin, code, invite: url.searchParams.get('invite') ?? '' }\n } catch {\n return null\n }\n}\n\nfunction readPref(key: string, fallback: string): string {\n try {\n return localStorage.getItem(`holdem:${key}`) ?? fallback\n } catch {\n return fallback\n }\n}\n\nfunction writePref(key: string, value: string): void {\n try {\n localStorage.setItem(`holdem:${key}`, value)\n } catch {\n // 忽略\n }\n}\n\nfunction buildLabel(): string {\n const raw = typeof __HOLDEM_BUILD__ === 'string' ? __HOLDEM_BUILD__ : ''\n const date = raw ? new Date(raw) : null\n const stamp = date && !Number.isNaN(date.getTime())\n ? date.toLocaleTimeString(undefined, { hour12: false }).slice(0, 5)\n : ''\n return stamp ? `@zhuweiyou/dsh-holdem · build ${stamp}` : '@zhuweiyou/dsh-holdem · dev'\n}\n\nexport function Lobby() {\n const state = useClientState()\n const deepLink = parseDeepLink()\n const [tab, setTab] = useState<'create' | 'join'>(deepLink ? 'join' : 'create')\n const [name, setName] = useState(() => rememberedName())\n const [title, setTitle] = useState('')\n const [blindLevel, setBlindLevel] = useState<string>('25/50')\n const [hosting, setHosting] = useState<string>(() => readPref('hosting', 'cloudflare'))\n const [workerUrl, setWorkerUrl] = useState<string>(() => readPref('worker-url', ''))\n const [joinText, setJoinText] = useState(() => {\n if (!deepLink) return ''\n const query = new URLSearchParams({ code: deepLink.code, role: 'auto' })\n if (deepLink.invite) query.set('invite', deepLink.invite)\n const origin = typeof location === 'undefined' ? '' : location.origin\n return `${origin}/holdem/play?${query.toString()}`\n })\n const [error, setError] = useState<string | null>(null)\n\n const submitCreate = async (): Promise<void> => {\n setError(null)\n if (!name.trim()) {\n setError(t('lobby.needName'))\n return\n }\n rememberName(name.trim())\n const option = hostingOption(hosting)\n if (hosting === 'cloudflare' && workerUrl.trim() === '') {\n setError(t('host.needCloudflare'))\n return\n }\n writePref('hosting', hosting)\n try {\n await createRoom(\n { title: title.trim() || undefined, blindLevel, displayName: name.trim() },\n option.resolveBase({ url: workerUrl }),\n )\n } catch (reason) {\n setError(reason instanceof Error ? reason.message : t('error.generic'))\n }\n }\n\n /** 加入只用邀请链接:链接里带着房号、邀请 token 和「在哪儿」(本机 / 局域网 / Cloudflare)。 */\n const submitJoin = async (role: 'sit' | 'watch'): Promise<void> => {\n setError(null)\n if (!name.trim()) {\n setError(t('lobby.needName'))\n return\n }\n const parsed = parseJoinLink(joinText)\n if (!parsed) {\n setError(t('lobby.needLink'))\n return\n }\n rememberName(name.trim())\n try {\n await joinRoom(\n { roomCode: parsed.code, invite: parsed.invite, displayName: name.trim(), role },\n parsed.base,\n )\n clearDeepLink()\n } catch (reason) {\n const where = parsed.base === '' ? (typeof location === 'undefined' ? '本机' : location.host) : new URL(parsed.base).host\n const message = reason instanceof Error ? reason.message : t('error.generic')\n setError(t('lobby.joinFailed', { where, message }))\n }\n }\n\n return (\n <div className={css.lobby}>\n <div className={css.lobbyHead}>\n <h1 className={css.lobbyTitle}>{t('panel.title')}</h1>\n <p className={css.lobbySubtitle}>{t('panel.subtitle')}</p>\n </div>\n\n {state.notice ? <div className={css.notice}>{state.notice}</div> : null}\n {error ? <div className={css.noticeError}>{error}</div> : null}\n\n <div className={css.tabs}>\n <button\n type=\"button\"\n className={cx(css.tab, tab === 'create' && css.tabActive)}\n onClick={() => setTab('create')}\n >\n {t('lobby.create')}\n </button>\n <button\n type=\"button\"\n className={cx(css.tab, tab === 'join' && css.tabActive)}\n onClick={() => setTab('join')}\n >\n {t('lobby.join')}\n </button>\n </div>\n\n <div className={css.lobbyBody}>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('common.name')}</span>\n <input\n className={css.input}\n value={name}\n maxLength={16}\n placeholder={t('lobby.namePlaceholder')}\n onChange={(event) => setName(event.target.value)}\n />\n </label>\n\n {tab === 'create' ? (\n <>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('lobby.title')}</span>\n <input\n className={css.input}\n value={title}\n maxLength={24}\n placeholder={t('lobby.titlePlaceholder')}\n onChange={(event) => setTitle(event.target.value)}\n />\n </label>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('lobby.blinds')}</span>\n <select className={css.input} value={blindLevel} onChange={(event) => setBlindLevel(event.target.value)}>\n {BLIND_LEVELS.map((level) => (\n <option key={level.id} value={level.id}>\n {level.id} · {t('table.blinds', { sb: level.sb, bb: level.bb, buyIn: formatChips(level.bb * 100) })}\n </option>\n ))}\n </select>\n </label>\n <div className={css.field}>\n <span className={css.fieldLabel}>{t('host.label')}</span>\n <div className={css.hostRow}>\n {HOSTING_OPTIONS.map((option) => (\n <button\n key={option.id}\n type=\"button\"\n className={cx(css.btn, css.btnChip, hosting === option.id && css.hostActive)}\n onClick={() => setHosting(option.id)}\n >\n {option.label()}\n </button>\n ))}\n </div>\n <p className={css.hint}>{hostingOption(hosting).hint()}</p>\n {hosting === 'cloudflare' ? <CloudflarePanel onWorkerUrl={setWorkerUrl} /> : null}\n </div>\n <button type=\"button\" className={cx(css.btn, css.btnPrimary, css.btnWide)} disabled={state.busy} onClick={() => void submitCreate()}>\n {t('lobby.createAction')}\n </button>\n <p className={css.hint}>6 人桌 · 每手 100BB · 超出座位自动观战</p>\n </>\n ) : (\n <>\n {deepLink ? <div className={css.inviteBanner}>{t('lobby.invited', { code: deepLink.code })}</div> : null}\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('lobby.linkOnly')}</span>\n <input\n className={css.input}\n value={joinText}\n placeholder={t('lobby.linkOnlyPlaceholder')}\n onChange={(event) => setJoinText(event.target.value)}\n />\n </label>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnPrimary, css.btnWide)}\n disabled={state.busy}\n onClick={() => void submitJoin('sit')}\n >\n {t('lobby.enter')}\n </button>\n <p className={css.hint}>{t('lobby.linkHint')}</p>\n </>\n )}\n </div>\n\n <p className={css.hint}>\n {t('lobby.hintPrefix')}\n <a className={css.hintLink} href={NPM_URL} target=\"_blank\" rel=\"noreferrer\">\n @zhuweiyou/dsh-holdem\n </a>\n {t('lobby.hintSuffix')}\n </p>\n <p className={css.buildTag}>{buildLabel()}</p>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { PlayerView } from '../types.ts'\nimport { t } from './i18n.ts'\nimport { createRoom, leaveRoom } from './store.ts'\nimport { copyText, cx, downloadJson, formatBb, formatChips, formatDuration, signedChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport function Settlement({ view }: { view: PlayerView }) {\n const summary = view.settlement\n const [copied, setCopied] = useState(false)\n if (!summary) {\n return (\n <div className={css.settle}>\n <p className={css.railEmpty}>{t('settle.empty')}</p>\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} onClick={() => void leaveRoom()}>\n {t('common.back')}\n </button>\n </div>\n )\n }\n\n const isHost = view.room.hostPlayerId === view.you.playerId\n const markdown = buildMarkdown(view)\n const fileName = `holdem-${summary.roomCode}-${summary.sessionId.slice(-6)}.json`\n\n const again = async (): Promise<void> => {\n const title = summary.title\n const blindLevel = view.room.settings.blindLevel\n const displayName = view.you.displayName\n await leaveRoom()\n await createRoom({ title, blindLevel, displayName })\n }\n\n return (\n <div className={css.settle}>\n <div className={css.settleHead}>\n <div>\n <h1 className={css.settleTitle}>{t('settle.title')}</h1>\n <p className={css.settleMeta}>\n {summary.reason === 'host-idle' ? t('settle.idle') : t('settle.dissolved')}\n {' · '}\n {t('settle.duration', { m: formatDuration(summary.durationMs), hands: summary.handsPlayed })}\n {' · '}\n {summary.title} #{summary.roomCode}\n </p>\n </div>\n <div className={css.settleActions}>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnGhost)}\n onClick={() => {\n void copyText(markdown).then((ok) => setCopied(ok))\n }}\n >\n {copied ? t('common.copied') : t('settle.copy')}\n </button>\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} onClick={() => downloadJson(fileName, summary)}>\n {t('settle.download')}\n </button>\n {isHost ? (\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} onClick={() => void again()}>\n {t('settle.again')}\n </button>\n ) : null}\n <button type=\"button\" className={cx(css.btn, isHost ? css.btnOutline : css.btnPrimary)} onClick={() => void leaveRoom()}>\n {t('settle.backHome')}\n </button>\n </div>\n </div>\n\n {summary.players.length === 0 ? (\n <p className={css.railEmpty}>{t('settle.empty')}</p>\n ) : (\n <div className={css.settleTable}>\n <div className={cx(css.settleRow, css.settleRowHead)}>\n <span>{t('settle.rank')}</span>\n <span>{t('settle.player')}</span>\n <span>{t('settle.hands')}</span>\n <span>{t('settle.wins')}</span>\n <span>{t('settle.net')}</span>\n <span>{t('settle.bb100')}</span>\n <span>{t('settle.showdown')}</span>\n </div>\n {summary.players.map((player) => (\n <div key={player.playerId} className={cx(css.settleRow, player.rank === 1 && css.settleRowFirst)}>\n <span className={css.settleRank}>{medal(player.rank)}</span>\n <span className={css.settlePlayer}>{player.displayName}</span>\n <span>{player.handsPlayed}</span>\n <span>{player.handsWon}</span>\n <span className={player.netChips > 0 ? css.netUp : player.netChips < 0 ? css.netDown : css.netFlat}>\n {signedChips(player.netChips)}\n </span>\n <span>{formatBb(view.room.settings.bb, player.netChips, player.handsPlayed)}</span>\n <span>\n {player.showdownsPlayed === 0\n ? '—'\n : `${player.showdownsWon}/${player.showdownsPlayed}`}\n </span>\n </div>\n ))}\n </div>\n )}\n\n <div className={css.settleHistory}>\n <h3 className={css.railTitle}>{t('rail.history')}</h3>\n <div className={css.historyScroll}>\n {summary.history.length === 0 ? <p className={css.railEmpty}>{t('settle.empty')}</p> : null}\n {[...summary.history].reverse().map((hand) => (\n <div key={hand.handNo} className={css.settleHandRow}>\n <span className={css.historyNo}>#{hand.handNo}</span>\n <span className={css.historyBoard}>\n {hand.board.map((card) => (\n <span key={card} className={css.historyCard}>{card}</span>\n ))}\n </span>\n <span className={css.settleHandPot}>{formatChips(hand.pots.reduce((sum, pot) => sum + pot.amount, 0))}</span>\n <span className={css.settleHandWinners}>\n {hand.winners\n .map((seat) => hand.deltas.find((delta) => delta.seat === seat)?.displayName ?? '')\n .join(' · ')}\n </span>\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n\nfunction medal(rank: number): string {\n if (rank === 1) return '🥇'\n if (rank === 2) return '🥈'\n if (rank === 3) return '🥉'\n return String(rank)\n}\n\nfunction buildMarkdown(view: PlayerView): string {\n const summary = view.settlement!\n const lines: string[] = []\n lines.push(`# 德州扑克战绩 · ${summary.roomCode}`)\n lines.push('')\n lines.push(`${summary.title} · ${summary.handsPlayed} 手 · ${new Date(summary.startedAt).toLocaleString()} → ${new Date(summary.endedAt).toLocaleString()}`)\n lines.push('')\n lines.push('| 名次 | 玩家 | 手数 | 胜局 | 净赢 | BB/100 | 摊牌 |')\n lines.push('| --- | --- | --- | --- | --- | --- | --- |')\n for (const player of summary.players) {\n lines.push(\n `| ${player.rank} | ${player.displayName} | ${player.handsPlayed} | ${player.handsWon} | ${signedChips(player.netChips)} | ${formatBb(view.room.settings.bb, player.netChips, player.handsPlayed)} | ${player.showdownsWon}/${player.showdownsPlayed} |`,\n )\n }\n lines.push('')\n lines.push('> 娱乐筹码,与 DeepSeek 余额无关。')\n return lines.join('\\n')\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type { LegalActions, TableAction } from '../types.ts'\nimport { t } from './i18n.ts'\nimport { clamp, cx, formatChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport interface ActionBarProps {\n legal: LegalActions\n potTotal: number\n bigBlind: number\n busy: boolean\n secondsLeft: number | null\n onAction: (action: TableAction) => void\n}\n\nexport function ActionBar({ legal, potTotal, bigBlind, busy, secondsLeft, onAction }: ActionBarProps) {\n const [raiseTo, setRaiseTo] = useState(legal.minRaiseTo)\n const lastLegal = useRef(`${legal.minRaiseTo}:${legal.maxRaiseTo}:${legal.canRaise}`)\n\n useEffect(() => {\n const key = `${legal.minRaiseTo}:${legal.maxRaiseTo}:${legal.canRaise}`\n if (lastLegal.current !== key) {\n lastLegal.current = key\n setRaiseTo(legal.minRaiseTo)\n }\n }, [legal.minRaiseTo, legal.maxRaiseTo, legal.canRaise])\n\n const step = Math.max(1, Math.round(bigBlind / 2))\n const raiseDisabled = !legal.canRaise || busy\n const presets: { label: string; value: number }[] = legal.canRaise\n ? [\n { label: t('table.halfPot'), value: presetTo(legal, potTotal, 0.5) },\n { label: t('table.twoThirds'), value: presetTo(legal, potTotal, 0.66) },\n { label: t('table.potBet'), value: presetTo(legal, potTotal, 1) },\n ]\n : []\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent): void => {\n const target = event.target as HTMLElement | null\n if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)) return\n const key = event.key.toLowerCase()\n if (key === 'f' && legal.canFold) onAction({ type: 'fold' })\n else if (key === 'c' && (legal.canCheck || legal.canCall)) onAction(legal.canCheck ? { type: 'check' } : { type: 'call' })\n else if (key === 'r' && legal.canRaise) onAction({ type: 'raise', to: clamp(raiseTo, legal.minRaiseTo, legal.maxRaiseTo) })\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [legal, onAction, raiseTo])\n\n const isAllIn = legal.canRaise && raiseTo >= legal.maxRaiseTo\n\n return (\n <div className={css.actionBar}>\n <div className={css.actionTimer}>\n <span className={css.actionTimerLabel}>{t('table.yourTurn')}</span>\n {secondsLeft !== null ? <span className={css.actionTimerValue}>{t('table.timer', { s: secondsLeft })}</span> : null}\n </div>\n <div className={css.actionRow}>\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} disabled={!legal.canFold || busy} onClick={() => onAction({ type: 'fold' })}>\n {t('table.fold')}\n </button>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnCall)}\n disabled={busy || (!legal.canCheck && !legal.canCall)}\n onClick={() => onAction(legal.canCheck ? { type: 'check' } : { type: 'call' })}\n >\n {legal.canCheck ? t('table.check') : t('table.call', { amount: formatChips(legal.callAmount) })}\n </button>\n {legal.canRaise ? (\n <div className={css.raiseGroup}>\n <div className={css.raiseHead}>\n <span className={css.raiseValue}>{isAllIn ? t('table.allinAction') : formatChips(raiseTo)}</span>\n <div className={css.presetRow}>\n {presets.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className={cx(css.btn, css.btnChip)}\n disabled={raiseDisabled}\n onClick={() => setRaiseTo(clamp(preset.value, legal.minRaiseTo, legal.maxRaiseTo))}\n >\n {preset.label}\n </button>\n ))}\n <button\n type=\"button\"\n className={cx(css.btn, css.btnChip)}\n disabled={raiseDisabled}\n onClick={() => setRaiseTo(legal.maxRaiseTo)}\n >\n {t('table.max')}\n </button>\n </div>\n </div>\n <input\n className={css.slider}\n type=\"range\"\n min={legal.minRaiseTo}\n max={legal.maxRaiseTo}\n step={step}\n value={clamp(raiseTo, legal.minRaiseTo, legal.maxRaiseTo)}\n disabled={raiseDisabled}\n onChange={(event) => setRaiseTo(Number(event.target.value))}\n />\n <button\n type=\"button\"\n className={cx(css.btn, css.btnRaise)}\n disabled={raiseDisabled}\n onClick={() => onAction({ type: 'raise', to: clamp(raiseTo, legal.minRaiseTo, legal.maxRaiseTo) })}\n >\n {isAllIn\n ? t('table.allinAction')\n : t('table.raiseTo', { amount: formatChips(clamp(raiseTo, legal.minRaiseTo, legal.maxRaiseTo)) })}\n </button>\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nfunction presetTo(legal: LegalActions, pot: number, fraction: number): number {\n const target = legal.minRaiseTo + Math.round(Math.max(pot, legal.minRaiseTo) * fraction)\n return clamp(target, legal.minRaiseTo, legal.maxRaiseTo)\n}\n","import { useState } from 'react'\nimport type { PlayerView } from '../types.ts'\nimport { getApiBase } from './api.ts'\nimport { t } from './i18n.ts'\nimport { copyText, cx } from './ui.ts'\nimport css from './styles.module.css'\n\n/** 邀请面板:一条链接 + 复制。远端(Cloudflare / 别人机器)用 joinUrl,本机优先局域网地址。 */\nexport function InviteSheet({ view, onClose }: { view: PlayerView; onClose: () => void }) {\n const room = view.room\n const [copied, setCopied] = useState(false)\n const remote = getApiBase() !== ''\n const link = remote ? room.joinUrl : room.lanUrl || room.joinUrl\n\n const copy = async (): Promise<void> => {\n if (!(await copyText(link))) return\n setCopied(true)\n setTimeout(() => setCopied(false), 1600)\n }\n\n return (\n <div className={css.sheetBackdrop} onClick={onClose} role=\"presentation\">\n <div className={css.sheet} role=\"dialog\" aria-label={t('invite.title')} onClick={(event) => event.stopPropagation()}>\n <header className={css.sheetHead}>\n <h2 className={css.sheetTitle}>{t('invite.title')}</h2>\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} onClick={onClose}>\n {t('common.close')}\n </button>\n </header>\n <div className={css.inviteLinkRow}>\n <input\n className={css.inviteLinkInput}\n value={link}\n readOnly\n spellCheck={false}\n onFocus={(event) => event.currentTarget.select()}\n />\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} onClick={() => void copy()}>\n {copied ? t('invite.copied') : t('invite.copy')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n","import type { Card } from '../types.ts'\nimport { cx } from './ui.ts'\nimport css from './styles.module.css'\n\nconst SUIT_SYMBOL: Record<string, string> = { s: '♠', h: '♥', d: '♦', c: '♣' }\nconst RED_SUITS = new Set(['h', 'd'])\n\nexport function suitOfCard(card: string): string {\n return card[1] ?? 's'\n}\n\nexport function rankOfCard(card: string): string {\n const char = card[0] ?? '?'\n return char === 'T' ? '10' : char\n}\n\nexport function isRedCard(card: string): boolean {\n return RED_SUITS.has(suitOfCard(card))\n}\n\nexport function CardView({ card, size = 'md', dim = false }: { card: Card; size?: 'sm' | 'md' | 'lg'; dim?: boolean }) {\n return (\n <div className={cx(css.card, css[`card_${size}`], isRedCard(card) ? css.cardRed : css.cardBlack, dim && css.cardDim)}>\n <span className={css.cardRank}>{rankOfCard(card)}</span>\n <span className={css.cardSuit}>{SUIT_SYMBOL[suitOfCard(card)] ?? '♠'}</span>\n </div>\n )\n}\n\nexport function CardBack({ size = 'sm' }: { size?: 'sm' | 'md' | 'lg' }) {\n return <div className={cx(css.card, css.cardBack, css[`card_${size}`])} aria-hidden=\"true\" />\n}\n\nexport function CardSlot({ filled, size = 'md', card }: { filled: boolean; size?: 'sm' | 'md' | 'lg'; card?: Card | undefined }) {\n if (filled && card) return <CardView card={card} size={size} />\n return <div className={cx(css.card, css.cardSlot, css[`card_${size}`])} aria-hidden=\"true\" />\n}\n","import type { SeatView, ShownHandView } from '../types.ts'\nimport { CardBack, CardView } from './CardView.tsx'\nimport { t } from './i18n.ts'\nimport { avatarStyle, cx, formatChips, initialOf, signedChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport interface SeatPodProps {\n seat: SeatView\n isYou: boolean\n isActor: boolean\n secondsLeft: number | null\n isDealer: boolean\n blind: 'sb' | 'bb' | null\n shown: ShownHandView | null\n className?: string | undefined\n canSit?: boolean | undefined\n onSit?: (() => void) | undefined\n onKick?: (() => void) | undefined\n}\n\nexport function SeatPod({\n seat,\n isYou,\n isActor,\n secondsLeft,\n isDealer,\n blind,\n shown,\n className,\n canSit,\n onSit,\n onKick,\n}: SeatPodProps) {\n if (!seat.playerId) {\n return (\n <div className={cx(css.seat, css.seatEmpty, className)}>\n <div className={css.seatEmptyText}>{t('table.sitDown')}</div>\n {canSit ? (\n <button type=\"button\" className={cx(css.btn, css.btnChip)} onClick={onSit}>\n {t('table.sitDown')}\n </button>\n ) : null}\n </div>\n )\n }\n\n const out = seat.folded || seat.sittingOut\n return (\n <div\n className={cx(\n css.seat,\n isYou && css.seatYou,\n isActor && css.seatActor,\n out && css.seatOut,\n !seat.connected && css.seatOffline,\n className,\n )}\n >\n <div className={css.seatTop}>\n <div className={css.avatar} style={avatarStyle(seat.playerId)}>\n {initialOf(seat.displayName)}\n {isActor && secondsLeft !== null ? (\n <span\n className={css.timerRing}\n style={{ '--progress': `${Math.max(0, Math.min(1, secondsLeft / 30)) * 360}deg` } as React.CSSProperties}\n aria-hidden=\"true\"\n />\n ) : null}\n </div>\n <div className={css.seatMeta}>\n <div className={css.seatName}>\n <span className={css.nameText}>{seat.displayName}</span>\n {isDealer ? <span className={cx(css.badge, css.badgeDealer)}>{t('table.dealer')}</span> : null}\n {blind === 'sb' ? <span className={cx(css.badge, css.badgeBlind)}>{t('table.sb')}</span> : null}\n {blind === 'bb' ? <span className={cx(css.badge, css.badgeBlind)}>{t('table.bb')}</span> : null}\n {isYou ? <span className={cx(css.badge, css.badgeYou)}>{t('table.you')}</span> : null}\n {seat.host ? <span className={cx(css.badge, css.badgeHost)}>{t('table.host')}</span> : null}\n </div>\n <div className={css.seatStack}>\n {formatChips(seat.stack)}\n {seat.handNet !== 0 ? (\n <span className={seat.handNet > 0 ? css.netUp : css.netDown}> {signedChips(seat.handNet)}</span>\n ) : null}\n </div>\n <div className={css.seatStatus}>\n {seat.allIn ? <span className={css.statusAllIn}>{t('table.allin')}</span> : null}\n {seat.folded ? <span className={css.statusFolded}>{t('table.folded')}</span> : null}\n {seat.sittingOut && !seat.autoFold ? <span className={css.statusMuted}>{t('table.sittingOut')}</span> : null}\n {seat.autoFold ? <span className={css.statusMuted}>{t('table.autofold')}</span> : null}\n {!seat.connected ? <span className={css.statusMuted}>{t('table.offline')}</span> : null}\n {seat.lastAction && !seat.folded ? <span className={css.statusAction}>{seat.lastAction}</span> : null}\n </div>\n </div>\n </div>\n\n {shown || seat.holeCount > 0 ? (\n <div className={css.seatCards}>\n {shown\n ? shown.cards.map((card) => <CardView key={card} card={card} size=\"sm\" dim={out} />)\n : Array.from({ length: seat.holeCount }, (_, index) => (\n <CardBack key={index} size=\"sm\" />\n ))}\n </div>\n ) : null}\n\n {onKick ? (\n <button type=\"button\" className={css.kickBtn} title={t('table.kick')} onClick={onKick}>\n ✕\n </button>\n ) : null}\n {seat.committed > 0 ? <div className={css.betChip}>{formatChips(seat.committed)}</div> : null}\n {shown ? <div className={css.handName}>{shown.name}</div> : null}\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { PlayerView } from '../types.ts'\nimport { t } from './i18n.ts'\nimport { runCommand } from './store.ts'\nimport { cx, formatBb, formatChips, signedChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport interface SideRailProps {\n view: PlayerView\n onChat: (text: string) => void\n busy: boolean\n}\n\nexport function SideRail({ view, onChat, busy }: SideRailProps) {\n const isHost = view.room.hostPlayerId === view.you.playerId\n const [draft, setDraft] = useState('')\n const send = (): void => {\n const text = draft.trim()\n if (!text) return\n setDraft('')\n onChat(text.slice(0, 80))\n }\n\n return (\n <aside className={css.rail}>\n <section className={css.railSection}>\n <h3 className={css.railTitle}>{t('rail.leaderboard')}</h3>\n <div className={css.leaderList}>\n {view.leaderboard.length === 0 ? <p className={css.railEmpty}>{t('rail.empty')}</p> : null}\n {view.leaderboard.map((entry, index) => (\n <div key={entry.playerId} className={cx(css.leaderRow, entry.playerId === view.you.playerId && css.leaderRowYou)}>\n <span className={css.leaderRank}>{index + 1}</span>\n <span className={css.leaderName}>{entry.displayName}</span>\n <span className={css.leaderHands}>{t('rail.hands', { n: entry.handsPlayed })}</span>\n <span className={entry.netChips > 0 ? css.netUp : entry.netChips < 0 ? css.netDown : css.netFlat}>\n {signedChips(entry.netChips)}\n </span>\n </div>\n ))}\n </div>\n </section>\n\n <section className={css.railSection}>\n <h3 className={css.railTitle}>{t('rail.history')}</h3>\n <div className={css.historyList}>\n {!view.lastHand ? <p className={css.railEmpty}>{t('rail.empty')}</p> : null}\n {view.lastHand ? (\n <div className={css.historyRow}>\n <span className={css.historyNo}>#{view.lastHand.handNo}</span>\n <span className={css.historyBoard}>\n {view.lastHand.board.map((card) => (\n <span key={card} className={css.historyCard}>{card}</span>\n ))}\n </span>\n <span className={css.historyPot}>{formatChips(view.lastHand.pots.reduce((sum, pot) => sum + pot.amount, 0))}</span>\n </div>\n ) : null}\n </div>\n </section>\n\n <section className={css.railSection}>\n <h3 className={css.railTitle}>{t('rail.spectators')}</h3>\n {view.spectators.length === 0 ? <p className={css.railEmpty}>{t('rail.noSpectators')}</p> : null}\n <div className={css.spectatorList}>\n {view.spectators.map((entry) => (\n <span key={entry.playerId} className={css.spectatorChip}>\n {entry.displayName}\n {isHost ? (\n <button\n type=\"button\"\n className={css.spectatorKick}\n title={t('table.kick')}\n onClick={() => {\n if (window.confirm(t('table.kickConfirm', { name: entry.displayName }))) {\n void runCommand({ type: 'hostKick', playerId: entry.playerId })\n }\n }}\n >\n ✕\n </button>\n ) : null}\n </span>\n ))}\n </div>\n </section>\n\n <section className={cx(css.railSection, css.railChat)}>\n <h3 className={css.railTitle}>{t('rail.chat')}</h3>\n <div className={css.chatList}>\n {view.chat.length === 0 ? <p className={css.railEmpty}>{t('rail.empty')}</p> : null}\n {view.chat.map((line, index) => (\n <div key={`${line.ts}-${index}`} className={css.chatLine}>\n <span className={css.chatName}>{line.displayName}</span>\n <span className={css.chatText}>{line.text}</span>\n </div>\n ))}\n </div>\n {view.room.settings.chatEnabled ? (\n <div className={css.chatComposer}>\n <input\n className={css.chatInput}\n value={draft}\n maxLength={80}\n placeholder={t('rail.chatPlaceholder')}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') send()\n }}\n />\n <button type=\"button\" className={cx(css.btn, css.btnChip)} disabled={busy || draft.trim().length === 0} onClick={send}>\n {t('rail.send')}\n </button>\n </div>\n ) : (\n <p className={css.railEmpty}>{t('rail.chatOff')}</p>\n )}\n </section>\n\n <div className={css.railFooter}>\n {t('rail.net')}: <strong>{signedChips(view.you.netChips)}</strong> · BB/100{' '}\n {formatBb(view.room.settings.bb, view.you.netChips, view.you.handsPlayed)}\n </div>\n </aside>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { PlayerView, SeatView, TableAction } from '../types.ts'\nimport { ActionBar } from './ActionBar.tsx'\nimport { InviteSheet } from './InviteSheet.tsx'\nimport { CardBack, CardSlot, CardView } from './CardView.tsx'\nimport { SeatPod } from './SeatPod.tsx'\nimport { SideRail } from './SideRail.tsx'\nimport { t } from './i18n.ts'\nimport { consumeAutoInvite, leaveRoom, runCommand, useClientState } from './store.ts'\nimport { cx, formatChips, signedChips } from './ui.ts'\nimport css from './styles.module.css'\n\nexport function Table({ view }: { view: PlayerView }) {\n const state = useClientState()\n const [railOpen, setRailOpen] = useState(() => readRailPref())\n const narrow = useNarrow()\n const hand = view.hand\n const room = view.room\n const youSeat = view.you.seat\n const actor = view.you.canAct && view.you.legal ? t('table.yourTurn') : actorLabel(view)\n\n const secondsLeft = useCountdown(hand?.deadlineAt ?? null)\n const nextHandSeconds = useCountdown(room.nextHandAt)\n const isHost = room.hostPlayerId === view.you.playerId\n const base = youSeat ?? 0\n const [inviteOpen, setInviteOpen] = useState(false)\n const [copied, setCopied] = useState(false)\n\n useEffect(() => {\n if (!copied) return undefined\n const timer = setTimeout(() => setCopied(false), 1600)\n return () => clearTimeout(timer)\n }, [copied])\n\n // 刚开完房:自动打开一次邀请面板,房主不用找入口\n useEffect(() => {\n if (!state.autoInvite) return\n setInviteOpen(true)\n consumeAutoInvite()\n }, [state.autoInvite])\n\n const act = (action: TableAction): void => {\n void runCommand({ type: 'action', action })\n }\n\n const seatedView = youSeat === null ? null : room.seats.find((seat) => seat.seat === youSeat) ?? null\n const emptySeats = room.seats.filter((seat) => seat.playerId === null).length\n\n return (\n <div className={css.table}>\n <header className={css.header}>\n <div className={css.headerMain}>\n <div className={css.titleRow}>\n <h1 className={css.roomTitle}>{room.title}</h1>\n <button type=\"button\" className={cx(css.btn, css.inviteBtn)} onClick={() => setInviteOpen(true)}>\n {t('table.invite')}\n </button>\n <span className={cx(css.phasePill, room.phase === 'hand' ? css.phasePillHand : css.phasePillLobby)}>\n {room.phase === 'hand' ? t('lobby.phase.hand') : t('lobby.phase.lobby')}\n </span>\n </div>\n <div className={css.metaRow}>\n <span>{t('table.blinds', { sb: room.settings.sb, bb: room.settings.bb, buyIn: formatChips(room.settings.buyIn) })}</span>\n <span>{t('table.hand', { n: room.handNo })}</span>\n <span className={cx(css.conn, state.connection === 'live' ? css.connLive : state.connection === 'polling' ? css.connPolling : css.connOffline)}>\n {state.connection === 'live' ? '●' : state.connection === 'polling' ? '◐' : '○'}\n </span>\n <span className={css.spectatorCount}>{t('common.spectators', { n: view.spectators.length })}</span>\n </div>\n </div>\n <div className={css.headerActions}>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnChip)}\n onClick={() => {\n setRailOpen((open) => {\n writeRailPref(!open)\n return !open\n })\n }}\n >\n {railOpen ? t('table.hideRail') : t('table.showRail')}\n </button>\n {isHost && room.phase !== 'hand' ? (\n <button type=\"button\" className={cx(css.btn, css.btnChip)} onClick={() => void runCommand({ type: 'hostPause' })}>\n {t('table.pause')}\n </button>\n ) : null}\n {isHost ? (\n <button\n type=\"button\"\n className={cx(css.btn, css.btnDanger)}\n onClick={() => {\n if (window.confirm(t('table.dissolveConfirm'))) void runCommand({ type: 'hostDissolve' })\n }}\n >\n {t('table.dissolve')}\n </button>\n ) : null}\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} onClick={() => void leaveRoom()}>\n {t('common.leave')}\n </button>\n </div>\n </header>\n\n <div className={css.tableBody}>\n <div className={css.feltArea}>\n <div className={css.felt}>\n {narrow ? (\n <div className={css.narrowList}>\n {room.seats\n .filter((seat) => seat.playerId !== null)\n .map((seat) => (\n <SeatRow key={seat.seat} seat={seat} view={view} />\n ))}\n {emptySeats > 0 ? <div className={css.narrowEmpty}>{t('table.emptySeats', { n: emptySeats })}</div> : null}\n </div>\n ) : (\n <div className={css.seatsLayer}>\n {room.seats.map((seat) => {\n const rel = (seat.seat - base + 6) % 6\n const shown = hand?.shownHands.find((entry) => entry.seat === seat.seat) ?? null\n const emptySeat = !seat.playerId\n return (\n <SeatPod\n key={seat.seat}\n seat={seat}\n isYou={seat.seat === youSeat}\n isActor={hand?.toActSeat === seat.seat && room.phase === 'hand'}\n secondsLeft={hand?.toActSeat === seat.seat ? secondsLeft : null}\n isDealer={hand?.button === seat.seat}\n blind={hand?.sbSeat === seat.seat ? 'sb' : hand?.bbSeat === seat.seat ? 'bb' : null}\n shown={shown}\n className={css[`pos${rel}`]}\n canSit={emptySeat && room.phase === 'lobby' && view.you.spectator}\n onSit={() => void runCommand({ type: 'sit' })}\n onKick={\n isHost && room.phase === 'lobby' && seat.playerId !== null && seat.playerId !== view.you.playerId\n ? () => {\n if (window.confirm(t('table.kickConfirm', { name: seat.displayName ?? '' }))) {\n void runCommand({ type: 'hostKick', playerId: seat.playerId as never })\n }\n }\n : undefined\n }\n />\n )\n })}\n </div>\n )}\n\n <div className={css.center}>\n <div className={css.streetLabel}>{t(`table.street.${hand?.street ?? 'preflop'}`)}</div>\n <div className={css.boardRow}>\n {Array.from({ length: 5 }, (_, index) => {\n const card = hand?.board[index]\n return <CardSlot key={card ?? `slot-${index}`} filled={Boolean(card)} card={card} size=\"md\" />\n })}\n </div>\n {hand && hand.potTotal > 0 ? (\n <div className={css.potRow}>\n <span className={css.potChips} aria-hidden=\"true\" />\n <span className={css.potAmount}>{t('table.pot', { amount: formatChips(hand.potTotal) })}</span>\n {hand.pots.length > 1 ? (\n <span className={css.sidePots}>\n {hand.pots.map((pot, index) => (\n <span key={index} className={css.sidePot}>\n {index === 0 ? t('table.potMain') : t('table.potSide', { n: index })} {formatChips(pot.amount)}\n </span>\n ))}\n </span>\n ) : null}\n </div>\n ) : null}\n {room.phase === 'lobby' ? (\n <div className={css.lobbyCenter}>\n <div className={css.centerTitle}>{t('table.waiting')}</div>\n <div className={css.centerHint}>\n {seatedView?.ready ? t('table.waitingReady') : null}\n </div>\n <div className={css.centerActions}>\n {isHost ? (\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} disabled={state.busy} onClick={() => void runCommand({ type: 'start' })}>\n {t('table.start')}\n </button>\n ) : null}\n {youSeat !== null ? (\n <button\n type=\"button\"\n className={cx(css.btn, css.btnOutline)}\n disabled={state.busy}\n onClick={() => void runCommand({ type: 'ready', ready: !view.you.ready })}\n >\n {view.you.ready ? t('table.unready') : t('table.ready')}\n </button>\n ) : null}\n </div>\n </div>\n ) : null}\n {room.phase === 'handOver' && view.lastHand ? (\n <div className={css.handOverBanner}>\n <div className={css.bannerTitle}>\n {bannerTitle(view)}\n </div>\n <div className={css.bannerDeltas}>\n {view.lastHand.deltas\n .filter((delta) => delta.net !== 0)\n .map((delta) => (\n <span key={delta.seat} className={delta.net > 0 ? css.netUp : css.netDown}>\n {delta.displayName} {signedChips(delta.net)}\n </span>\n ))}\n </div>\n {nextHandSeconds !== null ? (\n <div className={css.bannerNext}>{t('table.nextHand', { s: nextHandSeconds })}</div>\n ) : null}\n </div>\n ) : null}\n </div>\n </div>\n\n <div className={css.ownArea}>\n {view.you.spectator ? (\n <div className={css.ownHint}>\n <span>{t('table.spectatorHint')}</span>\n {room.phase === 'lobby' ? (\n <button type=\"button\" className={cx(css.btn, css.btnPrimary)} disabled={state.busy} onClick={() => void runCommand({ type: 'sit' })}>\n {t('table.sitDown')}\n </button>\n ) : null}\n </div>\n ) : (\n <>\n <div className={css.ownCards}>\n {view.you.holeCards.length > 0\n ? view.you.holeCards.map((card) => <CardView key={card} card={card} size=\"lg\" />)\n : room.phase === 'hand'\n ? [0, 1].map((index) => <CardBack key={index} size=\"lg\" />)\n : null}\n <div className={css.ownMeta}>\n <span className={css.ownName}>{seatedView?.displayName ?? view.you.displayName}</span>\n <span className={css.ownStack}>{formatChips(seatedView?.stack ?? 0)}</span>\n <span className={view.you.netChips >= 0 ? css.netUp : css.netDown}>{signedChips(view.you.netChips)}</span>\n </div>\n </div>\n {view.you.canAct && view.you.legal ? (\n <ActionBar\n legal={view.you.legal}\n potTotal={hand?.potTotal ?? 0}\n bigBlind={room.settings.bb}\n busy={state.busy}\n secondsLeft={secondsLeft}\n onAction={act}\n />\n ) : (\n <div className={css.ownHint}>\n <span>\n {room.phase === 'hand' && hand\n ? actor\n : room.phase === 'handOver'\n ? t('table.paused')\n : t('table.waiting')}\n </span>\n {room.phase === 'lobby' ? (\n <div className={css.ownButtons}>\n <button\n type=\"button\"\n className={cx(css.btn, css.btnOutline)}\n disabled={state.busy}\n onClick={() => void runCommand({ type: 'ready', ready: !view.you.ready })}\n >\n {view.you.ready ? t('table.unready') : t('table.ready')}\n </button>\n <button type=\"button\" className={cx(css.btn, css.btnGhost)} disabled={state.busy} onClick={() => void runCommand({ type: 'stand' })}>\n {t('table.stand')}\n </button>\n </div>\n ) : null}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n\n {inviteOpen ? <InviteSheet view={view} onClose={() => setInviteOpen(false)} /> : null}\n\n {railOpen ? (\n <div className={css.railWrap}>\n <SideRail view={view} busy={state.busy} onChat={(text) => void runCommand({ type: 'chat', text })} />\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nconst RAIL_KEY = 'holdem:rail'\n\nfunction readRailPref(): boolean {\n try {\n return localStorage.getItem(RAIL_KEY) !== 'closed'\n } catch {\n return true\n }\n}\n\nfunction writeRailPref(open: boolean): void {\n try {\n localStorage.setItem(RAIL_KEY, open ? 'open' : 'closed')\n } catch {\n // 忽略\n }\n}\n\nfunction actorLabel(view: PlayerView): string {\n const seat = view.hand?.toActSeat\n if (seat === undefined || seat === null) return t('table.waiting')\n const name = view.room.seats.find((entry) => entry.seat === seat)?.displayName ?? '—'\n return t('table.waitTurn', { name })\n}\n\nfunction bannerTitle(view: PlayerView): string {\n const last = view.lastHand\n if (!last) return ''\n if (last.foldedWin) return t('table.foldWin')\n const names = last.winners\n .map((seat) => view.room.seats.find((entry) => entry.seat === seat)?.displayName ?? '—')\n .join(' · ')\n const amount = last.pots.reduce((sum, pot) => sum + pot.amount, 0)\n return t('table.winner', { name: names, amount: formatChips(amount) })\n}\n\nfunction SeatRow({ seat, view }: { seat: SeatView; view: PlayerView }) {\n const shown = view.hand?.shownHands.find((entry) => entry.seat === seat.seat) ?? null\n return (\n <div className={cx(css.narrowRow, seat.seat === view.you.seat && css.narrowRowYou, seat.folded && css.seatOut)}>\n <span className={css.narrowName}>{seat.displayName ?? '—'}</span>\n <span className={css.narrowStack}>{formatChips(seat.stack)}</span>\n <span className={css.narrowCards}>\n {shown\n ? shown.cards.map((card) => <CardView key={card} card={card} size=\"sm\" />)\n : Array.from({ length: seat.holeCount }, (_, index) => <CardBack key={index} size=\"sm\" />)}\n </span>\n <span className={css.narrowStatus}>\n {seat.folded ? t('table.folded') : seat.allIn ? t('table.allin') : seat.lastAction ?? ''}\n </span>\n </div>\n )\n}\n\nfunction useCountdown(target: string | null): number | null {\n const [now, setNow] = useState(() => Date.now())\n useEffect(() => {\n if (!target) return undefined\n const timer = setInterval(() => setNow(Date.now()), 250)\n return () => clearInterval(timer)\n }, [target])\n if (!target) return null\n const remaining = Date.parse(target) - now\n if (!Number.isFinite(remaining)) return null\n return Math.max(0, Math.ceil(remaining / 1000))\n}\n\nfunction useNarrow(): boolean {\n const [narrow, setNarrow] = useState(() => typeof window !== 'undefined' && window.innerWidth < 900)\n useEffect(() => {\n const media = window.matchMedia('(max-width: 899px)')\n const update = (): void => setNarrow(media.matches)\n update()\n media.addEventListener('change', update)\n return () => media.removeEventListener('change', update)\n }, [])\n return narrow\n}\n","import { useEffect } from 'react'\nimport { Lobby } from './Lobby.tsx'\nimport { Settlement } from './Settlement.tsx'\nimport { Table } from './Table.tsx'\nimport { t } from './i18n.ts'\nimport { bootstrap, clearToast, useClientState } from './store.ts'\nimport { cx } from './ui.ts'\nimport css from './styles.module.css'\n\nexport function HoldemPanel() {\n const state = useClientState()\n\n useEffect(() => {\n void bootstrap()\n }, [])\n\n const closed = state.view?.room.phase === 'closed' && state.view.settlement !== null\n\n return (\n <div className={css.panel}>\n {!state.booted ? (\n <div className={css.loading}>\n <div className={css.loadingMark} aria-hidden=\"true\" />\n <p>{t('common.loading')}</p>\n </div>\n ) : state.view ? (\n closed ? <Settlement view={state.view} /> : <Table view={state.view} />\n ) : (\n <Lobby />\n )}\n {state.toast ? (\n <button\n type=\"button\"\n className={cx(css.toast, state.toast.kind === 'error' && css.toastError)}\n onClick={clearToast}\n >\n {state.toast.text}\n </button>\n ) : null}\n </div>\n )\n}\n","import type { PanelIconProps } from '@deepseek-ai/dsh-client-ui-slots'\n\n/** 侧栏面板图标:一只筹码叠着两张牌。 */\nexport function PanelIcon({ size = 20, active = false }: PanelIconProps) {\n const accent = active ? 'var(--dsw-alias-brand-primary)' : 'currentColor'\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <rect x=\"4.5\" y=\"3.5\" width=\"9\" height=\"13\" rx=\"2\" stroke={accent} strokeWidth=\"1.4\" transform=\"rotate(-12 9 10)\" />\n <rect x=\"9\" y=\"6\" width=\"9\" height=\"13\" rx=\"2\" stroke={accent} strokeWidth=\"1.4\" transform=\"rotate(9 13.5 12.5)\" />\n <circle cx=\"7.2\" cy=\"17.4\" r=\"4.1\" stroke={accent} strokeWidth=\"1.4\" />\n <circle cx=\"7.2\" cy=\"17.4\" r=\"1.7\" stroke={accent} strokeWidth=\"1.2\" strokeDasharray=\"1.5 1.8\" />\n </svg>\n )\n}\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { PanelIconProps } from '@deepseek-ai/dsh-client-ui-slots'\nimport { PANEL_KEY } from '../invariant.ts'\nimport { HoldemPanel } from './HoldemPanel.tsx'\nimport { PanelIcon } from './PanelIcon.tsx'\nimport { t } from './i18n.ts'\n\nexport { PANEL_KEY }\n\nexport function registerClientSlots(ctx: ClientContext): void {\n ctx.slots.inject('sidebar.panellist', () => ctx.slots.register({\n name: 'sidebar.panellist',\n id: PANEL_KEY,\n order: 30,\n label: () => t('panel.title'),\n }, function HoldemIcon(props: PanelIconProps) {\n return (\n <span\n onClick={() => ctx.layout.selectPanel(PANEL_KEY)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') ctx.layout.selectPanel(PANEL_KEY)\n }}\n role=\"presentation\"\n >\n <PanelIcon {...props} />\n </span>\n )\n }))\n\n ctx.slots.inject('main', () => ctx.slots.register({\n name: 'main',\n key: PANEL_KEY,\n }, HoldemPanel))\n}\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { PANEL_KEY } from '../invariant.ts'\nimport { DICTS, setTranslator } from './i18n.ts'\nimport { registerClientSlots } from './slots.tsx'\nimport { dispose } from './store.ts'\n\nexport const name = '@zhuweiyou/dsh-holdem-client'\nexport const inject = ['slots', 'layout', 'locale']\n\nconst NS = 'holdem'\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n const offZh = ctx.locale.register(NS, 'zh', DICTS.zh)\n const offEn = ctx.locale.register(NS, 'en', DICTS.en)\n const sync = (): void => setTranslator(ctx.locale.getLocale().id ?? 'zh')\n sync()\n const offLocale = ctx.locale.subscribe(sync)\n return () => {\n offZh()\n offEn()\n offLocale()\n }\n }, 'holdem: locale')\n\n ctx.effect(() => {\n registerClientSlots(ctx)\n // 邀请深链:/ ?dsh-panel=holdem&code=...&invite=...\n try {\n const params = new URLSearchParams(location.search)\n if (params.get('dsh-panel') === PANEL_KEY) ctx.layout.selectPanel(PANEL_KEY)\n } catch {\n // ignore\n }\n }, 'holdem: slots')\n\n ctx.effect(() => () => dispose(), 'holdem: dispose')\n}\n"],"mappings":"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"}