27 Commits

Author SHA1 Message Date
94ceca9454 🚀Bumped version to 0.1.1 2021-04-07 20:57:48 +02:00
2119e9b231 Merge branch 'main' of git.odit.services:lfk/beamershow into main
# Conflicts:
#	package.json
2021-04-07 20:57:00 +02:00
cfd64c2f19 Updated release-it config 2021-04-07 20:56:51 +02:00
a7e84c7d42 Updated release-it config 2021-04-07 20:56:21 +02:00
70bfbfcd53 Sorted translations 🌍
closes #1
2021-04-07 20:53:21 +02:00
c5e4facffa i18n run 2021-04-07 20:52:55 +02:00
b36764869b Added/updated settings translations 2021-04-07 20:46:29 +02:00
de7e96cd01 Implemented settings dialog 2021-04-07 20:44:24 +02:00
d5ce648a53 CNF now opens settings 2021-04-07 20:43:53 +02:00
fca7a99689 Formatting 2021-04-07 20:38:10 +02:00
cb559da57c removed unused stuff from the store
ref #1
2021-04-07 20:37:59 +02:00
abdc510305 Added track to config
ref #1
2021-04-07 20:35:46 +02:00
fe0cba9058 removed useless console log 2021-04-07 20:12:28 +02:00
64ce42d8a0 Added url validation fix 2021-04-07 19:58:52 +02:00
fdabe4b79c Merge branch 'main' of git.odit.services:lfk/beamershow into main 2021-04-07 19:49:23 +02:00
70e5f172a6 Added missing let
ref #1
2021-04-07 19:49:21 +02:00
fa35ac8254 Added missing let
ref #1
2021-04-07 19:48:26 +02:00
7f6134d0ef Implemented fix for url crashing 2021-04-07 19:44:44 +02:00
ca48959581 Added release comand and config
ref #2
2021-04-06 11:03:04 +02:00
e5c51b956e Removed license export from drone pipelines
ref #2
2021-04-06 10:58:48 +02:00
d809dcba79 Added drone file for dev and tag build
ref #2
2021-04-06 10:57:52 +02:00
b42684f7fc Added beamershow docker-compose
ref #2
2021-04-06 10:56:19 +02:00
b3b06bc30e Added nginx conf for dockerfile
ref #2
2021-04-06 10:54:35 +02:00
c83ff39677 Added 2-staged dockerfile
ref #2
2021-04-06 10:54:13 +02:00
85b40c10bf Precommit hooks doing their best to not die
ref #1
2021-04-06 10:24:15 +02:00
10b862d43a Added js part of runners by laptime
ref #1
2021-04-06 10:22:35 +02:00
3275ae2609 Added html/template for the top runenry by laptime
ref #1
2021-04-06 10:21:11 +02:00
15 changed files with 449 additions and 128 deletions

60
.drone.yml Normal file
View File

@@ -0,0 +1,60 @@
---
kind: secret
name: docker_username
get:
path: odit-registry-builder
name: username
---
kind: secret
name: docker_password
get:
path: odit-registry-builder
name: password
---
kind: pipeline
type: kubernetes
name: build:dev
steps:
- name: build dev
image: plugins/docker
depends_on: [clone]
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: registry.odit.services/lfk/selfservice
tags:
- dev
registry: registry.odit.services
mtu: 1000
trigger:
branch:
- dev
event:
- push
---
kind: pipeline
type: kubernetes
name: build:tags
steps:
- name: build $DRONE_TAG
image: plugins/docker
depends_on: [clone]
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: registry.odit.services/lfk/selfservice
tags:
- '${DRONE_TAG}'
registry: registry.odit.services
mtu: 1000
trigger:
event:
- tag

View File

@@ -1,4 +1,5 @@
{ {
"i18n-ally.localesPaths": "src/locales", "i18n-ally.localesPaths": "src/locales",
"i18n-ally.keystyle": "nested" "i18n-ally.keystyle": "nested",
"i18n-ally.sourceLanguage": "de"
} }

5
CHANGELOG.md Normal file
View File

