Files
The-Workers-Club/templates/base.html

212 lines
8.8 KiB
HTML

<!doctype html>
<html lang="en" class="h-full bg-slate-950">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>{{ title or app_brand }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
brand: {
50: '#eff6ff',
100: '#dbeafe',
600: '#2563eb',
700: '#1d4ed8'
}
}
}
}
}
</script>
<style>
/* Every box prints on its own page */
@media print {
.print-block {
page-break-before: always !important;
break-before: page !important;
}
/* remove first blank page */
.print-block:first-child {
page-break-before: avoid !important;
break-before: avoid !important;
}
}
/* Base print reset */
@media print {
html, body {
background: #ffffff !important;
color: #000000 !important;
}
/* Hide app chrome */
header,
nav,
footer,
.fixed,
#mobileNav,
#navToggle {
display: none !important;
visibility: hidden !important;
}
/* Remove Tailwind background classes */
.bg-slate-950,
.bg-slate-900\/60,
.bg-slate-950\/60 {
background: #ffffff !important;
}
.text-slate-100,
.text-slate-200,
.text-slate-300,
.text-slate-400 {
color: #000000 !important;
}
/* Force links to print black */
a {
color: #000000 !important;
text-decoration: underline !important;
}
/* Expand content full width */
main {
padding: 0 !important;
margin: 0 !important;
max-width: 100% !important;
}
/* Page breaks for nice sections */
.print-section {
page-break-before: always;
}
/* Avoid truncation */
.no-break {
page-break-inside: avoid;
}
}
</style>
</head>
<body class="h-full text-slate-100 pt-[env(safe-area-inset-top)] pb-[env(safe-area-inset-bottom)]">
<div class="min-h-screen">
<!-- Topbar -->
<header class="sticky top-0 z-50 backdrop-blur bg-slate-950/70 border-b border-slate-800">
<div class="max-w-6xl mx-auto px-4">
<div class="h-14 flex items-center justify-between">
<!-- Brand -->
<a href="{{ url_for('dashboard') }}" class="flex items-center gap-2">
<div class="h-7 w-7 rounded bg-brand-600/20 border border-brand-600/30 grid place-items-center font-bold">SC</div>
<span class="font-semibold tracking-wide">{{ app_brand }}</span>
</a>
{% if current_user.is_authenticated %}
<!-- Desktop nav -->
<nav class="hidden md:flex items-center gap-2 text-sm">
<a class="px-3 py-1.5 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('dashboard') }}">Home</a>
<a class="px-3 py-1.5 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('availability') }}">Your Availability</a>
<a class="px-3 py-1.5 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('request_off') }}">Request Off</a>
<a class="px-3 py-1.5 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('secret_santa') }}">Secret Santa</a>
{% if current_user.role == 'admin' %}
<a class="px-3 py-1.5 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('admin_users') }}">Admin</a>
{% endif %}
<form method="post" action="{{ url_for('logout') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button class="px-3 py-1.5 rounded-lg bg-brand-600 text-white hover:bg-brand-700" type="submit">Logout</button>
</form>
</nav>
<!-- Mobile menu -->
<button id="navToggle" class="md:hidden inline-flex items-center justify-center h-9 w-9 rounded-lg border border-slate-700 hover:border-slate-500" aria-label="Open menu" aria-expanded="false" aria-controls="mobileNav">
<svg id="navIconOpen" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path stroke-linecap="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg>
<svg id="navIconClose" class="h-5 w-5 hidden" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path stroke-linecap="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
</button>
{% endif %}
</div>
</div>
<!-- Mobile nav panel -->
<div id="mobileNav" class="md:hidden max-w-6xl mx-auto px-4 pb-3 hidden">
<div class="grid gap-2 text-sm">
<a class="px-3 py-2 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('dashboard') }}">Home</a>
<a class="px-3 py-2 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('availability') }}">Availability</a>
<a class="px-3 py-2 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('request_off') }}">Request Off</a>
<a class="px-3 py-2 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('secret_santa') }}">Secret Santa</a>
{% if current_user.role == 'admin' %}
<a class="px-3 py-2 rounded-lg border border-slate-700 hover:border-slate-500" href="{{ url_for('admin_users') }}">Admin</a>
{% endif %}
<form method="post" action="{{ url_for('logout') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button class="px-3 py-2 rounded-lg bg-brand-600 text-white hover:bg-brand-700" type="submit">Logout</button>
</form>
</div>
</div>
</header>
<!-- Main content -->
<main class="max-w-6xl mx-auto px-4 pt-6 pb-[6.5rem]"> <!-- ⬅️ room for bottom nav + iOS inset -->
{% with msgs = get_flashed_messages(with_categories=true) %}
{% if msgs %}
<div class="space-y-2 mb-4">
{% for cat,msg in msgs %}
<div class="rounded-lg px-3 py-2 text-sm border {{ 'bg-emerald-500/15 border-emerald-700 text-emerald-200' if cat=='ok' else 'bg-red-500/15 border-red-700 text-red-200' }}">{{ msg }}</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{{ content|safe }}
</main>
<!-- Bottom nav -->
{% if current_user.is_authenticated %}
<nav class="fixed bottom-0 inset-x-0 z-50 bg-[#111827] border-t border-gray-800 md:hidden pb-[env(safe-area-inset-bottom)]">
<div class="flex justify-around text-sm text-gray-400">
<a href="{{ url_for('dashboard') }}" class="flex flex-col items-center justify-center py-2 px-3 {% if 'dashboard' in request.path %}text-white{% endif %}">
<svg class="w-5 h-5 mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-width="2" d="M3 12l2-2 7-7 7 7 2 2"/></svg>
Home
</a>
<a href="{{ url_for('availability') }}" class="flex flex-col items-center justify-center py-2 px-3 {% if 'availability' in request.path %}text-white{% endif %}">
<svg class="w-5 h-5 mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-width="2" d="M8 7V3m8 4V3M3 11h18"/></svg>
Availability
</a>
<a href="{{ url_for('request_off') }}" class="flex flex-col items-center justify-center py-2 px-3 {% if 'request' in request.path %}text-white{% endif %}">
<svg class="w-5 h-5 mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-width="2" d="M9 5v6m4 0h6"/></svg>
Requests
</a>
<a href="{{ url_for('secret_santa') }}" class="flex flex-col items-center justify-center py-2 px-3 {% if 'secret' in request.path %}text-white{% endif %}">
<svg class="w-5 h-5 mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5z"/></svg>
Gifts
</a>
</div>
</nav>
{% endif %}
<footer class="text-xs text-center text-slate-500 py-6">© {{ app_brand }}</footer>
</div>
<!-- Nav toggle -->
<script>
(function () {
const btn = document.getElementById('navToggle');
const menu = document.getElementById('mobileNav');
const openI = document.getElementById('navIconOpen');
const closeI = document.getElementById('navIconClose');
if (!btn || !menu) return;
btn.addEventListener('click', () => {
const isHidden = menu.classList.contains('hidden');
menu.classList.toggle('hidden');
btn.setAttribute('aria-expanded', String(isHidden));
openI.classList.toggle('hidden', !isHidden);
closeI.classList.toggle('hidden', isHidden);
});
})();
</script>
</body>
</html>