feat: initialize mobile blackjack app with authentication and game features
This commit is contained in:
81
src/components/Card.js
Normal file
81
src/components/Card.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { colors, fonts } from '../theme';
|
||||
|
||||
const suitSymbols = {
|
||||
S: '♠',
|
||||
H: '♥',
|
||||
D: '♦',
|
||||
C: '♣'
|
||||
};
|
||||
|
||||
const suitColors = {
|
||||
S: '#1c1c1c',
|
||||
C: '#1c1c1c',
|
||||
H: colors.red,
|
||||
D: colors.red
|
||||
};
|
||||
|
||||
export default function Card({ rank, suit, hidden }) {
|
||||
if (hidden || rank === 'X') {
|
||||
return (
|
||||
<View style={[styles.card, styles.cardBack]}>
|
||||
<View style={styles.backPattern} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const symbol = suitSymbols[suit] || '?';
|
||||
const color = suitColors[suit] || colors.text;
|
||||
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
<Text style={[styles.corner, { color }]}>{rank}</Text>
|
||||
<Text style={[styles.corner, { color }]}>{symbol}</Text>
|
||||
<Text style={[styles.center, { color }]}>{symbol}</Text>
|
||||
<View style={styles.cornerBottom}>
|
||||
<Text style={[styles.corner, { color }]}>{rank}</Text>
|
||||
<Text style={[styles.corner, { color }]}>{symbol}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
width: 54,
|
||||
height: 78,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#fdf8f0',
|
||||
padding: 6,
|
||||
marginRight: 6,
|
||||
borderWidth: 1,
|
||||
borderColor: '#d2c1a4',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
cardBack: {
|
||||
backgroundColor: '#152d52',
|
||||
borderColor: '#0d1e38',
|
||||
alignItems: 'center',
|
||||
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'
|
||||
},
|
||||
center: {
|
||||
fontSize: 24,
|
||||
fontFamily: fonts.display,
|
||||
textAlign: 'center'
|
||||
},
|
||||
cornerBottom: {
|
||||
transform: [{ rotate: '180deg' }]
|
||||
}
|
||||
});
|
||||
55
src/components/CasinoButton.js
Normal file
55
src/components/CasinoButton.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { colors, fonts } from '../theme';
|
||||
|
||||
const gradients = {
|
||||
gold: [colors.goldBright, colors.gold],
|
||||
red: ['#f05a4f', colors.red],
|
||||
green: ['#39c377', '#1f7a44']
|
||||
};
|
||||
|
||||
export default function CasinoButton({ label, onPress, variant = 'gold', disabled }) {
|
||||
const textColor = variant === 'gold' ? '#2b1d0b' : '#f7f2e6';
|
||||
return (
|
||||
<Pressable onPress={onPress} disabled={disabled} style={styles.wrapper}>
|
||||
<LinearGradient
|
||||
colors={gradients[variant] || gradients.gold}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={[styles.button, disabled && styles.disabled]}
|
||||
>
|
||||
<View style={styles.inner}>
|
||||
<Text style={[styles.text, { color: textColor }]}>{label}</Text>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
shadowColor: colors.shadow,
|
||||
shadowOpacity: 0.4,
|
||||
shadowRadius: 6,
|
||||
shadowOffset: { width: 0, height: 4 }
|
||||
},
|
||||
button: {
|
||||
borderRadius: 999,
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 24,
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255,255,255,0.2)'
|
||||
},
|
||||
inner: {
|
||||
alignItems: 'center'
|
||||
},
|
||||
text: {
|
||||
fontSize: 16,
|
||||
fontFamily: fonts.body,
|
||||
letterSpacing: 1,
|
||||
textTransform: 'uppercase'
|
||||
},
|
||||
disabled: {
|
||||
opacity: 0.5
|
||||
}
|
||||
});
|
||||
45
src/components/Chip.js
Normal file
45
src/components/Chip.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { colors, fonts } from '../theme';
|
||||
|
||||
const chipColors = {
|
||||
blue: colors.chipBlue,
|
||||
red: colors.chipRed,
|
||||
green: colors.chipGreen
|
||||
};
|
||||
|
||||
export default function Chip({ label, color = 'blue' }) {
|
||||
return (
|
||||
<View style={[styles.chip, { backgroundColor: chipColors[color] || colors.chipBlue }]}>
|
||||
<View style={styles.inner}>
|
||||
<Text style={styles.text}>{label}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
chip: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 24,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderWidth: 3,
|
||||
borderColor: '#f2f1e8'
|
||||
},
|
||||
inner: {
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 14,
|
||||
borderWidth: 2,
|
||||
borderColor: 'rgba(255,255,255,0.7)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
text: {
|
||||
color: '#f7f2e6',
|
||||
fontWeight: '700',
|
||||
fontSize: 12,
|
||||
fontFamily: fonts.mono
|
||||
}
|
||||
});
|
||||
33
src/components/DealerArea.js
Normal file
33
src/components/DealerArea.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import Card from './Card';
|
||||
import { colors, fonts } from '../theme';
|
||||
|
||||
export default function DealerArea({ hand }) {
|
||||
return (
|
||||
<View style={styles.wrapper}>
|
||||
<Text style={styles.label}>Osztó</Text>
|
||||
<View style={styles.hand}>
|
||||
{hand.map((card, idx) => (
|
||||
<Card key={`${card.rank}-${card.suit}-${idx}`} rank={card.rank} suit={card.suit} hidden={card.hidden} />
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
alignItems: 'center'
|
||||
},
|
||||
label: {
|
||||
color: colors.goldBright,
|
||||
letterSpacing: 2,
|
||||
textTransform: 'uppercase',
|
||||
fontSize: 12,
|
||||
fontFamily: fonts.body
|
||||
},
|
||||
hand: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 6
|
||||
}
|
||||
});
|
||||
73
src/components/Seat.js
Normal file
73
src/components/Seat.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import Card from './Card';
|
||||
import { colors, fonts } from '../theme';
|
||||
|
||||
export default function Seat({ seat, highlight }) {
|
||||
const isEmpty = !seat.username;
|
||||
|
||||
return (
|
||||
<View style={[styles.seat, highlight && styles.highlight]}>
|
||||
<Text style={styles.name}>{isEmpty ? 'Üres hely' : seat.username}</Text>
|
||||
{!isEmpty && seat.bet > 0 && (
|
||||
<Text style={styles.bet}>Tet: {seat.bet} Ft</Text>
|
||||
)}
|
||||
{!isEmpty && seat.hand?.length > 0 && (
|
||||
<View style={styles.hand}>
|
||||
{seat.hand.map((card, idx) => (
|
||||
<Card key={`${card.rank}-${card.suit}-${idx}`} rank={card.rank} suit={card.suit} hidden={card.hidden} />
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
{!isEmpty && seat.result && (
|
||||
<Text style={styles.result}>
|
||||
{seat.result.outcome === 'win' && 'Nyereség'}
|
||||
{seat.result.outcome === 'blackjack' && 'Blackjack!'}
|
||||
{seat.result.outcome === 'push' && 'Döntetlen'}
|
||||
{seat.result.outcome === 'bust' && 'Bukás'}
|
||||
{seat.result.outcome === 'lose' && 'Vesztettél'}
|
||||
{seat.result.outcome === 'left' && 'Kilépett'}
|
||||
{seat.result.outcome === 'disconnect' && 'Eltűnt'}
|
||||
{seat.result.outcome === 'moved' && 'Átült'}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
seat: {
|
||||
padding: 8,
|
||||
borderRadius: 12,
|
||||
backgroundColor: 'rgba(0,0,0,0.3)',
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255,255,255,0.1)'
|
||||
},
|
||||
highlight: {
|
||||
borderColor: colors.goldBright,
|
||||
shadowColor: colors.goldBright,
|
||||
shadowOpacity: 0.6,
|
||||
shadowRadius: 8
|
||||
},
|
||||
name: {
|
||||
color: colors.text,
|
||||
fontSize: 12,
|
||||
fontFamily: fonts.body,
|
||||
fontWeight: '600'
|
||||
},
|
||||
bet: {
|
||||
color: colors.goldBright,
|
||||
fontSize: 11,
|
||||
marginTop: 2,
|
||||
fontFamily: fonts.mono
|
||||
},
|
||||
hand: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 4
|
||||
},
|
||||
result: {
|
||||
marginTop: 4,
|
||||
color: colors.muted,
|
||||
fontSize: 10,
|
||||
fontFamily: fonts.body
|
||||
}
|
||||
});
|
||||
54
src/components/TableBackground.js
Normal file
54
src/components/TableBackground.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { colors } from '../theme';
|
||||
|
||||
export default function TableBackground({ children }) {
|
||||
return (
|
||||
<View style={styles.wrapper}>
|
||||
<LinearGradient
|
||||
colors={[colors.tableEdge, '#3e2a10']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={styles.edge}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.tableFelt, colors.tableFeltDark]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={styles.felt}
|
||||
>
|
||||
<View style={styles.innerRing} />
|
||||
{children}
|
||||
</LinearGradient>
|
||||
</LinearGradient>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
flex: 1,
|
||||
padding: 12
|
||||
},
|
||||
edge: {
|
||||
flex: 1,
|
||||
borderRadius: 220,
|
||||
padding: 10
|
||||
},
|
||||
felt: {
|
||||
flex: 1,
|
||||
borderRadius: 200,
|
||||
padding: 20,
|
||||
overflow: 'hidden'
|
||||
},
|
||||
innerRing: {
|
||||
position: 'absolute',
|
||||
top: 16,
|
||||
bottom: 16,
|
||||
left: 16,
|
||||
right: 16,
|
||||
borderWidth: 2,
|
||||
borderColor: 'rgba(255,255,255,0.15)',
|
||||
borderRadius: 180
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user