feat(auth): session-expired banner + autofocus + 44px touch target on login
- Amber aria-live banner when ?reason=expired (set by hooks.server.ts after the backend rejects an expired fa_session) with a one-line explainer about the 8h idle window. - autofocus on email so users returning after a session-expired kick can immediately retype credentials. - min-h-[44px] on the submit button hits the iOS HIG / WCAG 2.1 AAA touch target minimum — relevant for the reader cohort on phones. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,10 @@ import AuthHeader from '../AuthHeader.svelte';
|
|||||||
let {
|
let {
|
||||||
data,
|
data,
|
||||||
form
|
form
|
||||||
}: { data: { registered: boolean }; form?: { error?: string; success?: boolean } } = $props();
|
}: {
|
||||||
|
data: { registered: boolean; reason?: string | null };
|
||||||
|
form?: { error?: string; success?: boolean };
|
||||||
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@@ -38,6 +41,17 @@ let {
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if data.reason === 'expired'}
|
||||||
|
<div
|
||||||
|
role="status"
|
||||||
|
aria-live="polite"
|
||||||
|
class="mb-5 rounded-sm border border-amber-200 bg-amber-50 px-4 py-3 font-sans"
|
||||||
|
>
|
||||||
|
<p class="text-xs font-medium text-amber-900">{m.error_session_expired()}</p>
|
||||||
|
<p class="mt-1 text-xs text-amber-800">{m.error_session_expired_explainer()}</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<h1 class="mb-6 font-sans text-sm font-bold tracking-widest text-ink uppercase">
|
<h1 class="mb-6 font-sans text-sm font-bold tracking-widest text-ink uppercase">
|
||||||
{m.login_heading()}
|
{m.login_heading()}
|
||||||
</h1>
|
</h1>
|
||||||
@@ -49,11 +63,13 @@ let {
|
|||||||
class="mb-1.5 block font-sans text-xs font-bold tracking-widest text-ink-2 uppercase"
|
class="mb-1.5 block font-sans text-xs font-bold tracking-widest text-ink-2 uppercase"
|
||||||
>{m.login_label_email()}</label
|
>{m.login_label_email()}</label
|
||||||
>
|
>
|
||||||
|
<!-- svelte-ignore a11y_autofocus -->
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
name="email"
|
name="email"
|
||||||
id="email"
|
id="email"
|
||||||
required
|
required
|
||||||
|
autofocus
|
||||||
autocomplete="email"
|
autocomplete="email"
|
||||||
class="block w-full border border-line px-3 py-2.5 font-serif text-sm text-ink placeholder-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
class="block w-full border border-line px-3 py-2.5 font-serif text-sm text-ink placeholder-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
||||||
/>
|
/>
|
||||||
@@ -81,7 +97,7 @@ let {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="mt-2 w-full bg-primary py-2.5 font-sans text-xs font-bold tracking-widest text-primary-fg uppercase transition-colors hover:bg-primary/90"
|
class="mt-2 min-h-[44px] w-full bg-primary py-2.5 font-sans text-xs font-bold tracking-widest text-primary-fg uppercase transition-colors hover:bg-primary/90"
|
||||||
>
|
>
|
||||||
{m.login_btn_submit()}
|
{m.login_btn_submit()}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user