@@ -0,0 +1,5 @@
### Changelog
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### 0.1.1

View File

@@ -2,4 +2,11 @@ FROM node:15.11.0-alpine3.13
WORKDIR /app WORKDIR /app
COPY . . COPY . .
RUN yarn RUN yarn
RUN yarn build RUN yarn build
# final image
FROM alpine
COPY --from=0 /app/dist /app
FROM fholzer/nginx-brotli:v1.19.1
COPY --from=1 /app /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf

7
docker-compose.yml Normal file
View File

@@ -0,0 +1,7 @@
version: "3"
services:
httpd:
build: .
#image: registry.odit.services/lfk/beamershow:latest
ports:
- 4052:80

View File

@@ -222,6 +222,35 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
# release-it
**Author**: Lars Kappert
**Repo**: https://github.com/release-it/release-it
**License**: MIT
**Description**: Generic CLI tool to automate versioning and package publishing related tasks.
## License Text
MIT License
Copyright (c) 2018 Lars Kappert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# svelte # svelte
**Author**: Rich Harris **Author**: Rich Harris
**Repo**: https://github.com/sveltejs/svelte **Repo**: https://github.com/sveltejs/svelte
@@ -267,6 +296,34 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# validator
**Author**: Chris O'Hara <cohara87@gmail.com>
**Repo**: https://github.com/chriso/validator.js
**License**: MIT
**Description**: String validation and sanitization
## License Text
Copyright (c) 2018 Chris O'Hara <cohara87@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# vite # vite
**Author**: Evan You **Author**: Evan You
**Repo**: https://github.com/vitejs/vite **Repo**: https://github.com/vitejs/vite

60
nginx.conf Normal file
View File

@@ -0,0 +1,60 @@
events {
}
http {
include mime.types;
sendfile on;
server {
error_page 404 /index.html;
root /usr/share/nginx/html;
location = /index.html {
add_header Cache-Control 'no-store';
}
location = / {
add_header Cache-Control 'no-store';
}
location = /env.js {
add_header Cache-Control 'no-store';
}
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(?:ico|css|gif|jpe?g|png)$ {
expires 1y;
add_header Pragma public;
add_header Cache-Control "public";
}
# --- Brotli
brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;
# --- GZIP
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types application/javascript
application/rss+xml
application/vnd.ms-fontobject
application/x-font
application/x-font-opentype
application/x-font-otf
application/x-font-truetype
application/x-font-ttf
application/x-javascript
application/xhtml+xml
application/xml
font/opentype
font/otf
font/ttf
image/svg+xml
image/x-icon
text/css
text/javascript
text/plain
text/xml;
}
}

View File

@@ -1,27 +1,48 @@
{ {
"name": "@lfk/beamershow", "name": "@lfk/beamershow",
"version": "0.0.0", "version": "0.1.1",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"format": "prettier --write --plugin-search-dir=. ./**/*.html ./**/*.svelte", "format": "prettier --write --plugin-search-dir=. ./**/*.html ./**/*.svelte",
"prepare": "husky install", "prepare": "husky install",
"license:export": "license-exporter --markdown && git stage licenses.md" "license:export": "license-exporter --markdown && git stage licenses.md",
}, "release": "release-it --only-version"
"devDependencies": { },
"@odit/license-exporter": "^0.0.11", "devDependencies": {
"@svitejs/vite-plugin-svelte": "^0.11.1", "@odit/license-exporter": "^0.0.11",
"@tsconfig/svelte": "^1.0.10", "@svitejs/vite-plugin-svelte": "^0.11.1",
"@types/html-minifier": "^4.0.0", "@tsconfig/svelte": "^1.0.10",
"axios": "^0.21.1", "@types/html-minifier": "^4.0.0",
"html-minifier": "^4.0.0", "axios": "^0.21.1",
"husky": "^5.1.3", "html-minifier": "^4.0.0",
"prettier": "^2.2.1", "husky": "^5.1.3",
"prettier-plugin-svelte": "^2.2.0", "prettier": "^2.2.1",
"svelte": "3.36.0", "prettier-plugin-svelte": "^2.2.0",
"svelte-i18n": "3.3.9", "release-it": "14.5.0",
"svelte-preprocess": "4.7.0", "svelte": "3.36.0",
"vite": "2.1.4", "svelte-i18n": "3.3.9",
"vite-plugin-windicss": "0.11.2" "svelte-preprocess": "4.7.0",
} "validator": "^13.5.2",
} "vite": "2.1.4",
"vite-plugin-windicss": "0.11.2"
},
"release-it": {
"git": {
"commit": true,
"requireCleanWorkingDir": false,
"commitMessage": "🚀Bumped version to ${version}",
"requireBranch": "main",
"push": false,
"tag": true,
"tagName": null,
"tagAnnotation": "${version}"
},
"npm": {
"publish": false
},
"hooks": {
"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node order.js && git add src/locales"
}
}
}

