/* global React */ const { useState, useEffect, useRef, useCallback, createContext, useContext } = React; /* ---------------- Ornaments ---------------- */ // gold swept-wing divider with a faceted red gem in the centre function WingDivider({ w = 220, flip = false }) { return ( React.createElement("svg", { width: w, height: 22, viewBox: "0 0 220 22", fill: "none", style: { display: "block", transform: flip ? "scaleY(-1)" : "none" } }, React.createElement("defs", null, React.createElement("linearGradient", { id: "wg", x1: 0, y1: 0, x2: 0, y2: 1 }, React.createElement("stop", { offset: 0, stopColor: "#cfe6ff" }), React.createElement("stop", { offset: .55, stopColor: "#7eb3ff" }), React.createElement("stop", { offset: 1, stopColor: "#4a73e8" }))), // left + right swept chevrons React.createElement("path", { d: "M14 11 L92 11 L86 6 M92 11 L86 16", stroke: "url(#wg)", strokeWidth: 2, strokeLinecap: "round" }), React.createElement("path", { d: "M206 11 L128 11 L134 6 M128 11 L134 16", stroke: "url(#wg)", strokeWidth: 2, strokeLinecap: "round" }), // gem React.createElement("path", { d: "M110 2 L118 8 L110 20 L102 8 Z", fill: "#7c4dff", stroke: "#cfe0ff", strokeWidth: 1.2 }), React.createElement("path", { d: "M110 2 L118 8 L110 11 L102 8 Z", fill: "#b39dff", opacity: .9 }) ) ); } /* ---------------- Coin / Ticket ---------------- */ const Coin = ({ s = 16 }) => React.createElement("span", { className: "coin", style: { fontSize: s } }); function TicketIcon({ s = 18 }) { return React.createElement("svg", { width: s, height: s * 0.7, viewBox: "0 0 24 16" }, React.createElement("defs", null, React.createElement("linearGradient", { id: "tk", x1: 0, y1: 0, x2: 0, y2: 1 }, React.createElement("stop", { offset: 0, stopColor: "#ffe9a8" }), React.createElement("stop", { offset: 1, stopColor: "#c2902f" }))), React.createElement("path", { d: "M2 3 H22 V6 A2 2 0 0 0 22 10 V13 H2 V10 A2 2 0 0 0 2 6 Z", fill: "url(#tk)", stroke: "#7a4f12", strokeWidth: .8 }), React.createElement("line", { x1: 12, y1: 4, x2: 12, y2: 12, stroke: "#7a4f12", strokeWidth: .9, strokeDasharray: "1.4 1.6" }) ); } /* ---------------- Buttons ---------------- */ function Btn({ kind = "gold", size = "md", disabled, onClick, children, style, full }) { const cls = `btn btn-${size} ${disabled ? "btn-off" : "btn-" + kind}`; return React.createElement("button", { className: cls, disabled, onClick, style: Object.assign(full ? { width: "100%" } : {}, style || {}) }, children); } /* ---------------- Progress ---------------- */ function Progress({ value, max }) { const pct = Math.max(0, Math.min(100, (value / max) * 100)); return React.createElement("div", { className: "prog" }, React.createElement("i", { style: { width: pct + "%" } })); } /* ---------------- Panel ---------------- */ function Panel({ title, children, red, style, headRight }) { return React.createElement("div", { className: "panel" + (red ? " panel-red" : ""), style }, title && React.createElement("div", null, React.createElement("div", { className: "panel-head" }, React.createElement(WingDivider, { w: 70 }), React.createElement("span", { className: "ph-title gold-text" }, title), React.createElement(WingDivider, { w: 70, flip: false }) ), React.createElement("div", { className: "hr-gold", style: { margin: "0 14px" } }) ), children ); } /* ---------------- Section label (Latin sub) ---------------- */ function SubLabel({ children }) { return React.createElement("div", { className: "disp upper", style: { fontSize: 10, color: "var(--txt-mute)", fontWeight: 600, letterSpacing: ".22em" } }, children); } /* ---------------- Tabs ---------------- */ function TopTabs({ tabs, active, onChange }) { return React.createElement("div", { style: { display: "flex", gap: 8, padding: "0 14px", marginTop: 12 } }, tabs.map(t => { const on = t.key === active; return React.createElement("button", { key: t.key, onClick: () => onChange(t.key), className: "toptab" + (on ? " on" : ""), }, React.createElement("div", { className: "tt-zh" }, t.zh), React.createElement("div", { className: "tt-en disp upper" }, t.en) ); }) ); } function SubTabs({ tabs, active, onChange }) { return React.createElement("div", { style: { display: "flex", gap: 8, padding: "10px 14px 0" } }, tabs.map(t => { const on = t.key === active; return React.createElement("button", { key: t.key, onClick: () => onChange(t.key), className: "subtab" + (on ? " on" : "") }, t.label); }) ); } /* ---------------- Game State ---------------- */ const GameContext = createContext(null); const useGame = () => useContext(GameContext); const GIFT_POOL = [ { n: "禮物折扣券", v: 200 }, { n: "麥圈", v: 3344 }, { n: "資料卡邊框", v: 5200 }, { n: "尾燈", v: 18800 }, { n: "黑金頭條", v: 52000 }, { n: "全服飄屏", v: 100000 }, { n: "限定座駕", v: 300000 }, { n: "幸運星", v: 10 }, { n: "玫瑰", v: 500 }, { n: "跑車鑰匙", v: 9900 }, { n: "藍圖碎片", v: 20 }, { n: "氮氣罐", v: 30 }, { n: "賽道券", v: 50 }, { n: "輪胎", v: 100 }, { n: "方向盤", v: 200 }, { n: "獎盃", v: 1000 }, ]; function GameProvider({ children }) { const [coins, setCoins] = useState(0); const [tickets, setTickets] = useState(0); const [toast, setToast] = useState(null); const showToast = useCallback((msg) => { setToast(msg); clearTimeout(showToast._t); showToast._t = setTimeout(() => setToast(null), 2200); }, []); const refreshWallet = useCallback(async () => { try { const info = await scf("info"); if (info && info.gold != null) setCoins(Number(info.gold)); } catch (e) { } try { const m = await scf("money/info"); if (m && m.ticket != null) setTickets(Number(m.ticket)); } catch (e) { } }, []); useEffect(() => { refreshWallet(); }, [refreshWallet]); const value = { coins, setCoins, tickets, setTickets, showToast, toast, refreshWallet }; return React.createElement(GameContext.Provider, { value }, children); } const fmt = (n) => n.toLocaleString("en-US"); Object.assign(window, { WingDivider, Coin, TicketIcon, Btn, Progress, Panel, SubLabel, TopTabs, SubTabs, GameContext, useGame, GameProvider, GIFT_POOL, fmt, useState, useEffect, useRef, useCallback, });