Compare commits
13 Commits
625c0c3ed2
...
rebuild
| Author | SHA1 | Date | |
|---|---|---|---|
|
fac25ca67b
|
|||
|
d11f22f5f8
|
|||
|
42f2a5ba21
|
|||
|
31cd1a61ad
|
|||
|
9f63e3a77a
|
|||
|
4c5499d050
|
|||
|
497a108647
|
|||
|
38e6c145e2
|
|||
|
828cc0547e
|
|||
|
c3248099c6
|
|||
|
2aa8c4178a
|
|||
|
52b8db4a5a
|
|||
|
012a0043b3
|
@@ -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
12
pnpm-lock.yaml
generated
@@ -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
|
||||
|
||||
65
src/app.css
65
src/app.css
@@ -6,73 +6,44 @@
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
--primary: 221.2 83.2% 53.3%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 72.2% 50.6%;
|
||||
--destructive: 0 72.22% 50.59%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 222.2 84% 4.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--ring: 221.2 83.2% 53.3%;
|
||||
--radius: 0.75rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
--primary: 217.2 91.2% 59.8%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 224.3 76.3% 48%;
|
||||
}
|
||||
}
|
||||
35
src/lib/components/ui/checkbox/checkbox.svelte
Normal file
35
src/lib/components/ui/checkbox/checkbox.svelte
Normal 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>
|
||||
6
src/lib/components/ui/checkbox/index.ts
Normal file
6
src/lib/components/ui/checkbox/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import Root from "./checkbox.svelte";
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Checkbox,
|
||||
};
|
||||
@@ -8,30 +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 credentials for an account that is allowed to create
|
||||
runners and their selfservice links.</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="email">Email</Label>
|
||||
<Input id="email" type="email" placeholder="m@example.com" required />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="password">Password</Label>
|
||||
<Input id="password" type="password" required />
|
||||
<Label for="password">Token</Label>
|
||||
<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>
|
||||
|
||||
BIN
src/routes/(components)/sampleqrlfkselfservice.png
Normal file
BIN
src/routes/(components)/sampleqrlfkselfservice.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 787 B |
@@ -1,39 +1,62 @@
|
||||
<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";
|
||||
import sampleQR from "./sampleqrlfkselfservice.png";
|
||||
|
||||
const Steps = {
|
||||
WELCOME: {
|
||||
name: "Welcome",
|
||||
progress: 0,
|
||||
showback: false,
|
||||
},
|
||||
SIGNUP: {
|
||||
name: "Signup",
|
||||
progress: 25,
|
||||
showback: true,
|
||||
},
|
||||
SIGNUP_MAIL: {
|
||||
name: "Signup with Mail",
|
||||
progress: 50,
|
||||
showback: true,
|
||||
},
|
||||
SIGNUP_AGB_ACCEPT: {
|
||||
name: "Accept terms",
|
||||
progress: 75,
|
||||
showback: true,
|
||||
},
|
||||
SIGNUP_SUCCESS: {
|
||||
name: "Done",
|
||||
progress: 100,
|
||||
showback: false,
|
||||
},
|
||||
SIGNIN: {
|
||||
name: "Signin",
|
||||
progress: 50,
|
||||
},
|
||||
SIGNIN_BARCODE: {
|
||||
name: "Signin with Barcode",
|
||||
progress: 100,
|
||||
showback: false,
|
||||
},
|
||||
SIGNIN_MAIL: {
|
||||
name: "Signin by Mail",
|
||||
progress: 75,
|
||||
showback: true,
|
||||
},
|
||||
SIGNIN_MAIL_SUCCESS: {
|
||||
name: "Signin by Mail Success",
|
||||
progress: 100,
|
||||
showback: false,
|
||||
},
|
||||
} as const;
|
||||
|
||||
type StepType = (typeof Steps)[keyof typeof Steps];
|
||||
let currentStep = $state<StepType>(Steps.WELCOME);
|
||||
let agbAgreed = $state<boolean>(false);
|
||||
let email = $state<string>("");
|
||||
let firstname = $state<string>("");
|
||||
let lastname = $state<string>("");
|
||||
let remainingseconds = $state<number>(5);
|
||||
</script>
|
||||
|
||||
<div class="pt-48">
|
||||
@@ -44,12 +67,15 @@
|
||||
<Card.Description
|
||||
>Let me guide you through the signup process.</Card.Description
|
||||
>
|
||||
<Progress value={currentStep.progress} />
|
||||
{#if currentStep.name !== Steps.WELCOME.name}
|
||||
<Progress value={currentStep.progress} />
|
||||
{/if}
|
||||
</Card.Header>
|
||||
<Card.Content class="grid gap-4">
|
||||
{#if currentStep.name == Steps.WELCOME.name}
|
||||
<div class="grid gap-2">
|
||||
<Button
|
||||
autofocus
|
||||
class="w-full"
|
||||
on:click={() => {
|
||||
currentStep = Steps.SIGNUP;
|
||||
@@ -66,53 +92,102 @@
|
||||
>
|
||||
</div>
|
||||
{:else if currentStep.name == Steps.SIGNUP.name}
|
||||
<div class="grid gap-2">
|
||||
<Label for="firstname">Please enter your first name</Label>
|
||||
<Input id="firstname" type="text" placeholder="Max" required />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="lastname">Please enter your last name</Label>
|
||||
<Input
|
||||
id="lastname"
|
||||
type="text"
|
||||
placeholder="Mustermann"
|
||||
required
|
||||
/>
|
||||
<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
|
||||
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 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
|
||||
autofocus
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
bind:value={email}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" variant="default" class="w-full"
|
||||
>Continue</Button
|
||||
>
|
||||
</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 bind:checked={agbAgreed} 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
|
||||
disabled={!agbAgreed}
|
||||
variant="default"
|
||||
class="w-full"
|
||||
on:click={() => {
|
||||
currentStep = Steps.SIGNUP_MAIL;
|
||||
currentStep = Steps.SIGNUP_SUCCESS;
|
||||
}}>Continue</Button
|
||||
>
|
||||
{:else if currentStep.name == Steps.SIGNUP_MAIL.name}
|
||||
<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" />
|
||||
</div>
|
||||
{: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 />
|
||||
You can scan this qr code to login to our selfservice.
|
||||
<!-- TODO: generate actual qr code -->
|
||||
<img class="mx-auto h-56" src={sampleQR} alt="" />
|
||||
</p>
|
||||
{:else if currentStep.name == Steps.SIGNIN.name}
|
||||
<div class="grid gap-2">
|
||||
<Button
|
||||
class="w-full"
|
||||
on:click={() => {
|
||||
currentStep = Steps.SIGNIN_BARCODE;
|
||||
}}>I brought my Barcode</Button
|
||||
>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Button
|
||||
variant="secondary"
|
||||
class="w-full"
|
||||
on:click={() => {
|
||||
currentStep = Steps.SIGNIN_MAIL;
|
||||
}}>I don't have my barcode with me</Button
|
||||
>
|
||||
</div>
|
||||
{:else if currentStep.name == Steps.SIGNIN_BARCODE.name}
|
||||
Just walk up to the next available person and show them your barcode.
|
||||
{:else if currentStep.name == Steps.SIGNIN_MAIL.name}
|
||||
<div class="grid gap-2">
|
||||
@@ -123,6 +198,7 @@
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
bind:value={email}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
@@ -130,14 +206,18 @@
|
||||
<Button
|
||||
class="w-full"
|
||||
on:click={() => {
|
||||
currentStep = Steps.SIGNIN_BARCODE;
|
||||
}}>Next!</Button
|
||||
console.log("Email: ", email);
|
||||
currentStep = Steps.SIGNIN_MAIL_SUCCESS;
|
||||
}}>Continue</Button
|
||||
>
|
||||
</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.
|
||||
{/if}
|
||||
</Card.Content>
|
||||
<Card.Footer>
|
||||
{#if currentStep.name != Steps.WELCOME.name}
|
||||
<Card.Footer class="grid gap-2">
|
||||
{#if currentStep.showback}
|
||||
<Button
|
||||
variant="destructive"
|
||||
class="w-full"
|
||||
@@ -149,12 +229,12 @@
|
||||
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;
|
||||
case Steps.SIGNIN_BARCODE.name:
|
||||
currentStep = Steps.SIGNIN;
|
||||
break;
|
||||
case Steps.SIGNIN_MAIL.name:
|
||||
currentStep = Steps.SIGNIN;
|
||||
break;
|
||||
@@ -164,6 +244,15 @@
|
||||
}}>Go Back</Button
|
||||
>
|
||||
{/if}
|
||||
{#if currentStep.progress == 100}
|
||||
<Button
|
||||
variant="default"
|
||||
class="w-full"
|
||||
on:click={() => {
|
||||
currentStep = Steps.WELCOME;
|
||||
}}>Done</Button
|
||||
>
|
||||
{/if}
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="container flex items-center justify-between py-2">
|
||||
<h1 class="text-xl font-bold">Lauf für Kaya! Kiosk</h1>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button on:click={toggleMode} variant="outline" size="icon">
|
||||
<!-- <Button on:click={toggleMode} variant="outline" size="icon">
|
||||
<Sun
|
||||
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
|
||||
/>
|
||||
@@ -26,7 +26,7 @@
|
||||
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
|
||||
/>
|
||||
<span class="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</Button> -->
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
|
||||
Reference in New Issue
Block a user