🎉 initial commit
This commit is contained in:
		
							
								
								
									
										24
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
**/.classpath
 | 
			
		||||
**/.dockerignore
 | 
			
		||||
**/.env
 | 
			
		||||
**/.git
 | 
			
		||||
**/.gitignore
 | 
			
		||||
**/.project
 | 
			
		||||
**/.settings
 | 
			
		||||
**/.toolstarget
 | 
			
		||||
**/.vs
 | 
			
		||||
**/.vscode
 | 
			
		||||
**/*.*proj.user
 | 
			
		||||
**/*.dbmdl
 | 
			
		||||
**/*.jfm
 | 
			
		||||
**/azds.yaml
 | 
			
		||||
**/charts
 | 
			
		||||
**/docker-compose*
 | 
			
		||||
**/compose*
 | 
			
		||||
**/Dockerfile*
 | 
			
		||||
**/node_modules
 | 
			
		||||
**/npm-debug.log
 | 
			
		||||
**/obj
 | 
			
		||||
**/secrets.dev.yaml
 | 
			
		||||
**/values.dev.yaml
 | 
			
		||||
README.md
 | 
			
		||||
							
								
								
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/node_modules/
 | 
			
		||||
/dist/
 | 
			
		||||
.DS_Store
 | 
			
		||||
package-lock.json
 | 
			
		||||
yarn.lock
 | 
			
		||||
/out
 | 
			
		||||
/yarn.lock
 | 
			
		||||
/app/node_modules
 | 
			
		||||
/app/dist
 | 
			
		||||
							
								
								
									
										1
									
								
								.husky/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.husky/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
_
 | 
			
		||||
							
								
								
									
										5
									
								
								.husky/pre-commit
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.husky/pre-commit
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
. "$(dirname "$0")/_/husky.sh"
 | 
			
		||||
 | 
			
		||||
yarn format
 | 
			
		||||
yarn license:export
 | 
			
		||||
							
								
								
									
										7
									
								
								.vscode/i18n-ally-custom-framework.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.vscode/i18n-ally-custom-framework.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
languageIds:
 | 
			
		||||
    - javascript
 | 
			
		||||
    - svelte
 | 
			
		||||
    - html
 | 
			
		||||
monopoly: false
 | 
			
		||||
refactorTemplates:
 | 
			
		||||
    - "{$_('$1')}"
 | 
			
		||||
							
								
								
									
										4
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
    "i18n-ally.localesPaths": "src/locales",
 | 
			
		||||
    "i18n-ally.keystyle": "nested"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
FROM node:15.11.0-alpine3.13
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
COPY . .
 | 
			
		||||
RUN yarn
 | 
			
		||||
RUN yarn build
 | 
			
		||||
							
								
								
									
										362
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										362
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,362 @@
 | 
			
		||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Creative
 | 
			
		||||
Commons Corporation ("Creative Commons") is not a law firm and does not provide
 | 
			
		||||
legal services or legal advice. Distribution of Creative Commons public licenses
 | 
			
		||||
does not create a lawyer-client or other relationship. Creative Commons makes
 | 
			
		||||
its licenses and related information available on an "as-is" basis. Creative
 | 
			
		||||
Commons gives no warranties regarding its licenses, any material licensed
 | 
			
		||||
under their terms and conditions, or any related information. Creative Commons
 | 
			
		||||
disclaims all liability for damages resulting from their use to the fullest
 | 
			
		||||
extent possible.
 | 
			
		||||
 | 
			
		||||
Using Creative Commons Public Licenses
 | 
			
		||||
 | 
			
		||||
Creative Commons public licenses provide a standard set of terms and conditions
 | 
			
		||||
that creators and other rights holders may use to share original works of
 | 
			
		||||
authorship and other material subject to copyright and certain other rights
 | 
			
		||||
specified in the public license below. The following considerations are for
 | 
			
		||||
informational purposes only, are not exhaustive, and do not form part of our
 | 
			
		||||
licenses.
 | 
			
		||||
 | 
			
		||||
Considerations for licensors: Our public licenses are intended for use by
 | 
			
		||||
those authorized to give the public permission to use material in ways otherwise
 | 
			
		||||
restricted by copyright and certain other rights. Our licenses are irrevocable.
 | 
			
		||||
Licensors should read and understand the terms and conditions of the license
 | 
			
		||||
they choose before applying it. Licensors should also secure all rights necessary
 | 
			
		||||
before applying our licenses so that the public can reuse the material as
 | 
			
		||||
expected. Licensors should clearly mark any material not subject to the license.
 | 
			
		||||
This includes other CC-licensed material, or material used under an exception
 | 
			
		||||
or limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors
 | 
			
		||||
 | 
			
		||||
Considerations for the public: By using one of our public licenses, a licensor
 | 
			
		||||
grants the public permission to use the licensed material under specified
 | 
			
		||||
terms and conditions. If the licensor's permission is not necessary for any
 | 
			
		||||
reason–for example, because of any applicable exception or limitation to copyright–then
 | 
			
		||||
that use is not regulated by the license. Our licenses grant only permissions
 | 
			
		||||
under copyright and certain other rights that a licensor has authority to
 | 
			
		||||
grant. Use of the licensed material may still be restricted for other reasons,
 | 
			
		||||
including because others have copyright or other rights in the material. A
 | 
			
		||||
licensor may make special requests, such as asking that all changes be marked
 | 
			
		||||
or described. Although not required by our licenses, you are encouraged to
 | 
			
		||||
respect those requests where reasonable. More considerations for the public
 | 
			
		||||
: wiki.creativecommons.org/Considerations_for_licensees
 | 
			
		||||
 | 
			
		||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public
 | 
			
		||||
License
 | 
			
		||||
 | 
			
		||||
By exercising the Licensed Rights (defined below), You accept and agree to
 | 
			
		||||
be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike
 | 
			
		||||
4.0 International Public License ("Public License"). To the extent this Public
 | 
			
		||||
License may be interpreted as a contract, You are granted the Licensed Rights
 | 
			
		||||
in consideration of Your acceptance of these terms and conditions, and the
 | 
			
		||||
Licensor grants You such rights in consideration of benefits the Licensor
 | 
			
		||||
receives from making the Licensed Material available under these terms and
 | 
			
		||||
conditions.
 | 
			
		||||
 | 
			
		||||
Section 1 – Definitions.
 | 
			
		||||
 | 
			
		||||
a. Adapted Material means material subject to Copyright and Similar Rights
 | 
			
		||||
that is derived from or based upon the Licensed Material and in which the
 | 
			
		||||
Licensed Material is translated, altered, arranged, transformed, or otherwise
 | 
			
		||||
modified in a manner requiring permission under the Copyright and Similar
 | 
			
		||||
Rights held by the Licensor. For purposes of this Public License, where the
 | 
			
		||||
Licensed Material is a musical work, performance, or sound recording, Adapted
 | 
			
		||||
Material is always produced where the Licensed Material is synched in timed
 | 
			
		||||
relation with a moving image.
 | 
			
		||||
 | 
			
		||||
b. Adapter's License means the license You apply to Your Copyright and Similar
 | 
			
		||||
Rights in Your contributions to Adapted Material in accordance with the terms
 | 
			
		||||
and conditions of this Public License.
 | 
			
		||||
 | 
			
		||||
c. BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses,
 | 
			
		||||
approved by Creative Commons as essentially the equivalent of this Public
 | 
			
		||||
License.
 | 
			
		||||
 | 
			
		||||
d. Copyright and Similar Rights means copyright and/or similar rights closely
 | 
			
		||||
related to copyright including, without limitation, performance, broadcast,
 | 
			
		||||
sound recording, and Sui Generis Database Rights, without regard to how the
 | 
			
		||||
rights are labeled or categorized. For purposes of this Public License, the
 | 
			
		||||
rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
 | 
			
		||||
 | 
			
		||||
e. Effective Technological Measures means those measures that, in the absence
 | 
			
		||||
of proper authority, may not be circumvented under laws fulfilling obligations
 | 
			
		||||
under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996,
 | 
			
		||||
