diff --git a/src/components/Card.js b/src/components/Card.js
index 1a610ac..ed57592 100644
--- a/src/components/Card.js
+++ b/src/components/Card.js
@@ -1,4 +1,5 @@
-import { StyleSheet, Text, View } from 'react-native';
+import { useEffect, useRef } from 'react';
+import { Animated, StyleSheet, Text, View } from 'react-native';
import { colors, fonts } from '../theme';
const suitSymbols = {
@@ -15,12 +16,70 @@ const suitColors = {
D: colors.red
};
-export default function Card({ rank, suit, hidden }) {
+export default function Card({ rank, suit, hidden, size = 'normal', animate = true, delay = 0 }) {
+ const scaleMap = { tiny: 0.78, small: 0.92, normal: 1.06, large: 1.18 };
+ const scale = scaleMap[size] ?? 1;
+ const appear = useRef(new Animated.Value(animate ? 0 : 1)).current;
+
+ useEffect(() => {
+ if (!animate) {
+ return;
+ }
+ Animated.timing(appear, {
+ toValue: 1,
+ duration: 260,
+ delay,
+ useNativeDriver: true
+ }).start();
+ }, [animate, appear, delay]);
+
+ const animatedStyle = animate
+ ? {
+ opacity: appear,
+ transform: [
+ {
+ translateY: appear.interpolate({
+ inputRange: [0, 1],
+ outputRange: [-12 * scale, 0]
+ })
+ },
+ {
+ scale: appear.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0.96, 1]
+ })
+ }
+ ]
+ }
+ : null;
+
+ const cardStyle = [
+ styles.card,
+ {
+ width: 54 * scale,
+ height: 78 * scale,
+ borderRadius: 8 * scale,
+ padding: 6 * scale,
+ marginRight: 6 * scale
+ }
+ ];
+ const cornerStyle = [styles.corner, { fontSize: 12 * scale, lineHeight: 13 * scale }];
+ const centerStyle = [styles.center, { fontSize: 24 * scale, lineHeight: 26 * scale }];
+ const backPatternStyle = [
+ styles.backPattern,
+ {
+ width: 32 * scale,
+ height: 46 * scale,
+ borderRadius: 6 * scale,
+ borderWidth: Math.max(1, Math.round(2 * scale))
+ }
+ ];
+
if (hidden || rank === 'X') {
return (
-
-
-
+
+
+
);
}
@@ -28,29 +87,29 @@ export default function Card({ rank, suit, hidden }) {
const color = suitColors[suit] || colors.text;
return (
-
- {rank}
- {symbol}
- {symbol}
+
+ {rank}
+ {symbol}
+ {symbol}
- {rank}
- {symbol}
+ {rank}
+ {symbol}
-
+
);
}
const styles = StyleSheet.create({
card: {
- width: 54,
- height: 78,
- borderRadius: 8,
backgroundColor: '#fdf8f0',
- padding: 6,
- marginRight: 6,
borderWidth: 1,
borderColor: '#d2c1a4',
- justifyContent: 'space-between'
+ justifyContent: 'space-between',
+ overflow: 'hidden',
+ shadowColor: '#000',
+ shadowOpacity: 0.18,
+ shadowRadius: 6,
+ shadowOffset: { width: 0, height: 3 }
},
cardBack: {
backgroundColor: '#152d52',
@@ -59,21 +118,17 @@ const styles = StyleSheet.create({
justifyContent: 'center'
},
backPattern: {
- width: 32,
- height: 46,
- borderRadius: 6,
- borderWidth: 2,
borderColor: 'rgba(255,255,255,0.4)'
},
corner: {
- fontSize: 12,
fontFamily: fonts.body,
- fontWeight: '700'
+ fontWeight: '700',
+ includeFontPadding: false
},
center: {
- fontSize: 24,
fontFamily: fonts.display,
- textAlign: 'center'
+ textAlign: 'center',
+ includeFontPadding: false
},
cornerBottom: {
transform: [{ rotate: '180deg' }]
diff --git a/src/components/CasinoButton.js b/src/components/CasinoButton.js
index 14dc8de..2c35220 100644
--- a/src/components/CasinoButton.js
+++ b/src/components/CasinoButton.js
@@ -42,8 +42,8 @@ const styles = StyleSheet.create({
borderColor: 'rgba(255,255,255,0.2)'
},
buttonSmall: {
- paddingVertical: 8,
- paddingHorizontal: 16
+ paddingVertical: 9,
+ paddingHorizontal: 18
},
inner: {
alignItems: 'center'
@@ -56,7 +56,7 @@ const styles = StyleSheet.create({
},
textSmall: {
fontSize: 13,
- letterSpacing: 0.8
+ letterSpacing: 0.7
},
disabled: {
opacity: 0.5
diff --git a/src/components/Chip.js b/src/components/Chip.js
index 71d8ab9..b221da8 100644
--- a/src/components/Chip.js
+++ b/src/components/Chip.js
@@ -11,7 +11,7 @@ export default function Chip({ label, color = 'blue', size = 'default' }) {
const isSmall = size === 'small';
return (
-
+
{label}
@@ -20,9 +20,9 @@ export default function Chip({ label, color = 'blue', size = 'default' }) {
const styles = StyleSheet.create({
chip: {
- width: 48,
- height: 48,
- borderRadius: 24,
+ width: 56,
+ height: 56,
+ borderRadius: 28,
alignItems: 'center',
justifyContent: 'center',
borderWidth: 3,
@@ -34,21 +34,27 @@ const styles = StyleSheet.create({
borderRadius: 20
},
inner: {
- width: 28,
- height: 28,
- borderRadius: 14,
+ width: 32,
+ height: 32,
+ borderRadius: 16,
borderWidth: 2,
borderColor: 'rgba(255,255,255,0.7)',
alignItems: 'center',
justifyContent: 'center'
},
+ innerSmall: {
+ width: 22,
+ height: 22,
+ borderRadius: 11,
+ borderWidth: 1.5
+ },
text: {
color: '#f7f2e6',
fontWeight: '700',
- fontSize: 12,
+ fontSize: 13,
fontFamily: fonts.mono
},
textSmall: {
- fontSize: 11
+ fontSize: 10
}
});
diff --git a/src/components/DealerArea.js b/src/components/DealerArea.js
index 0f8c814..cfd6961 100644
--- a/src/components/DealerArea.js
+++ b/src/components/DealerArea.js
@@ -2,13 +2,20 @@ import { StyleSheet, Text, View } from 'react-native';
import Card from './Card';
import { colors, fonts } from '../theme';
-export default function DealerArea({ hand }) {
+export default function DealerArea({ hand, cardSize = 'small', delayBase = 0 }) {
return (
Osztó
{hand.map((card, idx) => (
-
+
))}
@@ -23,7 +30,7 @@ const styles = StyleSheet.create({
color: colors.goldBright,
letterSpacing: 2,
textTransform: 'uppercase',
- fontSize: 12,
+ fontSize: 13,
fontFamily: fonts.body
},
hand: {
diff --git a/src/screens/TableScreen.js b/src/screens/TableScreen.js
index 77b15e9..f1aade0 100644
--- a/src/screens/TableScreen.js
+++ b/src/screens/TableScreen.js
@@ -5,12 +5,46 @@ import { BlurView } from 'expo-blur';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { WS_URL } from '../api';
import { colors, fonts } from '../theme';
+import Card from '../components/Card';
import CasinoButton from '../components/CasinoButton';
import Chip from '../components/Chip';
import DealerArea from '../components/DealerArea';
-import Seat from '../components/Seat';
-import TableBackground from '../components/TableBackground';
-import TableMarkings from '../components/TableMarkings';
+
+const emptySeat = (index) => ({
+ index,
+ userId: null,
+ username: '',
+ bet: 0,
+ hand: [],
+ result: null,
+ isYou: false
+});
+
+const getHandTotal = (hand) => {
+ if (!hand || hand.length === 0) {
+ return null;
+ }
+ let total = 0;
+ let aces = 0;
+ for (const card of hand) {
+ if (!card || card.rank === 'X') {
+ return null;
+ }
+ if (card.rank === 'A') {
+ total += 11;
+ aces += 1;
+ } else if (['J', 'Q', 'K'].includes(card.rank)) {
+ total += 10;
+ } else {
+ total += Number(card.rank);
+ }
+ }
+ while (total > 21 && aces > 0) {
+ total -= 10;
+ aces -= 1;
+ }
+ return total;
+};
export default function TableScreen({ token, tableId, user, onLeave }) {
const [table, setTable] = useState(null);
@@ -18,9 +52,14 @@ export default function TableScreen({ token, tableId, user, onLeave }) {
const [message, setMessage] = useState('');
const [betAmount, setBetAmount] = useState(10);
const [turnSeconds, setTurnSeconds] = useState(null);
+ const [roundSeconds, setRoundSeconds] = useState(null);
const [controlsVisible, setControlsVisible] = useState(true);
+ const [seatLayout, setSeatLayout] = useState(null);
+ const [winOverlay, setWinOverlay] = useState(null);
+ const [confettiKey, setConfettiKey] = useState(0);
const wsRef = useRef(null);
const hideTimerRef = useRef(null);
+ const lastWinRoundRef = useRef(null);
const pulse = useRef(new Animated.Value(0)).current;
const insets = useSafeAreaInsets();
const { width, height } = useWindowDimensions();
@@ -70,6 +109,8 @@ export default function TableScreen({ token, tableId, user, onLeave }) {
const mySeat = useMemo(() => table?.seats?.find((seat) => seat.isYou), [table]);
const isMyTurn = table?.phase === 'playing' && table?.currentSeatIndex === mySeat?.index;
const bettingLocked = ['playing', 'dealer', 'payout'].includes(table?.phase);
+ const showBetControls = !bettingLocked;
+ const showActionControls = table?.phase === 'playing';
const scheduleHide = useCallback(() => {
if (hideTimerRef.current) {
@@ -113,6 +154,22 @@ export default function TableScreen({ token, tableId, user, onLeave }) {
return () => clearInterval(interval);
}, [table?.turnEndsAt, isMyTurn]);
+ useEffect(() => {
+ if (!table?.roundStartsAt || table?.phase !== 'betting') {
+ setRoundSeconds(null);
+ return;
+ }
+
+ const update = () => {
+ const msLeft = Math.max(0, table.roundStartsAt - Date.now());
+ setRoundSeconds(Math.ceil(msLeft / 1000));
+ };
+
+ update();
+ const interval = setInterval(update, 250);
+ return () => clearInterval(interval);
+ }, [table?.roundStartsAt, table?.phase]);
+
useEffect(() => {
if (!isMyTurn) {
pulse.stopAnimation();
@@ -128,6 +185,24 @@ export default function TableScreen({ token, tableId, user, onLeave }) {
).start();
}, [isMyTurn, pulse]);
+ useEffect(() => {
+ if (table?.phase !== 'payout' || !mySeat?.result) {
+ return;
+ }
+
+ if (lastWinRoundRef.current === table.roundId) {
+ return;
+ }
+
+ if (['win', 'blackjack'].includes(mySeat.result.outcome)) {
+ lastWinRoundRef.current = table.roundId;
+ setWinOverlay({ payout: mySeat.result.payout, outcome: mySeat.result.outcome });
+ setConfettiKey((prev) => prev + 1);
+ const timer = setTimeout(() => setWinOverlay(null), 2600);
+ return () => clearTimeout(timer);
+ }
+ }, [table?.phase, table?.roundId, mySeat?.result]);
+
const pulseStyle = {
transform: [
{
@@ -159,29 +234,65 @@ export default function TableScreen({ token, tableId, user, onLeave }) {
};
const seats = table?.seats || [];
+ const activePlayers = seats.filter((seat) => seat.userId).length;
+ const showRoundTimer = roundSeconds !== null && table?.phase === 'betting' && activePlayers > 1;
- if (isPortrait) {
- return (
-
-
- Fordítsd el a telefont
- A blackjack asztal fekvő nézetben működik jól.
-
-
-
-
-
- );
- }
+ const uiScale = useMemo(() => {
+ const base = isPortrait ? Math.min(width / 390, height / 844) : Math.min(width / 844, height / 390);
+ return Math.max(0.88, Math.min(base, 1.15));
+ }, [width, height, isPortrait]);
+
+ const seatMetrics = useMemo(() => {
+ if (!seatLayout) {
+ return {
+ width: Math.round(150 * uiScale),
+ height: Math.round(110 * uiScale)
+ };
+ }
+ const baseWidth = seatLayout.width * (isPortrait ? 0.24 : 0.18);
+ const clamped = Math.max(120, Math.min(baseWidth, 190));
+ const widthValue = Math.round(clamped * uiScale);
+ return {
+ width: widthValue,
+ height: Math.round(widthValue * 0.78)
+ };
+ }, [seatLayout, isPortrait, uiScale]);
+
+ const seatAnchors = useMemo(() => {
+ if (isPortrait) {
+ return [
+ { x: 0.12, y: 0.32 },
+ { x: 0.88, y: 0.32 },
+ { x: 0.12, y: 0.58 },
+ { x: 0.88, y: 0.58 }
+ ];
+ }
+ return [
+ { x: 0.2, y: 0.26 },
+ { x: 0.8, y: 0.26 },
+ { x: 0.2, y: 0.64 },
+ { x: 0.8, y: 0.64 }
+ ];
+ }, [isPortrait]);
+
+ const seatSlots = useMemo(() => {
+ return seatAnchors.map((_, idx) => seats[idx] ?? emptySeat(idx));
+ }, [seatAnchors, seats]);
+
+ const seatPositions = useMemo(() => {
+ if (!seatLayout) {
+ return [];
+ }
+ return seatAnchors.map((anchor) => ({
+ left: seatLayout.width * anchor.x - seatMetrics.width / 2,
+ top: seatLayout.height * anchor.y - seatMetrics.height / 2
+ }));
+ }, [seatLayout, seatAnchors, seatMetrics]);
+
+ const seatCardSize = uiScale > 1.02 ? 'normal' : 'small';
+ const playerCardSize = uiScale > 1 ? 'large' : 'normal';
+ const myTotal = getHandTotal(mySeat?.hand);
+ const dealerDelayBase = seatSlots.length * 140;
return (
Asztal {tableId}
- Egyenleg: {balance} Ft
+ {balance} Ft
-
+
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
- {seats.map((seat) => (
-
-
-
- ))}
-
-
- {controlsVisible ? (
-
-
-
- Tét
-
- adjustBet(-10)} style={[styles.betAdjust, bettingLocked && styles.betAdjustDisabled]} disabled={bettingLocked}>
- -
-
-
- adjustBet(10)} style={[styles.betAdjust, bettingLocked && styles.betAdjustDisabled]} disabled={bettingLocked}>
- +
-
+ setSeatLayout(event.nativeEvent.layout)}>
+ {seatSlots.map((seat, idx) => {
+ const pos = seatPositions[idx];
+ if (!pos) {
+ return null;
+ }
+ const highlight = seat.userId && table?.currentSeatIndex === seat.index;
+ return (
+
+
- send({ type: 'bet', amount: betAmount })} variant="gold" size="small" disabled={bettingLocked} />
- send({ type: 'ready' })} variant="green" size="small" disabled={bettingLocked} />
-
-
-
-
- {isMyTurn && turnSeconds !== null ? (
- Idő: {turnSeconds} mp
- ) : null}
-
- send({ type: 'action', action: 'hit' })} variant="gold" size="small" disabled={!isMyTurn} />
- send({ type: 'action', action: 'stand' })} variant="gold" size="small" disabled={!isMyTurn} />
- send({ type: 'action', action: 'double' })} variant="gold" size="small" disabled={!isMyTurn} />
-
-
+ );
+ })}
- ) : (
-
- )}
- {message ? {message} : null}
-
-
+
+
+ {(mySeat?.hand || []).map((card, idx) => (
+
+
+
+ ))}
+
+ {myTotal !== null ? (
+ Összeg: {myTotal}
+ ) : null}
+ {mySeat ? (
+ Tét: {mySeat.bet || betAmount} Ft
+ ) : null}
+
+
+ {controlsVisible ? (
+
+ {showRoundTimer ? (
+ Kezdés: {roundSeconds} mp
+ ) : null}
+
+ {showBetControls ? (
+
+
+ Tét
+
+ adjustBet(-10)}
+ style={[styles.betAdjust, bettingLocked && styles.betAdjustDisabled]}
+ disabled={bettingLocked}
+ >
+ -
+
+
+ adjustBet(10)}
+ style={[styles.betAdjust, bettingLocked && styles.betAdjustDisabled]}
+ disabled={bettingLocked}
+ >
+ +
+
+
+ send({ type: 'bet', amount: betAmount })} variant="gold" size="small" disabled={bettingLocked} />
+ send({ type: 'ready' })} variant="green" size="small" disabled={bettingLocked} />
+
+
+ ) : null}
+
+ {showActionControls ? (
+
+
+ {isMyTurn ? 'HIT' : 'Várakozás'}
+ {isMyTurn && turnSeconds !== null ? (
+ {turnSeconds} mp
+ ) : null}
+
+
+ send({ type: 'action', action: 'hit' })} variant="gold" size="small" disabled={!isMyTurn} />
+ send({ type: 'action', action: 'stand' })} variant="gold" size="small" disabled={!isMyTurn} />
+ send({ type: 'action', action: 'double' })} variant="gold" size="small" disabled={!isMyTurn} />
+
+
+ ) : null}
+
+ ) : (
+
+ )}
+
+ {message ? {message} : null}
+
+
+
+
+ {winOverlay ? (
+
+
+
+ Nyertél!
+ +{winOverlay.payout} Ft
+
+
+ ) : null}
);
}
+function PortraitSeat({ seat, highlight, cardSize, scale, dealIndex }) {
+ const isEmpty = !seat.userId;
+ const hand = seat.hand || [];
+ const total = getHandTotal(hand);
+ const label = seat.userId ? (seat.isYou ? 'ÉN' : seat.username || 'Játékos') : 'Üres hely';
+
+ return (
+
+ {highlight ? : null}
+
+
+
+
+
+
+
+ {label}
+
+ {hand.length > 0 ? (
+
+ {hand.map((card, idx) => (
+
+
+
+ ))}
+
+ ) : null}
+ {total !== null ? Összeg: {total} : null}
+
+ {seat.bet > 0 ? `${seat.bet} Ft` : 'TÉT'}
+
+ {seat.result?.outcome === 'blackjack' ? (
+
+ BLACKJACK!
+
+ ) : null}
+
+ );
+}
+
+function ConfettiBurst({ trigger, width, height }) {
+ const pieces = useMemo(() => {
+ const palette = ['#f7d488', '#d94a3d', '#39c377', '#2f7dd3', '#f2f1e8'];
+ return Array.from({ length: 22 }, (_, idx) => {
+ return {
+ key: `${trigger}-${idx}`,
+ x: Math.random() * Math.max(0, width - 24),
+ delay: idx * 70,
+ rotate: Math.random() * 180,
+ drift: (Math.random() - 0.5) * 80,
+ size: 6 + Math.random() * 6,
+ color: palette[idx % palette.length],
+ anim: new Animated.Value(0)
+ };
+ });
+ }, [trigger, width]);
+
+ useEffect(() => {
+ const animations = pieces.map((piece) =>
+ Animated.timing(piece.anim, {
+ toValue: 1,
+ duration: 1600,
+ delay: piece.delay,
+ useNativeDriver: true
+ })
+ );
+ Animated.parallel(animations).start();
+ }, [pieces]);
+
+ return (
+
+ {pieces.map((piece) => (
+
+ ))}
+
+ );
+}
+
const styles = StyleSheet.create({
container: {
flex: 1,
@@ -274,64 +590,215 @@ const styles = StyleSheet.create({
},
tableTitle: {
color: colors.goldBright,
- fontSize: 20,
+ fontSize: 22,
fontFamily: fonts.display,
- letterSpacing: 2
+ letterSpacing: 1
},
balance: {
color: colors.muted,
- marginTop: 4,
+ marginTop: 2,
fontFamily: fonts.mono
},
tableWrap: {
flex: 1,
- justifyContent: 'flex-start',
- alignItems: 'center',
- marginTop: 8,
+ marginTop: 10,
marginBottom: 8,
width: '100%'
},
tableSurface: {
flex: 1,
width: '100%',
- padding: 0
+ borderRadius: 26,
+ overflow: 'hidden'
},
- tableInner: {
- flex: 1,
- position: 'relative'
+ tableGradient: {
+ flex: 1
},
- dealerArea: {
- alignItems: 'center',
- paddingTop: 8
+ tableGlow: {
+ ...StyleSheet.absoluteFillObject,
+ backgroundColor: 'rgba(255,255,255,0.02)'
+ },
+ tableArc: {
+ position: 'absolute',
+ left: '10%',
+ right: '10%',
+ borderRadius: 999,
+ borderWidth: 1,
+ borderColor: 'rgba(255,255,255,0.12)'
+ },
+ tableArcTop: {
+ top: 26
+ },
+ tableArcMid: {
+ top: 130,
+ borderColor: 'rgba(255,255,255,0.08)'
+ },
+ tableArcBottom: {
+ bottom: 200,
+ borderColor: 'rgba(255,255,255,0.1)'
},
tableContent: {
flex: 1,
- justifyContent: 'space-between',
- paddingBottom: 140
+ paddingHorizontal: 16
+ },
+ dealerArea: {
+ alignItems: 'center',
+ marginTop: 6
},
seatLayer: {
flex: 1,
- position: 'relative'
+ position: 'relative',
+ marginTop: 6,
+ marginBottom: 6
},
seatSpot: {
+ position: 'absolute'
+ },
+ seatCard: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'flex-start'
+ },
+ seatCardActive: {
+ shadowColor: colors.goldBright,
+ shadowOpacity: 0.6,
+ shadowRadius: 12
+ },
+ seatGlow: {
position: 'absolute',
- width: 90,
- transform: [{ translateX: -45 }]
+ top: -8,
+ left: -8,
+ right: -8,
+ bottom: -8,
+ borderRadius: 999,
+ borderWidth: 1,
+ borderColor: 'rgba(255,214,138,0.6)'
},
- controlsOverlay: {
- position: 'absolute',
- left: 20,
- right: 20,
- bottom: 10,
- gap: 10
+ avatarWrap: {
+ marginTop: 2,
+ marginBottom: 4
},
- controlsReveal: {
- ...StyleSheet.absoluteFillObject
+ avatarRing: {
+ width: 38,
+ height: 38,
+ borderRadius: 19,
+ borderWidth: 1,
+ borderColor: 'rgba(255,255,255,0.35)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'rgba(0,0,0,0.25)'
},
- blurPanel: {
- borderRadius: 18,
- paddingVertical: 8,
+ avatarHead: {
+ width: 10,
+ height: 10,
+ borderRadius: 5,
+ borderWidth: 1,
+ borderColor: 'rgba(255,255,255,0.3)',
+ marginBottom: 2
+ },
+ avatarBody: {
+ width: 18,
+ height: 10,
+ borderRadius: 6,
+ borderWidth: 1,
+ borderColor: 'rgba(255,255,255,0.25)'
+ },
+ seatName: {
+ color: colors.text,
+ fontFamily: fonts.body,
+ fontSize: 12,
+ marginBottom: 2
+ },
+ seatNameYou: {
+ fontWeight: '800',
+ color: colors.goldBright
+ },
+ seatHand: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginTop: 2
+ },
+ seatCardStack: {
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ seatTotal: {
+ marginTop: 3,
+ color: colors.muted,
+ fontSize: 11,
+ fontFamily: fonts.mono
+ },
+ betPill: {
+ marginTop: 4,
paddingHorizontal: 10,
+ paddingVertical: 4,
+ borderRadius: 10,
+ borderWidth: 1,
+ borderColor: colors.goldBright,
+ backgroundColor: 'rgba(0,0,0,0.25)'
+ },
+ betPillEmpty: {
+ borderColor: 'rgba(255,255,255,0.18)'
+ },
+ betPillText: {
+ color: colors.goldBright,
+ fontFamily: fonts.mono,
+ fontSize: 12
+ },
+ blackjackTag: {
+ marginTop: 4,
+ paddingHorizontal: 8,
+ paddingVertical: 2,
+ borderRadius: 8,
+ backgroundColor: 'rgba(0,0,0,0.45)',
+ borderWidth: 1,
+ borderColor: colors.gold
+ },
+ blackjackText: {
+ color: colors.goldBright,
+ fontSize: 10,
+ fontFamily: fonts.body
+ },
+ playerArea: {
+ alignItems: 'center',
+ marginTop: 4,
+ marginBottom: 4
+ },
+ playerHand: {
+ flexDirection: 'row',
+ alignItems: 'center'
+ },
+ playerCard: {
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ playerTotal: {
+ marginTop: 6,
+ color: colors.muted,
+ fontFamily: fonts.mono,
+ fontSize: 12
+ },
+ playerBet: {
+ marginTop: 2,
+ color: colors.goldBright,
+ fontFamily: fonts.body,
+ fontSize: 14
+ },
+ controlsArea: {
+ marginTop: 4,
+ gap: 12,
+ paddingBottom: 6
+ },
+ roundTimer: {
+ textAlign: 'center',
+ color: colors.goldBright,
+ fontFamily: fonts.mono,
+ fontSize: 12
+ },
+ controlsPanel: {
+ borderRadius: 18,
+ paddingVertical: 10,
+ paddingHorizontal: 12,
backgroundColor: 'rgba(10, 18, 14, 0.45)',
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.12)',
@@ -341,17 +808,18 @@ const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
- gap: 8
+ gap: 10,
+ flexWrap: 'wrap'
},
betControls: {
flexDirection: 'row',
alignItems: 'center',
- gap: 6
+ gap: 8
},
betAdjust: {
- width: 28,
- height: 28,
- borderRadius: 14,
+ width: 32,
+ height: 32,
+ borderRadius: 16,
backgroundColor: 'rgba(255,255,255,0.12)',
alignItems: 'center',
justifyContent: 'center'
@@ -364,6 +832,38 @@ const styles = StyleSheet.create({
betAdjustDisabled: {
opacity: 0.4
},
+ actionWrap: {
+ alignItems: 'center',
+ gap: 10
+ },
+ actionHint: {
+ minWidth: '80%',
+ borderRadius: 18,
+ paddingVertical: 10,
+ paddingHorizontal: 16,
+ borderWidth: 1,
+ borderColor: 'rgba(255,255,255,0.2)',
+ backgroundColor: 'rgba(0,0,0,0.25)',
+ alignItems: 'center'
+ },
+ actionHintActive: {
+ borderColor: colors.goldBright,
+ shadowColor: colors.goldBright,
+ shadowOpacity: 0.4,
+ shadowRadius: 10
+ },
+ actionHintText: {
+ color: colors.goldBright,
+ fontFamily: fonts.display,
+ fontSize: 16,
+ letterSpacing: 2
+ },
+ turnTimer: {
+ marginTop: 4,
+ color: colors.muted,
+ fontFamily: fonts.mono,
+ fontSize: 12
+ },
actionRow: {
flexDirection: 'row',
justifyContent: 'space-between',
@@ -377,46 +877,45 @@ const styles = StyleSheet.create({
message: {
color: colors.goldBright,
textAlign: 'center',
- marginTop: 8,
+ marginTop: 4,
fontFamily: fonts.body
},
- timer: {
- color: colors.goldBright,
- textAlign: 'center',
- marginBottom: 4,
- fontFamily: fonts.mono
+ controlsReveal: {
+ ...StyleSheet.absoluteFillObject
},
- rotateWrap: {
- flex: 1,
- alignItems: 'center',
+ winOverlay: {
+ ...StyleSheet.absoluteFillObject,
justifyContent: 'center',
- paddingHorizontal: 24
+ alignItems: 'center'
},
- rotateTitle: {
+ winCard: {
+ paddingHorizontal: 24,
+ paddingVertical: 16,
+ borderRadius: 18,
+ backgroundColor: 'rgba(8, 18, 12, 0.85)',
+ borderWidth: 1,
+ borderColor: colors.goldBright
+ },
+ winTitle: {
color: colors.goldBright,
fontFamily: fonts.display,
- fontSize: 24,
- letterSpacing: 2,
+ fontSize: 22,
textAlign: 'center'
},
- rotateSubtitle: {
- color: colors.muted,
- fontFamily: fonts.body,
- fontSize: 14,
- marginTop: 12,
+ winAmount: {
+ marginTop: 6,
+ color: colors.text,
+ fontFamily: fonts.mono,
+ fontSize: 18,
textAlign: 'center'
},
- rotateActions: {
- marginTop: 20
+ confettiLayer: {
+ ...StyleSheet.absoluteFillObject
+ },
+ confettiPiece: {
+ position: 'absolute',
+ top: 0,
+ borderRadius: 3,
+ opacity: 0.9
}
});
-
-const seatPositions = {
- 0: { left: '8%', top: '52%' },
- 1: { left: '22%', top: '45%' },
- 2: { left: '36%', top: '40%' },
- 3: { left: '50%', top: '38%' },
- 4: { left: '64%', top: '40%' },
- 5: { left: '78%', top: '45%' },
- 6: { left: '92%', top: '52%' }
-};