Improve live recordings UI, upload flow, and default Flux theme.

Refresh list status over Reverb with polling fallback, clarify queued vs processing, streamline upload empty states, and seed an admin login.
This commit is contained in:
ben
2026-08-12 20:14:35 +02:00
parent 148ba91816
commit c17f8fb506
28 changed files with 523 additions and 333 deletions
@@ -1,28 +1,59 @@
<div
class="max-w-2xl space-y-6 rounded border border-stone-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-800"
x-data="{ uploading: false, progress: 0 }"
class="max-w-2xl space-y-6 rounded-lg border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-800"
x-data="{
uploading: false,
progress: 0,
dragging: false,
openPicker() {
this.$refs.fileInput.click();
},
onDrop(event) {
this.dragging = false;
const files = event.dataTransfer?.files;
if (! files?.length) {
return;
}
const transfer = new DataTransfer();
Array.from(files).forEach((file) => transfer.items.add(file));
this.$refs.fileInput.files = transfer.files;
this.$refs.fileInput.dispatchEvent(new Event('change', { bubbles: true }));
},
}"
x-on:livewire-upload-start="uploading = true; progress = 0"
x-on:livewire-upload-finish="uploading = false; progress = 100"
x-on:livewire-upload-cancel="uploading = false"
x-on:livewire-upload-error="uploading = false"
x-on:livewire-upload-progress="progress = $event.detail.progress"
>
<flux:input
wire:model="title"
label="Title (optional)"
description="Used when you upload a single file. Leave blank to use embedded title or filename."
placeholder="Leave blank to use embedded title or filename"
/>
<div>
<flux:label>Audio files</flux:label>
<input
x-ref="fileInput"
type="file"
class="sr-only"
wire:model="audio"
multiple
accept=".mp3,.wav,.ogg,.oga,.flac,.m4a,.mp4,.aac,.webm,.wma,.aiff,.aif,audio/*"
>
<div
wire:drop.file="$upload('audio', { multiple: true, accept: '.mp3,.wav,.ogg,.oga,.flac,.m4a,.mp4,.aac,.webm,.wma,.aiff,.aif,audio/*' })"
wire:click="$upload('audio', { multiple: true, accept: '.mp3,.wav,.ogg,.oga,.flac,.m4a,.mp4,.aac,.webm,.wma,.aiff,.aif,audio/*' })"
role="button"
tabindex="0"
wire:keydown.enter="$upload('audio', { multiple: true, accept: '.mp3,.wav,.ogg,.oga,.flac,.m4a,.mp4,.aac,.webm,.wma,.aiff,.aif,audio/*' })"
class="mt-2 flex cursor-pointer flex-col items-center justify-center rounded-lg border border-dashed border-zinc-300 bg-zinc-50 px-6 py-10 text-center transition-colors data-dragging:border-accent data-dragging:bg-accent/5 dark:border-white/20 dark:bg-white/5 dark:data-dragging:border-accent dark:data-dragging:bg-accent/10"
x-on:click="openPicker()"
x-on:keydown.enter.prevent="openPicker()"
x-on:keydown.space.prevent="openPicker()"
x-on:dragenter.prevent="dragging = true"
x-on:dragover.prevent="dragging = true"
x-on:dragleave.prevent="dragging = false"
x-on:drop.prevent="onDrop($event)"
x-bind:class="dragging ? 'border-accent bg-accent/5 dark:border-accent dark:bg-accent/10' : 'border-zinc-300 bg-zinc-50 dark:border-white/20 dark:bg-white/5'"
class="mt-2 flex cursor-pointer flex-col items-center justify-center rounded-lg border border-dashed px-6 py-10 text-center transition-colors"
>
<div class="mb-3 flex size-12 items-center justify-center rounded-full bg-white shadow-sm ring-1 ring-zinc-200 dark:bg-zinc-800 dark:ring-white/10">
<flux:icon.cloud-arrow-up class="size-6 text-zinc-500 dark:text-zinc-400" />
@@ -57,11 +88,9 @@
@enderror
</div>
<flux:text class="text-sm text-zinc-500 dark:text-zinc-400">
Uploads start as soon as you drop or choose files. Duplicate files (same name and size, or identical content) are skipped.
</flux:text>
<div class="flex items-center gap-3">
<flux:link href="{{ route('recordings.index') }}">Cancel</flux:link>
</div>
@if ($showCancel)
<div class="flex items-center gap-3">
<flux:link href="{{ route('recordings.index') }}" wire:navigate>Cancel</flux:link>
</div>
@endif
</div>