and/or similar international agreements.
 | 
			
		||||
 | 
			
		||||
f. Exceptions and Limitations means fair use, fair dealing, and/or any other
 | 
			
		||||
exception or limitation to Copyright and Similar Rights that applies to Your
 | 
			
		||||
use of the Licensed Material.
 | 
			
		||||
 | 
			
		||||
g. License Elements means the license attributes listed in the name of a Creative
 | 
			
		||||
Commons Public License. The License Elements of this Public License are Attribution,
 | 
			
		||||
NonCommercial, and ShareAlike.
 | 
			
		||||
 | 
			
		||||
h. Licensed Material means the artistic or literary work, database, or other
 | 
			
		||||
material to which the Licensor applied this Public License.
 | 
			
		||||
 | 
			
		||||
i. Licensed Rights means the rights granted to You subject to the terms and
 | 
			
		||||
conditions of this Public License, which are limited to all Copyright and
 | 
			
		||||
Similar Rights that apply to Your use of the Licensed Material and that the
 | 
			
		||||
Licensor has authority to license.
 | 
			
		||||
 | 
			
		||||
j. Licensor means the individual(s) or entity(ies) granting rights under this
 | 
			
		||||
Public License.
 | 
			
		||||
 | 
			
		||||
k. NonCommercial means not primarily intended for or directed towards commercial
 | 
			
		||||
advantage or monetary compensation. For purposes of this Public License, the
 | 
			
		||||
exchange of the Licensed Material for other material subject to Copyright
 | 
			
		||||
and Similar Rights by digital file-sharing or similar means is NonCommercial
 | 
			
		||||
provided there is no payment of monetary compensation in connection with the
 | 
			
		||||
exchange.
 | 
			
		||||
 | 
			
		||||
l. Share means to provide material to the public by any means or process that
 | 
			
		||||
requires permission under the Licensed Rights, such as reproduction, public
 | 
			
		||||
display, public performance, distribution, dissemination, communication, or
 | 
			
		||||
importation, and to make material available to the public including in ways
 | 
			
		||||
that members of the public may access the material from a place and at a time
 | 
			
		||||
individually chosen by them.
 | 
			
		||||
 | 
			
		||||
m. Sui Generis Database Rights means rights other than copyright resulting
 | 
			
		||||
from Directive 96/9/EC of the European Parliament and of the Council of 11
 | 
			
		||||
March 1996 on the legal protection of databases, as amended and/or succeeded,
 | 
			
		||||
as well as other essentially equivalent rights anywhere in the world.
 | 
			
		||||
 | 
			
		||||
n. You means the individual or entity exercising the Licensed Rights under
 | 
			
		||||
this Public License. Your has a corresponding meaning.
 | 
			
		||||
 | 
			
		||||
Section 2 – Scope.
 | 
			
		||||
 | 
			
		||||
   a. License grant.
 | 
			
		||||
 | 
			
		||||
1. Subject to the terms and conditions of this Public License, the Licensor
 | 
			
		||||
hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive,
 | 
			
		||||
irrevocable license to exercise the Licensed Rights in the Licensed Material
 | 
			
		||||
to:
 | 
			
		||||
 | 
			
		||||
A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial
 | 
			
		||||
purposes only; and
 | 
			
		||||
 | 
			
		||||
B. produce, reproduce, and Share Adapted Material for NonCommercial purposes
 | 
			
		||||
only.
 | 
			
		||||
 | 
			
		||||
2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions
 | 
			
		||||
and Limitations apply to Your use, this Public License does not apply, and
 | 
			
		||||
You do not need to comply with its terms and conditions.
 | 
			
		||||
 | 
			
		||||
      3. Term. The term of this Public License is specified in Section 6(a).
 | 
			
		||||
 | 
			
		||||
4. Media and formats; technical modifications allowed. The Licensor authorizes
 | 
			
		||||
You to exercise the Licensed Rights in all media and formats whether now known
 | 
			
		||||
or hereafter created, and to make technical modifications necessary to do
 | 
			
		||||
so. The Licensor waives and/or agrees not to assert any right or authority
 | 
			
		||||
to forbid You from making technical modifications necessary to exercise the
 | 
			
		||||
Licensed Rights, including technical modifications necessary to circumvent
 | 
			
		||||
Effective Technological Measures. For purposes of this Public License, simply
 | 
			
		||||
making modifications authorized by this Section 2(a)(4) never produces Adapted
 | 
			
		||||
Material.
 | 
			
		||||
 | 
			
		||||
      5. Downstream recipients.
 | 
			
		||||
 | 
			
		||||
A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed
 | 
			
		||||
Material automatically receives an offer from the Licensor to exercise the
 | 
			
		||||
Licensed Rights under the terms and conditions of this Public License.
 | 
			
		||||
 | 
			
		||||
B. Additional offer from the Licensor – Adapted Material. Every recipient
 | 
			
		||||
of Adapted Material from You automatically receives an offer from the Licensor
 | 
			
		||||
to exercise the Licensed Rights in the Adapted Material under the conditions
 | 
			
		||||
of the Adapter's License You apply.
 | 
			
		||||
 | 
			
		||||
C. No downstream restrictions. You may not offer or impose any additional
 | 
			
		||||
or different terms or conditions on, or apply any Effective Technological
 | 
			
		||||
Measures to, the Licensed Material if doing so restricts exercise of the Licensed
 | 
			
		||||
Rights by any recipient of the Licensed Material.
 | 
			
		||||
 | 
			
		||||
6. No endorsement. Nothing in this Public License constitutes or may be construed
 | 
			
		||||
as permission to assert or imply that You are, or that Your use of the Licensed
 | 
			
		||||
Material is, connected with, or sponsored, endorsed, or granted official status
 | 
			
		||||
by, the Licensor or others designated to receive attribution as provided in
 | 
			
		||||
Section 3(a)(1)(A)(i).
 | 
			
		||||
 | 
			
		||||
   b. Other rights.
 | 
			
		||||
 | 
			
		||||
1. Moral rights, such as the right of integrity, are not licensed under this
 | 
			
		||||
Public License, nor are publicity, privacy, and/or other similar personality
 | 
			
		||||
rights; however, to the extent possible, the Licensor waives and/or agrees
 | 
			
		||||
not to assert any such rights held by the Licensor to the limited extent necessary
 | 
			
		||||
to allow You to exercise the Licensed Rights, but not otherwise.
 | 
			
		||||
 | 
			
		||||
2. Patent and trademark rights are not licensed under this Public License.
 | 
			
		||||
 | 
			
		||||
3. To the extent possible, the Licensor waives any right to collect royalties
 | 
			
		||||
from You for the exercise of the Licensed Rights, whether directly or through
 | 
			
		||||
a collecting society under any voluntary or waivable statutory or compulsory
 | 
			
		||||
licensing scheme. In all other cases the Licensor expressly reserves any right
 | 
			
		||||
to collect such royalties, including when the Licensed Material is used other
 | 
			
		||||
than for NonCommercial purposes.
 | 
			
		||||
 | 
			
		||||
Section 3 – License Conditions.
 | 
			
		||||
 | 
			
		||||
Your exercise of the Licensed Rights is expressly made subject to the following
 | 
			
		||||
conditions.
 | 
			
		||||
 | 
			
		||||
   a. Attribution.
 | 
			
		||||
 | 
			
		||||
1. If You Share the Licensed Material (including in modified form), You must:
 | 
			
		||||
 | 
			
		||||
A. retain the following if it is supplied by the Licensor with the Licensed
 | 
			
		||||
Material:
 | 
			
		||||
 | 
			
		||||
i. identification of the creator(s) of the Licensed Material and any others
 | 
			
		||||
designated to receive attribution, in any reasonable manner requested by the
 | 
			
		||||
Licensor (including by pseudonym if designated);
 | 
			
		||||
 | 
			
		||||
            ii. a copyright notice;
 | 
			
		||||
 | 
			
		||||
            iii. a notice that refers to this Public License;
 | 
			
		||||
 | 
			
		||||
            iv. a notice that refers to the disclaimer of warranties;
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
 | 
			
		||||
 | 
			
		||||
