Files
Kurt_kalendar/ht_booking/assets/views/calendar/week.html
2026-05-16 16:28:10 +02:00

186 lines
7.3 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ t(key="calendar-title", lang=lang) }}{% endblock title %}
{% block head %}
<style>
/* Sharpen the calendar grid. The daisyUI base tones give very low-contrast
hairline borders and dimmed text in both themes. Tying the borders and
the header tint to base-content keeps the table legible and easy to
follow on light and dark alike (public + admin calendars). */
#cal th,
#cal td {
border-color: hsl(var(--bc) / 0.25);
}
#cal thead tr,
#cal tbody td:first-child {
background-color: hsl(var(--bc) / 0.1);
}
#cal tbody td:first-child { opacity: 1; }
#cal thead .opacity-50 { opacity: 0.8; }
#cal td .opacity-30 { opacity: 0.7; }
#cal td a.opacity-30:hover { opacity: 1; }
</style>
{% if is_admin %}
<style>
/* Admin calendar — detailed-view toggle. The public calendar is unaffected. */
.cal-detail { display: none; }
#cal.cal--detailed .cal-chip {
position: static;
inset: auto;
margin: 0.25rem;
min-height: 3rem;
flex-direction: column;
align-items: stretch;
justify-content: center;
}
#cal.cal--detailed .cal-name {
white-space: normal;
font-weight: 600;
}
#cal.cal--detailed .cal-detail {
display: flex;
flex-direction: column;
gap: 1px;
margin-top: 2px;
font-weight: 400;
line-height: 1.25;
overflow-wrap: anywhere;
}
</style>
{% endif %}
{% endblock head %}
{% block content %}
<div class="mb-4 flex flex-wrap items-center justify-between gap-3">
<h1 class="text-2xl font-bold">
{% if is_admin %}{{ t(key="admin-title", lang=lang) }}{% else %}{{ t(key="calendar-title", lang=lang) }}{% endif %}
</h1>
{% if has_courts %}
<form method="get" action="{{ base_path }}" class="flex items-center gap-2">
<label class="text-sm font-medium opacity-70">{{ t(key="court-label", lang=lang) }}</label>
<input type="hidden" name="week" value="{{ week }}">
<select name="court" onchange="this.form.submit()" class="select select-bordered select-sm">
{% for c in courts %}
<option value="{{ c.id }}" {% if c.selected %}selected{% endif %}>{{ c.name }}</option>
{% endfor %}
</select>
</form>
{% endif %}
</div>
{% if has_courts %}
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
<div class="flex flex-wrap items-center gap-2">
<div class="join">
<a href="{{ base_path }}?court={{ court_id }}&week={{ prev_week }}"
class="btn btn-sm join-item">« {{ t(key="prev-week", lang=lang) }}</a>
<a href="{{ base_path }}?court={{ court_id }}&week={{ this_week }}"
class="btn btn-sm join-item">{{ t(key="this-week", lang=lang) }}</a>
<a href="{{ base_path }}?court={{ court_id }}&week={{ next_week }}"
class="btn btn-sm join-item">{{ t(key="next-week", lang=lang) }} »</a>
</div>
{% if is_admin %}
<button type="button" id="cal-detail-toggle" class="btn btn-sm gap-1" aria-pressed="false"
title="{{ t(key='view-details', lang=lang) }}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="h-4 w-4">
<path stroke-linecap="round" stroke-linejoin="round"
d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0ZM3.75 12h.007v.008H3.75V12Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm-.375 5.25h.007v.008H3.75v-.008Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" />
</svg>
{{ t(key="view-details", lang=lang) }}
</button>
{% endif %}
</div>
<div class="text-sm font-medium opacity-60">{{ court_name }} · {{ week_label }}</div>
</div>
<div class="overflow-x-auto rounded-lg border border-base-300 bg-base-100 shadow-sm">
<table id="cal" class="w-full border-collapse text-sm">
<thead>
<tr class="bg-base-200">
<th class="w-16 border border-base-300 p-2"></th>
{% for d in days %}
<th class="border border-base-300 p-2 text-center">
<div class="font-semibold">{{ t(key=d.key, lang=lang) }}</div>
<div class="text-xs font-normal opacity-50">{{ d.num }}</div>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
<td class="border border-base-300 bg-base-200 p-2 text-center font-medium opacity-70">{{ row.hour_label }}</td>
{% for cell in row.cells %}
<td class="relative h-14 border border-base-300">
{% if cell.booked %}
{% if is_admin %}
<a href="/admin/booking/{{ cell.booking_id }}"
class="cal-chip absolute inset-1 flex items-center overflow-hidden rounded px-1.5 text-xs font-medium text-white shadow-sm transition hover:opacity-90"
style="background-color: {{ cell.color }}">
<span class="cal-name min-w-0 truncate">{{ cell.name }}</span>
{% if cell.title or cell.contact or cell.note %}
<span class="cal-detail">
{%- if cell.title %}<span class="truncate opacity-95">{{ cell.title }}</span>{% endif -%}
{%- if cell.contact %}<span class="truncate opacity-80">{{ cell.contact }}</span>{% endif -%}
{%- if cell.note %}<span class="opacity-80">{{ cell.note }}</span>{% endif -%}
</span>
{% endif %}
</a>
{% else %}
<div class="absolute inset-1 flex items-center overflow-hidden rounded px-1.5 text-xs font-medium text-white shadow-sm"
style="background-color: {{ cell.color }}"{% if cell.title %} title="{{ cell.title }}"{% endif %}>
<span class="min-w-0 truncate">
{%- if cell.title %}{{ cell.title }}{% else %}{{ t(key="booked", lang=lang) }}{% endif -%}
</span>
</div>
{% endif %}
{% else %}
{% if is_admin %}
<a href="/admin/booking?court={{ court_id }}&date={{ cell.date }}&hour={{ cell.hour }}"
class="absolute inset-0 flex items-center justify-center text-lg opacity-30 transition hover:bg-base-200 hover:opacity-100">+</a>
{% else %}
<div class="absolute inset-0 flex items-center justify-center text-xs opacity-30">{{ t(key="free", lang=lang) }}</div>
{% endif %}
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="card border border-base-300 bg-base-100 shadow-sm">
<div class="card-body items-center text-center opacity-60">{{ t(key="no-courts", lang=lang) }}</div>
</div>
{% endif %}
{% endblock content %}
{% block js %}
{% if is_admin %}
<script>
// Detailed-view toggle for the admin calendar. The choice is remembered
// per browser; the public calendar never loads this script.
(function () {
var KEY = 'cal_detailed';
var tbl = document.getElementById('cal');
var btn = document.getElementById('cal-detail-toggle');
if (!tbl || !btn) return;
function apply(on) {
tbl.classList.toggle('cal--detailed', on);
btn.classList.toggle('btn-active', on);
btn.setAttribute('aria-pressed', on ? 'true' : 'false');
}
apply(localStorage.getItem(KEY) === '1');
btn.addEventListener('click', function () {
var on = !tbl.classList.contains('cal--detailed');
localStorage.setItem(KEY, on ? '1' : '0');
apply(on);
});
})();
</script>
{% endif %}
{% endblock js %}