RosterHash/templates/base.html
2025-09-09 09:36:58 -07:00

190 lines
8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}RosterHash{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="icon" type="image/png" href="/favicon.ico">
<link rel="apple-touch-icon" href="/rosterhash_logo.png">
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
<meta name="theme-color" content="#8b7ff5">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
</head>
<body>
<!-- Hamburger Menu Button - Uses CSS-only solution -->
<input type="checkbox" id="menu-toggle" class="menu-toggle-checkbox">
<label for="menu-toggle" class="menu-toggle" aria-label="Toggle menu">
<span class="menu-icon"></span>
</label>
<!-- Sidebar Menu -->
<div class="sidebar" id="sidebar">
<label for="menu-toggle" class="close-btn"></label>
<div class="sidebar-content">
<!-- Theme Toggle Section -->
<div class="sidebar-section">
<h3>Theme</h3>
<form method="post" action="/toggle_theme" style="display: inline;">
<input type="hidden" name="return_url" value="{{ request.url }}">
<button type="submit" class="theme-button">
{% if current_theme == 'dark' %}
<span>🌙</span>
<span>Dark Mode</span>
{% else %}
<span>☀️</span>
<span>Light Mode</span>
{% endif %}
</button>
</form>
</div>
<!-- Links Section -->
<div class="sidebar-section">
<h3>Links</h3>
<a href="https://sleeper.app" target="_blank" class="sidebar-link">
🏈 Sleeper App
</a>
<a href="https://github.com" target="_blank" class="sidebar-link">
💻 Source Code
</a>
</div>
<!-- About Section -->
<div class="sidebar-section">
<h3>About This WebApp</h3>
<div class="about-text">
<p>RosterHash gives you an at-a-glance view of your Sleeper leagues player's schedules and status.</p>
<p><strong>How to use:</strong></p>
<ul>
<li>Enter your Sleeper username on the home page</li>
<li>View all your leagues' matchup scores at the top</li>
<li>See when each of your players plays, grouped by league (indicated by colored borders)</li>
<li>Benched players are right-aligned and greyed out</li>
<li>Games and Days are collapsed if they're over.</li>
</ul>
<p class="cron-note">* * * * 4,7,1</p>
</div>
</div>
</div>
</div>
<!-- Overlay for sidebar -->
<label for="menu-toggle" class="sidebar-overlay" id="sidebar-overlay"></label>
<div class="container">
{% block content %}{% endblock %}
</div>
<!-- App version footer -->
<footer class="app-footer">
<div class="version">RosterHash v{{ app_version }}</div>
</footer>
<!-- Set theme based on server-side session -->
<script>
// Apply theme immediately to prevent flash
document.documentElement.setAttribute('data-theme', '{{ current_theme }}');
// For modern browsers with light-dark() support, also set color-scheme
document.documentElement.style.colorScheme = '{{ current_theme }}';
// Detect user's timezone and send to server if not already set
{% if not session.get('user_timezone') %}
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
if (userTimezone) {
// Send timezone to server via hidden form submission
const form = document.createElement('form');
form.method = 'POST';
form.action = '/set_timezone';
form.style.display = 'none';
const timezoneInput = document.createElement('input');
timezoneInput.type = 'hidden';
timezoneInput.name = 'timezone';
timezoneInput.value = userTimezone;
const returnUrlInput = document.createElement('input');
returnUrlInput.type = 'hidden';
returnUrlInput.name = 'return_url';
returnUrlInput.value = window.location.href;
form.appendChild(timezoneInput);
form.appendChild(returnUrlInput);
document.body.appendChild(form);
form.submit();
}
{% endif %}
// Collapsible functionality
function toggleDay(dayKey) {
const dayRow = document.querySelector(`[data-day="${dayKey}"]`);
const dayGames = document.getElementById(`day-${dayKey}`);
const indicator = dayRow.querySelector('.collapse-indicator');
dayRow.classList.toggle('collapsed');
if (dayRow.classList.contains('collapsed')) {
indicator.textContent = '▶';
dayGames.style.display = 'none';
} else {
indicator.textContent = '▼';
dayGames.style.display = 'block';
// Expand all games in this day
const gameCards = dayGames.querySelectorAll('.game-card');
gameCards.forEach(card => {
card.classList.remove('collapsed');
const gameIndicator = card.querySelector('.game-collapse-indicator');
const gameContent = card.querySelector('.game-content');
if (gameIndicator) gameIndicator.textContent = '▼';
if (gameContent) gameContent.style.display = 'block';
});
}
}
function toggleGame(dayKey, gameIndex) {
const gameCard = document.querySelector(`[data-day="${dayKey}"] [data-game="${gameIndex}"]`);
const gameContent = document.getElementById(`game-${dayKey}-${gameIndex}`);
const indicator = gameCard.querySelector('.game-collapse-indicator');
gameCard.classList.toggle('collapsed');
if (gameCard.classList.contains('collapsed')) {
indicator.textContent = '▶';
gameContent.style.display = 'none';
} else {
indicator.textContent = '▼';
gameContent.style.display = 'block';
}
}
// Initialize collapsed states on page load
document.addEventListener('DOMContentLoaded', function() {
// Hide content for collapsed day rows
document.querySelectorAll('.day-row.collapsed .day-games').forEach(dayGames => {
dayGames.style.display = 'none';
});
// Hide content for collapsed game cards
document.querySelectorAll('.game-card.collapsed .game-content').forEach(gameContent => {
gameContent.style.display = 'none';
});
});
// Register service worker for PWA functionality
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/static/sw.js')
.then(function(registration) {
console.log('RosterHash SW: Registered successfully');
})
.catch(function(error) {
console.log('RosterHash SW: Registration failed:', error);
});
});
}
</script>
</body>
</html>