Make the management app responsive on mobile
Replace the mobile nav's horizontal scroll strip (which wrapped into an unreadable jumble because daisyUI's .menu sets flex-wrap: wrap and .menu-horizontal never resets it) with a hamburger button that opens a proper left-side drawer, mirrored in controlpanel for the same bug. Move the theme toggle, "Management", and "Django admin" controls into that drawer below `lg`, leaving only the account icon in the navbar, so the club name has room to render in full instead of truncating to initials. Add a reusable `.table-cards` CSS pattern (app.css) that turns a list table into a stack of labelled cards below `md`, and apply it to every list/detail table in the management app -- members, families, teams, memberships, events, groups, locations, opponents, positions, referee levels/list, roles, sponsors, news, parent claims, team roster/staff, and the shared family-members table. Tables revert to normal desktop layout at `md` and up. Member list gets extra passes: search submits icon-only below `sm` so it fits next to the input, the Members/Guardians/Both tabs go full-width, and last/first name merge into one column. Action-button rows across every page stack full-width on mobile instead of wrapping mid-button (shared fix in base.html). Home dashboard's upcoming-events and news mini-tables become simple lists instead of overflowing tables. Also: brand truncates instead of overflowing on a long club name, a stray invalid xmlns attribute removed, a wrapping UUID badge hidden below `sm` on team detail. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -210,3 +210,59 @@
|
|||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Below `md`, a `.table-cards` table reads as a stack of cards instead of a
|
||||||
|
horizontally-scrolling grid: each row becomes a bordered block, each cell
|
||||||
|
becomes a label/value line pulling its label from `data-label` (set on the
|
||||||
|
<td> in the template -- there's no way to read the matching <th> text from
|
||||||
|
pure CSS). A <td> with no `data-label` renders as plain full-width content
|
||||||
|
instead of a label/value row -- for an image cell, a heading-style link, or
|
||||||
|
an actions row that already lays itself out. At `md` and up this reverts to
|
||||||
|
an ordinary table with nothing left over from the mobile styling. */
|
||||||
|
@media (width < 48rem) {
|
||||||
|
.table-cards, .table-cards :is(thead, tbody, tr, th, td) {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cards thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cards tbody tr {
|
||||||
|
border: 1px solid var(--color-base-300);
|
||||||
|
border-radius: var(--radius-box);
|
||||||
|
padding: 0 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cards tbody tr + tr {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cards td {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 0.6rem 0;
|
||||||
|
border-bottom: 1px solid var(--color-base-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cards td:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cards td[data-label]:before {
|
||||||
|
content: attr(data-label);
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cards td:not([data-label]) {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,15 @@
|
|||||||
{% block panel_title %}Control panel{% endblock panel_title %} · RosterChief
|
{% block panel_title %}Control panel{% endblock panel_title %} · RosterChief
|
||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
|
|
||||||
|
{% block nav_toggle %}
|
||||||
|
<button class="btn btn-ghost btn-square lg:hidden" type="button" onclick="document.getElementById('mobile_nav_modal').showModal()" aria-label="Menu">
|
||||||
|
{% lucide "menu" size=20 %}
|
||||||
|
</button>
|
||||||
|
{% endblock nav_toggle %}
|
||||||
|
|
||||||
|
{% comment %} Kept in the navbar itself only at `lg`+, where there's no hamburger drawer to hold them instead -- see the comment on `nav_icons_class` in _base.html. {% endcomment %}
|
||||||
|
{% block nav_icons_class %}hidden items-center lg:flex{% endblock nav_icons_class %}
|
||||||
|
|
||||||
{% block menu %}
|
{% block menu %}
|
||||||
{% comment %}
|
{% comment %}
|
||||||
Outside <main>, so it never scrolls with the content. Its own overflow-y-auto is for
|
Outside <main>, so it never scrolls with the content. Its own overflow-y-auto is for
|
||||||
@@ -18,6 +27,38 @@
|
|||||||
{% endblock menu %}
|
{% endblock menu %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
{# Below `lg` the sidebar is hidden and {% block nav_toggle %} above opens this instead. #}
|
||||||
|
<dialog id="mobile_nav_modal" class="modal modal-start lg:hidden">
|
||||||
|
<div class="modal-box h-full max-h-none w-72 max-w-[85vw] rounded-none p-0">
|
||||||
|
<div class="flex items-center justify-between border-b border-base-300 p-3">
|
||||||
|
<span class="font-roboto text-lg font-bold tracking-wider">Menu</span>
|
||||||
|
<form method="dialog">
|
||||||
|
<button class="btn btn-ghost btn-square btn-sm" aria-label="Close">{% lucide "x" size=18 %}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<ul class="menu w-full gap-1 p-3">
|
||||||
|
<li>
|
||||||
|
<button type="button" data-theme-toggle>
|
||||||
|
<span data-theme-icon="light" class="hidden items-center gap-3">{% lucide "sun" size=16 %} Light theme</span>
|
||||||
|
<span data-theme-icon="dark" class="hidden items-center gap-3">{% lucide "moon" size=16 %} Dark theme</span>
|
||||||
|
<span data-theme-icon="auto" class="hidden items-center gap-3">{% lucide "sun-moon" size=16 %} Auto theme</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{% if has_management_access %}
|
||||||
|
<li><a href="{% url "management:home" %}">{% lucide "layout-dashboard" size=16 %} Management</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.is_superuser %}
|
||||||
|
<li><a href="{% url "admin:index" %}">{% lucide "shield-cog" size=16 %} Django admin</a></li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="menu-title">Navigation</li>
|
||||||
|
{% include "controlpanel/_nav_items.html" %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<form method="dialog" class="modal-backdrop">
|
||||||
|
<button>close</button>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
{% if maintenance_on %}
|
{% if maintenance_on %}
|
||||||
<div class="alert alert-error mb-6">
|
<div class="alert alert-error mb-6">
|
||||||
{% lucide "wrench" size=20 %}
|
{% lucide "wrench" size=20 %}
|
||||||
@@ -28,7 +69,8 @@
|
|||||||
<a class="btn btn-sm gap-2 btn-error btn-soft" href="{% url 'controlpanel:features' %}">{% lucide "unlock" size=16 %} Reopen platform</a>
|
<a class="btn btn-sm gap-2 btn-error btn-soft" href="{% url 'controlpanel:features' %}">{% lucide "unlock" size=16 %} Reopen platform</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="mb-6 flex flex-wrap flex-row items-center justify-between gap-3">
|
<div class="mb-6 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between">
|
||||||
|
<div class="flex flex-row items-center gap-3">
|
||||||
{% block logo %}{% endblock logo %}
|
{% block logo %}{% endblock logo %}
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 grow">
|
<div class="flex flex-col gap-2 grow">
|
||||||
@@ -37,16 +79,12 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<span class="text-sm text-base-content/50">{% block subheading %}{% endblock subheading %}</span>
|
<span class="text-sm text-base-content/50">{% block subheading %}{% endblock subheading %}</span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-2">
|
<div class="flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:flex-wrap">
|
||||||
{% block actions %}{% endblock actions %}
|
{% block actions %}{% endblock actions %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Below `lg` the sidebar is hidden, so the same links appear here rather than nowhere. #}
|
|
||||||
<ul class="menu menu-horizontal mb-6 w-full gap-1 overflow-x-auto rounded-box bg-base-100 lg:hidden">
|
|
||||||
{% include "controlpanel/_nav_items.html" %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{% block panel %}{% endblock panel %}
|
{% block panel %}{% endblock panel %}
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ passes its own URL so admins land back on the member they were viewing; family_d
|
|||||||
leaves it unset, since staying on the family page is already the right place there.
|
leaves it unset, since staying on the family page is already the right place there.
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Last name" %}</th>
|
<th>{% trans "Name" %}</th>
|
||||||
<th>{% trans "First name" %}</th>
|
|
||||||
<th>{% trans "Email" %}</th>
|
<th>{% trans "Email" %}</th>
|
||||||
<th>{% trans "Type" %}</th>
|
<th>{% trans "Type" %}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
@@ -23,10 +22,9 @@ leaves it unset, since staying on the family page is already the right place the
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for person in group.all %}
|
{% for person in group.all %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover" href="{% url 'management:member_detail' person.pk %}">{{ person.last_name }}</a></td>
|
<td><a class="link link-hover font-semibold" href="{% url 'management:member_detail' person.pk %}">{{ person.last_name }}, {{ person.first_name }}</a></td>
|
||||||
<td>{{ person.first_name }}</td>
|
<td data-label="{% trans 'Email' %}">{{ person.contact_email|default:"-" }}</td>
|
||||||
<td>{{ person.contact_email|default:"-" }}</td>
|
<td data-label="{% trans 'Type' %}">
|
||||||
<td>
|
|
||||||
{% if is_club_admin %}
|
{% if is_club_admin %}
|
||||||
<form method="post" action="{% url 'management:family_membership_role_update' group.family.pk person.pk %}">
|
<form method="post" action="{% url 'management:family_membership_role_update' group.family.pk person.pk %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
@@ -43,7 +41,7 @@ leaves it unset, since staying on the family page is already the right place the
|
|||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if is_club_admin %}
|
{% if is_club_admin %}
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex flex-wrap justify-end gap-1">
|
||||||
{% if person.grant_login_form %}
|
{% if person.grant_login_form %}
|
||||||
<button class="btn btn-outline btn-sm" type="button" onclick="document.getElementById('grant_login_modal_{{ group.family.pk }}_{{ person.pk }}').showModal()" aria-label="{% trans 'Grant login' %}">
|
<button class="btn btn-outline btn-sm" type="button" onclick="document.getElementById('grant_login_modal_{{ group.family.pk }}_{{ person.pk }}').showModal()" aria-label="{% trans 'Grant login' %}">
|
||||||
{% lucide "key-round" size=14 %} {% trans "Grant login" %}
|
{% lucide "key-round" size=14 %} {% trans "Grant login" %}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
can_manage_referees, and an optional next_url to return to after a POST
|
can_manage_referees, and an optional next_url to return to after a POST
|
||||||
(defaults to the event detail page when blank).
|
(defaults to the event detail page when blank).
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">
|
<h2 class="card-title text-base">
|
||||||
{% lucide "flag" size=18 %} {% trans "Referees" %}
|
{% lucide "flag" size=18 %} {% trans "Referees" %}
|
||||||
<span class="badge badge-sm {% if referees_full %}badge-neutral{% else %}badge-outline{% endif %}">
|
<span class="badge badge-sm {% if referees_full %}badge-neutral{% else %}badge-outline{% endif %}">
|
||||||
|
|||||||
@@ -11,6 +11,15 @@
|
|||||||
{% block section_title %}{% trans "Management" %}{% endblock section_title %}
|
{% block section_title %}{% trans "Management" %}{% endblock section_title %}
|
||||||
{% endblock head_title %}
|
{% endblock head_title %}
|
||||||
|
|
||||||
|
{% block nav_toggle %}
|
||||||
|
<button class="btn btn-ghost btn-square lg:hidden" type="button" onclick="document.getElementById('mobile_nav_modal').showModal()" aria-label="{% trans 'Menu' %}">
|
||||||
|
{% lucide "menu" size=20 %}
|
||||||
|
</button>
|
||||||
|
{% endblock nav_toggle %}
|
||||||
|
|
||||||
|
{% comment %} Kept in the navbar itself only at `lg`+, where there's no hamburger drawer to hold them instead -- see the comment on `nav_icons_class` in _base.html. {% endcomment %}
|
||||||
|
{% block nav_icons_class %}hidden items-center lg:flex{% endblock nav_icons_class %}
|
||||||
|
|
||||||
{% block menu %}
|
{% block menu %}
|
||||||
<aside class="hidden w-64 shrink-0 overflow-y-auto border-r border-base-300 bg-base-100 lg:block">
|
<aside class="hidden w-64 shrink-0 overflow-y-auto border-r border-base-300 bg-base-100 lg:block">
|
||||||
<ul class="menu w-full gap-1 p-3 mt-4">
|
<ul class="menu w-full gap-1 p-3 mt-4">
|
||||||
@@ -20,7 +29,40 @@
|
|||||||
{% endblock menu %}
|
{% endblock menu %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="mb-6 flex flex-wrap flex-row items-center justify-between gap-3">
|
{# Below `lg` the sidebar is hidden and {% block nav_toggle %} above opens this instead. #}
|
||||||
|
<dialog id="mobile_nav_modal" class="modal modal-start lg:hidden">
|
||||||
|
<div class="modal-box h-full max-h-none w-72 max-w-[85vw] rounded-none p-0">
|
||||||
|
<div class="flex items-center justify-between border-b border-base-300 p-3">
|
||||||
|
<span class="font-roboto text-lg font-bold tracking-wider">{% trans "Menu" %}</span>
|
||||||
|
<form method="dialog">
|
||||||
|
<button class="btn btn-ghost btn-square btn-sm" aria-label="{% trans 'Close' %}">{% lucide "x" size=18 %}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<ul class="menu w-full gap-1 p-3">
|
||||||
|
<li>
|
||||||
|
<button type="button" data-theme-toggle>
|
||||||
|
<span data-theme-icon="light" class="hidden items-center gap-3">{% lucide "sun" size=16 %} {% trans "Light theme" %}</span>
|
||||||
|
<span data-theme-icon="dark" class="hidden items-center gap-3">{% lucide "moon" size=16 %} {% trans "Dark theme" %}</span>
|
||||||
|
<span data-theme-icon="auto" class="hidden items-center gap-3">{% lucide "sun-moon" size=16 %} {% trans "Auto theme" %}</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{% if has_management_access %}
|
||||||
|
<li><a href="{% url "management:home" %}">{% lucide "layout-dashboard" size=16 %} {% trans "Management" %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.is_superuser %}
|
||||||
|
<li><a href="{% url "admin:index" %}">{% lucide "shield-cog" size=16 %} {% trans "Django admin" %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="menu-title">{% trans "Navigation" %}</li>
|
||||||
|
{% include "management/_nav_items.html" %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<form method="dialog" class="modal-backdrop">
|
||||||
|
<button>{% trans "close" %}</button>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
{# flex-col below `sm`: title over a full-width, stacked column of action buttons reads far better on a phone than the same row wrapping mid-button. #}
|
||||||
|
<div class="mb-6 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between">
|
||||||
<div class="flex flex-col gap-2 grow">
|
<div class="flex flex-col gap-2 grow">
|
||||||
<h1 class="text-3xl font-bold">
|
<h1 class="text-3xl font-bold">
|
||||||
{% block heading %}{% trans "Management" %}{% endblock heading %}
|
{% block heading %}{% trans "Management" %}{% endblock heading %}
|
||||||
@@ -28,16 +70,11 @@
|
|||||||
<span class="text-sm text-base-content/50">{% block subheading %}{% endblock subheading %}</span>
|
<span class="text-sm text-base-content/50">{% block subheading %}{% endblock subheading %}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-2">
|
<div class="flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:flex-wrap">
|
||||||
{% block actions %}{% endblock actions %}
|
{% block actions %}{% endblock actions %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Below `lg` the sidebar is hidden, so the same links appear here rather than nowhere. #}
|
|
||||||
<ul class="menu menu-horizontal mb-6 w-full gap-1 overflow-x-auto rounded-box bg-base-100 lg:hidden">
|
|
||||||
{% include "management/_nav_items.html" %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{% comment %}
|
{% comment %}
|
||||||
A final billing notice follows the admin onto every management page -- but only at
|
A final billing notice follows the admin onto every management page -- but only at
|
||||||
error level (inside 7 days of archiving, or already past it). Shown from the moment
|
error level (inside 7 days of archiving, or already past it). Shown from the moment
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% lucide "user-check" size=18 %} {% trans "RSVPs" %}</h2>
|
<h2 class="card-title text-base">{% lucide "user-check" size=18 %} {% trans "RSVPs" %}</h2>
|
||||||
{% if has_attendance_rows %}
|
{% if has_attendance_rows %}
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('rsvp_modal').showModal()">
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('rsvp_modal').showModal()">
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
{% if event.kind == "game" %}
|
{% if event.kind == "game" %}
|
||||||
<div class="mb-6 card bg-base-100 shadow">
|
<div class="mb-6 card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">
|
<h2 class="card-title text-base">
|
||||||
{% lucide "trophy" size=18 %} {% trans "Game" %}
|
{% lucide "trophy" size=18 %} {% trans "Game" %}
|
||||||
{% if event.is_live %}<span class="badge badge-error gap-1 animate-pulse">{% lucide "circle" size=10 %} {% trans "Live" %}</span>{% endif %}
|
{% if event.is_live %}<span class="badge badge-error gap-1 animate-pulse">{% lucide "circle" size=10 %} {% trans "Live" %}</span>{% endif %}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Title" %}</th>
|
<th>{% trans "Title" %}</th>
|
||||||
@@ -52,14 +52,14 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for event in events %}
|
{% for event in events %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="flex flex-row items-center gap-2">
|
<td class="flex flex-row items-center gap-2 font-semibold">
|
||||||
<a class="link link-hover" href="{% url 'management:event_detail' event.pk %}">{{ event.title }}</a>
|
<a class="link link-hover" href="{% url 'management:event_detail' event.pk %}">{{ event.title }}</a>
|
||||||
{% if event.series_id %}<span class="tooltip" data-tip="{% trans 'Part of a series' %}">{% lucide "repeat" size=12 %}</span>{% endif %}
|
{% if event.series_id %}<span class="tooltip" data-tip="{% trans 'Part of a series' %}">{% lucide "repeat" size=12 %}</span>{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ event.get_kind_display }}</td>
|
<td data-label="{% trans 'Kind' %}">{{ event.get_kind_display }}</td>
|
||||||
<td>{{ event.start|date:"j M Y H:i" }}</td>
|
<td data-label="{% trans 'When' %}">{{ event.start|date:"j M Y H:i" }}</td>
|
||||||
<td>{% for team in event.teams.all %}{{ team.short_name }}{% if not forloop.last %}, {% endif %}{% empty %}—{% endfor %}</td>
|
<td data-label="{% trans 'Teams' %}">{% for team in event.teams.all %}{{ team.short_name }}{% if not forloop.last %}, {% endif %}{% empty %}—{% endfor %}</td>
|
||||||
<td>{{ event.location.name|default:"—" }}</td>
|
<td data-label="{% trans 'Location' %}">{{ event.location.name|default:"—" }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if event.can_manage %}
|
{% if event.can_manage %}
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex justify-end gap-1">
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title text-base">{% lucide "calendar" size=18 %} {% trans "Occurrences" %}</h2>
|
<h2 class="card-title text-base">{% lucide "calendar" size=18 %} {% trans "Occurrences" %}</h2>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "When" %}</th>
|
<th>{% trans "When" %}</th>
|
||||||
@@ -77,8 +77,8 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for occurrence in occurrences %}
|
{% for occurrence in occurrences %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover" href="{% url 'management:event_detail' occurrence.pk %}">{{ occurrence.start|date:"j M Y H:i" }}</a></td>
|
<td class="font-semibold"><a class="link link-hover" href="{% url 'management:event_detail' occurrence.pk %}">{{ occurrence.start|date:"j M Y H:i" }}</a></td>
|
||||||
<td>
|
<td data-label="{% trans 'Status' %}">
|
||||||
{% if occurrence.cancelled %}
|
{% if occurrence.cancelled %}
|
||||||
<span class="badge badge-outline gap-1">{% lucide "ban" size=12 %} {% trans "Cancelled" %}</span>
|
<span class="badge badge-outline gap-1">{% lucide "ban" size=12 %} {% trans "Cancelled" %}</span>
|
||||||
{% elif occurrence.detached %}
|
{% elif occurrence.detached %}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Family" %}</th>
|
<th>{% trans "Family" %}</th>
|
||||||
@@ -38,14 +38,14 @@
|
|||||||
{% for family in families %}
|
{% for family in families %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover font-semibold" href="{% url 'management:family_detail' family.pk %}">{{ family }}</a></td>
|
<td><a class="link link-hover font-semibold" href="{% url 'management:family_detail' family.pk %}">{{ family }}</a></td>
|
||||||
<td>
|
<td data-label="{% trans 'Parents / guardians' %}">
|
||||||
{% for guardian in family.guardians_display %}
|
{% for guardian in family.guardians_display %}
|
||||||
<a class="link link-hover" href="{% url 'management:member_detail' guardian.pk %}">{{ guardian }}</a>{% if not forloop.last %}, {% endif %}
|
<a class="link link-hover" href="{% url 'management:member_detail' guardian.pk %}">{{ guardian }}</a>{% if not forloop.last %}, {% endif %}
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<span class="opacity-40">-</span>
|
<span class="opacity-40">-</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-label="{% trans 'Children' %}">
|
||||||
{% for child in family.children_display %}
|
{% for child in family.children_display %}
|
||||||
<a class="link link-hover" href="{% url 'management:member_detail' child.pk %}">{{ child }}</a>{% if not forloop.last %}, {% endif %}
|
<a class="link link-hover" href="{% url 'management:member_detail' child.pk %}">{{ child }}</a>{% if not forloop.last %}, {% endif %}
|
||||||
{% empty %}
|
{% empty %}
|
||||||
|
|||||||
@@ -18,10 +18,12 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% comment %}
|
{% comment %}
|
||||||
Deliberately not wrapped in the usual overflow-x-auto: that makes a
|
overflow-x-auto is safe here: the member picker's dropdown
|
||||||
scroll container, which clips the member picker's absolutely
|
(searchable-select.js) is position: fixed, computed from the input's
|
||||||
positioned dropdown for every row but the first couple.
|
own screen position rather than document flow, so a scrolling
|
||||||
|
ancestor around the table no longer clips it.
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
|
<div class="overflow-x-auto">
|
||||||
<table class="table w-full">
|
<table class="table w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -35,6 +37,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template id="bulk-add-row-template">
|
<template id="bulk-add-row-template">
|
||||||
{% include "management/_group_bulk_add_row.html" with form=formset.empty_form %}
|
{% include "management/_group_bulk_add_row.html" with form=formset.empty_form %}
|
||||||
|
|||||||
@@ -10,12 +10,12 @@
|
|||||||
{% block panel %}
|
{% block panel %}
|
||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% trans "Members" %}</h2>
|
<h2 class="card-title text-base">{% trans "Members" %}</h2>
|
||||||
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:group_bulk_add' group.pk %}">{% lucide "users" size=14 %} {% trans "Add multiple" %}</a>
|
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:group_bulk_add' group.pk %}">{% lucide "users" size=14 %} {% trans "Add multiple" %}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Member" %}</th>
|
<th>{% trans "Member" %}</th>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for membership in memberships %}
|
{% for membership in memberships %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover" href="{% url 'management:member_detail' membership.member.pk %}">{{ membership.member }}</a></td>
|
<td class="font-semibold"><a class="link link-hover" href="{% url 'management:member_detail' membership.member.pk %}">{{ membership.member }}</a></td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<button class="btn btn-sm btn-outline btn-error" type="button" onclick="document.getElementById('{{ membership.pk|dom_id:"remove_member_modal" }}').showModal()">{% lucide "user-minus" size=14 %} {% trans "Remove" %}</button>
|
<button class="btn btn-sm btn-outline btn-error" type="button" onclick="document.getElementById('{{ membership.pk|dom_id:"remove_member_modal" }}').showModal()">{% lucide "user-minus" size=14 %} {% trans "Remove" %}</button>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Name" %}</th>
|
<th>{% trans "Name" %}</th>
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for group in groups %}
|
{% for group in groups %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover" href="{% url 'management:group_detail' group.pk %}">{{ group.name }}</a></td>
|
<td><a class="link link-hover font-semibold" href="{% url 'management:group_detail' group.pk %}">{{ group.name }}</a></td>
|
||||||
<td>{{ group.member_count }}</td>
|
<td data-label="{% trans 'Members' %}">{{ group.member_count }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex justify-end gap-1">
|
||||||
<a class="btn btn-outline btn-sm" href="{% url 'management:group_detail' group.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
<a class="btn btn-outline btn-sm" href="{% url 'management:group_detail' group.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
||||||
|
|||||||
@@ -96,53 +96,45 @@
|
|||||||
<div class="mb-6 grid gap-4 lg:grid-cols-2">
|
<div class="mb-6 grid gap-4 lg:grid-cols-2">
|
||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% lucide "calendar" size=18 %} {% trans "Upcoming events" %}</h2>
|
<h2 class="card-title text-base">{% lucide "calendar" size=18 %} {% trans "Upcoming events" %}</h2>
|
||||||
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:event_list' %}">{% lucide "arrow-right" size=14 %} {% trans "View all" %}</a>
|
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:event_list' %}">{% lucide "arrow-right" size=14 %} {% trans "View all" %}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-x-auto">
|
<ul class="divide-y divide-base-200">
|
||||||
<table class="table">
|
|
||||||
<tbody>
|
|
||||||
{% for event in upcoming_events %}
|
{% for event in upcoming_events %}
|
||||||
<tr>
|
<li class="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between sm:gap-4">
|
||||||
<td class="whitespace-nowrap">{{ event.start|date:"D j M, H:i" }}</td>
|
<div class="min-w-0">
|
||||||
<td>{{ event.title }}</td>
|
<div class="truncate font-semibold">{{ event.title }}</div>
|
||||||
<td>{{ event.get_kind_display }}</td>
|
<div class="truncate text-xs opacity-60">
|
||||||
<td>{% for team in event.teams.all %}{{ team.short_name }}{% if not forloop.last %}, {% endif %}{% empty %}—{% endfor %}</td>
|
{{ event.get_kind_display }}
|
||||||
</tr>
|
{% for team in event.teams.all %}· {{ team.short_name }}{% if not forloop.last %}, {% endif %}{% endfor %}
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td class="text-center opacity-60">{% trans "Nothing scheduled." %}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="shrink-0 whitespace-nowrap text-sm opacity-70">{{ event.start|date:"D j M, H:i" }}</div>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="py-2 text-center text-sm opacity-60">{% trans "Nothing scheduled." %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% lucide "newspaper" size=18 %} {% trans "News" %}</h2>
|
<h2 class="card-title text-base">{% lucide "newspaper" size=18 %} {% trans "News" %}</h2>
|
||||||
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:news_list' %}">{% lucide "arrow-right" size=14 %} {% trans "View all" %}</a>
|
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:news_list' %}">{% lucide "arrow-right" size=14 %} {% trans "View all" %}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-x-auto">
|
<ul class="divide-y divide-base-200">
|
||||||
<table class="table">
|
|
||||||
<tbody>
|
|
||||||
{% for news_item in published_news %}
|
{% for news_item in published_news %}
|
||||||
<tr>
|
<li class="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between sm:gap-4">
|
||||||
<td class="whitespace-nowrap">{{ news_item.published_at|date:"D j M" }}</td>
|
<a class="link link-hover truncate font-semibold" href="{% url 'management:news_detail' news_item.pk %}">{{ news_item.title }}</a>
|
||||||
<td><a class="link link-hover" href="{% url 'management:news_detail' news_item.pk %}">{{ news_item.title }}</a></td>
|
<span class="shrink-0 whitespace-nowrap text-sm opacity-70">{{ news_item.published_at|date:"D j M" }}</span>
|
||||||
</tr>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr>
|
<li class="py-2 text-center text-sm opacity-60">{% trans "Nothing published yet." %}</li>
|
||||||
<td class="text-center opacity-60">{% trans "Nothing published yet." %}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</ul>
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Name" %}</th>
|
<th>{% trans "Name" %}</th>
|
||||||
@@ -24,13 +24,13 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for location in locations %}
|
{% for location in locations %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td class="font-semibold">
|
||||||
{{ location.name }}
|
{{ location.name }}
|
||||||
{% if location.is_home %}<span class="badge badge-sm badge-primary ml-1">{% trans "Home" %}</span>{% endif %}
|
{% if location.is_home %}<span class="badge badge-sm badge-primary ml-1">{% trans "Home" %}</span>{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ location.address }}</td>
|
<td data-label="{% trans 'Address' %}">{{ location.address }}</td>
|
||||||
<td>{{ location.city }}</td>
|
<td data-label="{% trans 'City' %}">{{ location.city }}</td>
|
||||||
<td>{{ location.country }}</td>
|
<td data-label="{% trans 'Country' %}">{{ location.country }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex justify-end gap-1">
|
||||||
<a class="btn btn-outline btn-sm" href="{% url 'management:location_update' location.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
<a class="btn btn-outline btn-sm" href="{% url 'management:location_update' location.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
||||||
|
|||||||
@@ -119,7 +119,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<h3 class="text-sm font-semibold opacity-70">{% trans "Season history" %}</h3>
|
<h3 class="text-sm font-semibold opacity-70">{% trans "Season history" %}</h3>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Season" %}</th>
|
<th>{% trans "Season" %}</th>
|
||||||
@@ -131,10 +131,10 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for membership in membership_history %}
|
{% for membership in membership_history %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ membership.season.start_date|date:"Y" }} - {{ membership.season.end_date|date:"Y" }}</td>
|
<td class="font-semibold">{{ membership.season.start_date|date:"Y" }} - {{ membership.season.end_date|date:"Y" }}</td>
|
||||||
<td>{{ membership.get_status_display }}</td>
|
<td data-label="{% trans 'Status' %}">{{ membership.get_status_display }}</td>
|
||||||
<td>{{ membership.get_fee_status_display }}</td>
|
<td data-label="{% trans 'Fee status' %}">{{ membership.get_fee_status_display }}</td>
|
||||||
<td>{{ membership.license|default:"-" }}</td>
|
<td data-label="{% trans 'License' %}">{{ membership.license|default:"-" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
{% if referee_profile or is_club_admin %}
|
{% if referee_profile or is_club_admin %}
|
||||||
<div class="card bg-base-100 shadow mt-4">
|
<div class="card bg-base-100 shadow mt-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% lucide "flag" size=18 %} {% trans "Referee eligibility" %}</h2>
|
<h2 class="card-title text-base">{% lucide "flag" size=18 %} {% trans "Referee eligibility" %}</h2>
|
||||||
{% if is_club_admin %}
|
{% if is_club_admin %}
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('referee_eligibility_modal').showModal()">{% lucide "pencil" size=14 %} {% trans "Edit" %}</button>
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('referee_eligibility_modal').showModal()">{% lucide "pencil" size=14 %} {% trans "Edit" %}</button>
|
||||||
@@ -214,13 +214,13 @@
|
|||||||
{% for family_group in family_groups %}
|
{% for family_group in family_groups %}
|
||||||
<div class="card bg-base-100 shadow mt-4">
|
<div class="card bg-base-100 shadow mt-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">
|
<h2 class="card-title text-base">
|
||||||
{% lucide "users" size=18 %}
|
{% lucide "users" size=18 %}
|
||||||
<a class="link link-hover" href="{% url 'management:family_detail' family_group.family.pk %}">{{ family_group.family }}</a>
|
<a class="link link-hover" href="{% url 'management:family_detail' family_group.family.pk %}">{{ family_group.family }}</a>
|
||||||
</h2>
|
</h2>
|
||||||
{% if is_club_admin %}
|
{% if is_club_admin %}
|
||||||
<div class="flex gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('{{ family_group.family.pk|dom_id:"add_parent_modal" }}').showModal()">{% lucide "user-plus" size=14 %} {{ add_parent_label }}</button>
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('{{ family_group.family.pk|dom_id:"add_parent_modal" }}').showModal()">{% lucide "user-plus" size=14 %} {{ add_parent_label }}</button>
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('{{ family_group.family.pk|dom_id:"add_child_modal" }}').showModal()">{% lucide "baby" size=14 %} {{ add_child_label }}</button>
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('{{ family_group.family.pk|dom_id:"add_child_modal" }}').showModal()">{% lucide "baby" size=14 %} {{ add_child_label }}</button>
|
||||||
<button class="btn btn-outline btn-error btn-sm gap-2" type="button" onclick="document.getElementById('{{ family_group.family.pk|dom_id:"detach_family_modal" }}').showModal()">{% lucide "user-x" size=14 %} {{ remove_from_family_label }}</button>
|
<button class="btn btn-outline btn-error btn-sm gap-2" type="button" onclick="document.getElementById('{{ family_group.family.pk|dom_id:"detach_family_modal" }}').showModal()">{% lucide "user-x" size=14 %} {{ remove_from_family_label }}</button>
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
{% if is_club_admin %}
|
{% if is_club_admin %}
|
||||||
<div class="card bg-base-100 shadow mt-4">
|
<div class="card bg-base-100 shadow mt-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% lucide "users" size=18 %} {% trans "Family" %}</h2>
|
<h2 class="card-title text-base">{% lucide "users" size=18 %} {% trans "Family" %}</h2>
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('attach_family_modal').showModal()">{% lucide "user-plus" size=14 %} {% trans "Add to family" %}</button>
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('attach_family_modal').showModal()">{% lucide "user-plus" size=14 %} {% trans "Add to family" %}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,24 +4,25 @@
|
|||||||
{% block heading %}{% trans "Members" %}{% endblock heading %}
|
{% block heading %}{% trans "Members" %}{% endblock heading %}
|
||||||
|
|
||||||
{% block actions %}
|
{% block actions %}
|
||||||
<a class="btn btn-outline btn-info gap-2" href="{% url 'management:member_import_template' %}" xmlns:management="http://www.w3.org/1999/xhtml">{% lucide "download" size=16 %} {% trans "Download upload template" %}</a>
|
<a class="btn btn-sm btn-outline btn-info gap-2" href="{% url 'management:member_import_template' %}">{% lucide "download" size=14 %} {% trans "Download upload template" %}</a>
|
||||||
{% if is_club_admin %}
|
{% if is_club_admin %}
|
||||||
<a class="btn btn-outline btn-info gap-2" href="{% url 'management:member_import' %}">{% lucide "upload" size=16 %} {% trans "Mass upload" %}</a>
|
<a class="btn btn-sm btn-outline btn-info gap-2" href="{% url 'management:member_import' %}">{% lucide "upload" size=14 %} {% trans "Mass upload" %}</a>
|
||||||
<a class="btn btn-outline gap-2" href="{% url 'management:family_create' %}">{% lucide "users" size=16 %} {% trans "Add family" %}</a>
|
<a class="btn btn-sm btn-outline gap-2" href="{% url 'management:family_create' %}">{% lucide "users" size=14 %} {% trans "Add family" %}</a>
|
||||||
<a class="btn btn-outline gap-2" href="{% url 'management:member_create' %}">{% lucide "user-plus" size=16 %} {% trans "Add member" %}</a>
|
<a class="btn btn-sm btn-outline gap-2" href="{% url 'management:member_create' %}">{% lucide "user-plus" size=14 %} {% trans "Add member" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock actions %}
|
{% endblock actions %}
|
||||||
|
|
||||||
{% block panel %}
|
{% block panel %}
|
||||||
<form method="get" class="mb-2 flex flex-wrap items-center gap-2">
|
<form method="get" class="mb-2 flex items-center gap-2">
|
||||||
<label class="input">
|
<label class="input grow sm:grow-0">
|
||||||
<span class="opacity-50">{% lucide "search" size=16 %}</span>
|
<span class="opacity-50">{% lucide "search" size=16 %}</span>
|
||||||
<input type="search" name="q" value="{{ search }}" placeholder="{% trans 'Search members ...' %}" class="input input-bordered w-full max-w-xs">
|
<input type="search" name="q" value="{{ search }}" placeholder="{% trans 'Search members ...' %}" class="input input-bordered w-full sm:max-w-xs">
|
||||||
</label>
|
</label>
|
||||||
{% if selected_kind != "member" %}<input type="hidden" name="kind" value="{{ selected_kind }}">{% endif %}
|
{% if selected_kind != "member" %}<input type="hidden" name="kind" value="{{ selected_kind }}">{% endif %}
|
||||||
<button class="btn btn-outline gap-2" type="submit">{% lucide "search" size=16 %} {% trans "Search" %}</button>
|
{# Icon-only below `sm`: label text next to a growing input is what forced this row to wrap on a phone. #}
|
||||||
|
<button class="btn btn-outline gap-2" type="submit" aria-label="{% trans 'Search' %}">{% lucide "search" size=16 %}<span class="hidden sm:inline">{% trans "Search" %}</span></button>
|
||||||
{% if search %}
|
{% if search %}
|
||||||
<a class="btn gap-2" href="{% url "management:member_list" %}">{% lucide "x" size=16 %} {% trans "Clear filter" %}</a>
|
<a class="btn gap-2" href="{% url "management:member_list" %}" aria-label="{% trans 'Clear filter' %}">{% lucide "x" size=16 %}<span class="hidden sm:inline">{% trans "Clear filter" %}</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@@ -33,23 +34,23 @@
|
|||||||
with nothing on the page explaining why. ?kind= makes the exclusion an
|
with nothing on the page explaining why. ?kind= makes the exclusion an
|
||||||
explicit, reversible choice instead.
|
explicit, reversible choice instead.
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
<div class="mb-4 flex flex-wrap items-center gap-2">
|
<div class="mb-4 flex flex-col gap-2">
|
||||||
<div class="join">
|
<div class="join w-full">
|
||||||
<a href="{% querystring kind=None page=None %}" class="btn btn-sm join-item {% if selected_kind == "member" %}btn-primary{% endif %}">{% trans "Members" %}</a>
|
<a href="{% querystring kind=None page=None %}" class="btn btn-sm join-item flex-1 {% if selected_kind == "member" %}btn-primary{% endif %}">{% trans "Members" %}</a>
|
||||||
<a href="{% querystring kind="guardian" page=None %}" class="btn btn-sm join-item {% if selected_kind == "guardian" %}btn-primary{% endif %}">{% trans "Guardians" %}</a>
|
<a href="{% querystring kind="guardian" page=None %}" class="btn btn-sm join-item flex-1 {% if selected_kind == "guardian" %}btn-primary{% endif %}">{% trans "Guardians" %}</a>
|
||||||
<a href="{% querystring kind="both" page=None %}" class="btn btn-sm join-item {% if selected_kind == "both" %}btn-primary{% endif %}">{% trans "Both" %}</a>
|
<a href="{% querystring kind="both" page=None %}" class="btn btn-sm join-item flex-1 {% if selected_kind == "both" %}btn-primary{% endif %}">{% trans "Both" %}</a>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-xs opacity-60">{% trans "Guardians are parents linked only through a child -- no fee, not counted as a member." %}</span>
|
<span class="text-xs opacity-60">{% trans "Guardians are parents linked only through a child -- no fee, not counted as a member." %}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
{# table-cards: below `md` each row reads as a card instead of forcing a horizontal scroll -- see the .table-cards rule in app.css. #}
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Last name" %}</th>
|
<th>{% trans "Name" %}</th>
|
||||||
<th>{% trans "First name" %}</th>
|
|
||||||
<th>{% trans "Email" %}</th>
|
<th>{% trans "Email" %}</th>
|
||||||
<th>{% trans "Family" %}</th>
|
<th>{% trans "Family" %}</th>
|
||||||
<th>{% trans "Status" %}</th>
|
<th>{% trans "Status" %}</th>
|
||||||
@@ -59,10 +60,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for member in members %}
|
{% for member in members %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover" href="{% url 'management:member_detail' member.pk %}">{{ member.last_name }}</a></td>
|
<td><a class="link link-hover font-semibold" href="{% url 'management:member_detail' member.pk %}">{{ member.last_name }}, {{ member.first_name }}</a></td>
|
||||||
<td>{{ member.first_name }}</td>
|
<td data-label="{% trans 'Email' %}">{{ member.contact_email|default:"-" }}</td>
|
||||||
<td>{{ member.contact_email|default:"-" }}</td>
|
<td data-label="{% trans 'Family' %}">
|
||||||
<td>
|
|
||||||
{% if member.family_memberships_display %}
|
{% if member.family_memberships_display %}
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
{% for fm in member.family_memberships_display %}
|
{% for fm in member.family_memberships_display %}
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
<span class="opacity-40">-</span>
|
<span class="opacity-40">-</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-label="{% trans 'Status' %}">
|
||||||
{% if member.current_membership %}
|
{% if member.current_membership %}
|
||||||
<span class="badge badge-sm
|
<span class="badge badge-sm
|
||||||
{% if member.current_membership.status == "active" %}badge-success
|
{% if member.current_membership.status == "active" %}badge-success
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if is_club_admin %}
|
{% if is_club_admin %}
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex flex-wrap justify-end gap-1">
|
||||||
<a class="btn btn-outline btn-sm" href="{% url 'management:member_detail' member.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
<a class="btn btn-outline btn-sm" href="{% url 'management:member_detail' member.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
||||||
<button class="btn btn-sm btn-outline btn-error" type="button" onclick="document.getElementById('{{ member.pk|dom_id:"member_delete_modal" }}').showModal()" aria-label="{% trans 'Delete' %}">{% lucide "trash-2" size=14 %} {% trans "Delete" %}</button>
|
<button class="btn btn-sm btn-outline btn-error" type="button" onclick="document.getElementById('{{ member.pk|dom_id:"member_delete_modal" }}').showModal()" aria-label="{% trans 'Delete' %}">{% lucide "trash-2" size=14 %} {% trans "Delete" %}</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="text-center opacity-60">{% trans "No members yet." %}</td>
|
<td colspan="5" class="text-center opacity-60">{% trans "No members yet." %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -59,19 +59,19 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form method="get" class="mb-4">
|
<form method="get" class="mb-4">
|
||||||
<div class="flex flex-row items-center gap-2">
|
<div class="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:flex lg:flex-row lg:flex-wrap lg:items-center">
|
||||||
<label class="input">
|
<label class="input w-full lg:w-auto">
|
||||||
<span class="opacity-50">{% lucide "search" size=16 %}</span>
|
<span class="opacity-50">{% lucide "search" size=16 %}</span>
|
||||||
<input type="search" name="q" value="{{ search }}" placeholder="{% trans 'Search members ...' %}" class="input input-bordered">
|
<input type="search" name="q" value="{{ search }}" placeholder="{% trans 'Search members ...' %}" class="input input-bordered w-full">
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<select name="season" class="select select-bordered">
|
<select name="season" class="select select-bordered w-full lg:w-auto">
|
||||||
{% for season in seasons %}
|
{% for season in seasons %}
|
||||||
<option value="{{ season.pk }}" {% if season.pk == selected_season.pk %}selected{% endif %}>{% trans "Season" %} {{ season.start_date|date:"Y" }} - {{ season.end_date|date:"Y" }}</option>
|
<option value="{{ season.pk }}" {% if season.pk == selected_season.pk %}selected{% endif %}>{% trans "Season" %} {{ season.start_date|date:"Y" }} - {{ season.end_date|date:"Y" }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select name="fee_status" class="select select-bordered">
|
<select name="fee_status" class="select select-bordered w-full lg:w-auto">
|
||||||
<option value="not_paid" {% if selected_fee_status == "not_paid" %}selected{% endif %}>{% trans "Not paid (unpaid or partially)" %}</option>
|
<option value="not_paid" {% if selected_fee_status == "not_paid" %}selected{% endif %}>{% trans "Not paid (unpaid or partially)" %}</option>
|
||||||
{% for value, label in fee_status_choices %}
|
{% for value, label in fee_status_choices %}
|
||||||
<option value="{{ value }}" {% if value == selected_fee_status %}selected{% endif %}>{{ label|capfirst }}</option>
|
<option value="{{ value }}" {% if value == selected_fee_status %}selected{% endif %}>{{ label|capfirst }}</option>
|
||||||
@@ -79,22 +79,24 @@
|
|||||||
<option value="all" {% if selected_fee_status == "all" %}selected{% endif %}>{% trans "All" %}</option>
|
<option value="all" {% if selected_fee_status == "all" %}selected{% endif %}>{% trans "All" %}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select name="status" class="select select-bordered">
|
<select name="status" class="select select-bordered w-full lg:w-auto">
|
||||||
<option value="all" {% if selected_status == "all" %}selected{% endif %}>{% trans "All statuses" %}</option>
|
<option value="all" {% if selected_status == "all" %}selected{% endif %}>{% trans "All statuses" %}</option>
|
||||||
{% for value, label in status_choices %}
|
{% for value, label in status_choices %}
|
||||||
<option value="{{ value }}" {% if value == selected_status %}selected{% endif %}>{{ label|capfirst }}</option>
|
<option value="{{ value }}" {% if value == selected_status %}selected{% endif %}>{{ label|capfirst }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select name="team" class="select select-bordered">
|
<select name="team" class="select select-bordered w-full lg:w-auto">
|
||||||
<option value="" {% if not selected_team %}selected{% endif %}>{% trans "All teams" %}</option>
|
<option value="" {% if not selected_team %}selected{% endif %}>{% trans "All teams" %}</option>
|
||||||
{% for team in teams %}
|
{% for team in teams %}
|
||||||
<option value="{{ team.pk }}" {% if team.pk|stringformat:"s" == selected_team %}selected{% endif %}>{{ team }}</option>
|
<option value="{{ team.pk }}" {% if team.pk|stringformat:"s" == selected_team %}selected{% endif %}>{{ team }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<button class="btn btn-outline gap-2" type="submit">{% lucide "filter" size=16 %} {% trans "Filter" %}</button>
|
<div class="col-span-full flex gap-2 lg:col-span-1 lg:contents">
|
||||||
<a class="btn gap-2" href="{% url 'management:membership_list' %}">{% lucide "x" size=16 %} {% trans "Reset" %}</a>
|
<button class="btn btn-outline grow gap-2 lg:grow-0" type="submit">{% lucide "filter" size=16 %} {% trans "Filter" %}</button>
|
||||||
|
<a class="btn grow gap-2 lg:grow-0" href="{% url 'management:membership_list' %}">{% lucide "x" size=16 %} {% trans "Reset" %}</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@@ -104,20 +106,20 @@
|
|||||||
|
|
||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex flex-wrap items-center justify-between gap-2 mb-2">
|
||||||
<span class="text-sm opacity-70 font-semibold">
|
<span class="text-sm opacity-70 font-semibold">
|
||||||
{% blocktrans count counter=memberships|length %}{{ counter }} membership{% plural %}{{ counter }} memberships{% endblocktrans %}
|
{% blocktrans count counter=memberships|length %}{{ counter }} membership{% plural %}{{ counter }} memberships{% endblocktrans %}
|
||||||
</span>
|
</span>
|
||||||
<button class="btn btn-success btn-sm gap-2" type="submit">{% lucide "circle-check" size=14 %} {% trans "Mark selected as paid" %}</button>
|
<button class="btn btn-success btn-sm gap-2" type="submit">{% lucide "circle-check" size=14 %} {% trans "Mark selected as paid" %}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{# table-cards: this table is dense enough (10+ columns) that horizontal scroll alone stops being usable below `md` -- see the .table-cards rule in app.css. #}
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th><input type="checkbox" class="checkbox" id="select-all-memberships"></th>
|
<th><input type="checkbox" class="checkbox" id="select-all-memberships"></th>
|
||||||
<th>{% trans "Last name" %}</th>
|
<th>{% trans "Name" %}</th>
|
||||||
<th>{% trans "First name" %}</th>
|
|
||||||
<th>{% trans "Email" %}</th>
|
<th>{% trans "Email" %}</th>
|
||||||
<th>{% trans "Family" %}</th>
|
<th>{% trans "Family" %}</th>
|
||||||
<th>{% trans "Status" %}</th>
|
<th>{% trans "Status" %}</th>
|
||||||
@@ -132,10 +134,9 @@
|
|||||||
{% for membership in memberships %}
|
{% for membership in memberships %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><input type="checkbox" class="checkbox membership-row-checkbox" name="membership_ids" value="{{ membership.pk }}"></td>
|
<td><input type="checkbox" class="checkbox membership-row-checkbox" name="membership_ids" value="{{ membership.pk }}"></td>
|
||||||
<td><a class="link link-hover" href="{% url 'management:member_detail' membership.member.pk %}">{{ membership.member.last_name }}</a></td>
|
<td><a class="link link-hover font-semibold" href="{% url 'management:member_detail' membership.member.pk %}">{{ membership.member.last_name }}, {{ membership.member.first_name }}</a></td>
|
||||||
<td>{{ membership.member.first_name }}</td>
|
<td data-label="{% trans 'Email' %}">{{ membership.member.contact_email|default:"-" }}</td>
|
||||||
<td>{{ membership.member.contact_email|default:"-" }}</td>
|
<td data-label="{% trans 'Family' %}">
|
||||||
<td>
|
|
||||||
{% if membership.member.family_memberships_display %}
|
{% if membership.member.family_memberships_display %}
|
||||||
{% for fm in membership.member.family_memberships_display %}
|
{% for fm in membership.member.family_memberships_display %}
|
||||||
{{ fm.family }} {% if not forloop.last %},{% endif %}
|
{{ fm.family }} {% if not forloop.last %},{% endif %}
|
||||||
@@ -144,7 +145,7 @@
|
|||||||
<span class="opacity-40">-</span>
|
<span class="opacity-40">-</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-label="{% trans 'Status' %}">
|
||||||
<span class="badge badge-sm
|
<span class="badge badge-sm
|
||||||
{% if membership.status == "active" %}badge-success
|
{% if membership.status == "active" %}badge-success
|
||||||
{% elif membership.status == "pending" %}badge-warning
|
{% elif membership.status == "pending" %}badge-warning
|
||||||
@@ -153,7 +154,7 @@
|
|||||||
{{ membership.get_status_display }}
|
{{ membership.get_status_display }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-label="{% trans 'Fee status' %}">
|
||||||
<span class="badge badge-sm
|
<span class="badge badge-sm
|
||||||
{% if membership.fee_status == "paid" %}badge-success
|
{% if membership.fee_status == "paid" %}badge-success
|
||||||
{% elif membership.fee_status == "partially_paid" %}badge-warning
|
{% elif membership.fee_status == "partially_paid" %}badge-warning
|
||||||
@@ -162,17 +163,17 @@
|
|||||||
{{ membership.get_fee_status_display }}
|
{{ membership.get_fee_status_display }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="tabular-nums">€ {{ membership.fee_amount }}</td>
|
<td data-label="{% trans 'Owed' %}" class="tabular-nums">€ {{ membership.fee_amount }}</td>
|
||||||
<td class="tabular-nums">
|
<td data-label="{% trans 'Paid' %}" class="tabular-nums">
|
||||||
€ {{ membership.amount_paid }}
|
€ {{ membership.amount_paid }}
|
||||||
{% if membership.record_payment_form and membership.fee_amount %}
|
{% if membership.record_payment_form and membership.fee_amount %}
|
||||||
<div class="text-xs opacity-60">{% blocktrans with remaining=membership.remaining_balance_display %}{{ remaining }} left{% endblocktrans %}</div>
|
<div class="text-xs opacity-60">{% blocktrans with remaining=membership.remaining_balance_display %}{{ remaining }} left{% endblocktrans %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ membership.license|default:"-" }}</td>
|
<td data-label="{% trans 'License' %}">{{ membership.license|default:"-" }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if membership.record_payment_form %}
|
{% if membership.record_payment_form %}
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex flex-wrap justify-end gap-1">
|
||||||
<button class="btn btn-outline btn-sm" type="button" onclick="document.getElementById('{{ membership.pk|dom_id:"record_payment_modal" }}').showModal()">
|
<button class="btn btn-outline btn-sm" type="button" onclick="document.getElementById('{{ membership.pk|dom_id:"record_payment_modal" }}').showModal()">
|
||||||
{% lucide "receipt" size=12 %} {% trans "Record payment" %}
|
{% lucide "receipt" size=12 %} {% trans "Record payment" %}
|
||||||
</button>
|
</button>
|
||||||
@@ -185,7 +186,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="11" class="text-center opacity-60">{% trans "Nobody matches these filters." %}</td>
|
<td colspan="10" class="text-center opacity-60">{% trans "Nobody matches these filters." %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
<div class="card bg-base-100 shadow mt-4">
|
<div class="card bg-base-100 shadow mt-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% trans "Photos" %}</h2>
|
<h2 class="card-title text-base">{% trans "Photos" %}</h2>
|
||||||
{% if can_edit %}
|
{% if can_edit %}
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('add_photos_modal').showModal()">{% lucide "image-plus" size=14 %} {% trans "Add photos" %}</button>
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('add_photos_modal').showModal()">{% lucide "image-plus" size=14 %} {% trans "Add photos" %}</button>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Title" %}</th>
|
<th>{% trans "Title" %}</th>
|
||||||
@@ -26,16 +26,16 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for news_item in news_items %}
|
{% for news_item in news_items %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover" href="{% url 'management:news_detail' news_item.pk %}">{{ news_item.title }}</a></td>
|
<td><a class="link link-hover font-semibold" href="{% url 'management:news_detail' news_item.pk %}">{{ news_item.title }}</a></td>
|
||||||
<td>
|
<td data-label="{% trans 'Teams' %}">
|
||||||
{% for team in news_item.teams.all %}
|
{% for team in news_item.teams.all %}
|
||||||
<span class="badge badge-neutral badge-sm">{{ team.short_name }}</span>
|
<span class="badge badge-neutral badge-sm">{{ team.short_name }}</span>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<span class="opacity-60">{% trans "Club-wide" %}</span>
|
<span class="opacity-60">{% trans "Club-wide" %}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ news_item.get_visibility_display }}</td>
|
<td data-label="{% trans 'Visibility' %}">{{ news_item.get_visibility_display }}</td>
|
||||||
<td>
|
<td data-label="{% trans 'Status' %}">
|
||||||
{% if news_item.status == "draft" %}
|
{% if news_item.status == "draft" %}
|
||||||
<span class="badge badge-neutral badge-sm">{% trans "Draft" %}</span>
|
<span class="badge badge-neutral badge-sm">{% trans "Draft" %}</span>
|
||||||
{% elif news_item.is_scheduled %}
|
{% elif news_item.is_scheduled %}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<img src="{{ opponent.logo.url }}" alt="" class="size-8 rounded object-contain">
|
<img src="{{ opponent.logo.url }}" alt="" class="size-8 rounded object-contain">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ opponent.name }}</td>
|
<td class="font-semibold">{{ opponent.name }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex justify-end gap-1">
|
||||||
<a class="btn btn-outline btn-sm" href="{% url 'management:opponent_update' opponent.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
<a class="btn btn-outline btn-sm" href="{% url 'management:opponent_update' opponent.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title text-base">{% lucide "history" size=18 %} {% trans "Already dealt with" %}</h2>
|
<h2 class="card-title text-base">{% lucide "history" size=18 %} {% trans "Already dealt with" %}</h2>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Parent" %}</th>
|
<th>{% trans "Parent" %}</th>
|
||||||
@@ -104,9 +104,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for claim in reviewed %}
|
{% for claim in reviewed %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ claim.parent_name }}<div class="text-xs opacity-60">{{ claim.parent_email }}</div></td>
|
<td class="font-semibold">{{ claim.parent_name }}<div class="text-xs font-normal opacity-60">{{ claim.parent_email }}</div></td>
|
||||||
<td>{{ claim.claimed_child_name }}</td>
|
<td data-label="{% trans 'Claimed' %}">{{ claim.claimed_child_name }}</td>
|
||||||
<td>
|
<td data-label="{% trans 'Outcome' %}">
|
||||||
{% if claim.status == "approved" %}
|
{% if claim.status == "approved" %}
|
||||||
<span class="badge badge-success badge-sm">{% trans "Approved" %}</span>
|
<span class="badge badge-success badge-sm">{% trans "Approved" %}</span>
|
||||||
{% if claim.child %}<div class="text-xs opacity-60">{{ claim.child }}</div>{% endif %}
|
{% if claim.child %}<div class="text-xs opacity-60">{{ claim.child }}</div>{% endif %}
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
{% if claim.note %}<div class="text-xs opacity-60">{{ claim.note }}</div>{% endif %}
|
{% if claim.note %}<div class="text-xs opacity-60">{{ claim.note }}</div>{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ claim.reviewed_by|default:"—" }}</td>
|
<td data-label="{% trans 'Reviewed by' %}">{{ claim.reviewed_by|default:"—" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Ordering" %}</th>
|
<th>{% trans "Ordering" %}</th>
|
||||||
@@ -27,15 +27,15 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for position in positions %}
|
{% for position in positions %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ position.ordering }}</td>
|
<td data-label="{% trans 'Ordering' %}">{{ position.ordering }}</td>
|
||||||
<td>{{ position.name }}</td>
|
<td class="font-semibold">{{ position.name }}</td>
|
||||||
<td>{{ position.short_name }}</td>
|
<td data-label="{% trans 'Short name' %}">{{ position.short_name }}</td>
|
||||||
<td>
|
<td data-label="{% trans 'Staff position' %}">
|
||||||
<span class="badge badge-sm {% if position.staff_position %}badge-success{% else %}badge-neutral{% endif %}">
|
<span class="badge badge-sm {% if position.staff_position %}badge-success{% else %}badge-neutral{% endif %}">
|
||||||
{% if position.staff_position %}{% trans "Yes" %}{% else %}{% trans "No" %}{% endif %}
|
{% if position.staff_position %}{% trans "Yes" %}{% else %}{% trans "No" %}{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-label="{% trans 'Management position' %}">
|
||||||
<span class="badge badge-sm {% if position.management_position %}badge-success{% else %}badge-neutral{% endif %}">
|
<span class="badge badge-sm {% if position.management_position %}badge-success{% else %}badge-neutral{% endif %}">
|
||||||
{% if position.management_position %}{% trans "Yes" %}{% else %}{% trans "No" %}{% endif %}
|
{% if position.management_position %}{% trans "Yes" %}{% else %}{% trans "No" %}{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Ordering" %}</th>
|
<th>{% trans "Ordering" %}</th>
|
||||||
@@ -26,9 +26,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for level in levels %}
|
{% for level in levels %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ level.ordering }}</td>
|
<td data-label="{% trans 'Ordering' %}">{{ level.ordering }}</td>
|
||||||
<td>{{ level.name }}</td>
|
<td class="font-semibold">{{ level.name }}</td>
|
||||||
<td>
|
<td data-label="{% trans 'Qualifies for' %}">
|
||||||
{% for team in level.teams.all %}
|
{% for team in level.teams.all %}
|
||||||
<span class="badge badge-outline badge-sm">{{ team.name }}</span>
|
<span class="badge badge-outline badge-sm">{{ team.name }}</span>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Referee" %}</th>
|
<th>{% trans "Referee" %}</th>
|
||||||
@@ -21,9 +21,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for referee in referees %}
|
{% for referee in referees %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover" href="{% url 'management:member_detail' referee.pk %}">{{ referee }}</a></td>
|
<td><a class="link link-hover font-semibold" href="{% url 'management:member_detail' referee.pk %}">{{ referee }}</a></td>
|
||||||
<td>{{ referee.referee_profile.level|default:"—" }}</td>
|
<td data-label="{% trans 'Level' %}">{{ referee.referee_profile.level|default:"—" }}</td>
|
||||||
<td>
|
<td data-label="{% trans 'Can referee for' %}">
|
||||||
{% if referee.referee_profile.is_eligible %}
|
{% if referee.referee_profile.is_eligible %}
|
||||||
{% for team in referee.referee_profile.eligible_teams %}
|
{% for team in referee.referee_profile.eligible_teams %}
|
||||||
<span class="badge badge-outline badge-sm">{{ team.name }}</span>
|
<span class="badge badge-outline badge-sm">{{ team.name }}</span>
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
<span class="opacity-40">—</span>
|
<span class="opacity-40">—</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ referee.referee_profile.valid_until|default:"—" }}</td>
|
<td data-label="{% trans 'Valid until' %}">{{ referee.referee_profile.valid_until|default:"—" }}</td>
|
||||||
<td>
|
<td data-label="{% trans 'Status' %}">
|
||||||
{% if referee.referee_profile.is_eligible %}
|
{% if referee.referee_profile.is_eligible %}
|
||||||
<span class="badge badge-success badge-sm">{% trans "Valid" %}</span>
|
<span class="badge badge-success badge-sm">{% trans "Valid" %}</span>
|
||||||
{% elif not referee.referee_profile.level %}
|
{% elif not referee.referee_profile.level %}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
<span class="opacity-60">{% trans "No referees assigned yet." %}</span>
|
<span class="opacity-60">{% trans "No referees assigned yet." %}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<span class="badge badge-sm {% if not game.referee_rows %}badge-error{% elif not game.referees_full %}badge-warning{% else %}badge-success{% endif %}">
|
<span class="badge badge-sm {% if not game.referee_rows %}badge-error{% elif not game.referees_full %}badge-warning{% else %}badge-success{% endif %}">
|
||||||
{{ game.referee_rows|length }} / {{ game.max_referees }}
|
{{ game.referee_rows|length }} / {{ game.max_referees }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<h2 class="card-title text-base">{{ role_label }}</h2>
|
<h2 class="card-title text-base">{{ role_label }}</h2>
|
||||||
{% if description %}<p class="text-sm opacity-70">{{ description }}</p>{% endif %}
|
{% if description %}<p class="text-sm opacity-70">{{ description }}</p>{% endif %}
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Member" %}</th>
|
<th>{% trans "Member" %}</th>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for role in roles_for_section %}
|
{% for role in roles_for_section %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ role.member }}</td>
|
<td class="font-semibold">{{ role.member }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<form method="post" action="{% url 'management:role_revoke' role.pk %}">
|
<form method="post" action="{% url 'management:role_revoke' role.pk %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
@@ -30,16 +30,16 @@
|
|||||||
<img src="{{ sponsor.logo.url }}" alt="" class="size-8 rounded object-contain">
|
<img src="{{ sponsor.logo.url }}" alt="" class="size-8 rounded object-contain">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ sponsor.name }}</td>
|
<td class="font-semibold">{{ sponsor.name }}</td>
|
||||||
<td>
|
<td data-label="{% trans 'URL' %}">
|
||||||
{% if sponsor.url %}
|
{% if sponsor.url %}
|
||||||
<a class="link link-hover" href="{{ sponsor.url }}" target="_blank" rel="noopener noreferrer">{{ sponsor.url }}</a>
|
<a class="link link-hover" href="{{ sponsor.url }}" target="_blank" rel="noopener noreferrer">{{ sponsor.url }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="opacity-50">—</span>
|
<span class="opacity-50">—</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ sponsor.start_date|date:"Y-m-d" }}</td>
|
<td data-label="{% trans 'Start date' %}">{{ sponsor.start_date|date:"Y-m-d" }}</td>
|
||||||
<td>{{ sponsor.end_date|date:"Y-m-d"|default:"—" }}</td>
|
<td data-label="{% trans 'End date' %}">{{ sponsor.end_date|date:"Y-m-d"|default:"—" }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex justify-end gap-1">
|
||||||
<a class="btn btn-outline btn-sm" href="{% url 'management:sponsor_update' sponsor.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
<a class="btn btn-outline btn-sm" href="{% url 'management:sponsor_update' sponsor.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
||||||
|
|||||||
@@ -22,10 +22,12 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% comment %}
|
{% comment %}
|
||||||
Deliberately not wrapped in the usual overflow-x-auto: that makes a
|
overflow-x-auto is safe here: the member picker's dropdown
|
||||||
scroll container, which clips the member picker's absolutely
|
(searchable-select.js) is position: fixed, computed from the input's
|
||||||
positioned dropdown for every row but the first couple.
|
own screen position rather than document flow, so a scrolling
|
||||||
|
ancestor around the table no longer clips it.
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
|
<div class="overflow-x-auto">
|
||||||
<table class="table w-full">
|
<table class="table w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -43,6 +45,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template id="bulk-add-row-template">
|
<template id="bulk-add-row-template">
|
||||||
{% include "management/_team_bulk_add_row.html" with form=formset.empty_form %}
|
{% include "management/_team_bulk_add_row.html" with form=formset.empty_form %}
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
|
|
||||||
{% block heading %}{{ team.name }}{% endblock heading %}
|
{% block heading %}{{ team.name }}{% endblock heading %}
|
||||||
{% block subheading %}
|
{% block subheading %}
|
||||||
<span class="flex flex-row gap-2 items-center">
|
{# The raw id is a reference for support/debugging, not something a coach glancing at their phone needs -- hidden below `sm` rather than left to wrap awkwardly inside the pill. #}
|
||||||
|
<span class="flex flex-row items-center gap-2">
|
||||||
<span>{{ team.short_name }}</span>
|
<span>{{ team.short_name }}</span>
|
||||||
<span>·</span>
|
<span class="hidden sm:inline">·</span>
|
||||||
<span class="badge-sm badge badge-outline">{% lucide "bookmark" size=14 %} {{ team.pk }}</span>
|
<span class="badge badge-outline badge-sm hidden sm:inline-flex">{% lucide "bookmark" size=14 %} {{ team.pk }}</span>
|
||||||
</span>
|
</span>
|
||||||
{% endblock subheading %}
|
{% endblock subheading %}
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
|
|
||||||
{% block panel %}
|
{% block panel %}
|
||||||
<form method="get" class="mb-4">
|
<form method="get" class="mb-4">
|
||||||
<div class="flex flex-row items-center gap-2">
|
<div class="flex flex-row flex-wrap items-center gap-2">
|
||||||
<select name="season" class="select select-bordered">
|
<select name="season" class="select select-bordered">
|
||||||
{% for season in seasons %}
|
{% for season in seasons %}
|
||||||
<option value="{{ season.pk }}" {% if season.pk == selected_season.pk %}selected{% endif %}>{% trans "Season" %} {{ season.start_date|date:"Y" }} - {{ season.end_date|date:"Y" }}</option>
|
<option value="{{ season.pk }}" {% if season.pk == selected_season.pk %}selected{% endif %}>{% trans "Season" %} {{ season.start_date|date:"Y" }} - {{ season.end_date|date:"Y" }}</option>
|
||||||
@@ -123,40 +124,36 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title text-base">{% lucide "user-x" size=18 %} {% trans "No-shows" %}</h2>
|
<h2 class="card-title text-base">{% lucide "user-x" size=18 %} {% trans "No-shows" %}</h2>
|
||||||
<!-- <p class="text-sm opacity-70">{% trans "Said they'd attend, but were checked in as absent." %}</p> -->
|
<!-- <p class="text-sm opacity-70">{% trans "Said they'd attend, but were checked in as absent." %}</p> -->
|
||||||
<div class="overflow-x-auto">
|
<ul class="divide-y divide-base-200">
|
||||||
<table class="table">
|
|
||||||
<tbody>
|
|
||||||
{% for entry in no_shows %}
|
{% for entry in no_shows %}
|
||||||
<tr>
|
<li class="flex flex-col gap-1 py-2 sm:flex-row sm:items-center sm:justify-between sm:gap-4">
|
||||||
<td>{{ entry.member }}</td>
|
<div class="min-w-0">
|
||||||
<td class="opacity-70">{{ entry.event.title }}</td>
|
<span class="font-semibold">{{ entry.member }}</span>
|
||||||
<td class="whitespace-nowrap text-right opacity-60">{{ entry.event.start|date:"j M" }}</td>
|
<span class="text-sm opacity-70">· {{ entry.event.title }}</span>
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="3" class="text-center opacity-60">{% trans "None recorded." %}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="shrink-0 whitespace-nowrap text-sm opacity-60">{{ entry.event.start|date:"j M" }}</div>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="py-2 text-center text-sm opacity-60">{% trans "None recorded." %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% trans "Roster" %}</h2>
|
<h2 class="card-title text-base">{% trans "Roster" %}</h2>
|
||||||
{% if can_manage %}
|
{% if can_manage %}
|
||||||
<div class="flex gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:team_bulk_add' team.pk selected_season.pk %}">{% lucide "users" size=14 %} {% trans "Add multiple" %}</a>
|
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:team_bulk_add' team.pk selected_season.pk %}">{% lucide "users" size=14 %} {% trans "Add multiple" %}</a>
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('add_player_modal').showModal()">{% lucide "user-plus" size=14 %} {% trans "Add player" %}</button>
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('add_player_modal').showModal()">{% lucide "user-plus" size=14 %} {% trans "Add player" %}</button>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Member" %}</th>
|
<th>{% trans "Member" %}</th>
|
||||||
@@ -169,16 +166,16 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for membership in roster %}
|
{% for membership in roster %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ membership.member }}</td>
|
<td class="font-semibold">{{ membership.member }}</td>
|
||||||
<td>{{ membership.position }}</td>
|
<td data-label="{% trans 'Position' %}">{{ membership.position }}</td>
|
||||||
<td>{{ membership.jersey_number|default:"—" }}</td>
|
<td data-label="{% trans 'Jersey #' %}">{{ membership.jersey_number|default:"—" }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if membership.is_captain %}<span class="badge badge-neutral badge-sm">{% trans "Captain" %}</span>{% endif %}
|
{% if membership.is_captain %}<span class="badge badge-neutral badge-sm">{% trans "Captain" %}</span>{% endif %}
|
||||||
{% if membership.is_alternate_captain %}<span class="badge badge-neutral badge-sm">{% trans "Alternate captain" %}</span>{% endif %}
|
{% if membership.is_alternate_captain %}<span class="badge badge-neutral badge-sm">{% trans "Alternate captain" %}</span>{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if can_manage %}
|
{% if can_manage %}
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex flex-wrap justify-end gap-1">
|
||||||
<button class="btn btn-outline btn-sm" type="button" onclick="document.getElementById('{{ membership.pk|dom_id:"edit_player_modal" }}').showModal()" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</button>
|
<button class="btn btn-outline btn-sm" type="button" onclick="document.getElementById('{{ membership.pk|dom_id:"edit_player_modal" }}').showModal()" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</button>
|
||||||
<button class="btn btn-sm btn-outline btn-error" type="button" onclick="document.getElementById('{{ membership.pk|dom_id:"remove_player_modal" }}').showModal()" aria-label="{% trans 'Remove' %}">{% lucide "user-minus" size=14 %} {% trans "Remove" %}</button>
|
<button class="btn btn-sm btn-outline btn-error" type="button" onclick="document.getElementById('{{ membership.pk|dom_id:"remove_player_modal" }}').showModal()" aria-label="{% trans 'Remove' %}">{% lucide "user-minus" size=14 %} {% trans "Remove" %}</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -198,10 +195,10 @@
|
|||||||
|
|
||||||
<div class="card bg-base-100 shadow mt-4">
|
<div class="card bg-base-100 shadow mt-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% trans "Staff" %}</h2>
|
<h2 class="card-title text-base">{% trans "Staff" %}</h2>
|
||||||
{% if can_manage %}
|
{% if can_manage %}
|
||||||
<div class="flex gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:team_bulk_add' team.pk selected_season.pk %}">{% lucide "users" size=14 %} {% trans "Add multiple" %}</a>
|
<a class="btn btn-outline btn-sm gap-2" href="{% url 'management:team_bulk_add' team.pk selected_season.pk %}">{% lucide "users" size=14 %} {% trans "Add multiple" %}</a>
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('add_staff_modal').showModal()">{% lucide "user-plus" size=14 %} {% trans "Assign staff" %}</button>
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('add_staff_modal').showModal()">{% lucide "user-plus" size=14 %} {% trans "Assign staff" %}</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -263,10 +260,10 @@
|
|||||||
|
|
||||||
<div class="card bg-base-100 shadow mt-4">
|
<div class="card bg-base-100 shadow mt-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="card-title text-base">{% trans "Team photo" %}</h2>
|
<h2 class="card-title text-base">{% trans "Team photo" %}</h2>
|
||||||
{% if can_manage %}
|
{% if can_manage %}
|
||||||
<div class="flex gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
{% trans "Upload photo" as upload_photo_label %}
|
{% trans "Upload photo" as upload_photo_label %}
|
||||||
{% trans "Replace photo" as replace_photo_label %}
|
{% trans "Replace photo" as replace_photo_label %}
|
||||||
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('team_photo_modal').showModal()">
|
<button class="btn btn-outline btn-sm gap-2" type="button" onclick="document.getElementById('team_photo_modal').showModal()">
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="card bg-base-100 shadow">
|
<div class="card bg-base-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table table-cards">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Name" %}</th>
|
<th>{% trans "Name" %}</th>
|
||||||
@@ -26,10 +26,10 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for team in teams %}
|
{% for team in teams %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link link-hover" href="{% url 'management:team_detail' team.pk %}">{{ team.name }}</a></td>
|
<td><a class="link link-hover font-semibold" href="{% url 'management:team_detail' team.pk %}">{{ team.name }}</a></td>
|
||||||
<td>{{ team.short_name }}</td>
|
<td data-label="{% trans 'Short name' %}">{{ team.short_name }}</td>
|
||||||
<td>{{ team.player_count }}</td>
|
<td data-label="{% trans 'Players' %}">{{ team.player_count }}</td>
|
||||||
<td>{{ team.staff_count }}</td>
|
<td data-label="{% trans 'Staff' %}">{{ team.staff_count }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if is_club_admin %}
|
{% if is_club_admin %}
|
||||||
<div class="flex justify-end gap-1">
|
<div class="flex justify-end gap-1">
|
||||||
|
|||||||
@@ -31,14 +31,13 @@
|
|||||||
--text-3xl--line-height: calc(2.25 / 1.875);
|
--text-3xl--line-height: calc(2.25 / 1.875);
|
||||||
--text-4xl: 2.25rem;
|
--text-4xl: 2.25rem;
|
||||||
--text-4xl--line-height: calc(2.5 / 2.25);
|
--text-4xl--line-height: calc(2.5 / 2.25);
|
||||||
|
--font-weight-normal: 400;
|
||||||
--font-weight-medium: 500;
|
--font-weight-medium: 500;
|
||||||
--font-weight-semibold: 600;
|
--font-weight-semibold: 600;
|
||||||
--font-weight-bold: 700;
|
--font-weight-bold: 700;
|
||||||
--tracking-wide: 0.025em;
|
--tracking-wide: 0.025em;
|
||||||
--tracking-wider: 0.05em;
|
--tracking-wider: 0.05em;
|
||||||
--radius-lg: 0.5rem;
|
--radius-lg: 0.5rem;
|
||||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
||||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
--default-transition-duration: 150ms;
|
--default-transition-duration: 150ms;
|
||||||
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
@@ -776,26 +775,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.collapse-plus {
|
|
||||||
@layer daisyui.l1.l2 {
|
|
||||||
> .collapse-title:after {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
height: 0.5rem;
|
|
||||||
width: 0.5rem;
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
transition-property: all;
|
|
||||||
transition-duration: 300ms;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
top: 0.9rem;
|
|
||||||
inset-inline-end: 1.4rem;
|
|
||||||
--tw-content: "+";
|
|
||||||
content: var(--tw-content);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.dropdown {
|
.dropdown {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -1321,21 +1300,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.collapse-open {
|
|
||||||
@layer daisyui.l1.l2 {
|
|
||||||
grid-template-rows: max-content 1fr;
|
|
||||||
> .collapse-content {
|
|
||||||
--overflow-delay: 0.2s;
|
|
||||||
overflow: revert-layer;
|
|
||||||
content-visibility: visible;
|
|
||||||
min-height: fit-content;
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
@supports not (content-visibility: visible) {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.collapse {
|
.collapse {
|
||||||
visibility: collapse;
|
visibility: collapse;
|
||||||
}
|
}
|
||||||
@@ -1404,27 +1368,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toast {
|
|
||||||
@layer daisyui.l1.l2.l3 {
|
|
||||||
position: fixed;
|
|
||||||
inset-inline-start: auto;
|
|
||||||
inset-inline-end: calc(0.25rem * 4);
|
|
||||||
top: auto;
|
|
||||||
bottom: calc(0.25rem * 4);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: calc(0.25rem * 2);
|
|
||||||
background-color: transparent;
|
|
||||||
translate: var(--toast-x, 0) var(--toast-y, 0);
|
|
||||||
width: max-content;
|
|
||||||
max-width: calc(100vw - 2rem);
|
|
||||||
& > * {
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
animation: toast 0.25s ease-out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.toggle {
|
.toggle {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
border: var(--border) solid currentColor;
|
border: var(--border) solid currentColor;
|
||||||
@@ -1877,51 +1820,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.aura {
|
|
||||||
@layer daisyui.l1.l2.l3 {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
--aura-padding: 0.125rem;
|
|
||||||
padding: var(--aura-padding);
|
|
||||||
border-radius: calc(var(--aura-padding) + var(--aura-radius, var(--radius-box)));
|
|
||||||
animation: aura var(--tw-duration, 6s) linear infinite;
|
|
||||||
background-image: conic-gradient(from var(--aura-angle), transparent 225deg, currentColor);
|
|
||||||
&:has( > .card, > .alert) {
|
|
||||||
--aura-radius: var(--radius-box);
|
|
||||||
}
|
|
||||||
&:has( > .btn, > .input, > .select) {
|
|
||||||
--aura-radius: var(--radius-field);
|
|
||||||
}
|
|
||||||
&:has( > .checkbox, > .toggle, > .badge) {
|
|
||||||
--aura-radius: var(--radius-selector);
|
|
||||||
}
|
|
||||||
&:before, &:after {
|
|
||||||
animation: inherit;
|
|
||||||
background-color: inherit;
|
|
||||||
background-image: inherit;
|
|
||||||
border-radius: inherit;
|
|
||||||
position: absolute;
|
|
||||||
top: calc(1 / 2 * 100%);
|
|
||||||
left: calc(1 / 2 * 100%);
|
|
||||||
z-index: 0;
|
|
||||||
display: block;
|
|
||||||
opacity: 70%;
|
|
||||||
filter: blur(0.25rem);
|
|
||||||
translate: -50% -50%;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
opacity: 30%;
|
|
||||||
filter: blur(1rem);
|
|
||||||
}
|
|
||||||
& > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.steps {
|
.steps {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
display: inline-grid;
|
display: inline-grid;
|
||||||
@@ -2277,49 +2175,6 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
}
|
}
|
||||||
.menu-horizontal {
|
|
||||||
@layer daisyui.l1.l2 {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
& > li:not(.menu-title) > details {
|
|
||||||
& > :is(ul, menu) {
|
|
||||||
position: absolute;
|
|
||||||
margin-inline-start: 0;
|
|
||||||
margin-top: calc(0.25rem * 4);
|
|
||||||
transform-origin: top;
|
|
||||||
border-radius: var(--radius-box);
|
|
||||||
background-color: var(--color-base-100);
|
|
||||||
padding-block: calc(0.25rem * 2);
|
|
||||||
padding-inline-end: calc(0.25rem * 2);
|
|
||||||
opacity: 0%;
|
|
||||||
scale: 95%;
|
|
||||||
box-shadow: 0 1px 3px 0 oklch(0% 0 0/0.1), 0 1px 2px -1px oklch(0% 0 0/0.1);
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
@starting-style {
|
|
||||||
scale: 95%;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
animation: menu 0.2s;
|
|
||||||
transition-property: opacity, scale, display;
|
|
||||||
transition-behavior: allow-discrete;
|
|
||||||
transition-duration: 0.2s;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&[open] > :is(ul, menu) {
|
|
||||||
opacity: 100%;
|
|
||||||
scale: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& > li > details > :is(ul, menu) {
|
|
||||||
&:before {
|
|
||||||
--tw-content: none;
|
|
||||||
content: var(--tw-content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.avatar {
|
.avatar {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -2487,48 +2342,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.rating {
|
|
||||||
@layer daisyui.l1.l2.l3 {
|
|
||||||
position: relative;
|
|
||||||
display: inline-flex;
|
|
||||||
vertical-align: middle;
|
|
||||||
--size: var(--size-selector, 0.25rem) * 6;
|
|
||||||
input {
|
|
||||||
cursor: pointer;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
* {
|
|
||||||
border-radius: 0;
|
|
||||||
background-color: var(--color-base-content);
|
|
||||||
opacity: 20%;
|
|
||||||
width: calc(var(--size) * 1);
|
|
||||||
height: calc(var(--size));
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
animation: rating 0.25s ease-out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.rating-hidden {
|
|
||||||
width: calc(0.25rem * 2);
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
:checked, [aria-checked="true"], [aria-current="true"], :has( ~ :checked, ~ [aria-checked="true"], ~ [aria-current="true"]) {
|
|
||||||
opacity: 100%;
|
|
||||||
}
|
|
||||||
:focus-visible {
|
|
||||||
scale: 1.1;
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
transition: scale 0.2s ease-out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:active:focus {
|
|
||||||
animation: none;
|
|
||||||
scale: 1.1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@layer daisyui.l1.l2 {
|
|
||||||
--size: var(--size-selector, 0.25rem) * 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.navbar {
|
.navbar {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -2543,6 +2356,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.drawer {
|
||||||
|
@layer daisyui.l1.l2.l3 {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
grid-auto-columns: max-content auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
.card {
|
.card {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -2668,30 +2489,6 @@
|
|||||||
.sticky {
|
.sticky {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
}
|
}
|
||||||
.dropdown-right {
|
|
||||||
@layer daisyui.l1.l2 {
|
|
||||||
--anchor-h: right;
|
|
||||||
--anchor-v: span-bottom;
|
|
||||||
.dropdown-content {
|
|
||||||
inset-inline-start: 100%;
|
|
||||||
top: 0;
|
|
||||||
bottom: auto;
|
|
||||||
transform-origin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.dropdown-left {
|
|
||||||
@layer daisyui.l1.l2 {
|
|
||||||
--anchor-h: left;
|
|
||||||
--anchor-v: span-bottom;
|
|
||||||
.dropdown-content {
|
|
||||||
inset-inline-end: 100%;
|
|
||||||
top: 0;
|
|
||||||
bottom: auto;
|
|
||||||
transform-origin: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.dropdown-end {
|
.dropdown-end {
|
||||||
@layer daisyui.l1.l2 {
|
@layer daisyui.l1.l2 {
|
||||||
--anchor-h: span-left;
|
--anchor-h: span-left;
|
||||||
@@ -2961,25 +2758,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.btn-active {
|
|
||||||
@layer daisyui.l1.l2 {
|
|
||||||
--btn-bg: var(--btn-color, var(--color-base-200));
|
|
||||||
color: var(--btn-fg, var(--color-base-content));
|
|
||||||
--btn-border: var(--btn-bg);
|
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
|
||||||
--btn-border: color-mix(in oklab, var(--btn-bg), #000 calc(var(--depth) * 5%));
|
|
||||||
}
|
|
||||||
--btn-border-style: solid;
|
|
||||||
--btn-inset: 0 0.5px 0 0.5px oklch(100% 0 0 / calc(var(--depth) * 6%));
|
|
||||||
--btn-shadow: 0 3px 2px -2px var(--btn-bg),
|
|
||||||
0 4px 3px -2px var(--btn-bg);
|
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
|
||||||
--btn-shadow: 0 3px 2px -2px color-mix(in oklab, var(--btn-bg) calc(var(--depth) * 30%), #0000),
|
|
||||||
0 4px 3px -2px color-mix(in oklab, var(--btn-bg) calc(var(--depth) * 30%), #0000);
|
|
||||||
}
|
|
||||||
isolation: isolate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.stack {
|
.stack {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
display: inline-grid;
|
display: inline-grid;
|
||||||
@@ -3159,25 +2937,8 @@
|
|||||||
.z-10 {
|
.z-10 {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
.tab-content {
|
.z-50 {
|
||||||
@layer daisyui.l1.l2.l3 {
|
z-index: 50;
|
||||||
order: var(--tabcontent-order);
|
|
||||||
display: none;
|
|
||||||
border-color: transparent;
|
|
||||||
--tabcontent-radius-ss: var(--radius-box);
|
|
||||||
--tabcontent-radius-se: var(--radius-box);
|
|
||||||
--tabcontent-radius-es: var(--radius-box);
|
|
||||||
--tabcontent-radius-ee: var(--radius-box);
|
|
||||||
--tabcontent-order: 1;
|
|
||||||
width: 100%;
|
|
||||||
height: calc(100% - var(--tab-height) + var(--border));
|
|
||||||
margin: var(--tabcontent-margin);
|
|
||||||
border-width: var(--border);
|
|
||||||
border-start-start-radius: var(--tabcontent-radius-ss);
|
|
||||||
border-start-end-radius: var(--tabcontent-radius-se);
|
|
||||||
border-end-start-radius: var(--tabcontent-radius-es);
|
|
||||||
border-end-end-radius: var(--tabcontent-radius-ee);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.col-span-full {
|
.col-span-full {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
@@ -3452,17 +3213,6 @@
|
|||||||
padding-inline: calc(var(--size) / 2 - var(--border));
|
padding-inline: calc(var(--size) / 2 - var(--border));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tabs {
|
|
||||||
@layer daisyui.l1.l2.l3 {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
--tabs-height: auto;
|
|
||||||
--tabs-direction: row;
|
|
||||||
--tab-height: calc(var(--size-field, 0.25rem) * 10);
|
|
||||||
height: var(--tabs-height);
|
|
||||||
flex-direction: var(--tabs-direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.footer {
|
.footer {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -3658,15 +3408,32 @@
|
|||||||
.inline-flex {
|
.inline-flex {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
.inline-grid {
|
|
||||||
display: inline-grid;
|
|
||||||
}
|
|
||||||
.table {
|
.table {
|
||||||
display: table;
|
display: table;
|
||||||
}
|
}
|
||||||
.aspect-square {
|
.aspect-square {
|
||||||
aspect-ratio: 1 / 1;
|
aspect-ratio: 1 / 1;
|
||||||
}
|
}
|
||||||
|
.modal-start {
|
||||||
|
@layer daisyui.l1.l2 {
|
||||||
|
place-items: start;
|
||||||
|
.modal-box {
|
||||||
|
height: 100vh;
|
||||||
|
max-height: none;
|
||||||
|
width: auto;
|
||||||
|
max-width: none;
|
||||||
|
translate: -100% 0;
|
||||||
|
scale: 1;
|
||||||
|
--modal-tl: 0;
|
||||||
|
--modal-tr: var(--radius-box);
|
||||||
|
--modal-bl: 0;
|
||||||
|
--modal-br: var(--radius-box);
|
||||||
|
[dir="rtl"] & {
|
||||||
|
translate: 100% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.btn-circle {
|
.btn-circle {
|
||||||
@layer daisyui.l1.l2 {
|
@layer daisyui.l1.l2 {
|
||||||
border-radius: calc(infinity * 1px);
|
border-radius: calc(infinity * 1px);
|
||||||
@@ -3675,16 +3442,23 @@
|
|||||||
height: var(--size);
|
height: var(--size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.btn-square {
|
||||||
|
@layer daisyui.l1.l2 {
|
||||||
|
padding-inline: 0;
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
}
|
||||||
|
}
|
||||||
.size-8 {
|
.size-8 {
|
||||||
width: calc(var(--spacing) * 8);
|
width: calc(var(--spacing) * 8);
|
||||||
height: calc(var(--spacing) * 8);
|
height: calc(var(--spacing) * 8);
|
||||||
}
|
}
|
||||||
|
.h-10 {
|
||||||
|
height: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
.h-12 {
|
.h-12 {
|
||||||
height: calc(var(--spacing) * 12);
|
height: calc(var(--spacing) * 12);
|
||||||
}
|
}
|
||||||
.h-16 {
|
|
||||||
height: calc(var(--spacing) * 16);
|
|
||||||
}
|
|
||||||
.h-56 {
|
.h-56 {
|
||||||
height: calc(var(--spacing) * 56);
|
height: calc(var(--spacing) * 56);
|
||||||
}
|
}
|
||||||
@@ -3700,30 +3474,33 @@
|
|||||||
.max-h-60 {
|
.max-h-60 {
|
||||||
max-height: calc(var(--spacing) * 60);
|
max-height: calc(var(--spacing) * 60);
|
||||||
}
|
}
|
||||||
|
.max-h-none {
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
.min-h-6 {
|
.min-h-6 {
|
||||||
min-height: calc(var(--spacing) * 6);
|
min-height: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
|
.w-10 {
|
||||||
|
width: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
.w-12 {
|
.w-12 {
|
||||||
width: calc(var(--spacing) * 12);
|
width: calc(var(--spacing) * 12);
|
||||||
}
|
}
|
||||||
.w-16 {
|
.w-16 {
|
||||||
width: calc(var(--spacing) * 16);
|
width: calc(var(--spacing) * 16);
|
||||||
}
|
}
|
||||||
.w-20 {
|
|
||||||
width: calc(var(--spacing) * 20);
|
|
||||||
}
|
|
||||||
.w-24 {
|
.w-24 {
|
||||||
width: calc(var(--spacing) * 24);
|
width: calc(var(--spacing) * 24);
|
||||||
}
|
}
|
||||||
.w-28 {
|
|
||||||
width: calc(var(--spacing) * 28);
|
|
||||||
}
|
|
||||||
.w-60 {
|
.w-60 {
|
||||||
width: calc(var(--spacing) * 60);
|
width: calc(var(--spacing) * 60);
|
||||||
}
|
}
|
||||||
.w-64 {
|
.w-64 {
|
||||||
width: calc(var(--spacing) * 64);
|
width: calc(var(--spacing) * 64);
|
||||||
}
|
}
|
||||||
|
.w-72 {
|
||||||
|
width: calc(var(--spacing) * 72);
|
||||||
|
}
|
||||||
.w-full {
|
.w-full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -3736,6 +3513,9 @@
|
|||||||
.max-w-40 {
|
.max-w-40 {
|
||||||
max-width: calc(var(--spacing) * 40);
|
max-width: calc(var(--spacing) * 40);
|
||||||
}
|
}
|
||||||
|
.max-w-\[85vw\] {
|
||||||
|
max-width: 85vw;
|
||||||
|
}
|
||||||
.max-w-md {
|
.max-w-md {
|
||||||
max-width: var(--container-md);
|
max-width: var(--container-md);
|
||||||
}
|
}
|
||||||
@@ -3754,61 +3534,21 @@
|
|||||||
.min-w-40 {
|
.min-w-40 {
|
||||||
min-width: calc(var(--spacing) * 40);
|
min-width: calc(var(--spacing) * 40);
|
||||||
}
|
}
|
||||||
.min-w-64 {
|
|
||||||
min-width: calc(var(--spacing) * 64);
|
|
||||||
}
|
|
||||||
.flex-1 {
|
.flex-1 {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.flex-shrink {
|
|
||||||
flex-shrink: 1;
|
|
||||||
}
|
|
||||||
.shrink {
|
.shrink {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
.shrink-0 {
|
.shrink-0 {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.flex-grow {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
.grow {
|
.grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
.border-collapse {
|
.border-collapse {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
.transform {
|
|
||||||
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
|
||||||
}
|
|
||||||
.skeleton {
|
|
||||||
@layer daisyui.l1.l2.l3 {
|
|
||||||
border-radius: var(--radius-box);
|
|
||||||
background-color: var(--color-base-300);
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
transition-duration: 15s;
|
|
||||||
}
|
|
||||||
will-change: background-position;
|
|
||||||
background-image: linear-gradient( 105deg, #0000 0% 40%, var(--color-base-100) 50%, #0000 60% 100% );
|
|
||||||
background-size: 200% auto;
|
|
||||||
background-position-x: -50%;
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
animation: skeleton 1.8s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.aura-glow {
|
|
||||||
@layer daisyui.l1.l2 {
|
|
||||||
animation: none;
|
|
||||||
background-image: radial-gradient(closest-corner at center, currentColor 0%, transparent 90%);
|
|
||||||
&:before {
|
|
||||||
animation: aura-glow var(--tw-duration, 6s) ease-out infinite;
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
animation: aura-glow-after var(--tw-duration, 6s) ease-out infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.animate-pulse {
|
.animate-pulse {
|
||||||
animation: var(--animate-pulse);
|
animation: var(--animate-pulse);
|
||||||
}
|
}
|
||||||
@@ -3884,9 +3624,6 @@
|
|||||||
.justify-start {
|
.justify-start {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
.justify-items-start {
|
|
||||||
justify-items: start;
|
|
||||||
}
|
|
||||||
.gap-1 {
|
.gap-1 {
|
||||||
gap: var(--spacing);
|
gap: var(--spacing);
|
||||||
}
|
}
|
||||||
@@ -3916,9 +3653,6 @@
|
|||||||
.gap-x-4 {
|
.gap-x-4 {
|
||||||
column-gap: calc(var(--spacing) * 4);
|
column-gap: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
.gap-x-6 {
|
|
||||||
column-gap: calc(var(--spacing) * 6);
|
|
||||||
}
|
|
||||||
.gap-y-2 {
|
.gap-y-2 {
|
||||||
row-gap: calc(var(--spacing) * 2);
|
row-gap: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
@@ -3968,6 +3702,9 @@
|
|||||||
.rounded-lg {
|
.rounded-lg {
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
}
|
}
|
||||||
|
.rounded-none {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
.border {
|
.border {
|
||||||
border-style: var(--tw-border-style);
|
border-style: var(--tw-border-style);
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
@@ -4141,15 +3878,15 @@
|
|||||||
--btn-shadow: 0 0 0 0 oklch(0% 0 0/0);
|
--btn-shadow: 0 0 0 0 oklch(0% 0 0/0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mask-repeat {
|
|
||||||
mask-repeat: repeat;
|
|
||||||
}
|
|
||||||
.object-contain {
|
.object-contain {
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
.object-cover {
|
.object-cover {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
.p-0 {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
.p-2 {
|
.p-2 {
|
||||||
padding: calc(var(--spacing) * 2);
|
padding: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
@@ -4282,6 +4019,10 @@
|
|||||||
--tw-font-weight: var(--font-weight-medium);
|
--tw-font-weight: var(--font-weight-medium);
|
||||||
font-weight: var(--font-weight-medium);
|
font-weight: var(--font-weight-medium);
|
||||||
}
|
}
|
||||||
|
.font-normal {
|
||||||
|
--tw-font-weight: var(--font-weight-normal);
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
}
|
||||||
.font-semibold {
|
.font-semibold {
|
||||||
--tw-font-weight: var(--font-weight-semibold);
|
--tw-font-weight: var(--font-weight-semibold);
|
||||||
font-weight: var(--font-weight-semibold);
|
font-weight: var(--font-weight-semibold);
|
||||||
@@ -4294,9 +4035,6 @@
|
|||||||
--tw-tracking: var(--tracking-wider);
|
--tw-tracking: var(--tracking-wider);
|
||||||
letter-spacing: var(--tracking-wider);
|
letter-spacing: var(--tracking-wider);
|
||||||
}
|
}
|
||||||
.text-wrap {
|
|
||||||
text-wrap: wrap;
|
|
||||||
}
|
|
||||||
.whitespace-nowrap {
|
.whitespace-nowrap {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -4413,9 +4151,6 @@
|
|||||||
text-decoration-line: none;
|
text-decoration-line: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.underline {
|
|
||||||
text-decoration-line: underline;
|
|
||||||
}
|
|
||||||
.opacity-40 {
|
.opacity-40 {
|
||||||
opacity: 40%;
|
opacity: 40%;
|
||||||
}
|
}
|
||||||
@@ -4472,19 +4207,6 @@
|
|||||||
.filter {
|
.filter {
|
||||||
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
||||||
}
|
}
|
||||||
.transition {
|
|
||||||
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
|
|
||||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
|
||||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
|
||||||
}
|
|
||||||
.ease-in-out {
|
|
||||||
--tw-ease: var(--ease-in-out);
|
|
||||||
transition-timing-function: var(--ease-in-out);
|
|
||||||
}
|
|
||||||
.ease-out {
|
|
||||||
--tw-ease: var(--ease-out);
|
|
||||||
transition-timing-function: var(--ease-out);
|
|
||||||
}
|
|
||||||
.input-lg {
|
.input-lg {
|
||||||
@layer daisyui.l1.l2 {
|
@layer daisyui.l1.l2 {
|
||||||
--in-size-mul: 12;
|
--in-size-mul: 12;
|
||||||
@@ -4664,6 +4386,11 @@
|
|||||||
grid-column: span 2 / span 2;
|
grid-column: span 2 / span 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sm\:block {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
.sm\:hidden {
|
.sm\:hidden {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -4674,6 +4401,36 @@
|
|||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sm\:inline-flex {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:h-16 {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
height: calc(var(--spacing) * 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:w-16 {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
width: calc(var(--spacing) * 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:w-auto {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:max-w-xs {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
max-width: var(--container-xs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:grow-0 {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
.sm\:grid-cols-2 {
|
.sm\:grid-cols-2 {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
@@ -4684,34 +4441,51 @@
|
|||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sm\:flex-row {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:flex-wrap {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:items-center {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:justify-between {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:gap-3 {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
gap: calc(var(--spacing) * 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sm\:gap-4 {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
gap: calc(var(--spacing) * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
.sm\:px-6 {
|
.sm\:px-6 {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
padding-inline: calc(var(--spacing) * 6);
|
padding-inline: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.md\:col-span-2 {
|
.sm\:text-2xl {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 40rem) {
|
||||||
grid-column: span 2 / span 2;
|
font-size: var(--text-2xl);
|
||||||
|
line-height: var(--tw-leading, var(--text-2xl--line-height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.md\:col-span-4 {
|
.sm\:text-xl {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 40rem) {
|
||||||
grid-column: span 4 / span 4;
|
font-size: var(--text-xl);
|
||||||
}
|
line-height: var(--tw-leading, var(--text-xl--line-height));
|
||||||
}
|
|
||||||
.md\:mb-2 {
|
|
||||||
@media (width >= 48rem) {
|
|
||||||
margin-bottom: calc(var(--spacing) * 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.md\:grid {
|
|
||||||
@media (width >= 48rem) {
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.md\:hidden {
|
|
||||||
@media (width >= 48rem) {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.md\:grid-cols-2 {
|
.md\:grid-cols-2 {
|
||||||
@@ -4734,24 +4508,9 @@
|
|||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.md\:grid-cols-\[minmax\(0\,1fr\)_2\.5rem\] {
|
.lg\:col-span-1 {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 64rem) {
|
||||||
grid-template-columns: minmax(0,1fr) 2.5rem;
|
grid-column: span 1 / span 1;
|
||||||
}
|
|
||||||
}
|
|
||||||
.md\:grid-cols-\[minmax\(0\,2fr\)_minmax\(0\,2fr\)_7rem_2\.5rem\] {
|
|
||||||
@media (width >= 48rem) {
|
|
||||||
grid-template-columns: minmax(0,2fr) minmax(0,2fr) 7rem 2.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.md\:items-start {
|
|
||||||
@media (width >= 48rem) {
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.md\:justify-center {
|
|
||||||
@media (width >= 48rem) {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.lg\:block {
|
.lg\:block {
|
||||||
@@ -4759,16 +4518,36 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.lg\:contents {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lg\:flex {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
.lg\:hidden {
|
.lg\:hidden {
|
||||||
@media (width >= 64rem) {
|
@media (width >= 64rem) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.lg\:w-auto {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
.lg\:w-fit {
|
.lg\:w-fit {
|
||||||
@media (width >= 64rem) {
|
@media (width >= 64rem) {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.lg\:grow-0 {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
.lg\:grid-cols-2 {
|
.lg\:grid-cols-2 {
|
||||||
@media (width >= 64rem) {
|
@media (width >= 64rem) {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
@@ -4789,6 +4568,21 @@
|
|||||||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.lg\:flex-row {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lg\:flex-wrap {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lg\:items-center {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
.xl\:grid-cols-3 {
|
.xl\:grid-cols-3 {
|
||||||
@media (width >= 80rem) {
|
@media (width >= 80rem) {
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
@@ -4933,6 +4727,46 @@
|
|||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
}
|
}
|
||||||
|
@media (width < 48rem) {
|
||||||
|
.table-cards, .table-cards :is(thead, tbody, tr, th, td) {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.table-cards thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.table-cards tbody tr {
|
||||||
|
border: 1px solid var(--color-base-300);
|
||||||
|
border-radius: var(--radius-box);
|
||||||
|
padding: 0 0.75rem;
|
||||||
|
}
|
||||||
|
.table-cards tbody tr + tr {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
.table-cards td {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 0.6rem 0;
|
||||||
|
border-bottom: 1px solid var(--color-base-200);
|
||||||
|
}
|
||||||
|
.table-cards td:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.table-cards td[data-label]:before {
|
||||||
|
content: attr(data-label);
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.table-cards td:not([data-label]) {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
@layer base {
|
@layer base {
|
||||||
:where(:root),:root:has(input.theme-controller[value=light]:checked),[data-theme=light] {
|
:where(:root),:root:has(input.theme-controller[value=light]:checked),[data-theme=light] {
|
||||||
color-scheme: light;
|
color-scheme: light;
|
||||||
@@ -5219,26 +5053,6 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@property --tw-rotate-x {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-rotate-y {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-rotate-z {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-skew-x {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-skew-y {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-space-y-reverse {
|
@property --tw-space-y-reverse {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@@ -5405,10 +5219,6 @@
|
|||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
}
|
}
|
||||||
@property --tw-ease {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
50% {
|
50% {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
@@ -5417,11 +5227,6 @@
|
|||||||
@layer properties {
|
@layer properties {
|
||||||
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
||||||
*, ::before, ::after, ::backdrop {
|
*, ::before, ::after, ::backdrop {
|
||||||
--tw-rotate-x: initial;
|
|
||||||
--tw-rotate-y: initial;
|
|
||||||
--tw-rotate-z: initial;
|
|
||||||
--tw-skew-x: initial;
|
|
||||||
--tw-skew-y: initial;
|
|
||||||
--tw-space-y-reverse: 0;
|
--tw-space-y-reverse: 0;
|
||||||
--tw-divide-y-reverse: 0;
|
--tw-divide-y-reverse: 0;
|
||||||
--tw-border-style: solid;
|
--tw-border-style: solid;
|
||||||
@@ -5460,7 +5265,6 @@
|
|||||||
--tw-drop-shadow-color: initial;
|
--tw-drop-shadow-color: initial;
|
||||||
--tw-drop-shadow-alpha: 100%;
|
--tw-drop-shadow-alpha: 100%;
|
||||||
--tw-drop-shadow-size: initial;
|
--tw-drop-shadow-size: initial;
|
||||||
--tw-ease: initial;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,28 @@
|
|||||||
input.placeholder = select.dataset.searchPlaceholder || "";
|
input.placeholder = select.dataset.searchPlaceholder || "";
|
||||||
input.autocomplete = "off";
|
input.autocomplete = "off";
|
||||||
|
|
||||||
|
// `fixed`, not `absolute`: an absolutely positioned dropdown is clipped by
|
||||||
|
// the nearest scrolling ancestor (e.g. the overflow-x-auto wrapper the
|
||||||
|
// bulk-add tables would otherwise need on mobile), which is exactly what
|
||||||
|
// stopped those tables from getting one. Fixed positioning is relative to
|
||||||
|
// the viewport regardless of ancestors, so it's never clipped that way --
|
||||||
|
// position and size are computed in JS instead of via CSS, see positionList().
|
||||||
const list = document.createElement("ul");
|
const list = document.createElement("ul");
|
||||||
list.className = "menu absolute z-10 mt-1 w-full rounded-box bg-base-100 shadow max-h-60 overflow-y-auto flex-nowrap hidden";
|
list.className = "menu fixed z-50 rounded-box bg-base-100 shadow max-h-60 overflow-y-auto flex-nowrap hidden";
|
||||||
|
|
||||||
|
const positionList = () => {
|
||||||
|
const rect = input.getBoundingClientRect();
|
||||||
|
list.style.left = `${rect.left}px`;
|
||||||
|
list.style.top = `${rect.bottom + 4}px`;
|
||||||
|
list.style.width = `${rect.width}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Capture phase: a "scroll" event on an inner scroll container (the
|
||||||
|
// overflow-x-auto table wrapper) doesn't bubble up to window in the
|
||||||
|
// normal (bubbling) phase, but every scroll is seen on the way down in
|
||||||
|
// the capture phase, so this still fires no matter which ancestor moved.
|
||||||
|
window.addEventListener("scroll", () => { if (!list.classList.contains("hidden")) positionList(); }, true);
|
||||||
|
window.addEventListener("resize", () => { if (!list.classList.contains("hidden")) positionList(); });
|
||||||
|
|
||||||
select.parentNode.insertBefore(wrapper, select);
|
select.parentNode.insertBefore(wrapper, select);
|
||||||
if (isMultiple) {
|
if (isMultiple) {
|
||||||
@@ -115,7 +135,12 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
highlighted = -1;
|
highlighted = -1;
|
||||||
list.classList.toggle("hidden", matches.length === 0);
|
if (matches.length === 0) {
|
||||||
|
list.classList.add("hidden");
|
||||||
|
} else {
|
||||||
|
positionList();
|
||||||
|
list.classList.remove("hidden");
|
||||||
|
}
|
||||||
return matches;
|
return matches;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -53,10 +53,27 @@
|
|||||||
intrinsic width.
|
intrinsic width.
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
<div class="navbar shrink-0 border-b border-base-300 bg-base-100 px-3 shadow-sm sm:px-6">
|
<div class="navbar shrink-0 border-b border-base-300 bg-base-100 px-3 shadow-sm sm:px-6">
|
||||||
<div class="my-4 min-w-0 flex-1">
|
<div class="my-4 flex min-w-0 flex-1 items-center gap-1">
|
||||||
|
{% comment %}
|
||||||
|
Empty for pages with no menu (the auth screens) -- management/base.html
|
||||||
|
and controlpanel/base.html are the only overriders, each pairing this
|
||||||
|
with its own `{% block mobile_menu %}` dialog below in `main`.
|
||||||
|
{% endcomment %}
|
||||||
|
{% block nav_toggle %}{% endblock nav_toggle %}
|
||||||
|
<div class="min-w-0">
|
||||||
{% block brand %}{% endblock brand %}
|
{% block brand %}{% endblock brand %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
Hidden below `lg` wherever a hamburger drawer exists to hold them instead
|
||||||
|
(management/base.html, controlpanel/base.html override `nav_icons_class` to
|
||||||
|
`hidden lg:flex` and duplicate these same three controls inside their
|
||||||
|
{% block nav_toggle %} dialog) -- on a page with no such drawer (the auth
|
||||||
|
screens, the public club site) the default keeps them in the navbar itself,
|
||||||
|
since there'd be nowhere else for them to go.
|
||||||
|
{% endcomment %}
|
||||||
|
<div class="{% block nav_icons_class %}flex items-center{% endblock nav_icons_class %}">
|
||||||
<button class="btn btn-ghost" type="button" data-theme-toggle aria-label="Theme">
|
<button class="btn btn-ghost" type="button" data-theme-toggle aria-label="Theme">
|
||||||
<span data-theme-icon="light" class="hidden items-center gap-4">{% lucide "sun" size=20 %} <span class="hidden sm:inline">light</span></span>
|
<span data-theme-icon="light" class="hidden items-center gap-4">{% lucide "sun" size=20 %} <span class="hidden sm:inline">light</span></span>
|
||||||
<span data-theme-icon="dark" class="hidden items-center gap-4">{% lucide "moon" size=20 %} <span class="hidden sm:inline">dark</span></span>
|
<span data-theme-icon="dark" class="hidden items-center gap-4">{% lucide "moon" size=20 %} <span class="hidden sm:inline">dark</span></span>
|
||||||
@@ -72,7 +89,10 @@
|
|||||||
{% if user.is_superuser %}
|
{% if user.is_superuser %}
|
||||||
<a class="btn btn-ghost gap-4" href="{% url "admin:index" %}" aria-label="Django admin">{% lucide "shield-cog" %}<span class="hidden sm:inline">Django admin</span></a>
|
<a class="btn btn-ghost gap-4" href="{% url "admin:index" %}" aria-label="Django admin">{% lucide "shield-cog" %}<span class="hidden sm:inline">Django admin</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if user.is_authenticated %}
|
||||||
<div class="dropdown dropdown-end">
|
<div class="dropdown dropdown-end">
|
||||||
<div tabindex="0" role="button" class="btn btn-ghost gap-4" aria-label="Account">{% lucide "circle-user" %}<span class="hidden max-w-40 truncate sm:inline">{{ user.get_full_name }}</span></div>
|
<div tabindex="0" role="button" class="btn btn-ghost gap-4" aria-label="Account">{% lucide "circle-user" %}<span class="hidden max-w-40 truncate sm:inline">{{ user.get_full_name }}</span></div>
|
||||||
<ul tabindex="0" class="menu dropdown-content z-10 mt-2 w-60 rounded-box bg-base-100 p-2 shadow border border-base-content/20">
|
<ul tabindex="0" class="menu dropdown-content z-10 mt-2 w-60 rounded-box bg-base-100 p-2 shadow border border-base-content/20">
|
||||||
|
|||||||
@@ -34,25 +34,26 @@
|
|||||||
{% endblock extra %}
|
{% endblock extra %}
|
||||||
|
|
||||||
{% block brand %}
|
{% block brand %}
|
||||||
<a class="flex flex-row items-center gap-3" href="/">
|
{# min-w-0 on both the link and the text column: without it a flex child's default min-width:auto refuses to shrink past the club name's intrinsic width, so `truncate` never gets the chance to kick in and the name pushes the header wider than the viewport instead of ellipsizing. The avatar and tagline shrink/hide below `sm` for the same reason -- a long club name at full size has nowhere left to give. #}
|
||||||
|
<a class="flex min-w-0 flex-row items-center gap-2 sm:gap-3" href="/">
|
||||||
{% if club.logo %}
|
{% if club.logo %}
|
||||||
{# The ring is the club's own primary colour -- a plain frame around whatever crest they uploaded. #}
|
{# The ring is the club's own primary colour -- a plain frame around whatever crest they uploaded. #}
|
||||||
<div class="avatar">
|
<div class="avatar shrink-0">
|
||||||
<div class="w-16 rounded-full bg-base-100 ring-2 ring-primary ring-offset-2 ring-offset-base-100">
|
<div class="w-10 rounded-full bg-base-100 ring-2 ring-primary ring-offset-2 ring-offset-base-100 sm:w-16">
|
||||||
<img class="club-logo object-contain" src="{{ club.logo.url }}" alt="{{ club.name }}">
|
<img class="club-logo object-contain" src="{{ club.logo.url }}" alt="{{ club.name }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
{# Never the RosterChief mark: that would pass our branding off as the club's own. #}
|
{# Never the RosterChief mark: that would pass our branding off as the club's own. #}
|
||||||
<div class="avatar avatar-placeholder">
|
<div class="avatar avatar-placeholder shrink-0">
|
||||||
<div class="w-16 rounded-full bg-secondary text-secondary-content">
|
<div class="w-10 rounded-full bg-secondary text-secondary-content sm:w-16">
|
||||||
<span class="font-roboto text-xl font-bold">{{ club.initials }}</span>
|
<span class="font-roboto text-sm font-bold sm:text-xl">{{ club.initials }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex min-w-0 flex-col gap-1">
|
||||||
<div class="font-roboto text-2xl font-bold tracking-wider">{{ club.name }}</div>
|
<div class="truncate font-roboto text-lg font-bold tracking-wider sm:text-2xl">{{ club.name }}</div>
|
||||||
<div class="font-mono text-xs font-semibold text-base-content/50">Powered by RosterChief</div>
|
<div class="hidden truncate font-mono text-xs font-semibold text-base-content/50 sm:block">Powered by RosterChief</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{% endblock brand %}
|
{% endblock brand %}
|
||||||
|
|||||||
@@ -25,11 +25,11 @@
|
|||||||
{% endblock extra %}
|
{% endblock extra %}
|
||||||
|
|
||||||
{% block brand %}
|
{% block brand %}
|
||||||
<a class="flex flex-row items-center gap-2" href="/">
|
<a class="flex min-w-0 flex-row items-center gap-2" href="/">
|
||||||
<span class="logo inline-block h-16 w-16" role="img" aria-label="RosterChief"></span>
|
<span class="logo inline-block h-10 w-10 shrink-0 sm:h-16 sm:w-16" role="img" aria-label="RosterChief"></span>
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex min-w-0 flex-col gap-1">
|
||||||
<div class="font-roboto text-2xl font-bold tracking-wider">Roster<span class="text-sky-500">Chief</span></div>
|
<div class="truncate font-roboto text-lg font-bold tracking-wider sm:text-2xl">Roster<span class="text-sky-500">Chief</span></div>
|
||||||
<div class="font-mono text-xs font-semibold text-base-content/50">Club & Team Management</div>
|
<div class="hidden truncate font-mono text-xs font-semibold text-base-content/50 sm:block">Club & Team Management</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{% endblock brand %}
|
{% endblock brand %}
|
||||||
|
|||||||
Reference in New Issue
Block a user