This commit is contained in:
Priec
2026-05-16 12:45:38 +02:00
parent 164dacb678
commit 6c87a9d58f
5 changed files with 152 additions and 129 deletions

View File

@@ -10,54 +10,57 @@
<h1 class="text-2xl font-bold"> <h1 class="text-2xl font-bold">
{% if mode == "edit" %}{{ t(key="edit-booking", lang=lang) }}{% else %}{{ t(key="add-booking", lang=lang) }}{% endif %} {% if mode == "edit" %}{{ t(key="edit-booking", lang=lang) }}{% else %}{{ t(key="add-booking", lang=lang) }}{% endif %}
</h1> </h1>
<a href="/admin" class="text-sm text-blue-600 hover:underline">&larr; {{ t(key="back-to-calendar", lang=lang) }}</a> <a href="/admin" class="btn btn-ghost btn-sm">« {{ t(key="back-to-calendar", lang=lang) }}</a>
</div> </div>
<form method="post" action="{{ action }}" class="space-y-3 rounded-lg border bg-white p-4"> <div class="card border border-gray-200 bg-white shadow-sm">
<div class="card-body">
<form method="post" action="{{ action }}" class="space-y-2">
<input type="hidden" name="court_id" value="{{ court_id }}"> <input type="hidden" name="court_id" value="{{ court_id }}">
<div class="text-sm text-gray-600">{{ t(key="court-label", lang=lang) }}: <strong>{{ court_name }}</strong></div> <div class="text-sm text-gray-600">
<div> {{ t(key="court-label", lang=lang) }}: <strong>{{ court_name }}</strong>
<label class="block text-sm text-gray-600">{{ t(key="date", lang=lang) }}</label>
<input type="date" name="date" value="{{ date }}" required class="w-full rounded border-gray-300 text-sm">
</div> </div>
<div> <div class="form-control">
<label class="block text-sm text-gray-600">{{ t(key="hour", lang=lang) }}</label> <label class="label"><span class="label-text">{{ t(key="date", lang=lang) }}</span></label>
<select name="hour" class="w-full rounded border-gray-300 text-sm"> <input type="date" name="date" value="{{ date }}" required class="input input-bordered w-full">
</div>
<div class="form-control">
<label class="label"><span class="label-text">{{ t(key="hour", lang=lang) }}</span></label>
<select name="hour" class="select select-bordered w-full">
{% for h in hours %} {% for h in hours %}
<option value="{{ h.v }}" {% if h.v == hour %}selected{% endif %}>{{ h.label }}</option> <option value="{{ h.v }}" {% if h.v == hour %}selected{% endif %}>{{ h.label }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div> <div class="form-control">
<label class="block text-sm text-gray-600">{{ t(key="booking-color", lang=lang) }}</label> <label class="label"><span class="label-text">{{ t(key="booking-color", lang=lang) }}</span></label>
<input type="color" name="color" value="{{ color }}" class="h-9 w-16 rounded border-gray-300"> <input type="color" name="color" value="{{ color }}"
class="h-10 w-20 cursor-pointer rounded border border-gray-300">
</div> </div>
<div> <div class="form-control">
<label class="block text-sm text-gray-600">{{ t(key="booking-name", lang=lang) }}</label> <label class="label"><span class="label-text">{{ t(key="booking-name", lang=lang) }}</span></label>
<input name="name" value="{{ name }}" required class="w-full rounded border-gray-300 text-sm"> <input name="name" value="{{ name }}" required class="input input-bordered w-full">
</div> </div>
<div> <div class="form-control">
<label class="block text-sm text-gray-600">{{ t(key="booking-contact", lang=lang) }}</label> <label class="label"><span class="label-text">{{ t(key="booking-contact", lang=lang) }}</span></label>
<input name="contact" value="{{ contact }}" class="w-full rounded border-gray-300 text-sm"> <input name="contact" value="{{ contact }}" class="input input-bordered w-full">
</div> </div>
<div> <div class="form-control">
<label class="block text-sm text-gray-600">{{ t(key="booking-note", lang=lang) }}</label> <label class="label"><span class="label-text">{{ t(key="booking-note", lang=lang) }}</span></label>
<textarea name="note" rows="3" class="w-full rounded border-gray-300 text-sm">{{ note }}</textarea> <textarea name="note" rows="3" class="textarea textarea-bordered w-full">{{ note }}</textarea>
</div> </div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2 pt-2">
<button class="rounded bg-gray-900 px-4 py-2 text-sm text-white hover:bg-gray-700"> <button class="btn btn-neutral">{{ t(key="save", lang=lang) }}</button>
{{ t(key="save", lang=lang) }} <a href="/admin" class="btn btn-ghost">{{ t(key="cancel", lang=lang) }}</a>
</button>
<a href="/admin" class="rounded border px-4 py-2 text-sm hover:bg-gray-100">{{ t(key="cancel", lang=lang) }}</a>
</div> </div>
</form> </form>
</div>
</div>
{% if mode == "edit" %} {% if mode == "edit" %}
<form method="post" action="/admin/booking/{{ booking_id }}/delete" class="mt-3" <form method="post" action="/admin/booking/{{ booking_id }}/delete" class="mt-3"
onsubmit="return confirm('{{ t(key="confirm-delete", lang=lang) }}');"> onsubmit="return confirm('{{ t(key="confirm-delete", lang=lang) }}');">
<button class="rounded bg-red-600 px-4 py-2 text-sm text-white hover:bg-red-700"> <button class="btn btn-outline btn-error btn-sm">{{ t(key="delete", lang=lang) }}</button>
{{ t(key="delete", lang=lang) }}
</button>
</form> </form>
{% endif %} {% endif %}
</div> </div>

View File

@@ -5,36 +5,42 @@
{% block content %} {% block content %}
<div class="mb-4 flex items-center justify-between"> <div class="mb-4 flex items-center justify-between">
<h1 class="text-2xl font-bold">{{ t(key="manage-courts", lang=lang) }}</h1> <h1 class="text-2xl font-bold">{{ t(key="manage-courts", lang=lang) }}</h1>
<a href="/admin" class="text-sm text-blue-600 hover:underline">&larr; {{ t(key="back-to-calendar", lang=lang) }}</a> <a href="/admin" class="btn btn-ghost btn-sm">« {{ t(key="back-to-calendar", lang=lang) }}</a>
</div> </div>
{% if name_error %} {% if name_error %}
<div class="mb-3 rounded bg-red-100 px-3 py-2 text-sm text-red-700">{{ t(key="court-delete-error", lang=lang) }}</div> <div class="alert alert-error mb-4">
<span>{{ t(key="court-delete-error", lang=lang) }}</span>
</div>
{% endif %} {% endif %}
<div class="mb-6 overflow-auto rounded-lg border bg-white"> <div class="mb-6 overflow-x-auto rounded-lg border border-gray-200 bg-white shadow-sm">
<table class="w-full text-sm"> <table class="table">
<thead> <thead>
<tr class="bg-gray-100 text-left"> <tr>
<th class="p-2">{{ t(key="court-name", lang=lang) }}</th> <th>{{ t(key="court-name", lang=lang) }}</th>
<th class="p-2">{{ t(key="court-surface", lang=lang) }}</th> <th>{{ t(key="court-surface", lang=lang) }}</th>
<th class="p-2">{{ t(key="court-indoor", lang=lang) }}</th> <th>{{ t(key="court-indoor", lang=lang) }}</th>
<th class="p-2">{{ t(key="court-remove", lang=lang) }}</th> <th class="text-right">{{ t(key="court-remove", lang=lang) }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for c in courts %} {% for c in courts %}
<tr class="border-t"> <tr>
<td class="p-2">{{ c.name }}</td> <td class="font-medium">{{ c.name }}</td>
<td class="p-2">{{ c.surface }}</td> <td>{{ c.surface }}</td>
<td class="p-2">{{ c.indoor }}</td> <td>
<td class="p-2"> {% if c.indoor %}
<form method="post" action="/admin/courts/{{ c.id }}/delete" <span class="badge badge-success badge-sm"></span>
{% else %}
<span class="badge badge-ghost badge-sm"></span>
{% endif %}
</td>
<td class="text-right">
<form method="post" action="/admin/courts/{{ c.id }}/delete" class="inline"
data-court-name="{{ c.name }}" onsubmit="return promptCourtDelete(this);"> data-court-name="{{ c.name }}" onsubmit="return promptCourtDelete(this);">
<input type="hidden" name="confirm_name"> <input type="hidden" name="confirm_name">
<button class="rounded bg-red-600 px-3 py-1 text-sm text-white hover:bg-red-700"> <button class="btn btn-error btn-sm">{{ t(key="delete", lang=lang) }}</button>
{{ t(key="delete", lang=lang) }}
</button>
</form> </form>
</td> </td>
</tr> </tr>
@@ -43,24 +49,27 @@
</table> </table>
</div> </div>
<div class="max-w-md rounded-lg border bg-white p-4"> <div class="card max-w-md border border-gray-200 bg-white shadow-sm">
<h2 class="mb-3 font-semibold">{{ t(key="add-court", lang=lang) }}</h2> <div class="card-body">
<form method="post" action="/admin/courts" class="space-y-3"> <h2 class="card-title text-base">{{ t(key="add-court", lang=lang) }}</h2>
<div> <form method="post" action="/admin/courts" class="space-y-2">
<label class="block text-sm text-gray-600">{{ t(key="court-name", lang=lang) }}</label> <div class="form-control">
<input name="name" required class="w-full rounded border-gray-300 text-sm"> <label class="label"><span class="label-text">{{ t(key="court-name", lang=lang) }}</span></label>
<input name="name" required class="input input-bordered w-full">
</div> </div>
<div> <div class="form-control">
<label class="block text-sm text-gray-600">{{ t(key="court-surface", lang=lang) }}</label> <label class="label"><span class="label-text">{{ t(key="court-surface", lang=lang) }}</span></label>
<input name="surface" class="w-full rounded border-gray-300 text-sm"> <input name="surface" class="input input-bordered w-full">
</div> </div>
<label class="flex items-center gap-2 text-sm"> <div class="form-control">
<input type="checkbox" name="indoor" value="1"> {{ t(key="court-indoor", lang=lang) }} <label class="label cursor-pointer justify-start gap-3">
<input type="checkbox" name="indoor" value="1" class="checkbox checkbox-sm">
<span class="label-text">{{ t(key="court-indoor", lang=lang) }}</span>
</label> </label>
<button class="rounded bg-gray-900 px-4 py-2 text-sm text-white hover:bg-gray-700"> </div>
{{ t(key="add-court", lang=lang) }} <button class="btn btn-neutral mt-1">{{ t(key="add-court", lang=lang) }}</button>
</button>
</form> </form>
</div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@@ -3,23 +3,27 @@
{% block title %}{{ t(key="login-title", lang=lang) }}{% endblock title %} {% block title %}{{ t(key="login-title", lang=lang) }}{% endblock title %}
{% block content %} {% block content %}
<div class="mx-auto mt-8 max-w-sm rounded-lg border bg-white p-6"> <div class="mx-auto mt-8 max-w-sm">
<h1 class="mb-4 text-xl font-bold">{{ t(key="login-title", lang=lang) }}</h1> <div class="card border border-gray-200 bg-white shadow-sm">
<div class="card-body">
<h1 class="card-title">{{ t(key="login-title", lang=lang) }}</h1>
{% if error %} {% if error %}
<div class="mb-3 rounded bg-red-100 px-3 py-2 text-sm text-red-700">{{ t(key="login-error", lang=lang) }}</div> <div class="alert alert-error">
<span>{{ t(key="login-error", lang=lang) }}</span>
</div>
{% endif %} {% endif %}
<form method="post" action="/admin/login" class="space-y-3"> <form method="post" action="/admin/login" class="space-y-2">
<div> <div class="form-control">
<label class="block text-sm text-gray-600">{{ t(key="email", lang=lang) }}</label> <label class="label"><span class="label-text">{{ t(key="email", lang=lang) }}</span></label>
<input type="email" name="email" required class="w-full rounded border-gray-300 text-sm"> <input type="email" name="email" required class="input input-bordered w-full">
</div> </div>
<div> <div class="form-control">
<label class="block text-sm text-gray-600">{{ t(key="password", lang=lang) }}</label> <label class="label"><span class="label-text">{{ t(key="password", lang=lang) }}</span></label>
<input type="password" name="password" required class="w-full rounded border-gray-300 text-sm"> <input type="password" name="password" required class="input input-bordered w-full">
</div> </div>
<button class="w-full rounded bg-gray-900 py-2 text-sm text-white hover:bg-gray-700"> <button class="btn btn-neutral mt-2 w-full">{{ t(key="login-button", lang=lang) }}</button>
{{ t(key="login-button", lang=lang) }}
</button>
</form> </form>
</div>
</div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@@ -1,40 +1,45 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{ lang }}"> <html lang="{{ lang }}" data-theme="light">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{% block title %}{{ t(key="brand", lang=lang) }}{% endblock title %}</title> <title>{% block title %}{{ t(key="brand", lang=lang) }}{% endblock title %}</title>
<link href="https://cdn.jsdelivr.net/npm/daisyui@4/dist/full.min.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<style>
/* Keep buttons static — disable daisyUI's press-shrink animation. */
.btn { --animation-btn: 0; --btn-focus-scale: 1; }
</style>
{% block head %}{% endblock head %} {% block head %}{% endblock head %}
</head> </head>
<body class="min-h-screen bg-gray-50 text-gray-900 font-sans antialiased"> <body class="min-h-screen bg-gray-50 font-sans antialiased">
<header class="border-b bg-white"> <div class="navbar bg-white shadow-sm">
<div class="mx-auto flex max-w-6xl items-center justify-between px-5 py-3"> <div class="mx-auto flex w-full max-w-6xl flex-wrap items-center justify-between gap-2 px-4">
<a href="/" class="text-lg font-bold">{{ t(key="brand", lang=lang) }}</a> <a href="/" class="text-lg font-bold">{{ t(key="brand", lang=lang) }}</a>
<nav class="flex items-center gap-4 text-sm"> <nav class="flex flex-wrap items-center gap-1">
<a href="/" class="hover:underline">{{ t(key="nav-calendar", lang=lang) }}</a> <a href="/" class="btn btn-ghost btn-sm">{{ t(key="nav-calendar", lang=lang) }}</a>
{% if logged_in | default(value=false) %} {% if logged_in | default(value=false) %}
<a href="/admin" class="hover:underline">{{ t(key="admin-title", lang=lang) }}</a> <a href="/admin" class="btn btn-ghost btn-sm">{{ t(key="admin-title", lang=lang) }}</a>
<a href="/admin/courts" class="hover:underline">{{ t(key="manage-courts", lang=lang) }}</a> <a href="/admin/courts" class="btn btn-ghost btn-sm">{{ t(key="manage-courts", lang=lang) }}</a>
<form method="post" action="/admin/logout" class="inline"> <form method="post" action="/admin/logout">
<button class="hover:underline">{{ t(key="logout", lang=lang) }}</button> <button class="btn btn-ghost btn-sm">{{ t(key="logout", lang=lang) }}</button>
</form> </form>
{% else %} {% else %}
<a href="/admin/login" class="hover:underline">{{ t(key="nav-admin", lang=lang) }}</a> <a href="/admin/login" class="btn btn-ghost btn-sm">{{ t(key="nav-admin", lang=lang) }}</a>
{% endif %} {% endif %}
<span class="flex gap-1"> <div class="join ml-1">
<button onclick="setLang('en')" <button onclick="setLang('en')"
class="rounded px-2 py-0.5 {% if lang == 'en' %}bg-gray-900 text-white{% else %}bg-gray-200{% endif %}">EN</button> class="btn btn-xs join-item {% if lang == 'en' %}btn-neutral{% endif %}">EN</button>
<button onclick="setLang('sk')" <button onclick="setLang('sk')"
class="rounded px-2 py-0.5 {% if lang == 'sk' %}bg-gray-900 text-white{% else %}bg-gray-200{% endif %}">SK</button> class="btn btn-xs join-item {% if lang == 'sk' %}btn-neutral{% endif %}">SK</button>
</span> </div>
</nav> </nav>
</div> </div>
</header> </div>
<main class="mx-auto max-w-6xl px-5 py-6"> <main class="mx-auto max-w-6xl px-4 py-6">
{% block content %}{% endblock content %} {% block content %}{% endblock content %}
</main> </main>

