139 lines
7.2 KiB
PHP
139 lines
7.2 KiB
PHP
@php
|
|
$dirs = collect($entries)->where('type', 'dir')->count();
|
|
$files = collect($entries)->where('type', 'file')->count();
|
|
|
|
// Human-readable byte sizes for the mock listing (real values come from SFTP later).
|
|
$fmtSize = function (?int $bytes): string {
|
|
if ($bytes === null) {
|
|
return '—';
|
|
}
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
$i = 0;
|
|
$val = (float) $bytes;
|
|
while ($val >= 1024 && $i < count($units) - 1) {
|
|
$val /= 1024;
|
|
$i++;
|
|
}
|
|
|
|
return ($i === 0 ? (int) $val : number_format($val, 1)).' '.$units[$i];
|
|
};
|
|
@endphp
|
|
|
|
<div class="space-y-4" wire:init="load">
|
|
{{-- Header --}}
|
|
<div class="flex flex-wrap items-end justify-between gap-3">
|
|
<div>
|
|
<p class="font-mono text-[11px] uppercase tracking-[0.2em] text-accent-text">Dateien</p>
|
|
<h2 class="mt-0.5 font-display text-xl font-semibold text-ink sm:text-2xl">Dateien</h2>
|
|
</div>
|
|
<x-status-pill :status="$connected ? 'online' : 'offline'">{{ $connected ? 'SFTP verbunden' : 'nicht verbunden' }}</x-status-pill>
|
|
</div>
|
|
|
|
{{-- Breadcrumb / path --}}
|
|
<x-panel :padded="false">
|
|
<div class="flex flex-wrap items-center gap-x-1 gap-y-1.5 px-4 py-3 sm:px-5">
|
|
<x-icon name="folder" class="mr-1 h-4 w-4 shrink-0 text-ink-3" />
|
|
@foreach ($this->crumbs as $crumb)
|
|
@if (! $loop->first)
|
|
<span class="font-mono text-xs text-ink-4">/</span>
|
|
@endif
|
|
<button type="button" wire:click="go(@js($crumb['path']))" @class([
|
|
'inline-flex min-h-11 min-w-11 items-center justify-center px-2 font-mono text-xs',
|
|
'text-ink-3' => $loop->last,
|
|
'text-accent-text hover:text-accent' => ! $loop->last,
|
|
])>{{ $crumb['label'] }}</button>
|
|
@endforeach
|
|
</div>
|
|
</x-panel>
|
|
|
|
{{-- Listing --}}
|
|
<x-panel :title="$path" :subtitle="$dirs . ' Ordner · ' . $files . ' Dateien'" :padded="false">
|
|
<x-slot:actions>
|
|
<button type="button" class="inline-flex min-h-11 items-center gap-1.5 rounded-md border border-accent/25 bg-accent/10 px-3 py-1.5 text-xs text-accent-text hover:bg-accent/15">
|
|
<x-icon name="plus" class="h-3.5 w-3.5" /> Hochladen
|
|
</button>
|
|
</x-slot:actions>
|
|
|
|
{{-- Column header (desktop only) --}}
|
|
<div class="hidden border-b border-line px-4 py-2 sm:px-5 lg:grid lg:grid-cols-[minmax(0,1fr)_8rem_6rem_11rem_auto] lg:items-center lg:gap-4">
|
|
<span class="font-mono text-[10px] uppercase tracking-wider text-ink-4">Name</span>
|
|
<span class="font-mono text-[10px] uppercase tracking-wider text-ink-4">Rechte</span>
|
|
<span class="text-right font-mono text-[10px] uppercase tracking-wider text-ink-4">Größe</span>
|
|
<span class="font-mono text-[10px] uppercase tracking-wider text-ink-4">Geändert</span>
|
|
<span class="sr-only">Aktionen</span>
|
|
</div>
|
|
|
|
<div class="divide-y divide-line" wire:loading.class="opacity-40" wire:target="load,open,go,up">
|
|
@if (! $ready)
|
|
@for ($i = 0; $i < 8; $i++)
|
|
<div class="flex items-center gap-3 px-4 py-3 sm:px-5">
|
|
<x-skeleton class="h-8 w-8 rounded-sm" />
|
|
<x-skeleton class="h-3 w-48 max-w-full" />
|
|
<x-skeleton class="ml-auto hidden h-3 w-24 lg:block" />
|
|
</div>
|
|
@endfor
|
|
@else
|
|
@foreach ($entries as $e)
|
|
@php $isDir = $e['type'] === 'dir'; @endphp
|
|
<div class="group grid grid-cols-1 gap-x-4 gap-y-2 px-4 py-3 transition-colors hover:bg-raised sm:px-5 lg:grid-cols-[minmax(0,1fr)_8rem_6rem_11rem_auto] lg:items-center">
|
|
{{-- Name + icon (directories look clickable) --}}
|
|
<div class="flex min-w-0 items-center gap-3">
|
|
<span @class([
|
|
'grid h-8 w-8 shrink-0 place-items-center rounded-sm',
|
|
'bg-accent/10 text-accent-text' => $isDir,
|
|
'bg-raised text-ink-3' => ! $isDir,
|
|
])>
|
|
<x-icon :name="$isDir ? 'folder' : 'audit'" class="h-4 w-4" />
|
|
</span>
|
|
|
|
@if ($isDir)
|
|
<button type="button" wire:click="open(@js($e['name']))" class="min-w-0 flex-1 text-left">
|
|
<span class="truncate font-mono text-sm text-ink group-hover:text-accent-text">{{ $e['name'] }}/</span>
|
|
</button>
|
|
@else
|
|
<p class="min-w-0 flex-1 truncate font-mono text-sm text-ink-2">{{ $e['name'] }}</p>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Permissions (hidden on mobile; shown inline below name on tablet+) --}}
|
|
<p class="hidden font-mono text-xs text-ink-3 lg:block">{{ $e['perms'] }}</p>
|
|
|
|
{{-- Size (hidden on mobile) --}}
|
|
<p class="hidden font-mono text-xs text-ink-3 sm:block lg:text-right">{{ $fmtSize($e['size']) }}</p>
|
|
|
|
{{-- Modified --}}
|
|
<p class="hidden font-mono text-xs text-ink-3 sm:block">{{ $e['modified'] }}</p>
|
|
|
|
{{-- Compact meta line for mobile (perms · size · modified) --}}
|
|
<p class="flex flex-wrap items-center gap-x-2 font-mono text-[11px] text-ink-4 sm:hidden">
|
|
<span>{{ $e['perms'] }}</span>
|
|
<span>·</span>
|
|
<span>{{ $fmtSize($e['size']) }}</span>
|
|
<span>·</span>
|
|
<span>{{ $e['modified'] }}</span>
|
|
</p>
|
|
|
|
{{-- Row actions --}}
|
|
<div class="flex shrink-0 items-center gap-1 lg:justify-end">
|
|
@unless ($isDir)
|
|
{{-- R5: wire to wire-elements/modal --}}
|
|
<button type="button" class="inline-flex min-h-11 items-center rounded-sm px-2.5 py-1 font-mono text-[11px] text-ink-2 hover:bg-line hover:text-ink">
|
|
Download
|
|
</button>
|
|
@endunless
|
|
{{-- R5: wire to wire-elements/modal --}}
|
|
<button type="button" class="inline-flex min-h-11 items-center rounded-sm px-2.5 py-1 font-mono text-[11px] text-ink-2 hover:bg-line hover:text-ink">
|
|
Bearbeiten
|
|
</button>
|
|
{{-- R5: destructive → wire-elements/modal confirm + audit --}}
|
|
<button type="button" wire:click="confirmDelete(@js($e['name']))" class="inline-flex min-h-11 items-center rounded-sm px-2.5 py-1 font-mono text-[11px] text-offline hover:bg-offline/10">
|
|
Löschen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
@endif
|
|
</div>
|
|
</x-panel>
|
|
</div>
|