B. indicate if You modified the Licensed Material and retain an indication
 | 
			
		||||
of any previous modifications; and
 | 
			
		||||
 | 
			
		||||
C. indicate the Licensed Material is licensed under this Public License, and
 | 
			
		||||
include the text of, or the URI or hyperlink to, this Public License.
 | 
			
		||||
 | 
			
		||||
2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner
 | 
			
		||||
based on the medium, means, and context in which You Share the Licensed Material.
 | 
			
		||||
For example, it may be reasonable to satisfy the conditions by providing a
 | 
			
		||||
URI or hyperlink to a resource that includes the required information.
 | 
			
		||||
 | 
			
		||||
3. If requested by the Licensor, You must remove any of the information required
 | 
			
		||||
by Section 3(a)(1)(A) to the extent reasonably practicable.
 | 
			
		||||
 | 
			
		||||
b. ShareAlike.In addition to the conditions in Section 3(a), if You Share
 | 
			
		||||
Adapted Material You produce, the following conditions also apply.
 | 
			
		||||
 | 
			
		||||
1. The Adapter's License You apply must be a Creative Commons license with
 | 
			
		||||
the same License Elements, this version or later, or a BY-NC-SA Compatible
 | 
			
		||||
License.
 | 
			
		||||
 | 
			
		||||
2. You must include the text of, or the URI or hyperlink to, the Adapter's
 | 
			
		||||
License You apply. You may satisfy this condition in any reasonable manner
 | 
			
		||||
based on the medium, means, and context in which You Share Adapted Material.
 | 
			
		||||
 | 
			
		||||
3. You may not offer or impose any additional or different terms or conditions
 | 
			
		||||
on, or apply any Effective Technological Measures to, Adapted Material that
 | 
			
		||||
restrict exercise of the rights granted under the Adapter's License You apply.
 | 
			
		||||
 | 
			
		||||
Section 4 – Sui Generis Database Rights.
 | 
			
		||||
 | 
			
		||||
Where the Licensed Rights include Sui Generis Database Rights that apply to
 | 
			
		||||
Your use of the Licensed Material:
 | 
			
		||||
 | 
			
		||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,
 | 
			
		||||
reuse, reproduce, and Share all or a substantial portion of the contents of
 | 
			
		||||
the database for NonCommercial purposes only;
 | 
			
		||||
 | 
			
		||||
b. if You include all or a substantial portion of the database contents in
 | 
			
		||||
a database in which You have Sui Generis Database Rights, then the database
 | 
			
		||||
in which You have Sui Generis Database Rights (but not its individual contents)
 | 
			
		||||
is Adapted Material, including for purposes of Section 3(b); and
 | 
			
		||||
 | 
			
		||||
c. You must comply with the conditions in Section 3(a) if You Share all or
 | 
			
		||||
a substantial portion of the contents of the database.
 | 
			
		||||
 | 
			
		||||
For the avoidance of doubt, this Section 4 supplements and does not replace
 | 
			
		||||
Your obligations under this Public License where the Licensed Rights include
 | 
			
		||||
other Copyright and Similar Rights.
 | 
			
		||||
 | 
			
		||||
Section 5 – Disclaimer of Warranties and Limitation of Liability.
 | 
			
		||||
 | 
			
		||||
a. Unless otherwise separately undertaken by the Licensor, to the extent possible,
 | 
			
		||||
the Licensor offers the Licensed Material as-is and as-available, and makes
 | 
			
		||||
no representations or warranties of any kind concerning the Licensed Material,
 | 
			
		||||
whether express, implied, statutory, or other. This includes, without limitation,
 | 
			
		||||
warranties of title, merchantability, fitness for a particular purpose, non-infringement,
 | 
			
		||||
absence of latent or other defects, accuracy, or the presence or absence of
 | 
			
		||||
errors, whether or not known or discoverable. Where disclaimers of warranties
 | 
			
		||||
are not allowed in full or in part, this disclaimer may not apply to You.
 | 
			
		||||
 | 
			
		||||
b. To the extent possible, in no event will the Licensor be liable to You
 | 
			
		||||
on any legal theory (including, without limitation, negligence) or otherwise
 | 
			
		||||
for any direct, special, indirect, incidental, consequential, punitive, exemplary,
 | 
			
		||||
or other losses, costs, expenses, or damages arising out of this Public License
 | 
			
		||||
or use of the Licensed Material, even if the Licensor has been advised of
 | 
			
		||||
the possibility of such losses, costs, expenses, or damages. Where a limitation
 | 
			
		||||
of liability is not allowed in full or in part, this limitation may not apply
 | 
			
		||||
to You.
 | 
			
		||||
 | 
			
		||||
c. The disclaimer of warranties and limitation of liability provided above
 | 
			
		||||
shall be interpreted in a manner that, to the extent possible, most closely
 | 
			
		||||
approximates an absolute disclaimer and waiver of all liability.
 | 
			
		||||
 | 
			
		||||
Section 6 – Term and Termination.
 | 
			
		||||
 | 
			
		||||
a. This Public License applies for the term of the Copyright and Similar Rights
 | 
			
		||||
licensed here. However, if You fail to comply with this Public License, then
 | 
			
		||||
Your rights under this Public License terminate automatically.
 | 
			
		||||
 | 
			
		||||
b. Where Your right to use the Licensed Material has terminated under Section
 | 
			
		||||
6(a), it reinstates:
 | 
			
		||||
 | 
			
		||||
1. automatically as of the date the violation is cured, provided it is cured
 | 
			
		||||
within 30 days of Your discovery of the violation; or
 | 
			
		||||
 | 
			
		||||
      2. upon express reinstatement by the Licensor.
 | 
			
		||||
 | 
			
		||||
For the avoidance of doubt, this Section 6(b) does not affect any right the
 | 
			
		||||
Licensor may have to seek remedies for Your violations of this Public License.
 | 
			
		||||
 | 
			
		||||
c. For the avoidance of doubt, the Licensor may also offer the Licensed Material
 | 
			
		||||
under separate terms or conditions or stop distributing the Licensed Material
 | 
			
		||||
at any time; however, doing so will not terminate this Public License.
 | 
			
		||||
 | 
			
		||||
   d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
 | 
			
		||||
 | 
			
		||||
Section 7 – Other Terms and Conditions.
 | 
			
		||||
 | 
			
		||||
a. The Licensor shall not be bound by any additional or different terms or
 | 
			
		||||
conditions communicated by You unless expressly agreed.
 | 
			
		||||
 | 
			
		||||
b. Any arrangements, understandings, or agreements regarding the Licensed
 | 
			
		||||
Material not stated herein are separate from and independent of the terms
 | 
			
		||||
and conditions of this Public License.
 | 
			
		||||
 | 
			
		||||
Section 8 – Interpretation.
 | 
			
		||||
 | 
			
		||||
a. For the avoidance of doubt, this Public License does not, and shall not
 | 
			
		||||
be interpreted to, reduce, limit, restrict, or impose conditions on any use
 | 
			
		||||
of the Licensed Material that could lawfully be made without permission under
 | 
			
		||||
this Public License.
 | 
			
		||||
 | 
			
		||||
b. To the extent possible, if any provision of this Public License is deemed
 | 
			
		||||
unenforceable, it shall be automatically reformed to the minimum extent necessary
 | 
			
		||||
to make it enforceable. If the provision cannot be reformed, it shall be severed
 | 
			
		||||
from this Public License without affecting the enforceability of the remaining
 | 
			
		||||
terms and conditions.
 | 
			
		||||
 | 
			
		||||
c. No term or condition of this Public License will be waived and no failure
 | 
			
		||||
to comply consented to unless expressly agreed to by the Licensor.
 | 
			
		||||
 | 
			
		||||
d. Nothing in this Public License constitutes or may be interpreted as a limitation
 | 
			
		||||
upon, or waiver of, any privileges and immunities that apply to the Licensor
 | 
			
		||||
or You, including from the legal processes of any jurisdiction or authority.
 | 
			
		||||
 | 
			
		||||
Creative Commons is not a party to its public licenses. Notwithstanding, Creative
 | 
			
		||||
