Merge branch 'main' of git.odit.services:lfk/kiosk
All checks were successful
ci/woodpecker/push/build Pipeline was successful

This commit is contained in:
Nicolai Ort 2023-11-06 20:07:16 +01:00
commit 72ace57cb3
Signed by: niggl
GPG Key ID: 13AFA55AF62F269F
12 changed files with 313 additions and 328 deletions

View File

@ -2,8 +2,36 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [1.0.0](https://git.odit.services/lfk/kiosk/compare/0.6.0...1.0.0)
- feat: footer [`115767c`](https://git.odit.services/lfk/kiosk/commit/115767c656381336257c23ee30a130e7e9c60144)
- refactor: drop footer [`e512325`](https://git.odit.services/lfk/kiosk/commit/e5123251155f58e83f36c091b671acc73167ce68)
- feat: prevent F1 + F5 [`bb3c801`](https://git.odit.services/lfk/kiosk/commit/bb3c80190834be6d43f50cdb6eeb09ac75868259)
#### [0.6.0](https://git.odit.services/lfk/kiosk/compare/0.5.0...0.6.0)
> 19 April 2023
- feat!: move to single route application for kiosk mode [`bf8b351`](https://git.odit.services/lfk/kiosk/commit/bf8b351b644174a2dd39d38208a03a067de387be)
- refactor!: cleanup userdata localstorage + components [`c7c1c6d`](https://git.odit.services/lfk/kiosk/commit/c7c1c6dc41afc6ca3e66b507fd1ff50185f4e1be)
- 🚀Bumped version to 0.6.0 [`aa7d2db`](https://git.odit.services/lfk/kiosk/commit/aa7d2dbe1b67b33a59093bc53aa944cb6473ef03)
- add chrome kiosk command to readme [`01cd8d4`](https://git.odit.services/lfk/kiosk/commit/01cd8d4b78b3898d2f74f2b27cdad9e9745c1e33)
#### [0.5.0](https://git.odit.services/lfk/kiosk/compare/0.4.4...0.5.0)
> 19 April 2023
- feat(registration): autofocus input fields + done button [`cbfbd92`](https://git.odit.services/lfk/kiosk/commit/cbfbd92d0e4f9735a2192125f267f651ed36c9b1)
- 🚀Bumped version to 0.5.0 [`58830c5`](https://git.odit.services/lfk/kiosk/commit/58830c5db3d9903d590f535a4099ad93a8ff6519)
- feat(registration): disabled done button for 7.5s [`5f5b03a`](https://git.odit.services/lfk/kiosk/commit/5f5b03a8a086799543cf675ccc3a973b781d1987)
- feat(registration): support next input element with ENTER key [`066e67c`](https://git.odit.services/lfk/kiosk/commit/066e67c64f48b00673f2de7727acb230c94c3c13)
- feat(registration): disable text select [`418fe77`](https://git.odit.services/lfk/kiosk/commit/418fe7773fbc981186909a1f7c262c3c1fa1ece2)
#### [0.4.4](https://git.odit.services/lfk/kiosk/compare/0.4.3...0.4.4) #### [0.4.4](https://git.odit.services/lfk/kiosk/compare/0.4.3...0.4.4)
> 19 April 2023
- 🚀Bumped version to 0.4.4 [`4b6e11d`](https://git.odit.services/lfk/kiosk/commit/4b6e11d8d271c638b3c2e4cd3dc887680023dd5e)
- fix(registration): Added missing dark styling [`0698038`](https://git.odit.services/lfk/kiosk/commit/06980385230e32dffe1083ceb4f88e86a9197aef) - fix(registration): Added missing dark styling [`0698038`](https://git.odit.services/lfk/kiosk/commit/06980385230e32dffe1083ceb4f88e86a9197aef)
#### [0.4.3](https://git.odit.services/lfk/kiosk/compare/0.4.2...0.4.3) #### [0.4.3](https://git.odit.services/lfk/kiosk/compare/0.4.2...0.4.3)

View File

@ -25,3 +25,8 @@ pnpm build
docker build . docker build .
docker-compose up docker-compose up
``` ```
## Kiosk Google Chrome
```
chrome https://run.lauf-fuer-kaya.de/kiosk/ -kiosk
```

View File

@ -1,6 +1,6 @@
{ {
"name": "@lfk/kiosk", "name": "@lfk/kiosk",
"version": "0.4.4", "version": "1.0.0",
"private": false, "private": false,
"license": "MIT", "license": "MIT",
"repository": "https://git.odit.services/lfk/kiosk", "repository": "https://git.odit.services/lfk/kiosk",

View File

@ -1,49 +0,0 @@
<footer class="mt-auto w-full max-w-[85rem] py-10 px-4 sm:px-6 lg:px-8 mx-auto">
<!-- Grid -->
<div class="text-center">
<div>
<a
class="flex-none text-xl font-semibold text-black dark:text-white"
href="/"
aria-label="Brand">LfK Kiosk</a
>
</div>
<!-- End Col -->
<div class="mt-3">
<p class="text-gray-500">
Powered by <a
class="font-semibold text-blue-600 hover:text-blue-700 dark:text-blue-500 dark:hover:text-blue-400"
target="_blank"
rel="noreferrer"
href="https://odit.services/?ref=lfks">ODIT.Services</a
>
</p>
<p class="text-gray-500">© {new Date().getFullYear()} ODIT.Services</p>
</div>
<div class="mt-3 space-x-2">
<a
class="inline-flex justify-center items-center text-center text-gray-500 hover:bg-gray-100 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white transition dark:text-gray-500 dark:hover:text-gray-200 dark:hover:bg-gray-800"
target="_blank"
rel="noreferrer"
href="https://lauf-fuer-kaya.de/impressum"
>
Impressum
</a>
<p
class="inline-flex justify-center items-center text-center text-gray-500 hover:bg-gray-100 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white transition dark:text-gray-500 dark:hover:text-gray-200 dark:hover:bg-gray-800"
>
|
</p>
<a
class="inline-flex justify-center items-center text-center text-gray-500 hover:bg-gray-100 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white transition dark:text-gray-500 dark:hover:text-gray-200 dark:hover:bg-gray-800"
target="_blank"
rel="noreferrer"
href="https://lauf-fuer-kaya.de/datenschutz"
>
Datenschutz
</a>
</div>
</div>
</footer>

View File

@ -5,22 +5,16 @@ type UserState = {
access_token: string; access_token: string;
refresh_token: string; refresh_token: string;
isLoggedIn: boolean; isLoggedIn: boolean;
refreshInterval: NodeJS.Timer | undefined refreshInterval: NodeJS.Timer | undefined;
}; };
const userStore = () => {
const state: UserState = { const state: UserState = {
access_token: '', access_token: '',
refresh_token: '', refresh_token: '',
isLoggedIn: false, isLoggedIn: false,
refreshInterval: undefined refreshInterval: undefined
}; };
const userState = writable(state);
const { subscribe, set, update } = writable(state); async function auth_login(resAuth: ResponseAuth) {
const methods = {
async login(resAuth: ResponseAuth) {
update((state: UserState) => {
if (!resAuth) { if (!resAuth) {
return state; return state;
} }
@ -29,66 +23,48 @@ const userStore = () => {
state.refresh_token = resAuth.refresh_token; state.refresh_token = resAuth.refresh_token;
state.isLoggedIn = true; state.isLoggedIn = true;
state.refreshInterval = setInterval(() => { state.refreshInterval = setInterval(() => {
this.refreshAuth(); refreshAuth();
}, 2 * 60000) }, 2 * 60000);
localStorage.setItem('kiosk-userdata', JSON.stringify(state)); localStorage.setItem('kiosk-userdata', JSON.stringify(state));
localStorage.setItem('kiosk-access_token', state.access_token);
OpenAPI.TOKEN = resAuth.access_token; OpenAPI.TOKEN = resAuth.access_token;
userState.set(state);
return state; return state;
}); }
}, async function refreshAuth() {
async refreshAuth() {
try { try {
const authRes = await AuthService.authControllerRefresh({ token: state.refresh_token }) as ResponseAuth; const authRes = (await AuthService.authControllerRefresh({
token: state.refresh_token
})) as ResponseAuth;
OpenAPI.TOKEN = authRes.access_token; OpenAPI.TOKEN = authRes.access_token;
} catch { } catch {
this.logout(); logout();
} }
}, }
async loginFromStorage() { async function loginFromStorage() {
console.log('loginFromStorage'); const storagedata = localStorage.getItem('kiosk-userdata');
const access_token = localStorage.getItem('kiosk-access_token'); const userdata = JSON.parse(storagedata || '{}') as UserState;
if (!access_token) { if (!userdata.access_token) {
throw new Error('Unauthorized'); throw new Error('Unauthorized');
} }
const storagedata = localStorage.getItem('kiosk-userdata'); state.access_token = userdata.access_token;
const userdata = JSON.parse(storagedata || '{}') as UserState;
update((state: UserState) => {
state.access_token = access_token;
state.refresh_token = userdata.refresh_token; state.refresh_token = userdata.refresh_token;
state.isLoggedIn = true; state.isLoggedIn = true;
state.refreshInterval = setInterval(() => { state.refreshInterval = setInterval(() => {
this.refreshAuth(); refreshAuth();
}, 2 * 60000); }, 2 * 60000);
OpenAPI.TOKEN = userdata.access_token; OpenAPI.TOKEN = userdata.access_token;
userState.set(state);
return state; return state;
}); }
async function logout() {
await this.refreshAuth();
},
async logout() {
update((state: UserState) => {
state.isLoggedIn = false; state.isLoggedIn = false;
state.access_token = ''; state.access_token = '';
state.refresh_token = ''; state.refresh_token = '';
state.refreshInterval = undefined; state.refreshInterval = undefined;
localStorage.clear(); localStorage.clear();
return state; return state;
});
} }
};
return { export { auth_login, logout, loginFromStorage, refreshAuth, userState };
subscribe,
set,
update,
state,
...methods
};
};
export default userStore();

View File

@ -2,10 +2,18 @@
import { OpenAPI } from '@odit/lfk-client-js'; import { OpenAPI } from '@odit/lfk-client-js';
import { env } from '$env/dynamic/public'; import { env } from '$env/dynamic/public';
import '../app.postcss'; import '../app.postcss';
import "@fontsource/athiti" import '@fontsource/athiti';
import Footer from '../components/footer.svelte'; import { onMount } from 'svelte';
OpenAPI.BASE = env.PUBLIC_BASE_URL || 'https://run.lauf-fuer-kaya.de'; OpenAPI.BASE = env.PUBLIC_BASE_URL || 'https://run.lauf-fuer-kaya.de';
onMount(() => {
window.addEventListener('keydown', (e) => {
// F1
if (e.keyCode === 112) e.preventDefault();
// F5
if (e.keyCode === 116) e.preventDefault();
});
});
</script> </script>
<div class="dark:bg-slate-900 flex flex-col h-screen"> <div class="dark:bg-slate-900 flex flex-col h-screen">

View File

@ -1,41 +1,45 @@
<!-- Hero --> <script lang="ts">
<div import { loginFromStorage, userState } from '$lib/userstore';
class="relative overflow-hidden before:absolute before:top-0 before:left-1/2 before:bg-[url('/assets/polygon.svg')] before:bg-no-repeat before:bg-top before:bg-cover before:w-full before:h-full before:-z-[1] before:transform before:-translate-x-1/2 dark:before:bg-[url('/assets/polygon-dark.svg')]" import Register from './Register.svelte';
> import { onMount } from 'svelte';
<div class="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-10"> import Login from './Login.svelte';
<!-- Title -->
<div class="mt-5 max-w-2xl text-center mx-auto">
<h1 class="block font-bold text-gray-800 text-4xl md:text-5xl lg:text-6xl dark:text-gray-200">
LfK! Selfservice
<span class="bg-clip-text bg-gradient-to-tl from-blue-600 to-violet-600 text-transparent"
>Kiosk</span
>
</h1>
</div>
<!-- End Title -->
<div class="mt-5 max-w-3xl text-center mx-auto"> onMount(() => {
<p class="text-lg text-gray-600 dark:text-gray-400">Für die Anmeldung vor Ort</p> loginFromStorage();
</div> });
</script>
<!-- Buttons --> {#if $userState.isLoggedIn}
<div class="mt-8 grid gap-3 w-full sm:inline-flex sm:justify-center"> <Register />
{:else}
<Login />
{/if}
<div class="fixed bottom-0 w-full text-center text-xl p-4 dark:text-white select-none">
{#if $userState.isLoggedIn}
<b class="font-bold">LfK!2023</b> powered by
<b class="font-bold">ODIT.Services</b>
{:else}
<a <a
class="inline-flex justify-center items-center gap-x-3 text-center bg-gradient-to-tl from-blue-600 to-violet-600 hover:from-violet-600 hover:to-blue-600 border border-transparent text-white text-sm font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white py-3 px-4 dark:focus:ring-offset-gray-800" rel="noopener noreferrer"
href="./login" target="_blank"
href="https://lauf-fuer-kaya.de/datenschutz/"
class="underline">Datenschutzerklärung</a
> >
Kiosk starten |
<svg class="w-3 h-3" width="16" height="16" viewBox="0 0 16 16" fill="none"> <a
<path rel="noopener noreferrer"
d="M5.27921 2L10.9257 7.64645C11.1209 7.84171 11.1209 8.15829 10.9257 8.35355L5.27921 14" target="_blank"
stroke="currentColor" href="https://lauf-fuer-kaya.de/impressum/"
stroke-width="2" class="underline">Impressum</a
stroke-linecap="round" >
/> <br />
</svg> <br />
</a> <b class="font-bold">LfK!2023</b> powered by
<a
rel="noopener noreferrer"
target="_blank"
href="https://odit.services?ref=lfk"
class="underline">ODIT.Services</a
>
{/if}
</div> </div>
<!-- End Buttons -->
</div>
</div>
<!-- End Hero -->

120
src/routes/Login.svelte Normal file
View File

@ -0,0 +1,120 @@
<script lang="ts">
import { auth_login, loginFromStorage } from '$lib/userstore';
import { AuthService } from '@odit/lfk-client-js';
import { onMount } from 'svelte';
$: username = '';
$: password = '';
$: loginError = false;
onMount(() => {
loginFromStorage();
});
async function login() {
try {
const auth = (await AuthService.authControllerLogin({
username,
password
})) as import('@odit/lfk-client-js').ResponseAuth;
loginError = false;
auth_login(auth);
} catch (error) {
loginError = true;
}
}
</script>
<!-- -->
<div
class="relative overflow-hidden before:absolute before:top-0 before:left-1/2 before:bg-[url('/assets/polygon.svg')] before:bg-no-repeat before:bg-top before:bg-cover before:w-full before:h-full before:-z-[1] before:transform before:-translate-x-1/2 dark:before:bg-[url('/assets/polygon-dark.svg')]"
>
<div class="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-10">
<!-- Title -->
<div class="mt-5 max-w-2xl text-center mx-auto">
<h1 class="block font-bold text-gray-800 text-4xl md:text-5xl lg:text-6xl dark:text-gray-200">
LfK! Selfservice
<span class="bg-clip-text bg-gradient-to-tl from-blue-600 to-violet-600 text-transparent"
>Kiosk</span
>
</h1>
</div>
<!-- End Title -->
<div class="mt-5 max-w-3xl text-center mx-auto">
<p class="text-lg text-gray-600 dark:text-gray-400">Für die Anmeldung vor Ort</p>
</div>
<div class="w-full max-w-md mx-auto p-6">
<div
class="mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700"
>
<div class="p-4 sm:p-7">
<div class="text-center mb-8">
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Anmeldung</h1>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Hierfür wird ein LfK Läufersystem Account benötigt
</p>
</div>
{#if loginError}
<div
class="bg-red-500 text-sm text-white text-center font-semibold rounded-md shadow-lg mb-8"
role="alert"
>
<div class="p-4">Falscher Nutzername oder falsches Passwort</div>
</div>
{/if}
<!-- Form -->
<form on:submit|preventDefault={login}>
<div class="grid gap-y-4">
<!-- Form Group -->
<div>
<label for="username" class="block text-sm mb-2 dark:text-white">Benutzername</label
>
<div class="relative">
<input
bind:value={username}
type="username"
id="username"
name="username"
class="py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border"
required
aria-describedby="username-error"
/>
</div>
</div>
<!-- End Form Group -->
<!-- Form Group -->
<div>
<div class="flex justify-between items-center">
<label for="password" class="block text-sm mb-2 dark:text-white">Passwort</label>
</div>
<div class="relative">
<input
bind:value={password}
type="password"
id="password"
name="password"
class="py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border"
required
aria-describedby="password-error"
/>
</div>
</div>
<!-- End Form Group -->
<button
type="submit"
class="py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800"
>Anmelden</button
>
</div>
</form>
<!-- End Form -->
</div>
</div>
</div>
</div>
</div>

View File

@ -2,15 +2,33 @@
import { RunnerService, type ResponseRunner } from '@odit/lfk-client-js'; import { RunnerService, type ResponseRunner } from '@odit/lfk-client-js';
import bwipjs from 'bwip-js'; import bwipjs from 'bwip-js';
import lfkbackground from './background.png'; import lfkbackground from './background.png';
import { onMount } from 'svelte';
$: firstname = ''; $: firstname = '';
$: lastname = ''; $: lastname = '';
$: doneButtonEnabled = false;
$: showResult = false; $: showResult = false;
$: showError = false;
let response: ResponseRunner; let response: ResponseRunner;
const group = 1; //Default to Bürgerlauf const group = 1; //Default to Bürgerlauf
function focusFirstName() {
setTimeout(() => {
document.getElementById('firstname')?.focus();
}, 50);
setTimeout(() => {
document.getElementById('firstname')?.focus();
}, 100);
}
function focusDoneButton() {
setTimeout(() => {
document.getElementById('done')?.focus();
}, 50);
setTimeout(() => {
document.getElementById('done')?.focus();
}, 100);
}
async function register() { async function register() {
try { try {
response = (await RunnerService.runnerControllerPost({ response = (await RunnerService.runnerControllerPost({
@ -18,12 +36,18 @@
lastname, lastname,
group group
})) as ResponseRunner; })) as ResponseRunner;
showError = false;
showResult = true; showResult = true;
setTimeout(() => {
doneButtonEnabled = true;
setTimeout(() => {
focusDoneButton();
}, 25);
}, 7500);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
showError = true;
showResult = false; showResult = false;
localStorage.clear();
location.reload();
} }
firstname = ''; firstname = '';
lastname = ''; lastname = '';
@ -46,10 +70,14 @@
}); });
return canvas.toDataURL('image/png'); return canvas.toDataURL('image/png');
} }
onMount(() => {
focusFirstName();
});
</script> </script>
<div <div
class="dark:bg-slate-900 bg-gray-100 flex h-full items-center py-16" class="dark:bg-slate-900 bg-gray-100 flex h-full items-center py-16 select-none"
style="background: url({lfkbackground});background-position: center center!important;background-size: contain!important;background-repeat: no-repeat!important;" style="background: url({lfkbackground});background-position: center center!important;background-size: contain!important;background-repeat: no-repeat!important;"
> >
<div class="w-full max-w-md mx-auto p-6"> <div class="w-full max-w-md mx-auto p-6">
@ -72,6 +100,11 @@
<label for="firstname" class="block text-lg font-bold mb-2 sr-only">Vorname</label> <label for="firstname" class="block text-lg font-bold mb-2 sr-only">Vorname</label>
<div class="relative"> <div class="relative">
<input <input
on:keydown={(e) => {
if (e.keyCode === 13) {
document.getElementById('lastname')?.focus();
}
}}
type="text" type="text"
id="firstname" id="firstname"
name="firstname" name="firstname"
@ -178,8 +211,13 @@
<div class="mx-auto text-center items-center"> <div class="mx-auto text-center items-center">
<button <button
class:opacity-50={!doneButtonEnabled}
disabled={!doneButtonEnabled}
id="done"
on:click={() => { on:click={() => {
doneButtonEnabled = false;
showResult = false; showResult = false;
focusFirstName();
}} }}
class="w-full py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800" class="w-full py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800"
>Fertig</button >Fertig</button
@ -191,27 +229,3 @@
</div> </div>
</div> </div>
</div> </div>
<div class="fixed bottom-0 w-full text-center text-xl p-4 dark:text-white">
<a
rel="noopener noreferrer"
target="_blank"
href="https://lauf-fuer-kaya.de/datenschutz/"
class="underline">Datenschutzerklärung</a
>
|
<a
rel="noopener noreferrer"
target="_blank"
href="https://lauf-fuer-kaya.de/impressum/"
class="underline">Impressum</a
>
<br />
<br />
<b class="font-bold">LfK!2023</b> powered by
<a
rel="noopener noreferrer"
target="_blank"
href="https://odit.services?ref=lfk"
class="underline">ODIT.Services</a
>
</div>

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,95 +0,0 @@
<script lang="ts">
import { goto } from '$app/navigation';
import userstore from '$lib/userstore';
import { AuthService } from '@odit/lfk-client-js';
$: username = '';
$: password = '';
$: loginError = false;
async function login() {
try {
const auth = (await AuthService.authControllerLogin({
username,
password
})) as import('@odit/lfk-client-js').ResponseAuth;
loginError=false;
await userstore.login(auth);
goto('./registration', {replaceState: true})
} catch (error) {
console.log(error);
loginError = true;
}
}
</script>
<div class="dark:bg-slate-900 bg-gray-100 flex h-full items-center py-16">
<div class="w-full max-w-md mx-auto p-6">
<div
class="mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700"
>
<div class="p-4 sm:p-7">
<div class="text-center mb-8">
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Anmeldung</h1>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Hierfür wird ein LfK Läufersystem Account benötigt
</p>
</div>
{#if loginError}
<div class="bg-red-500 text-sm text-white text-center font-semibold rounded-md shadow-lg mb-8" role="alert">
<div class="p-4">Falscher Nutzername oder falsches Passwort</div>
</div>
{/if}
<!-- Form -->
<form on:submit|preventDefault={login}>
<div class="grid gap-y-4">
<!-- Form Group -->
<div>
<label for="username" class="block text-sm mb-2 dark:text-white">Benutzername</label>
<div class="relative">
<input
bind:value={username}
type="username"
id="username"
name="username"
class="py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border"
required
aria-describedby="username-error"
/>
</div>
</div>
<!-- End Form Group -->
<!-- Form Group -->
<div>
<div class="flex justify-between items-center">
<label for="password" class="block text-sm mb-2 dark:text-white">Passwort</label>
</div>
<div class="relative">
<input
bind:value={password}
type="password"
id="password"
name="password"
class="py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border"
required
aria-describedby="password-error"
/>
</div>
</div>
<!-- End Form Group -->
<button
type="submit"
class="py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800"
>Anmelden</button
>
</div>
</form>
<!-- End Form -->
</div>
</div>
</div>
</div>

View File

@ -1,26 +0,0 @@
<script lang="ts">
import { goto } from '$app/navigation';
import userstore from '$lib/userstore';
import { onMount } from 'svelte';
$: loginRendered = false;
onMount(async () => {
try {
await userstore.loginFromStorage();
loginRendered = true;
} catch (error) {
console.log(error);
userstore.logout();
goto('./login', {replaceState: true})
}
});
</script>
{#if loginRendered}
<slot />
{:else}
<div class="mx-auto mt-20">
<h1 class="block text-center text-2xl font-bold text-gray-800 dark:text-white">Lade Anmeldedaten...</h1>
</div>
{/if}