Align backend with frontend, make clips end-to-end, polish admin

Backend
- Add ClipSubmission entity + table (runtime bootstrapper) and
  POST /api/public/clips (server-derives platform from the link)
- Surface clip submissions in the admin season detail
- Add DELETE candidate/category/clip endpoints with audit entries

Frontend
- Clips admin: real moderation view (list, open link, delete) instead
  of placeholder; wired clipSubmissions through types/api/store
- Categories admin: add delete with confirm modal (matches Candidates)
- Voting ranking bar uses the unified purple gradient
- Fix ASCII transliterations to proper German umlauts across admin
- Remove orphan AdminView 2.vue

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
AzuTear
2026-06-18 07:53:19 +02:00
parent cca297a4eb
commit 24f9a69022
22 changed files with 504 additions and 145 deletions
+4 -4
View File
@@ -57,7 +57,7 @@ const votingChecklist = computed(() => [
<AdminPageHeader
eyebrow="Voting"
title="Voting-Status und Rankings"
description="Pruefe, ob Kategorien Kandidaten besitzen, ob das Jahr in der richtigen Phase ist und welche Kategorien aktuell die meiste Aktivitaet erzeugen."
description="Prüfe, ob Kategorien Kandidaten besitzen, ob das Jahr in der richtigen Phase ist und welche Kategorien aktuell die meiste Aktivität erzeugen."
:icon="Vote"
/>
@@ -97,7 +97,7 @@ const votingChecklist = computed(() => [
<strong class="text-violet-800">{{ category.votes.toLocaleString('de-DE') }}</strong>
</div>
<div class="mt-3 h-3 overflow-hidden rounded-full bg-violet-50">
<div class="h-full rounded-full bg-[linear-gradient(90deg,#a78bfa,#f5a9d6)]" :style="{ width: `${(category.votes / maxVotes) * 100}%` }" />
<div class="h-full rounded-full bg-gradient-to-r from-[#c4b5fd] to-[#7c5cff]" :style="{ width: `${(category.votes / maxVotes) * 100}%` }" />
</div>
</div>
<p v-if="store.admin.topCategories.length === 0" class="rounded-2xl border border-dashed border-violet-100 px-5 py-8 text-center text-sm text-slate-500">
@@ -118,7 +118,7 @@ const votingChecklist = computed(() => [
<p class="mt-1 truncate text-sm text-slate-500">{{ category.groupName }} · {{ category.candidateCount }} Kandidaten</p>
</div>
<span class="h-fit rounded-full border px-3 py-1 text-xs font-semibold" :class="category.ready ? 'border-emerald-100 bg-emerald-50 text-emerald-700' : 'border-amber-100 bg-amber-50 text-amber-700'">
{{ category.ready ? 'bereit' : 'pruefen' }}
{{ category.ready ? 'bereit' : 'prüfen' }}
</span>
</div>
</div>
@@ -142,7 +142,7 @@ const votingChecklist = computed(() => [
<p class="mt-1 text-sm leading-5 text-slate-500">{{ item.note }}</p>
</div>
<span class="rounded-full px-3 py-1 text-xs font-semibold" :class="item.done ? 'bg-emerald-100 text-emerald-700' : 'bg-amber-100 text-amber-700'">
{{ item.done ? 'ok' : 'pruefen' }}
{{ item.done ? 'ok' : 'prüfen' }}
</span>
</div>
</RouterLink>