|
|
@@ -1,5 +1,72 @@
|
|
|
-<form action="/auth/login" method="POST">
|
|
|
- <input name="username" placeholder="Username" required type="text" />
|
|
|
- <input name="password" placeholder="Password" required type="password" />
|
|
|
- <button type="submit">Login</button>
|
|
|
-</form>
|
|
|
+<script lang="ts">
|
|
|
+ import { enhance } from '$app/forms';
|
|
|
+
|
|
|
+ import logo from '$lib/assets/logo.svg';
|
|
|
+ import { GlassPane } from '$lib/components/common/glass-pane';
|
|
|
+ import { Alert } from '$lib/components/controls/alert';
|
|
|
+ import { Button } from '$lib/components/controls/button';
|
|
|
+ import * as Field from '$lib/components/controls/field';
|
|
|
+ import { Input } from '$lib/components/controls/input';
|
|
|
+
|
|
|
+ import type { ActionData } from './$types';
|
|
|
+
|
|
|
+ let { form }: { form: ActionData } = $props();
|
|
|
+
|
|
|
+ let loading = $state(false);
|
|
|
+</script>
|
|
|
+
|
|
|
+<svelte:head>
|
|
|
+ <title>Sign in - LocoStack</title>
|
|
|
+</svelte:head>
|
|
|
+
|
|
|
+<div class="flex min-h-screen items-center justify-center">
|
|
|
+ <div class="relative w-full max-w-sm">
|
|
|
+ <GlassPane class="px-8 py-10">
|
|
|
+ <!-- Logo mark + name -->
|
|
|
+ <div class="mb-8 flex flex-col items-center">
|
|
|
+ <img class="h-24 w-24" alt="LocoStack" src={logo} />
|
|
|
+ <h1 class="text-xl font-semibold tracking-tight text-white/90">LocoStack</h1>
|
|
|
+ <p class="text-sm text-white/45">Sign in to continue</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Form -->
|
|
|
+ <form
|
|
|
+ class="space-y-4"
|
|
|
+ method="POST"
|
|
|
+ use:enhance={() => {
|
|
|
+ loading = true;
|
|
|
+ return ({ update }) => {
|
|
|
+ loading = false;
|
|
|
+ update();
|
|
|
+ };
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {#if form?.error}
|
|
|
+ <Alert>{form.error}</Alert>
|
|
|
+ {/if}
|
|
|
+
|
|
|
+ <Field.Group>
|
|
|
+ <Field.Field>
|
|
|
+ <Field.Label for="username">Username</Field.Label>
|
|
|
+ <Input id="username" name="username" autocomplete="username" required type="text" />
|
|
|
+ </Field.Field>
|
|
|
+
|
|
|
+ <Field.Field>
|
|
|
+ <Field.Label for="password">Password</Field.Label>
|
|
|
+ <Input
|
|
|
+ id="password"
|
|
|
+ name="password"
|
|
|
+ autocomplete="current-password"
|
|
|
+ required
|
|
|
+ type="password"
|
|
|
+ />
|
|
|
+ </Field.Field>
|
|
|
+ </Field.Group>
|
|
|
+
|
|
|
+ <Button class="mt-2 w-full" disabled={loading} size="lg" type="submit">
|
|
|
+ {loading ? 'Signing in…' : 'Sign in'}
|
|
|
+ </Button>
|
|
|
+ </form>
|
|
|
+ </GlassPane>
|
|
|
+ </div>
|
|
|
+</div>
|