21 Commits
1.1.0 ... 1.2.0

Author SHA1 Message Date
d3d0b356ac chore(release): 1.2.0
All checks were successful
Build latest image / build-container (push) Successful in 1m11s
Build release images / build-container (push) Successful in 1m9s
2025-04-08 20:58:14 +02:00
3fdd8c80d8 fix: Updated styling
Some checks failed
Build latest image / build-container (push) Has been cancelled
2025-04-08 20:57:43 +02:00
3e3846f1cb feat: Full printing support 2025-04-08 20:56:16 +02:00
ed7242cc2a refactor(register): Switch to showing qr code
All checks were successful
Build latest image / build-container (push) Successful in 45s
2025-04-08 20:22:11 +02:00
6152500652 chore: Bump js lib 2025-04-08 20:14:12 +02:00
6ecaae1b8d style(docs): Linting
All checks were successful
Build latest image / build-container (push) Successful in 44s
2025-04-07 15:16:45 +02:00
5f97c9d8da refactor(svelte): Threw out workspace config 2025-04-07 15:11:21 +02:00
e32c2f3069 chore(release): 1.1.5
All checks were successful
Build latest image / build-container (push) Successful in 1m28s
Build release images / build-container (push) Successful in 44s
2025-04-07 15:01:23 +02:00
83826f966b feat: clock widget, general cleanups 2025-04-07 15:01:06 +02:00
1665fd67ae chore(deps): bump 2025-04-07 14:32:05 +02:00
7516d3579f chore(release): 1.1.4
All checks were successful
Build release images / build-container (push) Successful in 50s
Build latest image / build-container (push) Successful in 56s
2025-04-02 23:47:01 +02:00
2c503f9b03 feat: improve registration flow
Some checks failed
Build latest image / build-container (push) Has been cancelled
2025-04-02 23:46:48 +02:00
6a0b014d55 chore(release): 1.1.3
All checks were successful
Build release images / build-container (push) Successful in 1m0s
Build latest image / build-container (push) Successful in 1m3s
2025-04-02 22:36:00 +02:00
b7f792c6f9 fix: registration without email
Some checks failed
Build latest image / build-container (push) Has been cancelled
2025-04-02 22:35:50 +02:00
528b025e55 chore(release): 1.1.2
All checks were successful
Build release images / build-container (push) Successful in 55s
Build latest image / build-container (push) Successful in 57s
2025-04-02 22:27:01 +02:00
368e97c6bb fix: build
Some checks failed
Build latest image / build-container (push) Has been cancelled
2025-04-02 22:26:52 +02:00
6acd8bb634 🚀Bumped version to 1.1.1
Some checks failed
Build latest image / build-container (push) Failing after 19s
Build release images / build-container (push) Failing after 18s
2025-04-02 22:19:59 +02:00
6dcdba6568 feat: improved registration 2025-04-02 22:19:34 +02:00
525c096f7a feat: disable chrome autocomplete 2025-04-02 22:19:12 +02:00
0de50822cd Merge branch 'main' of git.odit.services:lfk/kiosk
Some checks failed
Build latest image / build-container (push) Failing after 18s
2025-03-22 23:10:31 +01:00
0177c50651 refactor(ci): Switch to actions 2025-03-22 23:08:06 +01:00
20 changed files with 1377 additions and 5873 deletions

27
.gitea/workflows/dev.yaml Normal file
View File

@@ -0,0 +1,27 @@
name: Build latest image
on:
push:
branches:
- main
jobs:
build-container:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login to registry
uses: docker/login-action@v3
with:
registry: registry.odit.services
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: |
${{ vars.REGISTRY }}/lfk/kiosk:latest
platforms: linux/amd64,linux/arm64

View File

@@ -0,0 +1,27 @@
name: Build release images
on:
push:
tags:
- "*.*.*"
jobs:
build-container:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login to registry
uses: docker/login-action@v3
with:
registry: registry.odit.services
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: |
${{ vars.REGISTRY }}/lfk/kiosk:${{ github.ref_name }}
platforms: linux/amd64,linux/arm64

View File

