Add a Competitions card to the control panel's Features page

Competition rows (events.services.competitions' per-club data-source
gate) could previously only be managed through the Django admin.
Adds a card alongside Flags/Switches with create/edit/delete, mirroring
the Flags card's own modal pattern -- no cascading effects to weigh on
delete since Event.competition matches by name, not a foreign key.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
2026-08-20 21:40:13 +02:00
parent 3159064e2a
commit 5889b3740e
6 changed files with 269 additions and 4 deletions

View File

@@ -3497,6 +3497,9 @@
.ml-2 {
margin-left: calc(var(--spacing) * 2);
}
.ml-auto {
margin-left: auto;
}
.status {
@layer daisyui.l1.l2.l3 {
display: inline-block;
@@ -3880,6 +3883,12 @@
.h-48 {
height: calc(var(--spacing) * 48);
}
.h-52 {
height: calc(var(--spacing) * 52);
}
.h-56 {
height: calc(var(--spacing) * 56);
}
.h-72 {
height: calc(var(--spacing) * 72);
}
@@ -3913,9 +3922,15 @@
.h-\[190px\] {
height: 190px;
}
.h-fit {
height: fit-content;
}
.h-full {
height: 100%;
}
.h-max {
height: max-content;
}
.h-px {
height: 1px;
}
@@ -3928,6 +3943,9 @@
.max-h-96 {
max-height: calc(var(--spacing) * 96);
}
.max-h-none {
max-height: none;
}
.min-h-6 {
min-height: calc(var(--spacing) * 6);
}
@@ -4174,6 +4192,9 @@
.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.grid-cols-5 {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
@@ -4317,6 +4338,9 @@
.rounded-md {
border-radius: var(--radius-md);
}
.rounded-none {
border-radius: 0;
}
.rounded-sm {
border-radius: var(--radius-sm);
}
@@ -4339,6 +4363,10 @@
border-top-style: var(--tw-border-style);
border-top-width: 1px;
}
.border-r {
border-right-style: var(--tw-border-style);
border-right-width: 1px;
}
.border-b {
border-bottom-style: var(--tw-border-style);
border-bottom-width: 1px;
@@ -4504,6 +4532,31 @@
--btn-shadow: 0 0 0 0 oklch(0% 0 0/0);
}
}
.btn-soft {
@layer daisyui.l1.l2.l3 {
--btn-bg: var(--btn-color, var(--color-base-content));
@supports (color: color-mix(in lab, red, red)) {
--btn-bg: color-mix(
in oklab,
var(--btn-color, var(--color-base-content)) 8%,
var(--btn-soft-bg, var(--color-base-100))
);
}
color: var(--btn-rest-fg, var(--btn-color, var(--color-base-content)));
--btn-border: var(--btn-color, var(--color-base-content));
@supports (color: color-mix(in lab, red, red)) {
--btn-border: color-mix(
in oklab,
var(--btn-color, var(--color-base-content)) 10%,
var(--btn-soft-bg, var(--color-base-100))
);
}
--btn-border-style: solid;
background-image: none;
--btn-inset: 0 0 0 0 oklch(0% 0 0/0);
--btn-shadow: 0 0 0 0 oklch(0% 0 0/0);
}
}
.btn-ghost {
@layer daisyui.l1.l2.l3 {
--btn-bg: #0000;
@@ -4526,6 +4579,9 @@
.object-cover {
object-fit: cover;
}
.p-0 {
padding: 0;
}
.p-1 {
padding: var(--spacing);
}
@@ -5027,6 +5083,9 @@
.opacity-0 {
opacity: 0%;
}
.opacity-40 {
opacity: 40%;
}
.opacity-50 {
opacity: 50%;
}