View File

@@ -1,5 +1,5 @@
<script> <script>
import { apikey, api_endpoint, lang, page, clear } from "./store.js"; import { apikey, api_endpoint, lang, clear, laptime_track } from "./store.js";
import { addMessages, init } from "svelte-i18n"; import { addMessages, init } from "svelte-i18n";
import en from "./locales/en.json"; import en from "./locales/en.json";
import de from "./locales/de.json"; import de from "./locales/de.json";
@@ -11,8 +11,13 @@
import Beamershow from "./Beamershow.svelte"; import Beamershow from "./Beamershow.svelte";
import Login from "./Login.svelte"; import Login from "./Login.svelte";
import Settings from "./Settings.svelte"; import Settings from "./Settings.svelte";
$: is_configured = $apikey && $apikey !== "null" && $apikey !== ""; export let settings_open = false;
$: settings_open = $page === "settings"; $: is_configured =
$apikey &&
$apikey !== "null" &&
$apikey !== "" &&
$laptime_track != 0 &&
$laptime_track != null;
init({ init({
fallbackLocale: "en-US", fallbackLocale: "en-US",
initialLocale: $lang, initialLocale: $lang,
@@ -35,9 +40,7 @@
} else if (command === "c" && e.key === "n") { } else if (command === "c" && e.key === "n") {
command += "n"; command += "n";
} else if (command === "cn" && e.key === "f") { } else if (command === "cn" && e.key === "f") {
clear();
settings_open = true; settings_open = true;
is_configured = true;
command = ""; command = "";
} else { } else {
command = ""; command = "";
@@ -48,7 +51,7 @@
</script> </script>
{#if settings_open && is_configured} {#if settings_open && is_configured}
<Settings /> <Settings bind:settings_open />
{:else if is_configured} {:else if is_configured}
<Beamershow /> <Beamershow />
{:else} {:else}

View File

@@ -1,15 +1,22 @@
<script> <script>
import axios from "axios"; import axios from "axios";
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { fade, slide } from "svelte/transition"; import { slide } from "svelte/transition";
import { apikey, api_endpoint, page, stationinfo } from "./store.js"; import { apikey, api_endpoint, laptime_track } from "./store.js";
function init(el) { function init(el) {
el.focus(); el.focus();
} }
$: pages = ["general", "runners_distance", "orgs_distance", "teams_distance"]; $: pages = [
"general",
"runners_distance",
"runners_laptime",
"orgs_distance",
"teams_distance",
];
$: current_page = "general"; $: current_page = "general";
$: general = {}; $: general = {};
$: runners = []; $: runners = [];
$: runners_by_laptime = [];
$: orgs = []; $: orgs = [];
$: teams = []; $: teams = [];
@@ -17,6 +24,23 @@
$: hours = (time.getHours() + "").padStart(2, "0"); $: hours = (time.getHours() + "").padStart(2, "0");
$: minutes = (time.getMinutes() + "").padStart(2, "0"); $: minutes = (time.getMinutes() + "").padStart(2, "0");
$: seconds = (time.getSeconds() + "").padStart(2, "0"); $: seconds = (time.getSeconds() + "").padStart(2, "0");
function format_laptime(laptime) {
if (laptime < 60) {
return `${laptime}s`;
}
if (laptime < 3600) {
return `${Math.floor(laptime / 60)}min ${
laptime - Math.floor(laptime / 60) * 60
}s`;
}
return `${Math.floor(laptime / 3600)}h ${
laptime - Math.floor(laptime / 3600) * 3600
}min ${
laptime -
Math.floor(laptime / 3600) * 3600 -
Math.floor(laptime / 60) * 60
}`;
}
function stats_general() { function stats_general() {
axios axios
.request({ .request({
@@ -45,6 +69,21 @@
console.log(e); console.log(e);
}); });
} }
function stats_runners_by_laptime() {
axios
.request({
method: "GET",
url:
$api_endpoint + "api/stats/runners/laptime?track=" + $laptime_track,
headers: { Authorization: "Bearer " + $apikey },
})
.then(function ({ data }) {
runners_by_laptime = data;
})
.catch(function (e) {
console.log(e);
});
}
function stats_orgs() { function stats_orgs() {
axios axios
.request({ .request({
@@ -81,6 +120,7 @@
function fetch_all() { function fetch_all() {
stats_general(); stats_general();
stats_runners(); stats_runners();
stats_runners_by_laptime();
stats_orgs(); stats_orgs();
stats_teams(); stats_teams();
} }
@@ -113,7 +153,7 @@
{general.total_runners} {general.total_runners}
</h1> </h1>
<h1 class="text-2xl font-semibold text-center text-gray-900"> <h1 class="text-2xl font-semibold text-center text-gray-900">
Läufer {$_("laeufer")}
</h1> </h1>
</div> </div>
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/2 md:w-1/3"> <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2 md:w-1/3">
@@ -121,7 +161,7 @@
{general.total_distance} {general.total_distance}
</h1> </h1>
<h1 class="text-2xl font-semibold text-center text-gray-900"> <h1 class="text-2xl font-semibold text-center text-gray-900">
Kilometer gesamt {$_("kilometer-gesamt")}
</h1> </h1>
</div> </div>
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/2 md:w-1/3"> <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2 md:w-1/3">
@@ -129,7 +169,7 @@
{general.total_donation} {general.total_donation}
</h1> </h1>
<h1 class="text-2xl font-semibold text-center text-gray-900"> <h1 class="text-2xl font-semibold text-center text-gray-900">
Spendensumme {$_("spendensumme")}
</h1> </h1>
</div> </div>
</div> </div>
@@ -137,7 +177,7 @@
{:else if current_page === "runners_distance"} {:else if current_page === "runners_distance"}
<div transition:slide|local> <div transition:slide|local>
<h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5"> <h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5">
Top-Läufer {$_("top-laeufer")} ({$_("distanz")})
</h1> </h1>
<table class="table p-4 bg-white shadow rounded-lg w-full"> <table class="table p-4 bg-white shadow rounded-lg w-full">
<thead> <thead>
@@ -145,22 +185,22 @@
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Platz {$_("platz")}
</th> </th>
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Läufer {$_("laeufer")}
</th> </th>
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Organisation {$_("organisation")}
</th> </th>
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Kilometer {$_("kilometer")}
</th> </th>
</tr> </tr>
</thead> </thead>
@@ -185,10 +225,10 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{:else if current_page === "orgs_distance"} {:else if current_page === "runners_laptime"}
<div transition:slide|local> <div transition:slide|local>
<h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5"> <h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5">
Top-Organsiationen {$_("top-laeufer")} ({$_("rundenzeit")})
</h1> </h1>
<table class="table p-4 bg-white shadow rounded-lg w-full"> <table class="table p-4 bg-white shadow rounded-lg w-full">
<thead> <thead>
@@ -196,17 +236,68 @@
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Platz {$_("platz")}
</th> </th>
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Organsiation {$_("laeufer")}
</th> </th>
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Kilometer {$_("organisation")}
</th>
<th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
>
{$_("schnellste-rundenzeit")}
</th>
</tr>
</thead>
<tbody>
{#each runners_by_laptime as r, i}
<tr class="text-gray-700">
<td class="border p-4 dark:border-dark-5">
{i + 1}
</td>
<td class="border p-4 dark:border-dark-5">
{r.firstname}
{r.lastname}
</td>
<td class="border p-4 dark:border-dark-5">
{r.group.name}
</td>
<td class="border p-4 dark:border-dark-5">
{format_laptime(r.minLaptime)}
</td>
</tr>
{/each}
</tbody>
</table>
</div>
{:else if current_page === "orgs_distance"}
<div transition:slide|local>
<h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5">
{$_("top-organsiationen")}
</h1>
<table class="table p-4 bg-white shadow rounded-lg w-full">
<thead>
<tr>
<th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
>
{$_("platz")}
</th>
<th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
>
{$_("organsiation")}
</th>
<th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
>
{$_("kilometer")}
</th> </th>
</tr> </tr>
</thead> </thead>
@@ -230,7 +321,7 @@
{:else if current_page === "teams_distance"} {:else if current_page === "teams_distance"}
<div transition:slide|local> <div transition:slide|local>
<h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5"> <h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5">
Top-Teams {$_("top-teams")}
</h1> </h1>
<table class="table p-4 bg-white shadow rounded-lg w-full"> <table class="table p-4 bg-white shadow rounded-lg w-full">
<thead> <thead>
@@ -238,17 +329,17 @@
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Platz {$_("platz")}
</th> </th>
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Team {$_("team")}
</th> </th>
<th <th
class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900" class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
> >
Kilometer {$_("kilometer")}
</th> </th>
</tr> </tr>
</thead> </thead>

View File

@@ -1,39 +1,19 @@
<script> <script>
import { apikey, lang, stationinfo, api_endpoint } from "./store.js"; import { apikey, lang, api_endpoint, laptime_track } from "./store.js";
import isURL from "validator/lib/isURL";
import isUUID from "validator/lib/isUUID";
import axios from "axios"; import axios from "axios";
import { _, locale } from "svelte-i18n"; import { _, locale } from "svelte-i18n";
let token; let token;
let api_endpoint_input; let api_endpoint_input = "";
let track;
$: error = false; $: error = false;
$: errormessage = ""; $: errormessage = "";
$: isTokenValid = $: isTokenValid =
token?.length === 44 && token?.length === 44 &&
token.split(".")[0].length === 7 && token.split(".")[0].length === 7 &&
isUUID(token.split(".")[1]); isUUID(token.split(".")[1]);
$: isEndpointValid = validURL(api_endpoint_input); $: isEndpointValid = isURL(api_endpoint_input);
function validURL(str) {
var pattern = new RegExp(
"^(https?:\\/\\/)?" + // protocol
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
"((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
"(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path
"(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
"(\\#[-a-z\\d_]*)?$",
"i"
); // fragment locator
return !!pattern.test(str);
}
function isUUID(uuid) {
let s = "" + uuid;
s = s.match(
"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
);
if (s === null) {
return false;
}
return true;
}
</script> </script>
<div class="w-full flex flex-wrap"> <div class="w-full flex flex-wrap">
@@ -82,13 +62,11 @@
</div> </div>
{/if} {/if}
{/if} {/if}
{#if $api_endpoint} {#if $api_endpoint && !$apikey}
<form <form
class="flex flex-col pt-3 md:pt-8" class="flex flex-col pt-3 md:pt-8"
onsubmit="event.preventDefault();" onsubmit="event.preventDefault();"
on:submit={() => { on:submit={() => {
console.log({ token });
// return
axios axios
.request({ .request({
method: "GET", method: "GET",
@@ -99,7 +77,6 @@
error = false; error = false;
errormessage = ""; errormessage = "";
apikey.set(token); apikey.set(token);
stationinfo.set(JSON.stringify(response.data));
}) })
.catch(function (e) { .catch(function (e) {
error = true; error = true;
@@ -135,6 +112,37 @@
>{$_("configure")}</button >{$_("configure")}</button
> >
</form> </form>
{:else if $api_endpoint && $apikey}
<form
class="flex flex-col pt-3 md:pt-8"
onsubmit="event.preventDefault();"
on:submit={() => {
laptime_track.set(track);
}}
>
<div class="flex flex-col pt-4">
<label for="track" class="text-lg">{$_("track_id")}</label>
<input
type="number"
id="track"
placeholder="Track"
bind:value={track}
class:border-red-500={!isTokenValid}
class:border-solid={!isTokenValid}
class:border-3={!isTokenValid}
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mt-1 leading-tight focus:outline-none focus:shadow-outline"
/>
</div>
<button
disabled={!track}
class:cursor-pointer={track}
class:opacity-50={!track}
id="configure"
type="submit"
class="bg-black text-white font-bold text-lg hover:bg-gray-700 p-2 mt-8 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black"
>{$_("configure")}</button
>
</form>
{:else} {:else}
<form <form
class="flex flex-col pt-3 md:pt-8" class="flex flex-col pt-3 md:pt-8"

View File

@@ -1,7 +1,7 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { apikey, api_endpoint, lang, laptime_track, clear } from "./store.js";
import { apikey, api_endpoint, lang, page, stationinfo } from "./store.js"; export let settings_open = false;
</script> </script>
<div class="p-5 min-h-screen"> <div class="p-5 min-h-screen">
@@ -9,34 +9,12 @@
Lauf Für Kaya! Beamershow Lauf Für Kaya! Beamershow
</h1> </h1>
<h1 class="text-3xl w-full text-center text-gray-900">{$_("settings")}</h1> <h1 class="text-3xl w-full text-center text-gray-900">{$_("settings")}</h1>
<p class="block text-sm font-bold text-gray-700 mt-2">{$_("api_endpoint")}</p>
<p class="block text-sm text-gray-700">{$api_endpoint}</p>
<p class="block text-sm font-bold text-gray-700 mt-2">{$_("api_key")}</p> <p class="block text-sm font-bold text-gray-700 mt-2">{$_("api_key")}</p>
<p class="block text-sm text-gray-700">{$apikey}</p> <p class="block text-sm text-gray-700">{$apikey}</p>
<p class="block text-sm font-bold text-gray-700 mt-2">
{$_("station_description")}
</p>
<p class="block text-sm text-gray-700">
{JSON.parse($stationinfo).description}
</p>
<p class="block text-sm font-bold text-gray-700 mt-2">{$_("station_id")}</p>
<p class="block text-sm text-gray-700">{JSON.parse($stationinfo).id}</p>
<p class="block text-sm font-bold text-gray-700 mt-2">{$_("track_id")}</p> <p class="block text-sm font-bold text-gray-700 mt-2">{$_("track_id")}</p>
<p class="block text-sm text-gray-700">{JSON.parse($stationinfo).track.id}</p> <p class="block text-sm text-gray-700">{$laptime_track}</p>
<p class="block text-sm font-bold text-gray-700 mt-2">{$_("track_name")}</p>
<p class="block text-sm text-gray-700">
{JSON.parse($stationinfo).track.name}
</p>
<p class="block text-sm font-bold text-gray-700 mt-2">
{$_("track_distance")}
</p>
<p class="block text-sm text-gray-700">
{JSON.parse($stationinfo).track.distance}
</p>
<p class="block text-sm font-bold text-gray-700 mt-2">
{$_("minimum_lap_time")}
</p>
<p class="block text-sm text-gray-700">
{JSON.parse($stationinfo).track.minimumLapTime}s
</p>
<p class="block text-sm font-bold text-gray-700 mt-2">{$_("language")}</p> <p class="block text-sm font-bold text-gray-700 mt-2">{$_("language")}</p>
<div class="w-full"> <div class="w-full">
<div class="inline-block mr-2 mt-2"> <div class="inline-block mr-2 mt-2">
@@ -95,16 +73,15 @@
<br /> <br />
<button <button
on:click={() => { on:click={() => {
page.set(""); settings_open = false;
}} }}
class="mb-3 w-full py-3 border-black border-3 text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black" class="mb-3 w-full py-3 border-black border-3 text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black"
>{$_("back_to_scanner")}</button >{$_("back_to_scanner")}</button
> >
<button <button
on:click={() => { on:click={() => {
apikey.set(""); clear();
api_endpoint.set(""); settings_open = false;
page.set("");
}} }}
class="w-full py-3 bg-black text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black" class="w-full py-3 bg-black text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black"
>{$_("log_out_from_this_client")}</button >{$_("log_out_from_this_client")}</button

View File

@@ -1,27 +1,41 @@
{ {
"api_endpoint": "API-Endpunkt", "api_endpoint": "API-Endpunkt",
"api_key": "API Key", "api_key": "API Key",
"back_to_scanner": "Zurück zum Scanner", "back_to_scanner": "Zurück zur Beamershow",
"client_token": "Client Token", "client_token": "Client Token",
"configuration": "Konfiguration", "configuration": "Konfiguration",
"configure": "Konfigurieren", "configure": "Konfigurieren",
"distanz": "Distanz",
"error": "Error!", "error": "Error!",
"kilometer": "Kilometer",
"kilometer-gesamt": "Kilometer gesamt",
"laeufer": "Läufer",
"language": "Sprache", "language": "Sprache",
"log_out_from_this_client": "Von diesem Scanner abmelden", "log_out_from_this_client": "Von dieser Beamershow abmelden",
"minimum_lap_time": "minimale Rundenzeit", "minimum_lap_time": "minimale Rundenzeit",
"organisation": "Organisation",
"organsiation": "Organsiation",
"platz": "Platz",
"please_check_your_token_and_try_again": "Bitte überprüfe den Token und versuche es erneut...", "please_check_your_token_and_try_again": "Bitte überprüfe den Token und versuche es erneut...",
"please_provide_a_valid_client_api_endpoint": "Bitte gebe einen gültigen API-Endpunkt an ...", "please_provide_a_valid_client_api_endpoint": "Bitte gebe einen gültigen API-Endpunkt an ...",
"please_provide_a_valid_client_token": "Bitte gebe einen gültigen Client-Token an ...", "please_provide_a_valid_client_token": "Bitte gebe einen gültigen Client-Token an ...",
"please_provide_the_scan_client_token": "Bitte gebe den Beamershow-Client-Token an.", "please_provide_the_scan_client_token": "Bitte gebe den Beamershow-Client-Token an.",
"please_scan_a_card": "Bitte scanne eine Karte ...", "please_scan_a_card": "Bitte scanne eine Karte ...",
"rundenzeit": "Rundenzeit",
"runner_card": "Läuferkarte", "runner_card": "Läuferkarte",
"scan": "Scannen!", "scan": "Scannen!",
"schnellste-rundenzeit": "Schnellste Rundenzeit",
"see_our_configuration_guide": "Siehe dir unsere Konfigurationsanleitung an.", "see_our_configuration_guide": "Siehe dir unsere Konfigurationsanleitung an.",
"settings": "Einstellungen", "settings": "Einstellungen",
"spendensumme": "Spendensumme",
"station_description": "Beschreibung der Scanstation", "station_description": "Beschreibung der Scanstation",
"station_id": "Scanstations-ID", "station_id": "Scanstations-ID",
"team": "Team",
"the_provided_scan_station_is_disabled": "Die angegebene Scanstation ist deaktiviert.", "the_provided_scan_station_is_disabled": "Die angegebene Scanstation ist deaktiviert.",
"the_provided_scan_station_token_is_invalid": "Der angegebene Scanstation-Token ist ungültig.", "the_provided_scan_station_token_is_invalid": "Der angegebene Scanstation-Token ist ungültig.",
"top-laeufer": "Top-Läufer",
"top-organsiationen": "Top-Organsiationen",
"top-teams": "Top-Teams",
"track_distance": "Länge des Tracks", "track_distance": "Länge des Tracks",
"track_id": "Track ID", "track_id": "Track ID",
"track_name": "Track Name" "track_name": "Track Name"

View File

@@ -1,27 +1,41 @@
{ {
"api_endpoint": "API Endpoint", "api_endpoint": "API Endpoint",
"api_key": "API Key", "api_key": "API Key",
"back_to_scanner": "Back to Scanner", "back_to_scanner": "Back to Beamershow",
"client_token": "Client Token", "client_token": "Client Token",
"configuration": "Configuration", "configuration": "Configuration",
"configure": "Configure", "configure": "Configure",
"distanz": "distance",
"error": "Error!", "error": "Error!",
"kilometer": "Kilometers",
"kilometer-gesamt": "Kilometers total",
"laeufer": "Runners",
"language": "Language", "language": "Language",
"log_out_from_this_client": "Log Out from this Client", "log_out_from_this_client": "Log Out from this Client",
"minimum_lap_time": "minimum lap time", "minimum_lap_time": "minimum lap time",
"organisation": "Organization",
"organsiation": "Organization",
"platz": "Place",
"please_check_your_token_and_try_again": "Please check your token and try again...", "please_check_your_token_and_try_again": "Please check your token and try again...",
"please_provide_a_valid_client_api_endpoint": "Please provide a valid api endpoint...", "please_provide_a_valid_client_api_endpoint": "Please provide a valid api endpoint...",
"please_provide_a_valid_client_token": "Please provide a valid client token...", "please_provide_a_valid_client_token": "Please provide a valid client token...",
"please_provide_the_scan_client_token": "Please provide the scan client token.", "please_provide_the_scan_client_token": "Please provide the scan client token.",
"please_scan_a_card": "please scan a card...", "please_scan_a_card": "please scan a card...",
"rundenzeit": "fastetst lap",
"runner_card": "Runner Card", "runner_card": "Runner Card",
"scan": "Scan!", "scan": "Scan!",
"schnellste-rundenzeit": "Fastest lap",
"see_our_configuration_guide": "See our configuration guide.", "see_our_configuration_guide": "See our configuration guide.",
"settings": "Settings", "settings": "Settings",
"spendensumme": "Donations",
"station_description": "Station Description", "station_description": "Station Description",
"station_id": "Scanstation ID", "station_id": "Scanstation ID",
"team": "Team",
"the_provided_scan_station_is_disabled": "The provided scan station is disabled.", "the_provided_scan_station_is_disabled": "The provided scan station is disabled.",
"the_provided_scan_station_token_is_invalid": "The provided scan station token is invalid.", "the_provided_scan_station_token_is_invalid": "The provided scan station token is invalid.",
"top-laeufer": "Top runners",
"top-organsiationen": "Top organizations",
"top-teams": "Top teams",
"track_distance": "Track Distance", "track_distance": "Track Distance",
"track_id": "Track ID", "track_id": "Track ID",
"track_name": "Track Name" "track_name": "Track Name"

View File

@@ -10,15 +10,10 @@ export const apikey = writable(stored_apikey);
apikey.subscribe((value) => { apikey.subscribe((value) => {
localStorage.setItem('apikey', value); localStorage.setItem('apikey', value);
}); });
const stored_stationinfo = localStorage.getItem('stationinfo'); const stored_laptime_track = localStorage.getItem('laptime_track');
export const stationinfo = writable(stored_stationinfo); export const laptime_track = writable(stored_laptime_track);
stationinfo.subscribe((value) => { laptime_track.subscribe((value) => {
localStorage.setItem('stationinfo', value); localStorage.setItem('laptime_track', value);
});
const stored_page = localStorage.getItem('page');
export const page = writable(stored_page);
page.subscribe((value) => {
localStorage.setItem('page', value);
}); });
const stored_lang = localStorage.getItem('lang') === 'null' ? navigator.language : localStorage.getItem('lang'); const stored_lang = localStorage.getItem('lang') === 'null' ? navigator.language : localStorage.getItem('lang');
export const lang = writable(stored_lang); export const lang = writable(stored_lang);
@@ -29,5 +24,6 @@ lang.subscribe((value) => {
export function clear(){ export function clear(){
api_endpoint.set(null) api_endpoint.set(null)
apikey.set(null); apikey.set(null);
laptime_track.set(null)
localStorage.clear(); localStorage.clear();
} }