Files
loft/frontend/src/lib/components/FileRow.svelte

168 lines
6.4 KiB
Svelte

<script lang="ts">
import type { FileRecord } from '$lib/types';
import { formatName, formatSize } from '$lib/format';
let {
file,
selected,
onselect,
onpreview,
ondownload,
ondelete
}: {
file: FileRecord;
selected: boolean;
onselect: () => void;
onpreview: () => void;
ondownload: () => void;
ondelete: () => void;
} = $props();
let confirming = $state(false);
</script>
<div
role="button"
tabindex="0"
onkeydown={(e) => {
if (e.key === 'Enter') {
onpreview();
} else if (e.key === ' ') {
e.preventDefault();
onselect();
}
}}
onclick={onselect}
ondblclick={onpreview}
class="flex items-stretch border-l transition-all hover:bg-white/2 {selected
? 'border-sky-400/50 bg-white/2 ring-1 ring-sky-400/50 ring-inset'
: 'border-sky-200/20 border-l-transparent hover:border-l-sky-400/50'}"
>
<span class="flex-1 truncate py-2 pl-6 text-sm font-medium text-white"
>{formatName(file.name)}</span
>
<span class="w-40 py-2 text-sm text-white/40">{formatSize(file.size)}</span>
<span class="w-48 py-2 text-sm text-white/40">{new Date(file.uploadedAt).toLocaleString()}</span
>
<div class="w-px self-stretch bg-sky-200/20"></div>
<div class="relative flex w-32 items-center justify-center gap-4">
<!-- Download -->
<button
class="cursor-pointer text-white/40 transition-all hover:scale-110 hover:text-emerald-400"
title="Download"
onclick={ondownload}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="7 10 12 15 17 10" />
<line x1="12" y1="15" x2="12" y2="3" />
</svg>
</button>
<!-- TODO: Copy -->
<button
class="cursor-pointer text-white/40 transition-all hover:scale-110 hover:text-blue-400"
title="Copy link"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
</svg>
</button>
<!-- Delete -->
<div class="relative">
<button
class="cursor-pointer text-white/40 transition-all hover:scale-110 hover:text-red-400"
title="Delete"
onclick={() => (confirming = true)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="3 6 5 6 21 6" />
<path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
<path d="M10 11v6" />
<path d="M14 11v6" />
<path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
</svg>
</button>
{#if confirming}
<div class="absolute top-1/2 left-6 z-10 flex -translate-y-1/2 items-center">
<div
class="h-0 w-0 border-t-4 border-r-4 border-b-4 border-t-transparent border-r-sky-200/20 border-b-transparent"
></div>
<div
class="flex items-center gap-2 rounded border border-sky-200/20 bg-[#0f1117] px-3 py-2 whitespace-nowrap"
>
<span class="text-xs text-white/40">Confirm action</span>
<button
class="cursor-pointer text-white/60 transition-colors hover:text-white"
title="Confirm"
onclick={() => {
ondelete();
confirming = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="20 6 9 17 4 12" />
</svg>
</button>
<button
class="cursor-pointer text-white/60 transition-colors hover:text-white"
title="Cancel"
onclick={() => (confirming = false)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</button>
</div>
</div>
{/if}
</div>
</div>
</div>