@@ -1,40 +0,0 @@
steps:
- name: build edge
image: woodpeckerci/plugin-docker-buildx
settings:
repo: registry.odit.services/lfk/kiosk
tags:
- edge
registry: registry.odit.services
platforms: linux/amd64,linux/arm64
cache_from: registry.odit.services/lfk/kiosk:edge
username:
from_secret: odit-registry-builder-username
password:
from_secret: odit-registry-builder-password
secrets:
- source: odit-npm-cache-url
target: NPM_REGISTRY_URL
when:
branch: dev
- name: build latest
image: woodpeckerci/plugin-docker-buildx
settings:
repo: registry.odit.services/lfk/kiosk
tags:
- latest
registry: registry.odit.services
platforms: linux/amd64,linux/arm64
username:
from_secret: odit-registry-builder-username
password:
from_secret: odit-registry-builder-password
secrets:
- source: odit-npm-cache-url
target: NPM_REGISTRY_URL
when:
branch: main
when:
event:
- push

View File

@@ -1,22 +0,0 @@
steps:
- name: type checks
image: registry.odit.services/hub/library/node:19.9.0-alpine3.16
commands:
- npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8
- pnpm i
- pnpm check
secrets:
- source: odit-npm-cache-url
target: NPM_REGISTRY_URL
- name: build check
image: registry.odit.services/hub/library/node:19.9.0-alpine3.16
commands:
- npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8
- pnpm i
- pnpm build
secrets:
- source: odit-npm-cache-url
target: NPM_REGISTRY_URL
when:
event:
- pull_request

View File