View File

@@ -9,9 +9,9 @@
</h1> </h1>
{% if has_courts %} {% if has_courts %}
<form method="get" action="{{ base_path }}" class="flex items-center gap-2"> <form method="get" action="{{ base_path }}" class="flex items-center gap-2">
<label class="text-sm text-gray-600">{{ t(key="court-label", lang=lang) }}</label> <label class="text-sm font-medium text-gray-600">{{ t(key="court-label", lang=lang) }}</label>
<input type="hidden" name="week" value="{{ week }}"> <input type="hidden" name="week" value="{{ week }}">
<select name="court" onchange="this.form.submit()" class="rounded border-gray-300 text-sm"> <select name="court" onchange="this.form.submit()" class="select select-bordered select-sm">
{% for c in courts %} {% for c in courts %}
<option value="{{ c.id }}" {% if c.selected %}selected{% endif %}>{{ c.name }}</option> <option value="{{ c.id }}" {% if c.selected %}selected{% endif %}>{{ c.name }}</option>
{% endfor %} {% endfor %}
@@ -22,26 +22,26 @@
{% if has_courts %} {% if has_courts %}
<div class="mb-3 flex flex-wrap items-center justify-between gap-2"> <div class="mb-3 flex flex-wrap items-center justify-between gap-2">
<div class="flex gap-2"> <div class="join">
<a href="{{ base_path }}?court={{ court_id }}&week={{ prev_week }}" <a href="{{ base_path }}?court={{ court_id }}&week={{ prev_week }}"
class="rounded border bg-white px-3 py-1 text-sm hover:bg-gray-100">&larr; {{ t(key="prev-week", lang=lang) }}</a> class="btn btn-sm join-item">« {{ t(key="prev-week", lang=lang) }}</a>
<a href="{{ base_path }}?court={{ court_id }}&week={{ this_week }}" <a href="{{ base_path }}?court={{ court_id }}&week={{ this_week }}"
class="rounded border bg-white px-3 py-1 text-sm hover:bg-gray-100">{{ t(key="this-week", lang=lang) }}</a> class="btn btn-sm join-item">{{ t(key="this-week", lang=lang) }}</a>
<a href="{{ base_path }}?court={{ court_id }}&week={{ next_week }}" <a href="{{ base_path }}?court={{ court_id }}&week={{ next_week }}"
class="rounded border bg-white px-3 py-1 text-sm hover:bg-gray-100">{{ t(key="next-week", lang=lang) }} &rarr;</a> class="btn btn-sm join-item">{{ t(key="next-week", lang=lang) }} »</a>
</div> </div>
<div class="text-sm font-medium text-gray-600">{{ court_name }} · {{ week_label }}</div> <div class="text-sm font-medium text-gray-500">{{ court_name }} · {{ week_label }}</div>
</div> </div>
<div class="overflow-auto rounded-lg border bg-white"> <div class="overflow-x-auto rounded-lg border border-gray-200 bg-white shadow-sm">
<table class="w-full border-collapse text-sm"> <table class="w-full border-collapse text-sm">
<thead> <thead>
<tr class="bg-gray-100"> <tr class="bg-gray-100">
<th class="w-16 border p-2"></th> <th class="w-16 border border-gray-200 p-2"></th>
{% for d in days %} {% for d in days %}
<th class="border p-2 text-center"> <th class="border border-gray-200 p-2 text-center">
<div class="font-semibold">{{ t(key=d.key, lang=lang) }}</div> <div class="font-semibold">{{ t(key=d.key, lang=lang) }}</div>
<div class="text-xs font-normal text-gray-500">{{ d.num }}</div> <div class="text-xs font-normal text-gray-400">{{ d.num }}</div>
</th> </th>
{% endfor %} {% endfor %}
</tr> </tr>
@@ -49,24 +49,24 @@
<tbody> <tbody>
{% for row in rows %} {% for row in rows %}
<tr> <tr>
<td class="border p-2 text-center font-medium text-gray-500">{{ row.hour_label }}</td> <td class="border border-gray-200 bg-gray-50 p-2 text-center font-medium text-gray-500">{{ row.hour_label }}</td>
{% for cell in row.cells %} {% for cell in row.cells %}
<td class="h-14 border p-1 align-top"> <td class="h-14 border border-gray-200 p-1 align-top">
{% if cell.booked %} {% if cell.booked %}
{% if is_admin %} {% if is_admin %}
<a href="/admin/booking/{{ cell.booking_id }}" <a href="/admin/booking/{{ cell.booking_id }}"
class="block h-full rounded px-1 py-1 text-xs font-medium text-white" class="block h-full rounded px-1 py-1 text-xs font-medium text-white shadow-sm transition hover:opacity-90"
style="background-color: {{ cell.color }}">{{ cell.name }}</a> style="background-color: {{ cell.color }}">{{ cell.name }}</a>
{% else %} {% else %}
<div class="h-full rounded px-1 py-1 text-xs font-medium text-white" <div class="h-full rounded px-1 py-1 text-xs font-medium text-white shadow-sm"
style="background-color: {{ cell.color }}" title="{{ cell.name }}">{{ t(key="booked", lang=lang) }}</div> style="background-color: {{ cell.color }}" title="{{ cell.name }}">{{ t(key="booked", lang=lang) }}</div>
{% endif %} {% endif %}
{% else %} {% else %}
{% if is_admin %} {% if is_admin %}
<a href="/admin/booking?court={{ court_id }}&date={{ cell.date }}&hour={{ cell.hour }}" <a href="/admin/booking?court={{ court_id }}&date={{ cell.date }}&hour={{ cell.hour }}"
class="block h-full rounded px-1 py-1 text-xs text-gray-400 hover:bg-gray-100">+</a> class="flex h-full items-center justify-center rounded text-lg text-gray-300 transition hover:bg-gray-100 hover:text-gray-500">+</a>
{% else %} {% else %}
<div class="h-full px-1 py-1 text-xs text-gray-300">{{ t(key="free", lang=lang) }}</div> <div class="px-1 py-1 text-xs text-gray-300">{{ t(key="free", lang=lang) }}</div>
{% endif %} {% endif %}
{% endif %} {% endif %}
</td> </td>
@@ -77,6 +77,8 @@
</table> </table>
</div> </div>
{% else %} {% else %}
<div class="rounded-lg border bg-white p-8 text-center text-gray-500">{{ t(key="no-courts", lang=lang) }}</div> <div class="card border border-gray-200 bg-white shadow-sm">
<div class="card-body items-center text-center text-gray-500">{{ t(key="no-courts", lang=lang) }}</div>
</div>
{% endif %} {% endif %}
{% endblock content %} {% endblock content %}