|
|
|
|
@@ -2,6 +2,37 @@
|
|
|
|
|
|
|
|
|
|
{% block title %}{{ t(key="calendar-title", lang=lang) }}{% endblock title %}
|
|
|
|
|
|
|
|
|
|
{% block head %}
|
|
|
|
|
{% 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">
|
|
|
|
|
@@ -22,6 +53,7 @@
|
|
|
|
|
|
|
|
|
|
{% 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>
|
|
|
|
|
@@ -30,11 +62,23 @@
|
|
|
|
|
<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 class="w-full border-collapse text-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>
|
|
|
|
|
@@ -55,9 +99,16 @@
|
|
|
|
|
{% if cell.booked %}
|
|
|
|
|
{% if is_admin %}
|
|
|
|
|
<a href="/admin/booking/{{ cell.booking_id }}"
|
|
|
|
|
class="absolute inset-1 flex items-center overflow-hidden rounded px-1.5 text-xs font-medium text-white shadow-sm transition hover:opacity-90"
|
|
|
|
|
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="min-w-0 truncate">{{ cell.name }}</span>
|
|
|
|
|
<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"
|
|
|
|
|
@@ -88,3 +139,29 @@
|
|
|
|
|
</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 %}
|
|
|
|
|
|