autofocus + more signup logic

This commit is contained in:
Philipp Dormann 2025-03-24 10:26:05 +01:00
parent 2aa8c4178a
commit c3248099c6
Signed by: philipp
GPG Key ID: 3BB9ADD52DCA4314
6 changed files with 155 additions and 48 deletions

View File

@ -24,6 +24,7 @@
"eslint": "^9.18.0",
"eslint-plugin-svelte": "^3.0.0",
"globals": "^16.0.0",
"lucide-svelte": "^0.483.0",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"tailwind-merge": "^3.0.2",

12
pnpm-lock.yaml generated
View File

@ -48,6 +48,9 @@ importers:
globals:
specifier: ^16.0.0
version: 16.0.0
lucide-svelte:
specifier: ^0.483.0
version: 0.483.0(svelte@5.25.2)
svelte:
specifier: ^5.0.0
version: 5.25.2
@ -1002,6 +1005,11 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lucide-svelte@0.483.0:
resolution: {integrity: sha512-MyMgEVLlFfPbyodGpkB+KCpyPkpjI7EKiFw1crA92B1ZXRK5hq5vTsGWAm9Nt3GAKHunoNc5MVsq3EOCz0DZSQ==}
peerDependencies:
svelte: ^3 || ^4 || ^5.0.0-next.42
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
@ -2332,6 +2340,10 @@ snapshots:
lru-cache@10.4.3: {}
lucide-svelte@0.483.0(svelte@5.25.2):
dependencies:
svelte: 5.25.2
magic-string@0.30.17:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0

View File

