add login page with contained inputs

This commit is contained in:
Justin Edmund 2025-11-30 22:26:32 -08:00
parent 762d5c0fc0
commit fd10dcfb15
2 changed files with 128 additions and 0 deletions

View file

@ -0,0 +1,34 @@
import type { Actions, PageServerLoad } from './$types'
import { fail, redirect } from '@sveltejs/kit'
export const load: PageServerLoad = async ({ locals, url }) => {
if (locals.session.isAuthenticated) {
redirect(302, url.searchParams.get('next') ?? '/me')
}
return {}
}
export const actions: Actions = {
default: async ({ request, fetch, url }) => {
const form = await request.formData()
const email = String(form.get('email') ?? '')
const password = String(form.get('password') ?? '')
if (!email || !password) {
return fail(400, { error: 'Email and password are required', email })
}
const res = await fetch('/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password, grant_type: 'password' })
})
if (res.ok) {
redirect(303, url.searchParams.get('next') ?? '/me')
}
const j = await res.json().catch(() => ({}))
return fail(res.status, { error: j.error ?? 'Login failed', email })
}
}

View file

@ -0,0 +1,94 @@
<script lang="ts">
import { enhance } from '$app/forms'
import AuthCard from '$lib/components/auth/AuthCard.svelte'
import Input from '$lib/components/ui/Input.svelte'
import Button from '$lib/components/ui/Button.svelte'
import * as m from '$lib/paraglide/messages'
interface Props {
form: { error?: string; email?: string } | null
}
let { form }: Props = $props()
let email = $state(form?.email ?? '')
let password = $state('')
let isSubmitting = $state(false)
</script>
<svelte:head>
<title>{m.auth_login_title()} | Granblue Party</title>
</svelte:head>
<AuthCard title={m.auth_login_title()}>
<form
method="post"
use:enhance={() => {
isSubmitting = true
return async ({ update }) => {
isSubmitting = false
await update()
}
}}
>
<Input
type="email"
name="email"
label={m.auth_login_email()}
bind:value={email}
autocomplete="email"
required
fullWidth
contained
/>
<Input
type="password"
name="password"
label={m.auth_login_password()}
bind:value={password}
autocomplete="current-password"
minlength={8}
required
fullWidth
contained
/>
{#if form?.error}
<p class="error">{form.error}</p>
{/if}
<Button type="submit" variant="primary" fullWidth disabled={isSubmitting}>
{isSubmitting ? m.auth_login_submitting() : m.auth_login_submit()}
</Button>
</form>
{#snippet footer()}
<p>
{m.auth_login_noAccount()}
<a href="/auth/register">{m.auth_login_register()}</a>
</p>
{/snippet}
</AuthCard>
<style lang="scss">
@use '$src/themes/spacing' as *;
@use '$src/themes/colors' as *;
@use '$src/themes/typography' as *;
form {
display: flex;
flex-direction: column;
gap: $unit-2x;
}
.error {
color: $error;
font-size: $font-small;
text-align: center;
margin: 0;
padding: $unit $unit-2x;
background: var(--danger-bg);
border-radius: $unit;
}
</style>