Commons may elect to apply one of its public licenses to material it publishes
 | 
			
		||||
and in those instances will be considered the "Licensor." The text of the
 | 
			
		||||
Creative Commons public licenses is dedicated to the public domain under the
 | 
			
		||||
CC0 Public Domain Dedication. Except for the limited purpose of indicating
 | 
			
		||||
that material is shared under a Creative Commons public license or as otherwise
 | 
			
		||||
permitted by the Creative Commons policies published at creativecommons.org/policies,
 | 
			
		||||
Creative Commons does not authorize the use of the trademark "Creative Commons"
 | 
			
		||||
or any other trademark or logo of Creative Commons without its prior written
 | 
			
		||||
consent including, without limitation, in connection with any unauthorized
 | 
			
		||||
modifications to any of its public licenses or any other arrangements, understandings,
 | 
			
		||||
or agreements concerning use of licensed material. For the avoidance of doubt,
 | 
			
		||||
this paragraph does not form part of the public licenses.
 | 
			
		||||
 | 
			
		||||
Creative Commons may be contacted at creativecommons.org.
 | 
			
		||||
							
								
								
									
										20
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
# @lfk/beamershow
 | 
			
		||||
 | 
			
		||||
## ✒️ Overview
 | 
			
		||||
This is an API client for [https://git.odit.services/lfk/backend](@lfk/backend)
 | 
			
		||||
- WebApp built with [Svelte](https://svelte.dev), [WindiCSS](https://windicss.org/) (to compile [TailwindCSS](https://tailwindcss.com/)) and [Vite](https://vitejs.dev).
 | 
			
		||||
 | 
			
		||||
## 🚀 Getting Started
 | 
			
		||||
```
 | 
			
		||||
yarn
 | 
			
		||||
```
 | 
			
		||||
## Development
 | 
			
		||||
```
 | 
			
		||||
yarn dev
 | 
			
		||||
/
 | 
			
		||||
yarn dev --open
 | 
			
		||||
```
 | 
			
		||||
## Build
 | 
			
		||||
```
 | 
			
		||||
yarn build
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										14
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="UTF-8" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
    <title>LfK!Beamershow</title>
 | 
			
		||||
    <base href="./" />
 | 
			
		||||
    <link rel="icon" type="image/png" href="./favicon.png" />
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body class="bg-white font-family-karla h-screen">
 | 
			
		||||
    <script type="module" src="./src/main.js"></script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										5004
									
								
								licenses.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5004
									
								
								licenses.md
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										16
									
								
								order.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								order.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
// get all language files
 | 
			
		||||
const files = fs.readdirSync('./src/locales/');
 | 
			
		||||
files.forEach((f) => {
 | 
			
		||||
	// read file as object
 | 
			
		||||
	const unordered = JSON.parse(fs.readFileSync(`src/locales/${f}`));
 | 
			
		||||
	// order object by keys alpabetically A-Z
 | 
			
		||||
	const ordered = Object.keys(unordered).sort().reduce((obj, key) => {
 | 
			
		||||
		obj[key] = unordered[key];
 | 
			
		||||
		return obj;
 | 
			
		||||
	}, {});
 | 
			
		||||
	// format output as json for commit diff compatibility
 | 
			
		||||
	const out = JSON.stringify(ordered, 0, 4);
 | 
			
		||||
	// write output file
 | 
			
		||||
	fs.writeFileSync(`src/locales/${f}`, out);
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										27
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "@lfk/beamershow",
 | 
			
		||||
	"version": "0.0.0",
 | 
			
		||||
	"scripts": {
 | 
			
		||||
		"dev": "vite",
 | 
			
		||||
		"build": "vite build",
 | 
			
		||||
		"format": "prettier --write --plugin-search-dir=. ./**/*.html ./**/*.svelte",
 | 
			
		||||
		"prepare": "husky install",
 | 
			
		||||
		"license:export": "license-exporter --markdown && git stage licenses.md"
 | 
			
		||||
	},
 | 
			
		||||
	"devDependencies": {
 | 
			
		||||
		"@odit/license-exporter": "^0.0.11",
 | 
			
		||||
		"@svitejs/vite-plugin-svelte": "^0.11.1",
 | 
			
		||||
		"@tsconfig/svelte": "^1.0.10",
 | 
			
		||||
		"@types/html-minifier": "^4.0.0",
 | 
			
		||||
		"axios": "^0.21.1",
 | 
			
		||||
		"html-minifier": "^4.0.0",
 | 
			
		||||
		"husky": "^5.1.3",
 | 
			
		||||
		"prettier": "^2.2.1",
 | 
			
		||||
		"prettier-plugin-svelte": "^2.2.0",
 | 
			
		||||
		"svelte": "3.36.0",
 | 
			
		||||
		"svelte-preprocess": "4.7.0",
 | 
			
		||||
		"vite": "2.1.4",
 | 
			
		||||
		"vite-plugin-windicss": "0.11.2",
 | 
			
		||||
		"svelte-i18n": "3.3.9"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								public/beamershow_background.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/beamershow_background.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 36 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/favicon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/favicon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 70 KiB  | 
							
								
								
									
										29
									
								
								src/App.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/App.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
<script>
 | 
			
		||||
  import { apikey, api_endpoint, lang, page } from "./store.js";
 | 
			
		||||
  import { addMessages, init } from "svelte-i18n";
 | 
			
		||||
  import en from "./locales/en.json";
 | 
			
		||||
  import de from "./locales/de.json";
 | 
			
		||||
  addMessages("en", en);
 | 
			
		||||
  addMessages("en-US", en);
 | 
			
		||||
  addMessages("de", de);
 | 
			
		||||
  addMessages("de-DE", de);
 | 
			
		||||
  //
 | 
			
		||||
  import Beamershow from "./Beamershow.svelte";
 | 
			
		||||
  import Login from "./Login.svelte";
 | 
			
		||||
  import Settings from "./Settings.svelte";
 | 
			
		||||
  $: is_configured = $apikey && $apikey !== "null" && $apikey !== "";
 | 
			
		||||
  $: settings_open = $page === "settings";
 | 
			
		||||
  init({
 | 
			
		||||
    fallbackLocale: "en-US",
 | 
			
		||||
    initialLocale: $lang,
 | 
			
		||||
  });
 | 
			
		||||
  console.log("app started with base url " + $api_endpoint);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#if settings_open && is_configured}
 | 
			
		||||
  <Settings />
 | 
			
		||||
{:else if is_configured}
 | 
			
		||||
  <Beamershow />
 | 
			
		||||
{:else}
 | 
			
		||||
  <Login />
 | 
			
		||||
{/if}
 | 
			
		||||
							
								
								
									
										219
									
								
								src/Beamershow.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								src/Beamershow.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,219 @@
 | 
			
		||||
<script>
 | 
			
		||||
  import axios from "axios";
 | 
			
		||||
  import { _ } from "svelte-i18n";
 | 
			
		||||
  import { apikey, api_endpoint, page, stationinfo } from "./store.js";
 | 
			
		||||
  function init(el) {
 | 
			
		||||
    el.focus();
 | 
			
		||||
  }
 | 
			
		||||
  $: pages = ["general", "runners_distance", "orgs_distance"];
 | 
			
		||||
  $: current_page = "general";
 | 
			
		||||
  $: general = {};
 | 
			
		||||
  $: runners = [];
 | 
			
		||||
  $: runners_filtered = runners
 | 
			
		||||
    .sort((a, b) => parseFloat(b.distance) - parseFloat(a.distance))
 | 
			
		||||
    .slice(0, 10);
 | 
			
		||||
  $: orgs = [];
 | 
			
		||||
  $: orgs_filtered = orgs
 | 
			
		||||
    .sort((a, b) => parseFloat(b.distance) - parseFloat(a.distance))
 | 
			
		||||
    .slice(0, 10);
 | 
			
		||||
  let time = new Date();
 | 
			
		||||
  $: hours = (time.getHours() + "").padStart(2, "0");
 | 
			
		||||
  $: minutes = (time.getMinutes() + "").padStart(2, "0");
 | 
			
		||||
  $: seconds = (time.getSeconds() + "").padStart(2, "0");
 | 
			
		||||
  function stats_general() {
 | 
			
		||||
    axios
 | 
			
		||||
      .request({
 | 
			
		||||
        method: "GET",
 | 
			
		||||
        url: $api_endpoint + "api/stats/",
 | 
			
		||||
        headers: { Authorization: "Bearer " + $apikey },
 | 
			
		||||
      })
 | 
			
		||||
      .then(function ({ data }) {
 | 
			
		||||
        general = data;
 | 
			
		||||
      })
 | 
			
		||||
      .catch(function (e) {
 | 
			
		||||
        error = true;
 | 
			
		||||
        errormessage = e.response.data.short;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
  function stats_runners() {
 | 
			
		||||
    axios
 | 
			
		||||
      .request({
 | 
			
		||||
        method: "GET",
 | 
			
		||||
        url: $api_endpoint + "api/stats/runners/distance",
 | 
			
		||||
        headers: { Authorization: "Bearer " + $apikey },
 | 
			
		||||
      })
 | 
			
		||||
      .then(function ({ data }) {
 | 
			
		||||
        runners = data;
 | 
			
		||||
      })
 | 
			
		||||
      .catch(function (e) {
 | 
			
		||||
        error = true;
 | 
			
		||||
        errormessage = e.response.data.short;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
  function stats_orgs() {
 | 
			
		||||
    axios
 | 
			
		||||
      .request({
 | 
			
		||||
        method: "GET",
 | 
			
		||||
        url: $api_endpoint + "api/stats/organizations/distance",
 | 
			
		||||
        headers: { Authorization: "Bearer " + $apikey },
 | 
			
		||||
      })
 | 
			
		||||
      .then(function ({ data }) {
 | 
			
		||||
        orgs = data;
 | 
			
		||||
      })
 | 
			
		||||
      .catch(function (e) {
 | 
			
		||||
        error = true;
 | 
			
		||||
        errormessage = e.response.data.short;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
  Array.prototype.cycle = function (str) {
 | 
			
		||||
    const i = this.indexOf(str);
 | 
			
		||||
    if (i === -1) return undefined;
 | 
			
		||||
    return this[(i + 1) % this.length];
 | 
			
		||||
  };
 | 
			
		||||
  function fetch_all() {
 | 
			
		||||
    stats_general();
 | 
			
		||||
    stats_runners();
 | 
			
		||||
    stats_orgs();
 | 
			
		||||
  }
 | 
			
		||||
  fetch_all();
 | 
			
		||||
  setInterval(() => {
 | 
			
		||||
    time = new Date();
 | 
			
		||||
  }, 1000);
 | 
			
		||||
  setInterval(() => {
 | 
			
		||||
    fetch_all();
 | 
			
		||||
  }, 15000);
 | 
			
		||||
  setInterval(() => {
 | 
			
		||||
    current_page = pages.cycle(current_page);
 | 
			
		||||
  }, 20000);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div
 | 
			
		||||
  class="min-h-screen flex items-center justify-center bg-gray-100"
 | 
			
		||||
  style="background-image: url('/beamershow_background.png');background-position: center;background-size: contain;background-repeat:no-repeat;"
 | 
			
		||||
>
 | 
			
		||||
  <div class="max-w-xl w-full">
 | 
			
		||||
    {#if current_page === "general"}
 | 
			
		||||
      <h1 class="mr-6 text-7xl font-semibold text-center text-gray-900">
 | 
			
		||||
        {hours}:{minutes}:{seconds}
 | 
			
		||||
      </h1>
 | 
			
		||||
      <!--  -->
 | 
			
		||||
      <div class="flex flex-wrap -mx-1 overflow-hidden mt-5">
 | 
			
		||||
        <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2 md:w-1/3">
 | 
			
		||||
          <h1 class="text-5xl font-semibold text-center text-gray-900">
 | 
			
		||||
            {general.total_runners}
 | 
			
		||||
          </h1>
 | 
			
		||||
          <h1 class="text-2xl font-semibold text-center text-gray-900">
 | 
			
		||||
            Läufer
 | 
			
		||||
          </h1>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2 md:w-1/3">
 | 
			
		||||
          <h1 class="text-5xl font-semibold text-center text-gray-900">
 | 
			
		||||
            {general.total_distance}
 | 
			
		||||
          </h1>
 | 
			
		||||
          <h1 class="text-2xl font-semibold text-center text-gray-900">
 | 
			
		||||
            Kilometer gesamt
 | 
			
		||||
          </h1>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="my-1 px-1 w-full overflow-hidden sm:w-1/2 md:w-1/3">
 | 
			
		||||
          <h1 class="text-5xl font-semibold text-center text-gray-900">
 | 
			
		||||
            {general.total_donation} €
 | 
			
		||||
          </h1>
 | 
			
		||||
          <h1 class="text-2xl font-semibold text-center text-gray-900">
 | 
			
		||||
            Spendensumme
 | 
			
		||||
          </h1>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    {:else if current_page === "runners_distance"}
 | 
			
		||||
      <h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5">
 | 
			
		||||
        Top-Läufer
 | 
			
		||||
      </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"
 | 
			
		||||
            >
 | 
			
		||||
              Läufer
 | 
			
		||||
            </th>
 | 
			
		||||
            <th
 | 
			
		||||
              class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
 | 
			
		||||
            >
 | 
			
		||||
              Firma
 | 
			
		||||
            </th>
 | 
			
		||||
            <th
 | 
			
		||||
              class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
 | 
			
		||||
            >
 | 
			
		||||
              Kilometer
 | 
			
		||||
            </th>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
          {#each runners_filtered 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">
 | 
			
		||||
                {r.distance / 1000} km
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          {/each}
 | 
			
		||||
        </tbody>
 | 
			
		||||
      </table>
 | 
			
		||||
    {:else if current_page === "orgs_distance"}
 | 
			
		||||
      <h1 class="mr-6 text-7xl font-semibold text-center text-gray-900 mb-5">
 | 
			
		||||
        Top-Firmen
 | 
			
		||||
      </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"
 | 
			
		||||
            >
 | 
			
		||||
              Firma
 | 
			
		||||
            </th>
 | 
			
		||||
            <th
 | 
			
		||||
              class="border p-4 dark:border-dark-5 whitespace-nowrap font-normal text-gray-900"
 | 
			
		||||
            >
 | 
			
		||||
              Kilometer
 | 
			
		||||
            </th>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
          {#each orgs_filtered as o, 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">
 | 
			
		||||
                {o.name}
 | 
			
		||||
              </td>
 | 
			
		||||
              <td class="border p-4 dark:border-dark-5">
 | 
			
		||||
                {o.distance / 1000} km
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          {/each}
 | 
			
		||||
        </tbody>
 | 
			
		||||
      </table>
 | 
			
		||||
    {:else}
 | 
			
		||||
      <!-- content here -->
 | 
			
		||||
    {/if}
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										268
									
								
								src/Login.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								src/Login.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,268 @@
 | 
			
		||||
<script>
 | 
			
		||||
  import { apikey, lang, stationinfo, api_endpoint } from "./store.js";
 | 
			
		||||
  import axios from "axios";
 | 
			
		||||
  import { _, locale } from "svelte-i18n";
 | 
			
		||||
  let token;
 | 
			
		||||
  let api_endpoint_input;
 | 
			
		||||
  $: error = false;
 | 
			
		||||
  $: errormessage = "";
 | 
			
		||||
  $: isTokenValid =
 | 
			
		||||
    token?.length === 44 &&
 | 
			
		||||
    token.split(".")[0].length === 7 &&
 | 
			
		||||
    isUUID(token.split(".")[1]);
 | 
			
		||||
  $: isEndpointValid = validURL(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>
 | 
			
		||||
 | 
			
		||||
<div class="w-full flex flex-wrap">
 | 
			
		||||
  <!-- Login Section -->
 | 
			
		||||
  <div class="w-full md:w-1/2 flex flex-col">
 | 
			
		||||
    <div class="flex justify-center md:justify-start pt-12 md:pl-12 md:-mb-24">
 | 
			
		||||
      <div class="bg-black text-white font-bold text-xl p-4">
 | 
			
		||||
        <img src="./favicon.png" alt="" style="height: 3rem;display: inline;" />
 | 
			
		||||
        LfK!Beamershow
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div
 | 
			
		||||
      class="flex flex-col justify-center md:justify-start my-auto pt-8 md:pt-0 px-8 md:px-24 lg:px-32"
 | 
			
		||||
    >
 | 
			
		||||
      <p class="text-center text-3xl">{$_("configuration")}</p>
 | 
			
		||||
      <p class="text-center">
 | 
			
		||||
        <a
 | 
			
		||||
          target="_blank"
 | 
			
		||||
          class="underline"
 | 
			
		||||
          href="https://docs.lauf-fuer-kaya.de/"
 | 
			
		||||
          >{$_("see_our_configuration_guide")}</a
 | 
			
		||||
        >
 | 
			
		||||
      </p>
 | 
			
		||||
      {#if error}
 | 
			
		||||
        {#if errormessage === "invalid_token"}
 | 
			
		||||
          <div
 | 
			
		||||
            class="text-white px-6 py-4 border-0 rounded relative bg-red-500 mt-2"
 | 
			
		||||
          >
 | 
			
		||||
            <span class="inline-block align-middle">
 | 
			
		||||
              <b class="capitalize">{$_("error")}</b><br />{$_(
 | 
			
		||||
                "the_provided_scan_station_token_is_invalid"
 | 
			
		||||
              )}<br />{$_("please_check_your_token_and_try_again")}
 | 
			
		||||
            </span>
 | 
			
		||||
          </div>
 | 
			
		||||
        {/if}
 | 
			
		||||
        {#if errormessage === "station_disabled"}
 | 
			
		||||
          <div
 | 
			
		||||
            class="text-white px-6 py-4 border-0 rounded relative bg-red-500 mt-2"
 | 
			
		||||
          >
 | 
			
		||||
            <span class="inline-block align-middle">
 | 
			
		||||
              <b class="capitalize">{$_("error")}</b><br />{$_(
 | 
			
		||||
                "the_provided_scan_station_is_disabled"
 | 
			
		||||
              )}
 | 
			
		||||
            </span>
 | 
			
		||||
          </div>
 | 
			
		||||
        {/if}
 | 
			
		||||
      {/if}
 | 
			
		||||
      {#if $api_endpoint}
 | 
			
		||||
        <form
 | 
			
		||||
          class="flex flex-col pt-3 md:pt-8"
 | 
			
		||||
          onsubmit="event.preventDefault();"
 | 
			
		||||
          on:submit={() => {
 | 
			
		||||
            console.log({ token });
 | 
			
		||||
            // return
 | 
			
		||||
            axios
 | 
			
		||||
              .request({
 | 
			
		||||
                method: "GET",
 | 
			
		||||
                url: $api_endpoint + "api/stats/runners/distance",
 | 
			
		||||
                headers: { Authorization: "Bearer " + token },
 | 
			
		||||
              })
 | 
			
		||||
              .then(function (response) {
 | 
			
		||||
                error = false;
 | 
			
		||||
                errormessage = "";
 | 
			
		||||
                apikey.set(token);
 | 
			
		||||
                stationinfo.set(JSON.stringify(response.data));
 | 
			
		||||
              })
 | 
			
		||||
              .catch(function (e) {
 | 
			
		||||
                error = true;
 | 
			
		||||
                errormessage = e.response.data.short;
 | 
			
		||||
              });
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <div class="flex flex-col pt-4">
 | 
			
		||||
            <label for="token" class="text-lg">{$_("client_token")}</label>
 | 
			
		||||
            <input
 | 
			
		||||
              type="text"
 | 
			
		||||
              id="token"
 | 
			
		||||
              placeholder={$_("client_token")}
 | 
			
		||||
              bind:value={token}
 | 
			
		||||
              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>
 | 
			
		||||
          {#if !isTokenValid}
 | 
			
		||||
            <span class="text-sm"
 | 
			
		||||
              >{$_("please_provide_a_valid_client_token")}</span
 | 
			
		||||
            >
 | 
			
		||||
          {/if}
 | 
			
		||||
          <button
 | 
			
		||||
            disabled={!isTokenValid}
 | 
			
		||||
            class:cursor-pointer={isTokenValid}
 | 
			
		||||
            class:opacity-50={!isTokenValid}
 | 
			
		||||
            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}
 | 
			
		||||
        <form
 | 
			
		||||
          class="flex flex-col pt-3 md:pt-8"
 | 
			
		||||
          onsubmit="event.preventDefault();"
 | 
			
		||||
          on:submit={() => {
 | 
			
		||||
            if (api_endpoint_input.substr(-1) !== "/") {
 | 
			
		||||
              api_endpoint_input = api_endpoint_input + "/";
 | 
			
		||||
            }
 | 
			
		||||
            api_endpoint.set(api_endpoint_input);
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <div class="flex flex-col pt-4">
 | 
			
		||||
            <label for="api_endpoint" class="text-lg"
 | 
			
		||||
              >{$_("api_endpoint")}</label
 | 
			
		||||
            >
 | 
			
		||||
            <input
 | 
			
		||||
              type="text"
 | 
			
		||||
              id="api_endpoint"
 | 
			
		||||
              placeholder={$_("api_endpoint")}
 | 
			
		||||
              bind:value={api_endpoint_input}
 | 
			
		||||
              class:border-red-500={!isEndpointValid}
 | 
			
		||||
              class:border-solid={!isEndpointValid}
 | 
			
		||||
              class:border-3={!isEndpointValid}
 | 
			
		||||
              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>
 | 
			
		||||
          {#if !isEndpointValid}
 | 
			
		||||
            <span class="text-sm"
 | 
			
		||||
              >{$_("please_provide_a_valid_client_api_endpoint")}</span
 | 
			
		||||
            >
 | 
			
		||||
          {/if}
 | 
			
		||||
          <button
 | 
			
		||||
            disabled={!isEndpointValid}
 | 
			
		||||
            class:cursor-pointer={isEndpointValid}
 | 
			
		||||
            class:opacity-50={!isEndpointValid}
 | 
			
		||||
            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>
 | 
			
		||||
      {/if}
 | 
			
		||||
      <div class="text-center pt-12 pb-12">
 | 
			
		||||
        <p>
 | 
			
		||||
          <svg
 | 
			
		||||
            style="height: 1rem;display: inline;"
 | 
			
		||||
            xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
            fill="none"
 | 
			
		||||
            stroke="currentColor"
 | 
			
		||||
            stroke-width="2"
 | 
			
		||||
            stroke-linecap="round"
 | 
			
		||||
            stroke-linejoin="round"
 | 
			
		||||
            class="feather feather-zap"
 | 
			
		||||
            viewBox="0 0 24 24"
 | 
			
		||||
          >
 | 
			
		||||
            <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" />
 | 
			
		||||
          </svg><span
 | 
			
		||||
            >powered by <a
 | 
			
		||||
              href="https://odit.services"
 | 
			
		||||
              target="_blank"
 | 
			
		||||
              class="underline">ODIT.Services</a
 | 
			
		||||
            >.</span
 | 
			
		||||
          >
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="w-full p-3">
 | 
			
		||||
      <div class="inline-block mr-2 mt-2">
 | 
			
		||||
        <button
 | 
			
		||||
          on:click={() => {
 | 
			
		||||
            lang.set("de-DE");
 | 
			
		||||
            locale.set("de-DE");
 | 
			
		||||
          }}
 | 
			
		||||
          type="button"
 | 
			
		||||
          class="bg-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md hover:bg-blue-700"
 | 
			
		||||
          >Deutsch
 | 
			
		||||
          <svg
 | 
			
		||||
            class="h-4 inline"
 | 
			
		||||
            xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
            viewBox="0 0 512 512"
 | 
			
		||||
            ><path
 | 
			
		||||
              d="M15.923 345.043C52.094 442.527 145.929 512 256 512s203.906-69.473 240.077-166.957L256 322.783l-240.077 22.26z"
 | 
			
		||||
              fill="#ffda44"
 | 
			
		||||
            /><path
 | 
			
		||||
              d="M256 0C145.929 0 52.094 69.472 15.923 166.957L256 189.217l240.077-22.261C459.906 69.472 366.071 0 256 0z"
 | 
			
		||||
            /><path
 | 
			
		||||
              d="M15.923 166.957C5.633 194.69 0 224.686 0 256s5.633 61.31 15.923 89.043h480.155C506.368 317.31 512 287.314 512 256s-5.632-61.31-15.923-89.043H15.923z"
 | 
			
		||||
              fill="#d80027"
 | 
			
		||||
            /></svg
 | 
			
		||||
          ></button
 | 
			
		||||
        >
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="inline-block mr-2 mt-2">
 | 
			
		||||
        <button
 | 
			
		||||
          on:click={() => {
 | 
			
		||||
            lang.set("en-US");
 | 
			
		||||
            locale.set("en-US");
 | 
			
		||||
          }}
 | 
			
		||||
          type="button"
 | 
			
		||||
          class="bg-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md hover:bg-blue-700"
 | 
			
		||||
          >English
 | 
			
		||||
          <svg
 | 
			
		||||
            class="h-4 inline"
 | 
			
		||||
            xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
            viewBox="0 0 512 512"
 | 
			
		||||
          >
 | 
			
		||||
            <circle cx="256" cy="256" r="256" fill="#f0f0f0" />
 | 
			
		||||
            <g fill="#d80027">
 | 
			
		||||
              <path
 | 
			
		||||
                d="M244.87 256H512c0-23.106-3.08-45.49-8.819-66.783H244.87V256zM244.87 122.435h229.556a257.35 257.35 0 00-59.07-66.783H244.87v66.783zM256 512c60.249 0 115.626-20.824 159.356-55.652H96.644C140.374 491.176 195.751 512 256 512zM37.574 389.565h436.852a254.474 254.474 0 0028.755-66.783H8.819a254.474 254.474 0 0028.755 66.783z"
 | 
			
		||||
              />
 | 
			
		||||
            </g>
 | 
			
		||||
            <path
 | 
			
		||||
              d="M118.584 39.978h23.329l-21.7 15.765 8.289 25.509-21.699-15.765-21.699 15.765 7.16-22.037a257.407 257.407 0 00-49.652 55.337h7.475l-13.813 10.035a255.58 255.58 0 00-6.194 10.938l6.596 20.301-12.306-8.941a253.567 253.567 0 00-8.372 19.873l7.267 22.368h26.822l-21.7 15.765 8.289 25.509-21.699-15.765-12.998 9.444A258.468 258.468 0 000 256h256V0c-50.572 0-97.715 14.67-137.416 39.978zm9.918 190.422l-21.699-15.765L85.104 230.4l8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765 8.289 25.509zm-8.289-100.083l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765zM220.328 230.4l-21.699-15.765L176.93 230.4l8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765 8.289 25.509zm-8.289-100.083l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765zm0-74.574l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765z"
 | 
			
		||||
              fill="#0052b4"
 | 
			
		||||
            />
 | 
			
		||||
          </svg></button
 | 
			
		||||
        >
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <!-- Image Section -->
 | 
			
		||||
  <div class="w-1/2 shadow-2xl">
 | 
			
		||||
    <img
 | 
			
		||||
      alt=""
 | 
			
		||||
      class="object-cover w-full h-screen hidden md:block"
 | 
			
		||||
      src="https://source.unsplash.com/IXUM4cJynP0"
 | 
			
		||||
    />
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										112
									
								
								src/Settings.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/Settings.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
<script>
 | 
			
		||||
  import { _ } from "svelte-i18n";
 | 
			
		||||
 | 
			
		||||
  import { apikey, api_endpoint, lang, page, stationinfo } from "./store.js";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="p-5 min-h-screen">
 | 
			
		||||
  <h1 class="font-bold text-3xl w-full text-center text-gray-900">
 | 
			
		||||
    Lauf Für Kaya! Beamershow
 | 
			
		||||
  </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_key")}</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 text-gray-700">{JSON.parse($stationinfo).track.id}</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>
 | 
			
		||||
  <div class="w-full">
 | 
			
		||||
    <div class="inline-block mr-2 mt-2">
 | 
			
		||||
      <button
 | 
			
		||||
        on:click={() => {
 | 
			
		||||
          lang.set("de-DE");
 | 
			
		||||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
        class:bg-blue-700={$lang === "de-DE"}
 | 
			
		||||
        class="bg-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md hover:bg-blue-700"
 | 
			
		||||
        >Deutsch
 | 
			
		||||
        <svg
 | 
			
		||||
          class="h-4 inline"
 | 
			
		||||
          xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
          viewBox="0 0 512 512"
 | 
			
		||||
          ><path
 | 
			
		||||
            d="M15.923 345.043C52.094 442.527 145.929 512 256 512s203.906-69.473 240.077-166.957L256 322.783l-240.077 22.26z"
 | 
			
		||||
            fill="#ffda44"
 | 
			
		||||
          /><path
 | 
			
		||||
            d="M256 0C145.929 0 52.094 69.472 15.923 166.957L256 189.217l240.077-22.261C459.906 69.472 366.071 0 256 0z"
 | 
			
		||||
          /><path
 | 
			
		||||
            d="M15.923 166.957C5.633 194.69 0 224.686 0 256s5.633 61.31 15.923 89.043h480.155C506.368 317.31 512 287.314 512 256s-5.632-61.31-15.923-89.043H15.923z"
 | 
			
		||||
            fill="#d80027"
 | 
			
		||||
          /></svg
 | 
			
		||||
        ></button
 | 
			
		||||
      >
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="inline-block mr-2 mt-2">
 | 
			
		||||
      <button
 | 
			
		||||
        on:click={() => {
 | 
			
		||||
          lang.set("en-EN");
 | 
			
		||||
        }}
 | 
			
		||||
        type="button"
 | 
			
		||||
        class:bg-blue-700={$lang === "en-EN"}
 | 
			
		||||
        class="bg-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md hover:bg-blue-700"
 | 
			
		||||
        >English
 | 
			
		||||
        <svg
 | 
			
		||||
          class="h-4 inline"
 | 
			
		||||
          xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
          viewBox="0 0 512 512"
 | 
			
		||||
        >
 | 
			
		||||
          <circle cx="256" cy="256" r="256" fill="#f0f0f0" />
 | 
			
		||||
          <g fill="#d80027">
 | 
			
		||||
            <path
 | 
			
		||||
              d="M244.87 256H512c0-23.106-3.08-45.49-8.819-66.783H244.87V256zM244.87 122.435h229.556a257.35 257.35 0 00-59.07-66.783H244.87v66.783zM256 512c60.249 0 115.626-20.824 159.356-55.652H96.644C140.374 491.176 195.751 512 256 512zM37.574 389.565h436.852a254.474 254.474 0 0028.755-66.783H8.819a254.474 254.474 0 0028.755 66.783z"
 | 
			
		||||
            />
 | 
			
		||||
          </g>
 | 
			
		||||
          <path
 | 
			
		||||
            d="M118.584 39.978h23.329l-21.7 15.765 8.289 25.509-21.699-15.765-21.699 15.765 7.16-22.037a257.407 257.407 0 00-49.652 55.337h7.475l-13.813 10.035a255.58 255.58 0 00-6.194 10.938l6.596 20.301-12.306-8.941a253.567 253.567 0 00-8.372 19.873l7.267 22.368h26.822l-21.7 15.765 8.289 25.509-21.699-15.765-12.998 9.444A258.468 258.468 0 000 256h256V0c-50.572 0-97.715 14.67-137.416 39.978zm9.918 190.422l-21.699-15.765L85.104 230.4l8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765 8.289 25.509zm-8.289-100.083l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765zM220.328 230.4l-21.699-15.765L176.93 230.4l8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765 8.289 25.509zm-8.289-100.083l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765zm0-74.574l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765z"
 | 
			
		||||
            fill="#0052b4"
 | 
			
		||||
          />
 | 
			
		||||
        </svg></button
 | 
			
		||||
      >
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <br />
 | 
			
		||||
  <button
 | 
			
		||||
    on:click={() => {
 | 
			
		||||
      page.set("");
 | 
			
		||||
    }}
 | 
			
		||||
    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
 | 
			
		||||
  >
 | 
			
		||||
  <button
 | 
			
		||||
    on:click={() => {
 | 
			
		||||
      apikey.set("");
 | 
			
		||||
      api_endpoint.set("");
 | 
			
		||||
      page.set("");
 | 
			
		||||
    }}
 | 
			
		||||
    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
 | 
			
		||||
  >
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										28
									
								
								src/locales/de.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/locales/de.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
{
 | 
			
		||||
    "api_endpoint": "API-Endpunkt",
 | 
			
		||||
    "api_key": "API Key",
 | 
			
		||||
    "back_to_scanner": "Zurück zum Scanner",
 | 
			
		||||
    "client_token": "Client Token",
 | 
			
		||||
    "configuration": "Konfiguration",
 | 
			
		||||
    "configure": "Konfigurieren",
 | 
			
		||||
    "error": "Error!",
 | 
			
		||||
    "language": "Sprache",
 | 
			
		||||
    "log_out_from_this_client": "Von diesem Scanner abmelden",
 | 
			
		||||
    "minimum_lap_time": "minimale Rundenzeit",
 | 
			
		||||
    "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_token": "Bitte gebe einen gültigen Client-Token an ...",
 | 
			
		||||
    "please_provide_the_scan_client_token": "Bitte gebe den Beamershow-Client-Token an.",
 | 
			
		||||
    "please_scan_a_card": "Bitte scanne eine Karte ...",
 | 
			
		||||
    "runner_card": "Läuferkarte",
 | 
			
		||||
    "scan": "Scannen!",
 | 
			
		||||
    "see_our_configuration_guide": "Siehe dir unsere Konfigurationsanleitung an.",
 | 
			
		||||
    "settings": "Einstellungen",
 | 
			
		||||
    "station_description": "Beschreibung der Scanstation",
 | 
			
		||||
    "station_id": "Scanstations-ID",
 | 
			
		||||
    "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.",
 | 
			
		||||
    "track_distance": "Länge des Tracks",
 | 
			
		||||
    "track_id": "Track ID",
 | 
			
		||||
    "track_name": "Track Name"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								src/locales/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/locales/en.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
{
 | 
			
		||||
    "api_endpoint": "API Endpoint",
 | 
			
		||||
    "api_key": "API Key",
 | 
			
		||||
    "back_to_scanner": "Back to Scanner",
 | 
			
		||||
    "client_token": "Client Token",
 | 
			
		||||
    "configuration": "Configuration",
 | 
			
		||||
    "configure": "Configure",
 | 
			
		||||
    "error": "Error!",
 | 
			
		||||
    "language": "Language",
 | 
			
		||||
    "log_out_from_this_client": "Log Out from this Client",
 | 
			
		||||
    "minimum_lap_time": "minimum lap time",
 | 
			
		||||
    "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_token": "Please provide a valid client token...",
 | 
			
		||||
    "please_provide_the_scan_client_token": "Please provide the scan client token.",
 | 
			
		||||
    "please_scan_a_card": "please scan a card...",
 | 
			
		||||
    "runner_card": "Runner Card",
 | 
			
		||||
    "scan": "Scan!",
 | 
			
		||||
    "see_our_configuration_guide": "See our configuration guide.",
 | 
			
		||||
    "settings": "Settings",
 | 
			
		||||
    "station_description": "Station Description",
 | 
			
		||||
    "station_id": "Scanstation ID",
 | 
			
		||||
    "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.",
 | 
			
		||||
    "track_distance": "Track Distance",
 | 
			
		||||
    "track_id": "Track ID",
 | 
			
		||||
    "track_name": "Track Name"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/main.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import App from './App.svelte';
 | 
			
		||||
import 'windi.css';
 | 
			
		||||
 | 
			
		||||
const app = new App({
 | 
			
		||||
	target: document.body
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default app;
 | 
			
		||||
							
								
								
									
										27
									
								
								src/store.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/store.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import { writable } from 'svelte/store';
 | 
			
		||||
 | 
			
		||||
const stored_api_endpoint = localStorage.getItem('api_endpoint')||"";
 | 
			
		||||
export const api_endpoint = writable(stored_api_endpoint);
 | 
			
		||||
api_endpoint.subscribe((value) => {
 | 
			
		||||
	localStorage.setItem('api_endpoint', value);
 | 
			
		||||
});
 | 
			
		||||
const stored_apikey = localStorage.getItem('apikey');
 | 
			
		||||
export const apikey = writable(stored_apikey);
 | 
			
		||||
apikey.subscribe((value) => {
 | 
			
		||||
	localStorage.setItem('apikey', value);
 | 
			
		||||
});
 | 
			
		||||
const stored_stationinfo = localStorage.getItem('stationinfo');
 | 
			
		||||
export const stationinfo = writable(stored_stationinfo);
 | 
			
		||||
stationinfo.subscribe((value) => {
 | 
			
		||||
	localStorage.setItem('stationinfo', 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');
 | 
			
		||||
export const lang = writable(stored_lang);
 | 
			
		||||
lang.subscribe((value) => {
 | 
			
		||||
	localStorage.setItem('lang', value);
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										13
									
								
								tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tailwind.config.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  theme: {
 | 
			
		||||
    extend: {
 | 
			
		||||
      colors: {
 | 
			
		||||
        reepolee: {
 | 
			
		||||
          500: "#b40000",
 | 
			
		||||
          600: "#9c0000",
 | 
			
		||||
          700: "#750000",
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										50
									
								
								vite.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								vite.config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
import svelte from '@svitejs/vite-plugin-svelte';
 | 
			
		||||
import windiCSS from 'vite-plugin-windicss';
 | 
			
		||||
import { minify } from 'html-minifier';
 | 
			
		||||
import { defineConfig } from 'vite';
 | 
			
		||||
//
 | 
			
		||||
const indexReplace = () => {
 | 
			
		||||
	return {
 | 
			
		||||
		name: 'html-transform',
 | 
			
		||||
		transformIndexHtml(html) {
 | 
			
		||||
			return minify(html, {
 | 
			
		||||
				collapseWhitespace: true
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default defineConfig(({ command, mode }) => {
 | 
			
		||||
	const isProduction = mode === 'production';
 | 
			
		||||
	return {
 | 
			
		||||
		base: './',
 | 
			
		||||
		build: {
 | 
			
		||||
			polyfillDynamicImport: false,
 | 
			
		||||
			cssCodeSplit: false,
 | 
			
		||||
			minify: isProduction
 | 
			
		||||
		},
 | 
			
		||||
		plugins: [
 | 
			
		||||
			windiCSS({
 | 
			
		||||
				//@ts-ignore
 | 
			
		||||
				verbose: true,
 | 
			
		||||
				silent: false,
 | 
			
		||||
				debug: true,
 | 
			
		||||
				config: 'tailwind.config.js', // tailwind config file path (optional)
 | 
			
		||||
				compile: false, // false: interpretation mode; true: compilation mode
 | 
			
		||||
				prefix: 'windi-', // set compilation mode style prefix
 | 
			
		||||
				globalPreflight: true, // set preflight style is global or scoped
 | 
			
		||||
				globalUtility: true // set utility style is global or scoped
 | 
			
		||||
			}),
 | 
			
		||||
			svelte({
 | 
			
		||||
				//@ts-ignore
 | 
			
		||||
				hot: !isProduction,
 | 
			
		||||
				emitCss: true,
 | 
			
		||||
				extensions: [ '.md', '.svx', '.svelte' ],
 | 
			
		||||
				preprocess: [
 | 
			
		||||
					//
 | 
			
		||||
				]
 | 
			
		||||
			}),
 | 
			
		||||
			indexReplace()
 | 
			
		||||
		]
 | 
			
		||||
	};
 | 
			
		||||
});
 | 
			
		||||
		Reference in New Issue
	
	Block a user