pokerboard/index.html
Weetile fcec6ca1e5
All checks were successful
Publish Package / build (push) Successful in 9s
+-1 minute (from 5 mins)
Signed-off-by: Weetile <weetile@noreply.localhost>
2025-03-13 22:16:28 +00:00

647 lines
21 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Poker Board</title>
<style>
:root {
--background: #121212;
--card: #1e1e1e;
--primary: #d32f2f;
--text: #ffffff;
--accent: #00c853;
}
body {
font-family: 'Arial', sans-serif;
background-color: var(--background);
color: var(--text);
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23222222' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}
.header {
width: 100%;
text-align: center;
background-color: var(--card);
padding: 20px 0;
border-bottom: 4px solid var(--primary);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
}
.logo {
font-size: 2.5rem;
font-weight: bold;
margin: 0;
color: var(--primary);
letter-spacing: 1px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
.content {
display: flex;
flex-direction: column;
align-items: center;
width: 90%;
max-width: 1200px;
margin: 30px 0;
}
.main-sections {
display: flex;
width: 100%;
gap: 30px;
margin-bottom: 30px;
align-items: center; /* Vertically center the sections */
}
.chip-values {
background-color: var(--card);
border-radius: 10px;
padding: 30px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
border: 1px solid #333;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center; /* Center content vertically */
}
.section-title {
text-align: center;
font-size: 1.8rem;
margin-top: 0;
margin-bottom: 25px;
color: var(--accent);
border-bottom: 2px solid var(--accent);
padding-bottom: 10px;
}
.chips {
display: flex;
justify-content: center;
flex-wrap: nowrap;
gap: 15px;
max-width: 100%;
overflow-x: auto; /* Allow horizontal scrolling if needed */
}
.chip {
text-align: center;
font-size: 1.2rem;
padding: 10px;
border-radius: 50%;
width: 75px; /* Slightly smaller to ensure fit */
height: 75px;
min-width: 75px; /* Prevent shrinking */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 4px solid #444;
}
.chip-color {
font-weight: bold;
font-size: 1.4rem;
}
.chip-value {
font-size: 2rem;
font-weight: bold;
}
.white-chip {
background-color: #f5f5f5;
color: #000;
}
.blue-chip {
background-color: #1976d2;
color: white;
}
.red-chip {
background-color: #d32f2f;
color: white;
}
.green-chip {
background-color: #388e3c;
color: white;
}
.black-chip {
background-color: #212121;
color: white;
border-color: #555;
}
.timer-section {
background-color: var(--card);
border-radius: 10px;
padding: 30px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
border: 1px solid #333;
flex: 1;
}
.timer-display {
font-size: 5rem;
font-weight: bold;
text-align: center;
margin: 20px 0;
font-family: 'Courier New', monospace;
color: var(--accent);
text-shadow: 0 0 10px rgba(0, 200, 83, 0.5);
}
.blind-levels {
font-size: 2.5rem;
text-align: center;
margin: 20px 0;
font-weight: bold;
}
.current-level {
color: var(--primary);
font-size: 3.2rem; /* Increased size as requested */
}
.next-level {
color: #888;
font-size: 1.8rem;
}
.timer-controls {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 30px;
flex-wrap: wrap;
}
button {
background-color: var(--primary);
color: white;
border: none;
border-radius: 5px;
padding: 12px 25px;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s;
font-weight: bold;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
button:hover {
background-color: #b71c1c;
transform: translateY(-2px);
}
button:active {
transform: translateY(1px);
}
.reset {
background-color: #333;
}
.reset:hover {
background-color: #444;
}
#remove-time {
background-color: #d81b60;
}
#remove-time:hover {
background-color: #ad1457;
}
footer {
margin-top: auto;
width: 100%;
background-color: var(--card);
padding: 15px 0;
text-align: center;
font-size: 0.9rem;
color: #888;
border-top: 2px solid var(--primary);
}
/* Card suit animation for background elements */
.card-suits {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: -1;
overflow: hidden;
}
.suit {
position: absolute;
opacity: 0.04;
font-size: 100px;
animation: float 15s infinite linear;
}
@keyframes float {
0% {
transform: translateY(100vh) rotate(0deg);
}
100% {
transform: translateY(-100px) rotate(360deg);
}
}
/* Announcement section styles */
.announcement-section {
background-color: var(--card);
border-radius: 10px;
padding: 30px;
margin-top: 30px;
margin-bottom: 30px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
width: 100%;
border: 1px solid #333;
}
.announcement-form {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.announcement-input {
flex: 1;
padding: 12px;
font-size: 1.1rem;
border-radius: 5px;
border: 1px solid #444;
background-color: #333;
color: white;
}
.announcement-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.announcement-item {
background-color: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 5px;
font-size: 1.8rem;
font-weight: bold;
display: flex;
justify-content: space-between;
align-items: center;
border-left: 5px solid var(--primary);
}
.delete-announcement {
background-color: rgba(0, 0, 0, 0.3);
color: white;
border: none;
border-radius: 50%;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 1.2rem;
transition: all 0.2s;
}
.delete-announcement:hover {
background-color: var(--primary);
transform: scale(1.1);
}
#add-announcement {
background-color: var(--accent);
}
#add-announcement:hover {
background-color: #00a844;
}
</style>
</head>
<body>
<!-- Background animation -->
<div class="card-suits" id="card-suits"></div>
<div class="header">
<h1 class="logo">Poker Board</h1>
</div>
<div class="content">
<div class="main-sections">
<div class="chip-values">
<h2 class="section-title">CHIP VALUES</h2>
<div class="chips">
<div class="chip white-chip">
<div class="chip-color">White</div>
<div class="chip-value">5</div>
</div>
<div class="chip blue-chip">
<div class="chip-color">Blue</div>
<div class="chip-value">10</div>
</div>
<div class="chip red-chip">
<div class="chip-color">Red</div>
<div class="chip-value">25</div>
</div>
<div class="chip green-chip">
<div class="chip-color">Green</div>
<div class="chip-value">100</div>
</div>
<div class="chip black-chip">
<div class="chip-color">Black</div>
<div class="chip-value">200</div>
</div>
</div>
</div>
<div class="timer-section">
<h2 class="section-title">BLINDS TIMER</h2>
<div class="blind-levels">
<div class="current-level" id="current-blinds">5 / 10</div>
<div class="next-level">Next: <span id="next-blinds">10 / 20</span></div>
</div>
<div class="timer-display" id="timer">30:00</div>
<div class="timer-controls">
<button id="start-pause">START</button>
<button id="reset" class="reset">RESET</button>
<button id="add-time">+1 MIN</button>
<button id="remove-time">-1 MIN</button>
</div>
</div>
</div>
<div class="announcement-section">
<h2 class="section-title">ANNOUNCEMENTS</h2>
<div class="announcement-form">
<input type="text" id="announcement-input" class="announcement-input" placeholder="Enter announcement...">
<button id="add-announcement">ADD</button>
</div>
<div class="announcement-list" id="announcement-list">
<!-- Announcements will be added here -->
</div>
</div>
</div>
<footer>
<a href="https://git.weetile.uk" style="color: inherit;">Otto Helen-Goldring © 2025</a>
</footer>
<script>
// Timer variables
let timerDuration = 15 * 60; // 15 minutes in seconds
let timeRemaining = timerDuration;
let timerInterval = null;
let isTimerRunning = false;
// Blind levels
let currentBlinds = { small: 5, big: 10 };
let blindLevels = [];
// Generate blind levels with the specified structure
function generateBlindLevels() {
// Initial specific blind levels as requested
blindLevels = [
{ small: 5, big: 10 },
{ small: 10, big: 20 },
{ small: 20, big: 40 },
{ small: 30, big: 60 },
{ small: 40, big: 80 },
{ small: 50, big: 100 },
{ small: 75, big: 150 },
{ small: 100, big: 200 },
{ small: 150, big: 300 },
{ small: 200, big: 400 },
{ small: 300, big: 600 },
{ small: 400, big: 800 },
{ small: 500, big: 1000 }
];
// Continue doubling from the last level
let lastLevel = blindLevels[blindLevels.length - 1];
let small = lastLevel.small * 2;
let big = lastLevel.big * 2;
// Add 7 more doubled levels
for (let i = 0; i < 7; i++) {
blindLevels.push({ small, big });
small *= 2;
big *= 2;
}
}
// Format time as MM:SS
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
// Update timer display
function updateTimerDisplay() {
document.getElementById('timer').textContent = formatTime(timeRemaining);
}
// Update blinds display
function updateBlindsDisplay() {
document.getElementById('current-blinds').textContent = `${currentBlinds.small} / ${currentBlinds.big}`;
// Find current level index
const currentLevelIndex = blindLevels.findIndex(level =>
level.small === currentBlinds.small && level.big === currentBlinds.big);
// Calculate next level
if (currentLevelIndex < blindLevels.length - 1) {
const nextLevel = blindLevels[currentLevelIndex + 1];
document.getElementById('next-blinds').textContent = `${nextLevel.small} / ${nextLevel.big}`;
} else {
document.getElementById('next-blinds').textContent = 'Max Level';
}
}
// Start or pause the timer
function toggleTimer() {
const button = document.getElementById('start-pause');
if (isTimerRunning) {
// Pause the timer
clearInterval(timerInterval);
button.textContent = 'RESUME';
isTimerRunning = false;
} else {
// Start the timer
timerInterval = setInterval(function() {
if (timeRemaining > 0) {
timeRemaining--;
updateTimerDisplay();
} else {
// Time's up, move to next blind level and restart the timer
incrementBlinds();
timeRemaining = timerDuration; // Reset time remaining to duration
updateTimerDisplay(); // Update display with new time
// Timer continues running without stopping
}
}, 1000);
button.textContent = 'PAUSE';
isTimerRunning = true;
}
}
// Reset the timer
function resetTimer() {
clearInterval(timerInterval);
timeRemaining = timerDuration;
updateTimerDisplay();
document.getElementById('start-pause').textContent = 'START';
isTimerRunning = false;
}
// Increment blinds to next level
function incrementBlinds() {
const currentLevelIndex = blindLevels.findIndex(level =>
level.small === currentBlinds.small && level.big === currentBlinds.big);
if (currentLevelIndex < blindLevels.length - 1) {
currentBlinds = blindLevels[currentLevelIndex + 1];
updateBlindsDisplay();
// Add visual feedback for blind increase
const blindsElement = document.getElementById('current-blinds');
blindsElement.style.transition = 'transform 0.5s, color 0.5s';
blindsElement.style.transform = 'scale(1.2)';
blindsElement.style.color = '#ff5252';
setTimeout(() => {
blindsElement.style.transform = 'scale(1)';
blindsElement.style.color = '';
}, 1500);
}
}
// Add 5 minutes to the timer
function addTime() {
timeRemaining += 1 * 60; // Add 1 minute
updateTimerDisplay();
}
// Remove 5 minutes from the timer
function removeTime() {
if (timeRemaining > 1 * 60) {
timeRemaining -= 1 * 60; // Remove 1 minute
} else {
timeRemaining = 0;
}
updateTimerDisplay();
}
// Create floating suit symbols for background
function createSuitSymbols() {
const suits = ['♠', '♥', '♦', '♣'];
const container = document.getElementById('card-suits');
for (let i = 0; i < 20; i++) {
const suit = document.createElement('div');
suit.className = 'suit';
suit.textContent = suits[Math.floor(Math.random() * suits.length)];
// Random position and animation properties
suit.style.left = `${Math.random() * 100}%`;
suit.style.animationDuration = `${15 + Math.random() * 20}s`;
suit.style.animationDelay = `${Math.random() * 15}s`;
container.appendChild(suit);
}
}
// Add announcement to the list
function addAnnouncement() {
const input = document.getElementById('announcement-input');
const text = input.value.trim();
if (text) {
const announcementList = document.getElementById('announcement-list');
// Create announcement item
const item = document.createElement('div');
item.className = 'announcement-item';
// Add announcement text
const span = document.createElement('span');
span.textContent = text;
item.appendChild(span);
// Add delete button
const deleteBtn = document.createElement('button');
deleteBtn.className = 'delete-announcement';
deleteBtn.textContent = '×';
deleteBtn.addEventListener('click', function() {
item.style.opacity = '0';
item.style.transition = 'opacity 0.3s';
setTimeout(() => {
announcementList.removeChild(item);
}, 300);
});
item.appendChild(deleteBtn);
// Add to list with animation
item.style.opacity = '0';
announcementList.appendChild(item);
setTimeout(() => {
item.style.opacity = '1';
item.style.transition = 'opacity 0.3s';
}, 10);
// Clear input
input.value = '';
}
}
// Initialize the app
function init() {
generateBlindLevels();
updateTimerDisplay();
updateBlindsDisplay();
createSuitSymbols();
// Timer control event listeners
document.getElementById('start-pause').addEventListener('click', toggleTimer);
document.getElementById('reset').addEventListener('click', resetTimer);
document.getElementById('add-time').addEventListener('click', addTime);
document.getElementById('remove-time').addEventListener('click', removeTime);
// Announcement event listeners
document.getElementById('add-announcement').addEventListener('click', addAnnouncement);
// Allow Enter key to submit announcement
document.getElementById('announcement-input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
addAnnouncement();
}
});
}
// Start the app
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>