Files
czech-fool/client/index.html
T
2025-11-05 03:26:06 +03:00

411 lines
19 KiB
HTML
Raw 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="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="format-detection" content="telephone=no">
<title>Чешский</title>
<!-- Раскомментируйте и укажите ваш WebSocket домен если используете reverse proxy -->
<!-- <meta name="ws-host" content="ws.domain.com"> -->
<!-- Favicon -->
<link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png">
<link rel="shortcut icon" href="/icon-192.png">
<!-- PWA Manifest -->
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#667eea">
<!-- iOS Icons -->
<link rel="apple-touch-icon" href="/icon-192.png">
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div id="app">
<!-- Экран лобби -->
<div id="lobby-screen" class="screen active">
<div class="container">
<h1>🎴 Чешский</h1>
<div id="create-room-section">
<h2>Создать комнату</h2>
<input type="text" id="nickname-input" placeholder="Введите никнейм" maxlength="20">
<button id="create-room-btn" class="btn btn-primary">Создать комнату</button>
<div id="bot-game-section">
<h3>🤖 Играть с ботами</h3>
<div class="bot-buttons">
<button id="play-with-1-bot-btn" class="btn btn-bot">Играть с 1 ботом</button>
<button id="play-with-2-bots-btn" class="btn btn-bot">Играть с 2 ботами</button>
<button id="play-with-3-bots-btn" class="btn btn-bot">Играть с 3 ботами</button>
</div>
</div>
</div>
<div id="rooms-section">
<h2>Доступные комнаты</h2>
<div id="rooms-list"></div>
</div>
<div id="rules-section">
<h2>📖 Правила игры</h2>
<div id="lobby-rules-content" class="rules-content"></div>
</div>
</div>
</div>
<!-- Экран комнаты -->
<div id="room-screen" class="screen">
<div class="container">
<div class="room-header">
<h2>Комната</h2>
<button id="leave-room-btn" class="btn btn-secondary">Покинуть</button>
</div>
<div id="players-waiting">
<h3>Игроки в комнате:</h3>
<div id="players-list"></div>
<!-- Настройки комнаты (только для создателя) -->
<div id="room-settings" style="display: none;">
<h3>Настройки игры</h3>
<div class="deck-size-toggle">
<label>
<span class="deck-label">36 карт</span>
<input type="checkbox" id="deck-size-toggle" checked>
<span class="toggle-slider"></span>
<span class="deck-label">52 карты</span>
</label>
<p class="hint-small">В режиме 36 карт восьмёрка не действует</p>
</div>
</div>
<div id="countdown-display" style="display: none;">
<div class="countdown-timer">
<span id="countdown-number">6</span>
</div>
<p class="countdown-text">Игра начинается...</p>
</div>
<button id="ready-toggle-btn" class="btn btn-primary">Готов</button>
<p class="hint">Игра начнётся когда все игроки будут готовы (минимум 2 игрока)</p>
</div>
</div>
</div>
<!-- Экран ошибки -->
<div id="error-screen" class="screen">
<div class="error-container">
<div class="error-content">
<h1>😕</h1>
<h2>Комната не найдена</h2>
<p id="error-message">Эта комната не существует или была удалена</p>
<button id="go-home-btn" class="btn btn-primary">На главную</button>
</div>
</div>
</div>
<!-- Экран игры -->
<div id="game-screen" class="screen">
<div class="game-container">
<!-- Кнопка покинуть комнату -->
<button id="leave-game-btn" class="leave-game-btn" title="Покинуть комнату">
<span class="leave-icon">🚪</span>
</button>
<!-- Кнопка полноэкранного режима -->
<button id="fullscreen-btn" class="fullscreen-btn" title="Полноэкранный режим">
<span class="fullscreen-icon">⛶</span>
</button>
<!-- Кнопка правил -->
<button id="rules-btn" class="rules-btn" title="Правила игры">📖</button>
<!-- Кнопка чата -->
<button id="chat-btn" class="chat-btn" title="Отправить сообщение">💬</button>
<!-- Кнопка toggle логов (только на мобильных) -->
<button id="toggle-log-btn" class="toggle-log-btn" title="Показать/скрыть логи">
<span class="toggle-log-icon">📋</span>
</button>
<!-- Кнопка выключения звука -->
<button id="toggle-sound-btn" class="toggle-sound-btn" title="Включить/выключить звук">
<span class="sound-icon">🔊</span>
</button>
<!-- Круговое игровое поле -->
<div class="game-table">
<!-- Игровой лог -->
<div id="game-log" class="game-log"></div>
<!-- Контейнер для противников -->
<div id="opponents-container">
<!-- Игрок слева -->
<div class="opponent-area opponent-left" id="opponent-left">
<div class="opponent-info">
<span class="opponent-name"></span>
<span class="opponent-score"></span>
</div>
<div class="opponent-cards"></div>
</div>
<!-- Игрок по центру -->
<div class="opponent-area opponent-top" id="opponent-top">
<div class="opponent-info">
<span class="opponent-name"></span>
<span class="opponent-score"></span>
</div>
<div class="opponent-cards"></div>
</div>
<!-- Игрок справа -->
<div class="opponent-area opponent-right" id="opponent-right">
<div class="opponent-info">
<span class="opponent-name"></span>
<span class="opponent-score"></span>
</div>
<div class="opponent-cards"></div>
</div>
</div>
<!-- Центральный круг с картой и колодой -->
<div class="game-circle">
<div class="center-area">
<div class="center-card-wrapper">
<!-- Индикатор выбранной масти -->
<div id="chosen-suit-indicator" style="display: none;"></div>
<div id="discard-pile" class="center-card"></div>
</div>
<div class="deck-area">
<div class="deck-count-badge" id="deck-count">0</div>
<div id="deck" class="card-pile">
<div class="card card-back">🎴</div>
</div>
<div class="deck-buttons">
<button id="draw-card-btn" class="btn btn-primary btn-sm">Взять</button>
<button id="skip-turn-btn" class="btn btn-secondary btn-sm" style="display: none;">Нету</button>
</div>
</div>
</div>
</div>
<!-- Контейнер игрока -->
<div class="player-container">
<!-- Информация об игроке -->
<div class="player-info">
<span class="player-name" id="player-name"></span>
<span class="player-score" id="player-score"></span>
</div>
<!-- Карты игрока внизу -->
<div class="player-hand">
<div id="hand-cards"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Модальное окно чата -->
<div id="chat-modal" class="modal">
<div class="modal-content chat-modal-content">
<h3>Отправить сообщение</h3>
<textarea id="chat-input" placeholder="Введите сообщение..." maxlength="200"></textarea>
<div class="chat-modal-buttons">
<button id="send-chat-btn" class="btn btn-primary">Отправить</button>
<button id="close-chat-btn" class="btn btn-secondary">Отмена</button>
</div>
</div>
</div>
<!-- Модальное окно выбора масти -->
<div id="suit-modal" class="modal">
<div class="modal-content">
<h3>Выберите масть</h3>
<div class="suit-selector">
<button class="suit-btn" data-suit="hearts">♥️ Черви</button>
<button class="suit-btn" data-suit="diamonds">♦️ Бубны</button>
<button class="suit-btn" data-suit="clubs">♣️ Трефы</button>
<button class="suit-btn" data-suit="spades">♠️ Пики</button>
</div>
<div class="modal-buttons" style="margin-top: 15px;">
<button id="cancel-suit-btn" class="btn btn-secondary">Отмена</button>
</div>
</div>
</div>
<!-- Модальное окно результатов -->
<div id="results-modal" class="modal">
<div class="modal-content">
<h2>Игра окончена!</h2>
<div id="results-content"></div>
<button id="close-results-btn" class="btn btn-primary">Новая игра</button>
</div>
</div>
<!-- Модальное окно присоединения к комнате -->
<div id="join-modal" class="modal">
<div class="modal-content">
<h3>Присоединиться к комнате</h3>
<input type="text" id="join-nickname-input" placeholder="Введите никнейм" maxlength="20">
<div class="modal-buttons">
<button id="join-confirm-btn" class="btn btn-primary">Присоединиться</button>
<button id="join-cancel-btn" class="btn btn-secondary">Отмена</button>
</div>
</div>
</div>
<!-- Модальное окно оповещения -->
<div id="alert-modal" class="modal">
<div class="modal-content">
<h3>Сообщение</h3>
<p id="alert-text" style="margin: 10px 0 20px 0;"></p>
<div class="modal-buttons">
<button id="alert-ok-btn" class="btn btn-primary">ОК</button>
</div>
</div>
</div>
<!-- Модальное окно подтверждения выхода -->
<div id="leave-confirm-modal" class="modal">
<div class="modal-content">
<h3>Покинуть комнату?</h3>
<p style="margin: 10px 0 20px 0;">Вы уверены, что хотите покинуть игру?</p>
<div class="modal-buttons">
<button id="leave-confirm-btn" class="btn btn-primary">Да, выйти</button>
<button id="leave-cancel-btn" class="btn btn-secondary">Отмена</button>
</div>
</div>
</div>
<!-- Модальное окно правил -->
<div id="rules-modal" class="modal">
<div class="modal-content rules-modal-content">
<button id="close-rules-btn" class="close-modal-btn">✕</button>
<h2>📖 Правила игры</h2>
<div id="rules-content" class="rules-content"></div>
</div>
</div>
</div>
<script src="/marked.min.js"></script>
<script src="/game.js"></script>
<!-- Service Worker Registration -->
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('ServiceWorker registered:', registration.scope);
})
.catch(err => {
console.log('ServiceWorker registration failed:', err);
});
});
}
// Функция проверки - находимся ли на главной странице (лобби)
function isOnLobbyScreen() {
const lobbyScreen = document.getElementById('lobby-screen');
return lobbyScreen && lobbyScreen.classList.contains('active');
}
// Функция проверки - находится ли элемент внутри блока руки
function isInsidePlayerHand(element) {
while (element) {
if (element.classList && element.classList.contains('player-hand')) {
return true;
}
element = element.parentElement;
}
return false;
}
// Функция проверки - находится ли элемент внутри модалки с прокруткой
function isInsideScrollableModal(element) {
while (element) {
if (element.classList && (
element.classList.contains('rules-modal-content') ||
element.classList.contains('modal-content')
)) {
return true;
}
element = element.parentElement;
}
return false;
}
// Отключаем pull-to-refresh только НЕ на главной странице
let touchStartY = 0;
document.addEventListener('touchstart', function(e) {
touchStartY = e.touches[0].clientY;
}, { passive: false });
document.addEventListener('touchmove', function(e) {
// Разрешаем все жесты на главной странице
if (isOnLobbyScreen()) {
return;
}
// Разрешаем скролл внутри блока руки игрока
if (isInsidePlayerHand(e.target)) {
return;
}
// Разрешаем скролл внутри модалок
if (isInsideScrollableModal(e.target)) {
return;
}
const touchY = e.touches[0].clientY;
const touchDiff = touchY - touchStartY;
// Если пользователь тянет вниз на верху страницы - блокируем
if (touchDiff > 0 && window.scrollY === 0) {
e.preventDefault();
}
// Блокируем мультитач
if (e.touches.length > 1) {
e.preventDefault();
}
}, { passive: false });
// Отключаем двойное нажатие для зума только НЕ на главной
let lastTouchEnd = 0;
document.addEventListener('touchend', function(e) {
// Разрешаем на главной странице
if (isOnLobbyScreen()) {
return;
}
const now = Date.now();
if (now - lastTouchEnd <= 300) {
e.preventDefault();
}
lastTouchEnd = now;
}, false);
// Предотвращаем обновление страницы через клавиатуру только НЕ на главной
document.addEventListener('keydown', function(e) {
// Разрешаем на главной странице
if (isOnLobbyScreen()) {
return;
}
if ((e.key === 'F5') ||
(e.ctrlKey && e.key === 'r') ||
(e.metaKey && e.key === 'r')) {
e.preventDefault();
return false;
}
});
</script>
</body>
</html>