@ -0,0 +1,35 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive } from "bits-ui";
import Check from "lucide-svelte/icons/check";
import Minus from "lucide-svelte/icons/minus";
import { cn } from "$lib/utils.js";
type $$Props = CheckboxPrimitive.Props;
type $$Events = CheckboxPrimitive.Events;
let className: $$Props["class"] = undefined;
export let checked: $$Props["checked"] = false;
export { className as class };
</script>
<CheckboxPrimitive.Root
class={cn(
"border-primary ring-offset-background focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground peer box-content h-4 w-4 shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
className
)}
bind:checked
{...$$restProps}
on:click
>
<CheckboxPrimitive.Indicator
class={cn("flex h-4 w-4 items-center justify-center text-current")}
let:isChecked
let:isIndeterminate
>
{#if isChecked}
<Check class="h-3.5 w-3.5" />
{:else if isIndeterminate}
<Minus class="h-3.5 w-3.5" />
{/if}
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>

View File

@ -0,0 +1,6 @@
import Root from "./checkbox.svelte";
export {
Root,
//
Root as Checkbox,
};

View File

@ -8,25 +8,26 @@
</script>
<div class="pt-48">
<div class="flex justify-center items-center overflow-hidden">
<form
onsubmit={() => {
loggedin = true;
}}
class="flex justify-center items-center overflow-hidden"
>
<Card.Root class="w-full max-w-sm">
<Card.Header>
<Card.Title class="text-2xl">Login</Card.Title>
<Card.Description
>Please enter kiosk credentials.</Card.Description
>
<Card.Description>Please enter kiosk credentials.</Card.Description>
</Card.Header>
<Card.Content class="grid gap-4">
<div class="grid gap-2">
<Label for="password">Token</Label>
<Input id="password" type="password" required />
<Input id="password" type="password" required autofocus />
</div>
</Card.Content>
<Card.Footer>
<Button class="w-full" on:click={() => (loggedin = true)}
>Sign in</Button
>
<Button class="w-full" type="submit">Sign in</Button>
</Card.Footer>
</Card.Root>
</div>
</form>
</div>

View File

@ -1,6 +1,7 @@
<script lang="ts">
import { Button } from "$lib/components/ui/button/index.js";
import * as Card from "$lib/components/ui/card/index.js";
import Checkbox from "$lib/components/ui/checkbox/checkbox.svelte";
import { Input } from "$lib/components/ui/input";
import { Label } from "$lib/components/ui/label";
import { Progress } from "$lib/components/ui/progress";
@ -21,7 +22,7 @@
progress: 50,
showback: true,
},
SIGNUP_MAIL_ACCEPT: {
SIGNUP_AGB_ACCEPT: {
name: "Accept terms",
progress: 75,
showback: true,
@ -56,6 +57,8 @@
type StepType = (typeof Steps)[keyof typeof Steps];
let currentStep = $state<StepType>(Steps.WELCOME);
let email = $state<string>("");
let firstname = $state<string>("");
let lastname = $state<string>("");
let remainingseconds = $state<number>(5);
// Function to handle automatic return to welcome screen
@ -74,7 +77,7 @@
return null;
}
import { onDestroy } from 'svelte';
import { onDestroy } from "svelte";
// Watch for changes to currentStep
$effect(() => {
@ -102,6 +105,7 @@
{#if currentStep.name == Steps.WELCOME.name}
<div class="grid gap-2">
<Button
autofocus
class="w-full"
on:click={() => {
currentStep = Steps.SIGNUP;
@ -118,42 +122,85 @@
>
</div>
{:else if currentStep.name == Steps.SIGNUP.name}
<form
class="grid gap-2"
onsubmit={() => {
currentStep = Steps.SIGNUP_MAIL;
}}
>
<div class="grid gap-2">
<Label for="firstname">Please enter your first name</Label>
<Input id="firstname" type="text" placeholder="Max" required />
<Input
on:keypress={(event) => {
console.log(event.key);
if (event.key === "Enter") {
document.getElementById("lastname")?.focus();
}
}}
bind:value={firstname}
id="firstname"
type="text"
placeholder="Max"
required
autofocus
/>
</div>
<div class="grid gap-2">
<Label for="lastname">Please enter your last name</Label>
<Input
bind:value={lastname}
id="lastname"
type="text"
placeholder="Mustermann"
required
/>
</div>
<Button
variant="default"
class="w-full"
on:click={() => {
currentStep = Steps.SIGNUP_MAIL;
}}>Continue</Button
<Button type="submit" variant="default" class="w-full"
>Continue</Button
>
</form>
{:else if currentStep.name == Steps.SIGNUP_MAIL.name}
<form
class="grid gap-2"
onsubmit={() => {
currentStep = Steps.SIGNUP_AGB_ACCEPT;
}}
>
<div class="grid gap-2">
<Label for="email"
>Enter your email to get an invitation to our selfservice
(optional)</Label
>
<Input id="email" type="email" placeholder="m@example.com" />
<Input
autofocus
id="email"
type="email"
placeholder="m@example.com"
bind:value={email}
/>
</div>
<Button
variant="default"
class="w-full"
on:click={() => {
currentStep = Steps.SIGNUP_MAIL_ACCEPT;
}}>Continue</Button
<Button type="submit" variant="default" class="w-full"
>Continue</Button
>
{:else if currentStep.name == Steps.SIGNUP_MAIL_ACCEPT.name}
</form>
{:else if currentStep.name == Steps.SIGNUP_AGB_ACCEPT.name}
{#if email !== ""}
By registering, you confirm that {email} is your email
{/if}
<div class="items-top flex space-x-2">
<Checkbox autofocus id="terms1" />
<div class="grid gap-1.5 leading-none">
<Label
for="terms1"
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions
</Label>
<p class="text-muted-foreground text-sm">
You agree to our Terms of Service and Privacy Policy.
</p>
</div>
</div>
<Button
variant="default"
class="w-full"
@ -163,13 +210,15 @@
>
{:else if currentStep.name == Steps.SIGNUP_SUCCESS.name}
<p class="text-center">
Alright that's it, just walk up to the next available person and tell them your name.<br>
Alright that's it, just walk up to the next available person and
tell them your name.<br />
You can scan this qr code to login to our selfservice.
</p>
TODO:
{:else if currentStep.name == Steps.SIGNIN.name}
<div class="grid gap-2">
<Button
autofocus
class="w-full"
on:click={() => {
currentStep = Steps.SIGNIN_BARCODE;
@ -210,7 +259,8 @@
>
</div>
{:else if currentStep.name == Steps.SIGNIN_MAIL_SUCCESS.name}
We found your email address, just walk up to the next available person and tell them your name.
We found your email address, just walk up to the next available person
and tell them your name.
{/if}
</Card.Content>
<Card.Footer class="grid gap-4">
@ -226,6 +276,9 @@
case Steps.SIGNUP_MAIL.name:
currentStep = Steps.SIGNUP;
break;
case Steps.SIGNUP_AGB_ACCEPT.name:
currentStep = Steps.SIGNUP_MAIL;
break;
case Steps.SIGNIN.name:
currentStep = Steps.WELCOME;
break;
@ -246,9 +299,8 @@
variant="default"
class="w-full"
on:click={() => {
currentStep=Steps.WELCOME;
}
}>Done</Button
currentStep = Steps.WELCOME;
}}>Done</Button
>
<p class="text-center">
Returning to the home screen in {remainingseconds} seconds...