feat(auth): build login page with LoginForm, brand panel, and title

Replaces placeholder with full login page: brand panel left,
LoginForm right, svelte:head title, signup link, no-nav-chrome.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-02 16:21:31 +02:00
parent 73acc0c638
commit 999e54de86
2 changed files with 64 additions and 6 deletions

View File

@@ -1,11 +1,25 @@
<div class="flex min-h-screen">
<div class="hidden md:flex md:w-1/2 bg-[var(--green)] items-center justify-center">
<script lang="ts">
import LoginForm from '$lib/auth/LoginForm.svelte';
let { form } = $props();
</script>
<svelte:head>
<title>Anmelden — Mealprep</title>
</svelte:head>
<!-- Mobile: stacked, Desktop: side by side -->
<div class="flex min-h-screen flex-col md:flex-row">
<div
class="bg-[var(--green)] flex flex-col items-center justify-center
px-6 py-7 text-center
md:w-1/2 md:min-h-screen md:px-10 md:py-12"
>
<span class="font-[var(--font-display)] text-4xl text-white font-medium">Mealprep</span>
</div>
<div class="flex-1 flex items-center justify-center p-6">
<div>
<h1 class="text-2xl font-medium">Anmelden</h1>
<p class="text-[var(--color-text-muted)] mt-2">Login-Formular folgt.</p>
<div class="flex flex-1 flex-col items-start justify-center px-[20px] py-[24px] md:items-center md:px-[56px] md:py-[48px]">
<div class="w-full max-w-[380px]">
<LoginForm {form} />
</div>
</div>
</div>

View File

@@ -0,0 +1,44 @@
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/svelte';
import Page from './+page.svelte';
vi.mock('$app/stores', async () => {
const { readable } = await import('svelte/store');
return {
page: readable({ url: new URL('http://localhost/login') })
};
});
vi.mock('$app/forms', () => ({
enhance: () => ({ destroy: () => {} })
}));
describe('login page', () => {
it('renders the login form', () => {
render(Page);
expect(screen.getByText('Willkommen zurück')).toBeInTheDocument();
});
it('renders the brand panel', () => {
render(Page);
expect(screen.getByText('Mealprep')).toBeInTheDocument();
});
it('sets the page title', () => {
render(Page);
expect(document.title).toBe('Anmelden — Mealprep');
});
it('does not render any navigation chrome', () => {
render(Page);
expect(screen.queryByRole('navigation')).not.toBeInTheDocument();
expect(screen.queryByText('Planer')).not.toBeInTheDocument();
expect(screen.queryByText('Rezepte')).not.toBeInTheDocument();
});
it('renders a link to the signup page', () => {
render(Page);
const link = screen.getByRole('link', { name: /registrieren/i });
expect(link).toHaveAttribute('href', '/signup');
});
});