guandan.dev

guandan.dev

https://git.tonybtw.com/guandan.dev.git git://git.tonybtw.com/guandan.dev.git
3,001 bytes raw
1
import { motion } from 'framer-motion'
2
import { Card as Card_Type, get_suit_symbol, get_rank_symbol, is_red_suit, is_wild, Rank, Rank_Red_Joker, Suit_Joker } from '../game/types'
3
4
interface Card_Props {
5
  card: Card_Type
6
  level: Rank
7
  selected: boolean
8
  on_click: () => void
9
}
10
11
export function Card({ card, level, selected, on_click }: Card_Props) {
12
  const is_joker = card.Suit === Suit_Joker
13
  const is_red = is_joker ? card.Rank === Rank_Red_Joker : is_red_suit(card.Suit)
14
  const is_wild_card = is_wild(card, level)
15
16
  return (
17
    <motion.div
18
      onClick={on_click}
19
      animate={{
20
        y: selected ? -20 : 0,
21
        scale: selected ? 1.05 : 1,
22
      }}
23
      whileHover={{ scale: 1.08 }}
24
      transition={{ type: 'spring', stiffness: 400, damping: 25 }}
25
      style={{
26
        width: 70,
27
        height: 100,
28
        backgroundColor: is_wild_card ? '#fff3cd' : '#fff',
29
        border: is_wild_card ? '3px solid #ffc107' : '2px solid #333',
30
        borderRadius: 8,
31
        position: 'relative',
32
        cursor: 'pointer',
33
        userSelect: 'none',
34
        boxShadow: selected ? '0 8px 16px rgba(0,0,0,0.3)' : '0 2px 4px rgba(0,0,0,0.1)',
35
        color: is_red ? '#dc3545' : '#000',
36
        fontWeight: 'bold',
37
      }}
38
    >
39
      <div style={{
40
        position: 'absolute',
41
        top: 4,
42
        left: 6,
43
        display: 'flex',
44
        flexDirection: 'column',
45
        alignItems: 'center',
46
        lineHeight: 1,
47
      }}>
48
        <span style={{ fontSize: 16, fontWeight: 'bold' }}>{is_joker ? (card.Rank === Rank_Red_Joker ? 'R' : 'B') : get_rank_symbol(card.Rank)}</span>
49
        <span style={{ fontSize: 18 }}>{is_joker ? '🃏' : get_suit_symbol(card.Suit)}</span>
50
      </div>
51
      <div style={{
52
        position: 'absolute',
53
        bottom: 4,
54
        right: 6,
55
        display: 'flex',
56
        flexDirection: 'column',
57
        alignItems: 'center',
58
        lineHeight: 1,
59
        transform: 'rotate(180deg)',
60
      }}>
61
        <span style={{ fontSize: 14 }}>{is_joker ? (card.Rank === Rank_Red_Joker ? 'R' : 'B') : get_rank_symbol(card.Rank)}</span>
62
        <span style={{ fontSize: 12 }}>{is_joker ? '🃏' : get_suit_symbol(card.Suit)}</span>
63
      </div>
64
      <div style={{
65
        position: 'absolute',
66
        top: '50%',
67
        left: '50%',
68
        transform: 'translate(-50%, -50%)',
69
        fontSize: is_joker ? 28 : 24,
70
      }}>
71
        {is_joker ? '🃏' : get_suit_symbol(card.Suit)}
72
      </div>
73
    </motion.div>
74
  )
75
}
76
77
export function Card_Back() {
78
  return (
79
    <div
80
      style={{
81
        width: 70,
82
        height: 100,
83
        backgroundColor: '#1e3a5f',
84
        border: '2px solid #0d1b2a',
85
        borderRadius: 8,
86
        display: 'flex',
87
        alignItems: 'center',
88
        justifyContent: 'center',
89
        backgroundImage: 'repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.1) 5px, rgba(255,255,255,0.1) 10px)',
90
      }}
91
    >
92
      <div style={{ color: '#fff', fontSize: 24 }}>🀄</div>
93
    </div>
94
  )
95
}