Refactor dashboard and upload flows

Remove dead admin UI code, redesign dashboard followers/following and upload experiences, and add schema audit tooling with repair migrations for forum and upload drift.
This commit is contained in:
2026-03-21 11:02:22 +01:00
parent 29c3ff8572
commit 979e011257
55 changed files with 2576 additions and 1923 deletions

View File

@@ -0,0 +1,68 @@
@props([
'name',
'value' => null,
'options' => [],
])
<div
x-data="{
open: false,
value: @js((string) ($value ?? '')),
options: @js(collect($options)->map(fn ($option) => [
'value' => (string) ($option['value'] ?? ''),
'label' => (string) ($option['label'] ?? ''),
])->values()->all()),
labelFor(selectedValue) {
const match = this.options.find((option) => option.value === selectedValue)
return match ? match.label : (this.options[0]?.label ?? '')
},
select(nextValue) {
this.value = nextValue
this.open = false
},
}"
class="relative"
@click.outside="open = false"
@keydown.escape.window="open = false"
>
<input type="hidden" name="{{ $name }}" x-model="value">
<button
type="button"
@click="open = !open"
class="flex w-full items-center justify-between gap-3 rounded-xl border border-white/[0.08] bg-black/20 px-4 py-3 text-left text-sm text-white transition-colors hover:border-white/[0.14] focus:border-sky-400/40 focus:outline-none"
:aria-expanded="open.toString()"
>
<span class="truncate" x-text="labelFor(value)"></span>
<i class="fa-solid fa-chevron-down text-xs text-white/40 transition-transform" :class="open ? 'rotate-180' : ''"></i>
</button>
<div
x-cloak
x-show="open"
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0 -translate-y-1"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-in duration-100"
x-transition:leave-start="opacity-100 translate-y-0"
x-transition:leave-end="opacity-0 -translate-y-1"
class="absolute left-0 right-0 z-50 mt-2 overflow-hidden rounded-2xl border border-white/[0.08] bg-slate-950/95 shadow-[0_24px_70px_rgba(0,0,0,0.45)] backdrop-blur"
style="display: none;"
>
<div class="p-2">
<template x-for="option in options" :key="option.value">
<button
type="button"
@click="select(option.value)"
class="flex w-full items-center justify-between rounded-xl px-3 py-2.5 text-left text-sm transition-colors"
:class="value === option.value
? 'bg-sky-400/20 text-white'
: 'text-white/75 hover:bg-white/[0.06] hover:text-white'"
>
<span x-text="option.label"></span>
<i x-show="value === option.value" class="fa-solid fa-check text-xs text-sky-200"></i>
</button>
</template>
</div>
</div>
</div>