Move the navigation into a floating toolbar at the bottom

The top app bar repeated the site's name, which already heads the upload
and download pages, and spread its actions to the window's far edge. A
floating toolbar centred above the bottom edge, as wide as its buttons,
now holds them: Upload and the admin pages with the current one filled,
and the account menu; guests get Upload, the theme toggle and Log in,
without tooltips. On a phone the sign-in card no longer stretches to the
full height, and the admin dashboard's empty state sits outside the
scrolling table.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
This commit is contained in:
Andreas Reinhold / reini
2026-09-13 11:12:12 +02:00
co-authored by Claude Opus 5
parent 2a363defd1
commit accbc17c1c
8 changed files with 161 additions and 98 deletions
@@ -11,51 +11,50 @@
</div>
<x-card :title="__('All Shares')" variant="outlined">
<div class="-mx-4 overflow-x-auto">
<x-table>
<thead>
<tr>
<x-sort-header column="token" :sort-by="$sortBy">{{ __('Token') }}</x-sort-header>
<x-sort-header column="files_count" :sort-by="$sortBy" class="text-end">{{ __('Files') }}</x-sort-header>
<x-sort-header column="total_size" :sort-by="$sortBy" class="text-end">{{ __('Size') }}</x-sort-header>
<x-sort-header column="download_count" :sort-by="$sortBy" class="text-end">{{ __('Downloads') }}</x-sort-header>
<x-sort-header column="expires_at" :sort-by="$sortBy">{{ __('Expires') }}</x-sort-header>
<x-sort-header column="created_at" :sort-by="$sortBy">{{ __('Created') }}</x-sort-header>
<th><span class="sr-only">{{ __('Actions') }}</span></th>
</tr>
</thead>
<tbody>
@forelse ($shares as $share)
<tr wire:key="share-{{ $share->id }}">
<td class="font-mono">{{ $share->token }}</td>
<td class="text-end tabular-nums">{{ $share->files_count }}</td>
<td class="text-end tabular-nums whitespace-nowrap">{{ Number::fileSize($share->total_size) }}</td>
<td class="text-end tabular-nums">{{ $share->download_count }}</td>
<td class="whitespace-nowrap">
@if ($share->expires_at)
<span @class(['text-error' => $share->isExpired()])>{{ $share->expires_at->diffForHumans() }}</span>
@else
<span class="text-on-surface-variant">{{ __('Never') }}</span>
@endif
</td>
<td class="whitespace-nowrap">{{ $share->created_at->diffForHumans() }}</td>
<td class="text-end whitespace-nowrap">
<x-button icon="open_in_new" :tooltip="__('Open')" :link="route('share.download', $share)" external />
<x-button icon="delete" :tooltip="__('Delete')" color="error" wire:click="$set('deletingShareId', {{ $share->id }})" data-test="delete-share-{{ $share->id }}" />
</td>
</tr>
@empty
{{-- Outside the table, so it stays centred on a phone instead of scrolling with the columns. --}}
@if ($shares->total() === 0)
<x-empty-state icon="link_off" :title="__('No shares yet')" :description="__('Shares appear here once someone uploads files.')" />
@else
<div class="-mx-4 overflow-x-auto">
<x-table>
<thead>
<tr>
<td colspan="7">
<x-empty-state icon="link_off" :title="__('No shares yet')" :description="__('Shares appear here once someone uploads files.')" />
</td>
<x-sort-header column="token" :sort-by="$sortBy">{{ __('Token') }}</x-sort-header>
<x-sort-header column="files_count" :sort-by="$sortBy" class="text-end">{{ __('Files') }}</x-sort-header>
<x-sort-header column="total_size" :sort-by="$sortBy" class="text-end">{{ __('Size') }}</x-sort-header>
<x-sort-header column="download_count" :sort-by="$sortBy" class="text-end">{{ __('Downloads') }}</x-sort-header>
<x-sort-header column="expires_at" :sort-by="$sortBy">{{ __('Expires') }}</x-sort-header>
<x-sort-header column="created_at" :sort-by="$sortBy">{{ __('Created') }}</x-sort-header>
<th><span class="sr-only">{{ __('Actions') }}</span></th>
</tr>
@endforelse
</tbody>
</x-table>
</div>
</thead>
<tbody>
@foreach ($shares as $share)
<tr wire:key="share-{{ $share->id }}">
<td class="font-mono">{{ $share->token }}</td>
<td class="text-end tabular-nums">{{ $share->files_count }}</td>
<td class="text-end tabular-nums whitespace-nowrap">{{ Number::fileSize($share->total_size) }}</td>
<td class="text-end tabular-nums">{{ $share->download_count }}</td>
<td class="whitespace-nowrap">
@if ($share->expires_at)
<span @class(['text-error' => $share->isExpired()])>{{ $share->expires_at->diffForHumans() }}</span>
@else
<span class="text-on-surface-variant">{{ __('Never') }}</span>
@endif
</td>
<td class="whitespace-nowrap">{{ $share->created_at->diffForHumans() }}</td>
<td class="text-end whitespace-nowrap">
<x-button icon="open_in_new" :tooltip="__('Open')" :link="route('share.download', $share)" external />
<x-button icon="delete" :tooltip="__('Delete')" color="error" wire:click="$set('deletingShareId', {{ $share->id }})" data-test="delete-share-{{ $share->id }}" />
</td>
</tr>
@endforeach
</tbody>
</x-table>
</div>
<div class="mt-4">{{ $shares->links() }}</div>
<div class="mt-4">{{ $shares->links() }}</div>
@endif
</x-card>
<x-modal wire:model="deletingShareId" :title="__('Delete this share?')" icon="delete">