intelidomWebsite/src/routes/admin/+page.svelte

228 lines
4.3 KiB
Svelte

<script lang="ts">
import { enhance } from '$app/forms';
import type { PageData, ActionData } from './$types';
let { data, form }: { data: PageData; form: ActionData } = $props();
let uploading = $state(false);
let fileInput: HTMLInputElement | undefined = $state();
</script>
<svelte:head>
<title>Admin — InteliDom d.o.o.</title>
<meta name="robots" content="noindex" />
</svelte:head>
<section class="admin">
<div class="bar">
<h1>Admin</h1>
<div class="bar-right">
{#if data.user}<span>Prijavljeni kot <strong>{data.user.name}</strong></span>{/if}
<form method="POST" action="?/logout" use:enhance>
<button class="ghost" type="submit">Odjava</button>
</form>
</div>
</div>
<form
class="card upload"
method="POST"
action="?/upload"
enctype="multipart/form-data"
use:enhance={() => {
uploading = true;
return async ({ update }) => {
await update();
uploading = false;
if (fileInput) fileInput.value = '';
};
}}
>
<h2>Dodaj sliko v galerijo</h2>
<input bind:this={fileInput} type="file" name="images" accept="image/*" multiple required />
<label>
Opis (neobvezno)
<input type="text" name="caption" placeholder="npr. Montaža omarice" />
</label>
{#if form?.error}<p class="error">{form.error}</p>{/if}
{#if form?.success}<p class="msg">{form.success}</p>{/if}
<button type="submit" disabled={uploading}>{uploading ? 'Nalaganje…' : 'Naloži'}</button>
</form>
<h2 class="section-title">Slike v galeriji</h2>
{#if data.images.length === 0}
<p class="notice">Ni slik. Naložite prvo zgoraj.</p>
{:else}
<div class="grid">
{#each data.images as image (image.id)}
<div class="tile">
<img src={image.url} alt={image.caption ?? ''} loading="lazy" />
{#if image.caption}<span class="cap">{image.caption}</span>{/if}
<form method="POST" action="?/delete" use:enhance>
<input type="hidden" name="id" value={image.id} />
<button class="del" type="submit" aria-label="Izbriši">Izbriši</button>
</form>
</div>
{/each}
</div>
{/if}
</section>
<style>
.admin {
width: 100%;
max-width: 900px;
margin: 0 auto;
padding: 0 1em 3em;
display: flex;
flex-direction: column;
gap: 1.2em;
}
h1 {
margin: 0;
font-weight: 600;
}
h2 {
margin: 0 0 0.3em;
font-weight: 600;
font-size: 1.1em;
}
.notice {
color: #9aa0a6;
}
.bar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1em;
flex-wrap: wrap;
color: #c7c9cf;
}
.bar-right {
display: flex;
align-items: center;
gap: 1em;
}
.card {
background: #11161a;
border: 1px solid rgba(229, 228, 234, 0.12);
border-radius: 12px;
padding: 1.4em;
display: flex;
flex-direction: column;
gap: 0.9em;
}
label {
display: flex;
flex-direction: column;
gap: 0.35em;
font-size: 0.9em;
color: #c7c9cf;
}
input[type='text'] {
background: #0a0d0f;
border: 1px solid rgba(229, 228, 234, 0.2);
border-radius: 8px;
padding: 0.6em 0.7em;
color: #e5e4ea;
font-family: inherit;
font-size: 1em;
}
input[type='file'] {
color: #c7c9cf;
font-family: inherit;
}
button {
background: #42af38;
color: #06210a;
border: none;
border-radius: 8px;
padding: 0.6em 1.1em;
font-weight: 600;
font-family: inherit;
font-size: 1em;
cursor: pointer;
align-self: flex-start;
}
button:disabled {
opacity: 0.6;
cursor: default;
}
button.ghost {
background: transparent;
color: #e5e4ea;
border: 1px solid rgba(229, 228, 234, 0.3);
}
.section-title {
margin-top: 0.5em;
}
.error {
color: #ff6b6b;
margin: 0;
font-size: 0.9em;
}
.msg {
color: #42af38;
margin: 0;
font-size: 0.9em;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 1em;
}
.tile {
position: relative;
border-radius: 10px;
overflow: hidden;
background: #11161a;
aspect-ratio: 4 / 3;
}
.tile img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.tile .cap {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 0.5em 0.6em;
font-size: 0.8em;
color: #fff;
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0));
}
.tile .del {
position: absolute;
top: 0.5em;
right: 0.5em;
background: rgba(220, 40, 40, 0.9);
color: #fff;
padding: 0.3em 0.6em;
font-size: 0.8em;
border-radius: 6px;
}
</style>