Renday commited on
Commit
78d0746
·
verified ·
1 Parent(s): 3fa5cc1

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +87 -64
templates/index.html CHANGED
@@ -7,104 +7,127 @@
7
  <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
8
  <script src="https://cdn.tailwindcss.com"></script>
9
  <style>
10
- .card { transition: all 0.2s; cursor: pointer; aspect-ratio: 2/3; width: 22vw; max-width: 90px; }
11
- .card.selected { border: 3px solid #f59e0b; transform: translateY(-10px); box-shadow: 0 10px 20px rgba(245, 158, 11, 0.4); }
12
- .poker-bg { background: radial-gradient(circle, #1a1a1a 0%, #000 100%); }
13
- .suit-red { color: #ef4444; }
14
- * { user-select: none; -webkit-tap-highlight-color: transparent; }
15
  </style>
16
  </head>
17
- <body class="poker-bg text-white min-h-screen flex flex-col items-center p-4">
18
 
19
- <div id="login-area" class="mt-20 text-center">
20
- <h1 class="text-6xl font-black text-yellow-500 italic mb-8 tracking-tighter">31 CARD</h1>
21
- <input type="email" id="email" placeholder="E-Mail Adresse" class="bg-gray-800 p-4 rounded-xl w-64 text-center outline-none border border-gray-700 focus:border-yellow-500 mb-4 block mx-auto">
22
- <button onclick="doLogin()" class="bg-yellow-600 hover:bg-yellow-500 px-12 py-4 rounded-xl font-bold uppercase transition-all">Beitreten</button>
23
- </div>
24
-
25
- <div id="game-area" class="hidden w-full max-w-md">
26
- <div id="admin-panel" class="hidden bg-yellow-500/10 p-3 rounded-xl border border-yellow-500/20 mb-4 flex justify-between items-center">
27
- <span class="text-[10px] font-bold text-yellow-500 uppercase">Admin Dealer</span>
28
- <button onclick="startRound()" class="bg-yellow-500 text-black px-4 py-1 rounded-lg text-[10px] font-bold uppercase italic">Spiel Starten</button>
29
  </div>
30
 
31
- <div id="status-text" class="text-center text-[10px] tracking-widest text-gray-500 mb-6 uppercase italic font-bold">Verbinde zum Tisch...</div>
32
-
33
- <div id="middle-cards" class="flex justify-center gap-2 mb-10 min-h-[100px]"></div>
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- <div class="bg-gray-900/50 p-6 rounded-[2.5rem] border border-white/5 relative shadow-2xl">
36
- <div class="absolute -top-3 left-1/2 -translate-x-1/2 bg-yellow-500 text-black px-4 py-0.5 rounded-full text-[10px] font-bold">DEIN SCORE: <span id="score">0</span></div>
37
-
38
- <div id="player-hand" class="flex justify-center gap-2 mb-6"></div>
39
-
40
- <div class="flex gap-2">
41
- <button onclick="action('swap_all')" class="bg-gray-800 hover:bg-gray-700 flex-1 py-4 rounded-xl text-[10px] font-bold uppercase">Alles Tauschen</button>
42
- <button onclick="action('knock')" class="bg-red-900 text-red-100 flex-1 py-4 rounded-xl text-[10px] font-bold uppercase shadow-lg shadow-red-900/20">Klopfen</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  </div>
44
  </div>
45
  </div>
46
 
47
  <script>
48
- const socket = io(window.location.origin);
49
- let myEmail = "", selHandIdx = null, myCurrentHand = [];
 
50
 
51
  async function doLogin() {
52
- myEmail = document.getElementById('email').value.trim();
53
- if(!myEmail.includes('@')) return alert("Bitte gültige E-Mail eingeben!");
54
-
55
- const res = await fetch('/login', {
56
- method: 'POST',
57
- headers: {'Content-Type': 'application/json'},
58
- body: JSON.stringify({email: myEmail})
59
  });
60
  const data = await res.json();
61
-
62
- if(data.stats && data.stats.is_admin) document.getElementById('admin-panel').classList.remove('hidden');
63
  document.getElementById('login-area').classList.add('hidden');
64
  document.getElementById('game-area').classList.remove('hidden');
65
  socket.emit('join_game', {email: myEmail});
66
  }
67
 
68
- function getCardHTML(c, onClick, isSelected) {
69
- if(!c) return `<div class="card bg-gray-800 rounded-xl border border-white/5"></div>`;
70
- const isRed = (c.suit === 'Herz' || c.suit === 'Karo');
71
- const icons = {'Herz':'♥','Karo':'♦','Pik':'♠','Kreuz':'♣'};
72
- return `
73
- <div onclick="${onClick}" class="card bg-white rounded-xl flex flex-col items-center justify-between p-2 text-black font-bold ${isSelected ? 'selected' : ''}">
74
- <div class="self-start text-xs ${isRed ? 'suit-red' : ''}">${c.rank}</div>
75
- <div class="text-3xl ${isRed ? 'suit-red' : ''}">${icons[c.suit]}</div>
76
- <div class="self-end text-xs rotate-180 ${isRed ? 'suit-red' : ''}">${c.rank}</div>
77
- </div>`;
78
- }
79
 
80
  socket.on('update_table', (data) => {
81
  const me = data.players.find(p => p.email === myEmail);
82
- const activePlayer = data.players[data.turn_idx];
83
- const isMyTurn = activePlayer?.email === myEmail;
84
-
85
- document.getElementById('status-text').innerText = isMyTurn ? "DU BIST DRAN!" : `WARTE AUF ${activePlayer ? activePlayer.email.split('@')[0] : 'SPIELER'}...`;
86
- document.getElementById('status-text').className = isMyTurn ? "text-green-500 text-center text-[10px] tracking-widest mb-6 uppercase font-bold animate-pulse" : "text-gray-500 text-center text-[10px] tracking-widest mb-6 uppercase font-bold";
87
 
88
- document.getElementById('middle-cards').innerHTML = data.middle.map((c, i) => getCardHTML(c, `swap(${i})`, false)).join('');
 
 
 
 
 
89
 
 
90
  if(me) {
91
- document.getElementById('score').innerText = me.score;
92
- myCurrentHand = me.hand;
93
- document.getElementById('player-hand').innerHTML = myCurrentHand.map((c, i) => getCardHTML(c, `selectHand(${i})`, selHandIdx === i)).join('');
 
 
94
  }
95
  });
96
 
97
- function selectHand(i) { selHandIdx = (selHandIdx === i) ? null : i; renderHand(); }
98
- function renderHand() {
99
- document.getElementById('player-hand').innerHTML = myCurrentHand.map((c, i) => getCardHTML(c, `selectHand(${i})`, selHandIdx === i)).join('');
100
- }
101
  function swap(mIdx) {
102
- if(selHandIdx === null) return alert("Wähle zuerst eine deiner Karten aus!");
103
  socket.emit('player_action', {email: myEmail, type: 'swap_one', h_idx: selHandIdx, m_idx: mIdx});
104
  selHandIdx = null;
105
  }
106
- function startRound() { socket.emit('start_round', {email: myEmail}); }
107
  function action(t) { socket.emit('player_action', {email: myEmail, type: t}); }
 
108
  </script>
109
  </body>
110
  </html>
 
7
  <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
8
  <script src="https://cdn.tailwindcss.com"></script>
9
  <style>
10
+ .card { transition: all 0.2s; cursor: pointer; aspect-ratio: 2/3; min-width: 70px; max-width: 100px; }
11
+ .card.selected { border: 3px solid #d4af37; box-shadow: 0 0 15px #d4af37; transform: translateY(-10px); }
12
+ .poker-bg { background: radial-gradient(circle, #1a1a1a 0%, #0a0a0a 100%); }
 
 
13
  </style>
14
  </head>
15
+ <body class="poker-bg text-white min-h-screen flex items-center justify-center p-2 sm:p-4 font-sans overflow-x-hidden">
16
 
17
+ <div class="w-full max-w-4xl bg-gray-900/90 backdrop-blur-xl rounded-3xl shadow-2xl p-4 sm:p-8 border border-white/10">
18
+
19
+ <div id="login-area" class="text-center py-12">
20
+ <h1 class="text-6xl font-black text-yellow-500 mb-2 italic">31 CARD</h1>
21
+ <p class="mb-8 text-gray-500 uppercase tracking-widest text-xs">52 Cards • Responsive</p>
22
+ <div class="max-w-xs mx-auto space-y-4">
23
+ <input type="email" id="email" placeholder="Deine E-Mail" class="bg-gray-800 border border-gray-700 text-white px-4 py-3 rounded-xl w-full outline-none focus:border-yellow-500 text-center">
24
+ <button onclick="doLogin()" class="bg-red-600 hover:bg-red-500 w-full py-4 rounded-xl font-bold uppercase tracking-widest transition-all">Anmelden</button>
25
+ </div>
 
26
  </div>
27
 
28
+ <div id="game-area" class="hidden">
29
+ <header class="flex justify-between items-center border-b border-gray-800 pb-4 mb-6">
30
+ <div>
31
+ <h2 id="status-text" class="text-xs font-bold uppercase tracking-widest text-gray-500 italic">Warte auf Start...</h2>
32
+ </div>
33
+ <div class="flex items-center gap-4">
34
+ <div class="text-right">
35
+ <p class="text-[10px] text-gray-500 uppercase font-black">Bankroll</p>
36
+ <p id="user-coins" class="text-xl font-black text-green-500">0 $</p>
37
+ </div>
38
+ <button onclick="doLogout()" class="text-red-500 bg-red-500/10 p-2 rounded-lg border border-red-500/20">
39
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" /></svg>
40
+ </button>
41
+ </div>
42
+ </header>
43
 
44
+ <div id="admin-panel" class="hidden bg-yellow-500/5 p-4 rounded-2xl border border-yellow-500/20 mb-6 flex flex-wrap items-center justify-between gap-4">
45
+ <div>
46
+ <p class="text-[10px] font-black text-yellow-500 uppercase">Admin Dealer</p>
47
+ <p class="text-[10px] text-gray-500">Starteinsatz festlegen</p>
48
+ </div>
49
+ <div class="flex gap-2">
50
+ <input type="number" id="bet-input" value="50" class="bg-gray-800 w-16 px-2 py-1 rounded text-sm outline-none border border-gray-700">
51
+ <button onclick="setBet()" class="bg-yellow-600 text-black px-3 py-1 rounded text-[10px] font-bold uppercase">Save</button>
52
+ <button onclick="startRound()" class="bg-green-600 px-4 py-1 rounded text-[10px] font-black uppercase italic">Start</button>
53
+ </div>
54
+ </div>
55
+
56
+ <div id="middle-cards" class="flex justify-center gap-2 sm:gap-4 mb-10 overflow-x-auto pb-4"></div>
57
+
58
+ <div class="bg-black/40 p-6 rounded-[2rem] border border-white/5 relative">
59
+ <div class="text-center mb-6">
60
+ <span class="text-[10px] text-gray-500 uppercase font-black tracking-widest">Deine Punkte:</span>
61
+ <span id="score" class="text-yellow-500 font-black ml-2 text-xl">0</span>
62
+ </div>
63
+ <div id="player-hand" class="flex justify-center gap-2 sm:gap-4 mb-8"></div>
64
+ <div class="flex justify-center gap-4">
65
+ <button onclick="action('swap_all')" class="bg-gray-800 px-6 py-3 rounded-xl font-bold text-[10px] uppercase">Alle Tauschen</button>
66
+ <button onclick="action('knock')" class="bg-red-600 px-8 py-3 rounded-xl font-black text-[10px] uppercase shadow-lg shadow-red-900/40">Klopfen</button>
67
+ </div>
68
  </div>
69
  </div>
70
  </div>
71
 
72
  <script>
73
+ const SPACE_URL = "https://renday-spiel31.hf.space";
74
+ const socket = io(SPACE_URL, { transports: ['websocket'] });
75
+ let myEmail = "", selHandIdx = null;
76
 
77
  async function doLogin() {
78
+ myEmail = document.getElementById('email').value;
79
+ if(!myEmail.includes('@')) return alert("E-Mail!");
80
+ const res = await fetch(`${SPACE_URL}/login`, {
81
+ method: 'POST',
82
+ headers: {'Content-Type': 'application/json'},
83
+ body: JSON.stringify({email: myEmail})
 
84
  });
85
  const data = await res.json();
86
+ document.getElementById('user-coins').innerText = data.stats.coins + " $";
87
+ if(data.stats.is_admin) document.getElementById('admin-panel').classList.remove('hidden');
88
  document.getElementById('login-area').classList.add('hidden');
89
  document.getElementById('game-area').classList.remove('hidden');
90
  socket.emit('join_game', {email: myEmail});
91
  }
92
 
93
+ function doLogout() { if(confirm("Abmelden?")) { socket.emit('leave_game', {email: myEmail}); location.reload(); } }
94
+ function setBet() { socket.emit('admin/set_bet', {bet: document.getElementById('bet-input').value}); }
95
+ function startRound() { socket.emit('start_round', {email: myEmail}); }
 
 
 
 
 
 
 
 
96
 
97
  socket.on('update_table', (data) => {
98
  const me = data.players.find(p => p.email === myEmail);
99
+ const isMyTurn = data.players[data.turn_idx]?.email === myEmail;
100
+
101
+ document.getElementById('status-text').innerText = isMyTurn ? "DU BIST DRAN" : `WARTEN...`;
102
+ document.getElementById('status-text').className = isMyTurn ? "text-green-400 font-black animate-pulse" : "text-gray-500";
 
103
 
104
+ const cardHTML = (c, onClick, sel = false) => `
105
+ <div onclick="${onClick}" class="card bg-white rounded-xl flex flex-col items-center justify-between p-2 sm:p-3 shadow-2xl text-black ${sel ? 'selected' : ''}">
106
+ <div class="self-start font-black text-sm sm:text-lg leading-none ${getColor(c.suit)}">${c.rank}</div>
107
+ <div class="text-2xl sm:text-4xl">${getSymbol(c.suit)}</div>
108
+ <div class="self-end font-black text-sm sm:text-lg leading-none rotate-180 ${getColor(c.suit)}">${c.rank}</div>
109
+ </div>`;
110
 
111
+ document.getElementById('middle-cards').innerHTML = data.middle.map((c, i) => cardHTML(c, `swap(${i})`)).join('');
112
  if(me) {
113
+ document.getElementById('user-coins').innerText = me.coins + " $";
114
+ if(me.hand.length > 0) {
115
+ document.getElementById('score').innerText = me.score;
116
+ document.getElementById('player-hand').innerHTML = me.hand.map((c, i) => cardHTML(c, `selectHand(${i})`, selHandIdx === i)).join('');
117
+ }
118
  }
119
  });
120
 
121
+ function getSymbol(s) { return { 'Herz': '♥', 'Karo': '♦', 'Pik': '♠', 'Kreuz': '♣' }[s] || s; }
122
+ function getColor(s) { return (s === 'Herz' || s === 'Karo') ? 'text-red-600' : 'text-gray-900'; }
123
+ function selectHand(i) { selHandIdx = (selHandIdx === i) ? null : i; socket.emit('join_game', {email: myEmail}); }
 
124
  function swap(mIdx) {
125
+ if(selHandIdx === null) return;
126
  socket.emit('player_action', {email: myEmail, type: 'swap_one', h_idx: selHandIdx, m_idx: mIdx});
127
  selHandIdx = null;
128
  }
 
129
  function action(t) { socket.emit('player_action', {email: myEmail, type: t}); }
130
+ socket.on('game_over', (d) => alert("Winner: " + d.winner));
131
  </script>
132
  </body>
133
  </html>