@@ -2,9 +2,59 @@
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.2.0](https://git.odit.services/lfk/kiosk/compare/1.1.5...1.2.0)
- refactor(svelte): Threw out workspace config [`5f97c9d`](https://git.odit.services/lfk/kiosk/commit/5f97c9d8da1a9002875d8fe35606c078c62c1d0a)
- feat: Full printing support [`3e3846f`](https://git.odit.services/lfk/kiosk/commit/3e3846f1cb1fe281edce7c6ce3485f54ddbed3e2)
- refactor(register): Switch to showing qr code [`ed7242c`](https://git.odit.services/lfk/kiosk/commit/ed7242cc2a6e1af22de8950a53b64e94459a2aee)
- style(docs): Linting [`6ecaae1`](https://git.odit.services/lfk/kiosk/commit/6ecaae1b8dcce099b82cd257a22bd1d579d79ba2)
- chore: Bump js lib [`6152500`](https://git.odit.services/lfk/kiosk/commit/61525006526ab5e237b0caf24a474618fc238372)
- fix: Updated styling [`3fdd8c8`](https://git.odit.services/lfk/kiosk/commit/3fdd8c80d8d72bdc899739896fa379ff7a7b620d)
#### [1.1.5](https://git.odit.services/lfk/kiosk/compare/1.1.4...1.1.5)
> 7 April 2025
- chore(release): 1.1.5 [`e32c2f3`](https://git.odit.services/lfk/kiosk/commit/e32c2f3069e03584f3829a96e3fea94f98bf419b)
- chore(deps): bump [`1665fd6`](https://git.odit.services/lfk/kiosk/commit/1665fd67ae7153ece759edbe3e74262eb207a2f6)
- feat: clock widget, general cleanups [`83826f9`](https://git.odit.services/lfk/kiosk/commit/83826f966bb0de2402889d6574c6db7730831119)
#### [1.1.4](https://git.odit.services/lfk/kiosk/compare/1.1.3...1.1.4)
> 2 April 2025
- feat: improve registration flow [`2c503f9`](https://git.odit.services/lfk/kiosk/commit/2c503f9b0333b668730c4eb11deb5184ee49f295)
- chore(release): 1.1.4 [`7516d35`](https://git.odit.services/lfk/kiosk/commit/7516d3579f31166f172cd5f5bcf071366d9c59ec)
#### [1.1.3](https://git.odit.services/lfk/kiosk/compare/1.1.2...1.1.3)
> 2 April 2025
- chore(release): 1.1.3 [`6a0b014`](https://git.odit.services/lfk/kiosk/commit/6a0b014d55b129eef17d70bb9a86203a272d3ad3)
- fix: registration without email [`b7f792c`](https://git.odit.services/lfk/kiosk/commit/b7f792c6f99249acd0c8c1154800c4442ad5a8b0)
#### [1.1.2](https://git.odit.services/lfk/kiosk/compare/1.1.1...1.1.2)
> 2 April 2025
- fix: build [`368e97c`](https://git.odit.services/lfk/kiosk/commit/368e97c6bba238b605532aa9c598ace5f2bac592)
- chore(release): 1.1.2 [`528b025`](https://git.odit.services/lfk/kiosk/commit/528b025e55ce6d4ab0dec32803d201d057725dac)
#### [1.1.1](https://git.odit.services/lfk/kiosk/compare/1.1.0...1.1.1)
> 2 April 2025
- refactor(ci): Switch to actions [`0177c50`](https://git.odit.services/lfk/kiosk/commit/0177c506516c5e21b4f73e1086b587ab2f1d8f50)
- feat: improved registration [`6dcdba6`](https://git.odit.services/lfk/kiosk/commit/6dcdba6568def337dcd1e4e6db5c75df09c1f938)
- 🚀Bumped version to 1.1.1 [`6acd8bb`](https://git.odit.services/lfk/kiosk/commit/6acd8bb6340f0d874e8ab8b9e1a93a5fd05fd3b6)
- feat: disable chrome autocomplete [`525c096`](https://git.odit.services/lfk/kiosk/commit/525c096f7a757105947da62e8dac75a24e0aa757)
#### [1.1.0](https://git.odit.services/lfk/kiosk/compare/1.0.0...1.1.0) #### [1.1.0](https://git.odit.services/lfk/kiosk/compare/1.0.0...1.1.0)
> 16 December 2024
- chore(deps): bump all [`b969932`](https://git.odit.services/lfk/kiosk/commit/b9699325828dd9b3ed51997d7a72f43449f000cf) - chore(deps): bump all [`b969932`](https://git.odit.services/lfk/kiosk/commit/b9699325828dd9b3ed51997d7a72f43449f000cf)
- 🚀Bumped version to 1.1.0 [`f7575f4`](https://git.odit.services/lfk/kiosk/commit/f7575f46e4197da893c002299f8e7fdefc5cb026)
- feat(ci)!: Switch to woodpecker [`16f9228`](https://git.odit.services/lfk/kiosk/commit/16f92283904bc3a2825ebb0fb0c7f130ffa8f057) - feat(ci)!: Switch to woodpecker [`16f9228`](https://git.odit.services/lfk/kiosk/commit/16f92283904bc3a2825ebb0fb0c7f130ffa8f057)
- feat: email [`a8d90d4`](https://git.odit.services/lfk/kiosk/commit/a8d90d48829fa708d1cdc5029d1e1ac2f28b1e4c) - feat: email [`a8d90d4`](https://git.odit.services/lfk/kiosk/commit/a8d90d48829fa708d1cdc5029d1e1ac2f28b1e4c)
- 2025 [`a2ffa50`](https://git.odit.services/lfk/kiosk/commit/a2ffa5055e58445bbbc6f932495eb8c4952fec99) - 2025 [`a2ffa50`](https://git.odit.services/lfk/kiosk/commit/a2ffa5055e58445bbbc6f932495eb8c4952fec99)

View File

@@ -1,9 +1,9 @@
FROM registry.odit.services/hub/library/node:19.9.0-alpine3.16 AS build FROM registry.odit.services/hub/library/node:23.10.0-alpine3.21 AS build
ARG NPM_REGISTRY_URL=registry.npmjs.org # ARG NPM_REGISTRY_URL=registry.npmjs.org
WORKDIR /app WORKDIR /app
COPY package.json *.config.cjs *.config.js *.config.ts tsconfig.json .npmrc ./ COPY package.json *.config.cjs *.config.js *.config.ts tsconfig.json .npmrc ./
RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8 RUN npm i -g pnpm@10.7
RUN pnpm i RUN pnpm i
COPY src ./src COPY src ./src
@@ -11,5 +11,5 @@ COPY static ./static
RUN pnpm build RUN pnpm build
# final image # final image
FROM registry.odit.services/library/nginx-brotli:3.15 as final FROM registry.odit.services/library/nginx-brotli:3.15 AS final
COPY --from=build /app/build /usr/share/nginx/html COPY --from=build /app/build /usr/share/nginx/html

View File

@@ -1,32 +1,38 @@
# @lfk/kiosk # @lfk/kiosk
## Overview 👀 ## Overview 👀
This is a simple kiosk style register form for the LfK runnersystem. This is a simple kiosk style register form for the LfK runnersystem.
The basic idea is: The basic idea is:
1. Create a runnersystem user with only `RUNNER:CREATE` permissions. 1. Create a runnersystem user with only `RUNNER:CREATE` permissions.
2. Login with this user under `/login` 2. Login with this user under `/login`
3. Runners can register via their firstnam and lastname 3. Runners can register via their firstname and lastname
4. The kiosk creates the runner via the backend and shows their id, firstname, lastname and a barcode containing their id 4. The kiosk creates the runner via the backend and shows their id, firstname, lastname and a barcode containing their id along
## Development 🛠️ ## Development 🛠️
```
```shell
pnpm i pnpm i
pnpm dev --open pnpm dev --open
``` ```
## Build 🚀 ## Build 🚀
```
```shell
pnpm i pnpm i
pnpm build pnpm build
``` ```
## Docker 🐳 ## Docker 🐳
```
```shell
docker build . docker build .
docker-compose up docker-compose up
``` ```
## Kiosk Google Chrome ## Kiosk Google Chrome
```
``` shell
chrome https://run.lauf-fuer-kaya.de/kiosk/ -kiosk chrome https://run.lauf-fuer-kaya.de/kiosk/ -kiosk
``` ```

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lfk/kiosk", "name": "@lfk/kiosk",
"version": "1.1.0", "version": "1.2.0",
"private": false, "private": false,
"license": "MIT", "license": "MIT",
"repository": "https://git.odit.services/lfk/kiosk", "repository": "https://git.odit.services/lfk/kiosk",
@@ -35,44 +35,42 @@
"devDependencies": { "devDependencies": {
"@odit/license-exporter": "0.2.0", "@odit/license-exporter": "0.2.0",
"@philippdormann/release-it": "^1.0.0", "@philippdormann/release-it": "^1.0.0",
"@sveltejs/adapter-static": "3.0.6", "@sveltejs/adapter-static": "3.0.8",
"@sveltejs/kit": "2.12.0", "@sveltejs/kit": "2.20.4",
"@sveltejs/vite-plugin-svelte": "^5.0.2", "@sveltejs/vite-plugin-svelte": "^5.0.3",
"@types/bwip-js": "^3.2.3", "@types/bwip-js": "^3.2.3",
"@typescript-eslint/eslint-plugin": "8.18.0", "@typescript-eslint/eslint-plugin": "8.29.0",
"@typescript-eslint/parser": "8.18.0", "@typescript-eslint/parser": "8.29.0",
"auto-changelog": "2.5.0", "auto-changelog": "2.5.0",
"autoprefixer": "10.4.20", "eslint": "9.24.0",
"eslint": "9.17.0", "eslint-config-prettier": "10.1.1",
"eslint-config-prettier": "9.1.0", "prettier": "3.5.3",
"postcss": "8.4.49", "prettier-plugin-svelte": "3.3.3",
"postcss-load-config": "6.0.1", "svelte": "5.25.7",
"prettier": "3.4.2", "svelte-check": "4.1.5",
"prettier-plugin-svelte": "3.3.2",
"svelte": "5.14.0",
"svelte-check": "4.1.1",
"svelte-preprocess": "6.0.3", "svelte-preprocess": "6.0.3",
"tailwindcss": "3.4.16",
"tslib": "2.8.1", "tslib": "2.8.1",
"typescript": "5.7.2", "typescript": "5.8.3",
"vite": "6.0.3" "vite": "6.2.5"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@fontsource/athiti": "^5.1.0", "@fontsource/athiti": "^5.2.5",
"@odit/lfk-client-js": "1.1.3", "@odit/lfk-client-js": "1.2.1",
"bwip-js": "4.5.1", "@tailwindcss/vite": "^4.1.3",
"eslint-plugin-svelte": "^2.46.1" "bwip-js": "4.5.3",
"eslint-plugin-svelte": "^3.5.1",
"tailwindcss": "^4.1.3"
}, },
"release-it": { "release-it": {
"git": { "git": {
"commit": true, "commit": true,
"requireCleanWorkingDir": false, "requireCleanWorkingDir": false,
"commitMessage": "🚀Bumped version to ${version}", "commitMessage": "chore(release): ${version}",
"requireBranch": "main", "requireBranch": "main",
"push": true, "push": true,
"tag": true, "tag": true,
"tagName": null, "tagName": "${version}",
"tagAnnotation": "${version}" "tagAnnotation": "${version}"
}, },
"npm": { "npm": {

2081
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +0,0 @@
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer
]
};
module.exports = config;

4
src/app.css Normal file
View File

@@ -0,0 +1,4 @@
@import 'tailwindcss';
* {
font-family: 'Athiti', sans-serif;
}

View File

@@ -5,11 +5,6 @@
<link rel="icon" href="%sveltekit.assets%/favicon.png" /> <link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
%sveltekit.head% %sveltekit.head%
<style>
body {
font-family: 'Athiti', sans-serif;
}
</style>
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div> <div style="display: contents">%sveltekit.body%</div>

View File

@@ -1,4 +0,0 @@
/* Write your global styles here, in PostCSS syntax */
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -1,11 +1,11 @@
<script> <script>
import { OpenAPI } from '@odit/lfk-client-js'; import { OpenAPI } from '@odit/lfk-client-js';
import { env } from '$env/dynamic/public';
import '../app.postcss';
import '@fontsource/athiti'; import '@fontsource/athiti';
import '../app.css';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import lfkbackground from './background.png';
OpenAPI.BASE = env.PUBLIC_BASE_URL || 'https://run.lauf-fuer-kaya.de'; OpenAPI.BASE = 'https://run.lauf-fuer-kaya.de';
onMount(() => { onMount(() => {
window.addEventListener('keydown', (e) => { window.addEventListener('keydown', (e) => {
// F1 // F1
@@ -14,10 +14,25 @@
if (e.keyCode === 116) e.preventDefault(); if (e.keyCode === 116) e.preventDefault();
}); });
}); });
let time = new Date();
$: hours = (time.getHours() + '').padStart(2, '0');
$: minutes = (time.getMinutes() + '').padStart(2, '0');
$: seconds = (time.getSeconds() + '').padStart(2, '0');
setInterval(() => {
time = new Date();
}, 500);
</script> </script>
<div class="dark:bg-slate-900 flex flex-col h-screen"> <div
class="text-neutral-800 flex flex-col h-screen print:h-full"
style="background: url({lfkbackground});background-position: center center!important;background-size: contain!important;background-repeat: no-repeat!important;"
>
<main class="flex-grow"> <main class="flex-grow">
<div
class="text-6xl font-semibold text-right text-gray-900 font-mono top-2 w-full fixed pr-4 xl:top-6 xl:pr-8 print:hidden"
>
{hours}:{minutes}:{seconds}
</div>
<slot /> <slot />
</main> </main>
</div> </div>

View File

@@ -14,7 +14,7 @@
{:else} {:else}
<Login /> <Login />
{/if} {/if}
<div class="fixed bottom-0 w-full text-center text-xl p-4 dark:text-white select-none"> <div class="fixed bottom-0 w-full text-center text-xl p-4 dark:text-white select-none print:absolute print:bottom-auto">
{#if $userState.isLoggedIn} {#if $userState.isLoggedIn}
<b class="font-bold">LfK!2025</b> powered by <b class="font-bold">LfK!2025</b> powered by
<b class="font-bold">ODIT.Services</b> <b class="font-bold">ODIT.Services</b>
@@ -33,7 +33,6 @@
class="underline">Impressum</a class="underline">Impressum</a
> >
<br /> <br />
<br />
<b class="font-bold">LfK!2025</b> powered by <b class="font-bold">LfK!2025</b> powered by
<a <a
rel="noopener noreferrer" rel="noopener noreferrer"

View File

@@ -26,95 +26,84 @@
</script> </script>
<!-- --> <!-- -->
<div <div class="relative overflow-hidden">
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-md mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-10">
> <div class="text-center">
<div class="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-10"> <h1 class="block text-7xl font-bold">LfK!Kiosk</h1>
<h1 class="block text-4xl font-bold">Login</h1>
<!-- <p class="mt-2 text-sm text-gray-600 dark:text-gray-400">Melde dich für den LfK an</p> -->
</div>
<!-- Title --> <!-- Title -->
<div class="mt-5 max-w-2xl text-center mx-auto"> <!-- <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"> <h1 class="block font-bold text-gray-800 text-4xl md:text-5xl lg:text-6xl dark:text-gray-200">
LfK! Selfservice LfK! Selfservice
<span class="bg-clip-text bg-gradient-to-tl from-blue-600 to-violet-600 text-transparent" <span class="bg-clip-text bg-gradient-to-tl from-blue-600 to-violet-600 text-transparent"
>Kiosk</span >Kiosk</span
> >
</h1> </h1>
</div> </div> -->
<!-- End Title --> <!-- End Title -->
<div class="mt-5 max-w-3xl text-center mx-auto"> {#if loginError}
<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 <div
class="mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700" class="bg-red-500 text-white text-center font-semibold rounded-md shadow-lg mb-8 mt-4"
role="alert"
> >
<div class="p-4 sm:p-7"> <div class="p-4">Falscher Nutzername oder falsches Passwort</div>
<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> {/if}
<!-- Form -->
<form on:submit|preventDefault={login}>
<div class="grid gap-y-4">
<!-- Form Group -->
<div>
<label for="username" class="block font-semibold">Benutzername</label>
<div class="relative">
<input
autofocus
bind:value={username}
autocomplete="one-time-code"
type="username"
id="username"
name="username"
placeholder="Benutzername"
class="placeholder:text-neutral-800 py-3 px-4 block w-full rounded-md focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border bg-white"
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 font-semibold">Passwort</label>
</div>
<div class="relative">
<input
bind:value={password}
autocomplete="one-time-code"
type="password"
id="password"
name="password"
placeholder="Passwort"
class="placeholder:text-neutral-800 py-3 px-4 block w-full rounded-md focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border bg-white"
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 dark:focus:ring-offset-gray-800"
>Anmelden</button
>
</div>
</form>
<!-- End Form -->
</div> </div>
</div> </div>

View File

@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
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 { onMount } from 'svelte'; import { onMount } from 'svelte';
$: firstname = ''; $: firstname = '';
@@ -32,10 +31,16 @@
async function register() { async function register() {
try { try {
let emailToSend = null;
if (email !== '') {
if (email.includes('@')) {
emailToSend = email;
}
}
response = (await RunnerService.runnerControllerPost({ response = (await RunnerService.runnerControllerPost({
firstname, firstname,
lastname, lastname,
email, email: emailToSend,
group group
})) as ResponseRunner; })) as ResponseRunner;
showResult = true; showResult = true;
@@ -57,19 +62,26 @@
function textToBase64Barcode(text: string, is_qrcode: boolean) { function textToBase64Barcode(text: string, is_qrcode: boolean) {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
let bcid = 'code128';
if (is_qrcode) { if (is_qrcode) {
bcid = 'qrcode'; bwipjs.toCanvas(canvas, {
bcid: 'qrcode',
text: `${text}`,
scale: 10,
includetext: false,
textxalign: 'center',
backgroundcolor: 'ffffff'
});
} else {
bwipjs.toCanvas(canvas, {
bcid: 'code128',
text: `${text}`,
scale: 10,
includetext: true,
textxalign: 'center',
backgroundcolor: 'ffffff',
height: 10
});
} }
bwipjs.toCanvas(canvas, {
bcid,
text: `${text}`,
scale: 10,
includetext: true,
textxalign: 'center',
backgroundcolor: 'ffffff',
height: 10
});
return canvas.toDataURL('image/png'); return canvas.toDataURL('image/png');
} }
@@ -78,16 +90,13 @@
}); });
</script> </script>
<div <div class="flex h-full items-center py-16 select-none print:py-0 print:items-baseline">
class="dark:bg-slate-900 bg-gray-100 flex h-full items-center py-16 select-none" <div class="w-full max-w-md mx-auto p-6 print:p-0">
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 <!-- <div
class="mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700" class="mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-200"
> --> > -->
<div class="p-4 sm:p-7"> <div class="p-4 sm:p-7 print:p-0 print:sm:p-0">
<div class="mt-5"> <div class="mt-5 print:mt-0">
<!-- Form --> <!-- Form -->
{#if !showResult} {#if !showResult}
<div class="text-center"> <div class="text-center">
@@ -104,13 +113,18 @@
<input <input
on:keydown={(e) => { on:keydown={(e) => {
if (e.keyCode === 13) { if (e.keyCode === 13) {
e.preventDefault();
document.getElementById('lastname')?.focus();
}
if (e.keyCode === 40) {
document.getElementById('lastname')?.focus(); document.getElementById('lastname')?.focus();
} }
}} }}
type="text" type="text"
autocomplete="one-time-code"
id="firstname" id="firstname"
name="firstname" name="firstname"
class="py-3 px-4 block w-full border-gray-200 rounded-md focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border" class="font-semibold placeholder:font-normal placeholder:text-black dark:placeholder:text-gray-200 py-3 px-4 block w-full border-gray-500 rounded-md focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-200 dark:text-white border bg-white"
required required
placeholder="Vorname" placeholder="Vorname"
bind:value={firstname} bind:value={firstname}
@@ -149,10 +163,23 @@
<label for="lastname" class="block text-lg font-bold mb-2 sr-only">Nachname</label> <label for="lastname" class="block text-lg font-bold mb-2 sr-only">Nachname</label>
<div class="relative"> <div class="relative">
<input <input
on:keydown={(e) => {
if (e.keyCode === 13) {
e.preventDefault();
document.getElementById('email')?.focus();
}
if (e.keyCode === 38) {
document.getElementById('firstname')?.focus();
}
if (e.keyCode === 40) {
document.getElementById('email')?.focus();
}
}}
autocomplete="one-time-code"
type="lastname" type="lastname"
id="lastname" id="lastname"
name="lastname" name="lastname"
class="py-3 px-4 block w-full border-gray-200 rounded-md focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border" class="font-semibold placeholder:font-normal placeholder:text-black dark:placeholder:text-gray-200 py-3 px-4 block w-full border-gray-500 rounded-md focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-200 dark:text-white border bg-white"
required required
placeholder="Nachname" placeholder="Nachname"
aria-describedby="lastname-error" aria-describedby="lastname-error"
@@ -188,14 +215,28 @@
<!-- Form Group --> <!-- Form Group -->
<div> <div>
<label for="email" class="block text-lg font-bold mb-2 sr-only">E-Mail (optional)</label> <label for="email" class="block text-lg font-bold mb-2 sr-only"
>E-Mail (optional)</label
>
<div class="relative"> <div class="relative">
<input <input
on:keydown={(e) => {
if (e.keyCode === 13) {
e.preventDefault();
document.getElementById('submit')?.focus();
}
if (e.keyCode === 38) {
document.getElementById('lastname')?.focus();
}
if (e.keyCode === 40) {
document.getElementById('submit')?.focus();
}
}}
autocomplete="one-time-code"
type="email" type="email"
id="email" id="email"
name="email" name="email"
class="py-3 px-4 block w-full border-gray-200 rounded-md focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border" class="font-semibold placeholder:font-normal placeholder:text-black dark:placeholder:text-gray-200 py-3 px-4 block w-full border-gray-500 rounded-md focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-200 dark:text-white border bg-white"
required
placeholder="E-Mail (optional)" placeholder="E-Mail (optional)"
aria-describedby="lastname-error" aria-describedby="lastname-error"
bind:value={email} bind:value={email}
@@ -227,11 +268,37 @@
</p> --> </p> -->
</div> </div>
<!-- End Form Group --> <!-- End Form Group -->
<p
class="bg-white text-gray-800 dark:bg-gray-800 dark:text-gray-400 rounded border p-3"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="inline"
><circle cx="12" cy="12" r="10" /><path d="M12 16v-4" /><path
d="M12 8h.01"
/></svg
>
Mit der Registrierung akzeptieren Sie die AGBs sowie die Datenschutzerklärung des Lauf
für Kaya! 2025 sowie der ODIT.Services GmbH.
</p>
<button <button
on:keydown={(e) => {
if (e.keyCode === 38) {
document.getElementById('email')?.focus();
}
}}
id="submit"
type="submit" type="submit"
disabled={!firstname || !lastname} disabled={!firstname || !lastname}
class="py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold disabled:opacity-70 bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all dark:focus:ring-offset-gray-800" class="py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold disabled:opacity-70 bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all dark:focus:ring-offset-gray-800 cursor-pointer"
>Anmelden</button >Anmelden</button
> >
</div> </div>
@@ -239,21 +306,46 @@
<!-- End Form --> <!-- End Form -->
{:else} {:else}
<div class="mb-2 text-center"> <div class="mb-2 text-center">
<h3 class="text-4xl font-semibold dark:text-white"> <h3 class="text-4xl font-semibold dark:text-white print:text-5xl">
{response.firstname} {response.firstname}
{response.lastname} {response.lastname}
</h3> </h3>
</div> </div>
<div class="mb-2 text-center"> <div class="mb-2 text-center hidden print:block">
<h3 class="text-4xl font-semibold dark:text-white">
Runner-ID
</h3>
<h3 class="text-2xl font-semibold dark:text-white">
Zeige diesen Code am Infozelt vor, um deine Läuferkarte zu erhalten
</h3>
<img <img
class="w-full md:w-auto mb-2 mx-auto bg-white p-4" class="w-full md:w-auto mb-2 mx-auto bg-white p-4 print:hidden"
alt="runner id" alt="runner id"
src={textToBase64Barcode(response.id.toString(), false)} src={textToBase64Barcode(response.id.toString(), false)}
/> />
<img
class="w-3/4 md:w-auto mb-2 mx-auto bg-white p-4 hidden print:block"
alt="runner id print only"
src={textToBase64Barcode(response.id.toString(), false)}
/>
</div> </div>
<div class="mx-auto text-center items-center"> <div class="mb-2 text-center">
<h3 class="text-4xl font-semibold dark:text-white hidden print:block">
Selfservice
</h3>
<h3 class="text-xl font-semibold dark:text-white">
Scanne diesen QR-Code, um zu unserem Selfservice zu gelangen. Hier findest du deine Rundenzeiten, Spenden und Urkunden.
</h3>
<img
class="w-full md:w-auto mb-2 mx-auto bg-white p-4"
alt="runner selfservice"
src={textToBase64Barcode(response.selfserviceLink.toString(), true)}
/>
</div>
<div class="mx-auto text-center items-center print:hidden">
<button <button
class:opacity-50={!doneButtonEnabled} class:opacity-50={!doneButtonEnabled}
disabled={!doneButtonEnabled} disabled={!doneButtonEnabled}
@@ -263,7 +355,7 @@
showResult = false; showResult = false;
focusFirstName(); 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 cursor-pointer"
>Fertig</button >Fertig</button
> >
</div> </div>
@@ -272,4 +364,4 @@
<!-- </div> --> <!-- </div> -->
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,11 +0,0 @@
const config = {
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
extend: {}
},
plugins: []
};
module.exports = config;

View File

@@ -1,6 +1,9 @@
import { sveltekit } from '@sveltejs/kit/vite'; import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite'; import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({ export default defineConfig({
plugins: [sveltekit()] plugins: [
}); tailwindcss(),
sveltekit(),
],
});