add: frontend profile data etc
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import { applyAction, enhance } from "$app/forms";
|
||||
import { page } from "$app/stores";
|
||||
// import Developer from "$lib/img/hero-image.png";
|
||||
import Avatar from "$lib/img/teamavatar.png";
|
||||
import Avatar from "$lib/img/TeamAvatar.jpeg";
|
||||
onMount(() => {
|
||||
console.log("Page data in Header:", $page);
|
||||
});
|
||||
|
||||
117
frontend/src/lib/components/ImageInput.svelte
Normal file
117
frontend/src/lib/components/ImageInput.svelte
Normal file
@@ -0,0 +1,117 @@
|
||||
<script>
|
||||
// @ts-nocheck
|
||||
export let avatar;
|
||||
|
||||
export let fieldName;
|
||||
export let title;
|
||||
|
||||
let newAvatar;
|
||||
const onFileSelected = (e) => {
|
||||
const target = e.target;
|
||||
if (target && target.files) {
|
||||
let reader = new FileReader();
|
||||
reader.readAsDataURL(target.files[0]);
|
||||
reader.onload = (e) => {
|
||||
newAvatar = e.target?.result;
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div id="app">
|
||||
{#if avatar}
|
||||
<img class="avatar" src={avatar} alt="d" />
|
||||
{:else}
|
||||
<img
|
||||
class="avatar"
|
||||
src={newAvatar
|
||||
? newAvatar
|
||||
: "https://cdn4.iconfinder.com/data/icons/small-n-flat/24/user-alt-512.png"}
|
||||
alt=""
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
name={fieldName}
|
||||
required
|
||||
on:change={(e) => onFileSelected(e)}
|
||||
/>
|
||||
<label for="file" class="btn-3">
|
||||
{#if newAvatar}
|
||||
<span>Bild ausgewählt, clicke Hochladen.</span>
|
||||
{:else}
|
||||
<span>{title}</span>
|
||||
{/if}
|
||||
</label>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-flow: column;
|
||||
color: rgb(148 163 184);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
display: flex;
|
||||
width: 8rem;
|
||||
}
|
||||
[type="file"] {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
width: 0;
|
||||
}
|
||||
[type="file"] + label {
|
||||
background: #9b9b9b;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: 500;
|
||||
margin-bottom: 1rem;
|
||||
outline: none;
|
||||
padding: 1rem 50px;
|
||||
position: relative;
|
||||
transition: all 0.3s;
|
||||
vertical-align: middle;
|
||||
}
|
||||
[type="file"] + label:hover {
|
||||
background-color: #9b9b9b;
|
||||
}
|
||||
[type="file"] + label.btn-3 {
|
||||
background-color: #d43aff;
|
||||
border-radius: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
[type="file"] + label.btn-3 span {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
width: 100%;
|
||||
}
|
||||
[type="file"] + label.btn-3::before {
|
||||
color: #fff;
|
||||
content: "\01F4F7";
|
||||
font-size: 200%;
|
||||
height: 100%;
|
||||
left: 45%;
|
||||
position: absolute;
|
||||
top: -180%;
|
||||
transition: all 0.3s;
|
||||
width: 100%;
|
||||
}
|
||||
[type="file"] + label.btn-3:hover {
|
||||
background-color: rgba(14, 166, 236, 0.5);
|
||||
}
|
||||
[type="file"] + label.btn-3:hover span {
|
||||
transform: translateY(300%);
|
||||
}
|
||||
[type="file"] + label.btn-3:hover::before {
|
||||
top: 0;
|
||||
}
|
||||
</style>
|
||||
100
frontend/src/lib/components/InputField.svelte
Normal file
100
frontend/src/lib/components/InputField.svelte
Normal file
@@ -0,0 +1,100 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { t } from "svelte-i18n";
|
||||
|
||||
/** @type {string} */
|
||||
export let name;
|
||||
|
||||
/** @type {string} */
|
||||
export let type = "text";
|
||||
|
||||
/** @type {string} */
|
||||
export let value = "";
|
||||
|
||||
/** @type {string} */
|
||||
export let placeholder = "";
|
||||
|
||||
/** @type {string} */
|
||||
export let label = "";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
/**
|
||||
* @param {Event} event - The input event
|
||||
*/
|
||||
function handleInput(event) {
|
||||
const target = event.target;
|
||||
|
||||
if (target instanceof HTMLInputElement) {
|
||||
const inputValue = target.value;
|
||||
value = inputValue;
|
||||
// dispatch("input", { name, value: inputValue });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the field
|
||||
* @param {string} name - The name of the field
|
||||
* @param {string} value - The value of the field
|
||||
* @returns {string|null} The error message or null if valid
|
||||
*/
|
||||
function validateField(name, value) {
|
||||
switch (name) {
|
||||
case "first_name":
|
||||
case "last_name":
|
||||
return value.trim() ? null : $t("required");
|
||||
case "email":
|
||||
return /^\S+@\S+\.\S+$/.test(value) ? null : $t("invalid_email");
|
||||
case "password":
|
||||
return !value.trim() || value.length >= 8
|
||||
? null
|
||||
: $t("required_password");
|
||||
// case "password2":
|
||||
// // Note: This case might need special handling as it depends on another field
|
||||
// return $t("required_password_match");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$: error = validateField(name, value);
|
||||
</script>
|
||||
|
||||
<div class="input-box">
|
||||
<span class="label">{label}</span>
|
||||
<div class="input-error-container">
|
||||
{#if error}
|
||||
<span class="error-message">{error}</span>
|
||||
{/if}
|
||||
<input
|
||||
{name}
|
||||
{type}
|
||||
{placeholder}
|
||||
{value}
|
||||
on:input={handleInput}
|
||||
on:blur={handleInput}
|
||||
class="input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.input-error-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
width: 100%;
|
||||
max-width: 444px;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #eb5424;
|
||||
font-size: 12px;
|
||||
margin-bottom: 5px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
127
frontend/src/lib/components/Modal.svelte
Normal file
127
frontend/src/lib/components/Modal.svelte
Normal file
@@ -0,0 +1,127 @@
|
||||
<script>
|
||||
import { quintOut } from "svelte/easing";
|
||||
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
const modal = (/** @type {Element} */ node, { duration = 300 } = {}) => {
|
||||
const transform = getComputedStyle(node).transform;
|
||||
|
||||
return {
|
||||
duration,
|
||||
easing: quintOut,
|
||||
css: (/** @type {any} */ t, /** @type {number} */ u) => {
|
||||
return `transform:
|
||||
${transform}
|
||||
scale(${t})
|
||||
translateY(${u * -100}%)
|
||||
`;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
function closeModal() {
|
||||
dispatch("close", {});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="modal-background">
|
||||
<div
|
||||
transition:modal={{ duration: 1000 }}
|
||||
class="modal"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<!-- svelte-ignore a11y-missing-attribute -->
|
||||
<a
|
||||
title="Close"
|
||||
class="modal-close"
|
||||
on:click={closeModal}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
on:keydown={(e) => e.key == "Enter" && closeModal()}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 384 512"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="sr-only">Close modal</span>
|
||||
</a>
|
||||
<div class="container">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.modal-background {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: relative;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 70%;
|
||||
box-shadow: 0 0 10px hsl(0 0% 0% / 10%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
@media (max-width: 990px) {
|
||||
.modal {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
.modal-close {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-close svg {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
fill: rgb(14 165 233 /1);
|
||||
transition: all 0.5s;
|
||||
}
|
||||
.modal-close:hover svg {
|
||||
fill: rgb(225 29 72);
|
||||
transform: scale(1.5);
|
||||
}
|
||||
.modal .container {
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
align-items: center;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.modal .container {
|
||||
flex-direction: column;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
24
frontend/src/lib/components/SmallLoader.svelte
Normal file
24
frontend/src/lib/components/SmallLoader.svelte
Normal file
@@ -0,0 +1,24 @@
|
||||
<script>
|
||||
/** @type {number | null} */
|
||||
export let width;
|
||||
/** @type {string | null} */
|
||||
export let message;
|
||||
</script>
|
||||
|
||||
<div class="loading">
|
||||
<p class="simple-loader" style={width ? `width: ${width}px` : ""} />
|
||||
{#if message}
|
||||
<p>{message}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.loading p {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1,46 +1,46 @@
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url(https://fonts.gstatic.com/s/robotomono/v22/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_gPq_ROW9.ttf)
|
||||
format("truetype");
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url(https://fonts.gstatic.com/s/robotomono/v22/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_gPq_ROW9.ttf)
|
||||
format("truetype");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(https://fonts.gstatic.com/s/robotomono/v22/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_ROW9.ttf)
|
||||
format("truetype");
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(https://fonts.gstatic.com/s/robotomono/v22/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_ROW9.ttf)
|
||||
format("truetype");
|
||||
}
|
||||
|
||||
html {
|
||||
padding: 0 30px;
|
||||
background-color: black;
|
||||
color: #9b9b9b;
|
||||
font-family: "Quicksand", sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
padding: 0 30px;
|
||||
background-color: black;
|
||||
color: #9b9b9b;
|
||||
font-family: "Quicksand", sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
}
|
||||
body {
|
||||
max-width: 1200px;
|
||||
margin: 5em auto 0 auto;
|
||||
max-width: 1200px;
|
||||
margin: 5em auto 0 auto;
|
||||
}
|
||||
pre,
|
||||
code {
|
||||
display: inline;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-size: 16px;
|
||||
display: inline;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: "Roboto Mono", monospace;
|
||||
color: white;
|
||||
border-style: none;
|
||||
height: 21px;
|
||||
font-size: 16px;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
color: white;
|
||||
border-style: none;
|
||||
height: 21px;
|
||||
font-size: 16px;
|
||||
}
|
||||
button {
|
||||
font-size: 16px;
|
||||
font-size: 16px;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
@@ -48,474 +48,466 @@ h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
h2 {
|
||||
margin: 0 0 45px 0;
|
||||
color: #fff;
|
||||
font-size: 36px;
|
||||
margin: 0 0 45px 0;
|
||||
color: #fff;
|
||||
font-size: 36px;
|
||||
}
|
||||
h3 {
|
||||
margin: 0 0 2rem 0;
|
||||
color: #fff;
|
||||
font-size: 32px;
|
||||
margin: 0 0 2rem 0;
|
||||
color: #fff;
|
||||
font-size: 32px;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 45px;
|
||||
line-height: 1.8;
|
||||
margin: 0 0 45px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
ul {
|
||||
margin: 0 0 32px;
|
||||
margin: 0 0 32px;
|
||||
}
|
||||
a {
|
||||
transition: border 0.2s ease-in-out;
|
||||
border-bottom: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
color: #00b7ef;
|
||||
transition: border 0.2s ease-in-out;
|
||||
border-bottom: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
color: #00b7ef;
|
||||
}
|
||||
a:hover {
|
||||
border-bottom-color: #00b7ef;
|
||||
border-bottom-color: #00b7ef;
|
||||
}
|
||||
li {
|
||||
line-height: 1.8;
|
||||
line-height: 1.8;
|
||||
}
|
||||
li strong {
|
||||
color: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
.image {
|
||||
width: 100%;
|
||||
margin: 0 0 32px;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
margin: 0 0 32px;
|
||||
padding: 0;
|
||||
}
|
||||
.image img {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.optanon-alert-box-wrapper {
|
||||
left: 0;
|
||||
left: 0;
|
||||
}
|
||||
.hidden {
|
||||
display: none !important;
|
||||
display: none !important;
|
||||
}
|
||||
.hide-mobile {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
body {
|
||||
margin: 8em auto 0 auto;
|
||||
}
|
||||
.hide-mobile {
|
||||
display: initial;
|
||||
}
|
||||
body {
|
||||
margin: 8em auto 0 auto;
|
||||
}
|
||||
.hide-mobile {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 3em 0 0;
|
||||
background: black;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 3em 0 0;
|
||||
background: black;
|
||||
}
|
||||
.header.top-banner-open {
|
||||
margin-top: 5px;
|
||||
transition: all 0.2s linear;
|
||||
margin-top: 5px;
|
||||
transition: all 0.2s linear;
|
||||
}
|
||||
.header .header-container {
|
||||
width: 100%;
|
||||
max-width: calc(1200px + 10em);
|
||||
height: 5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
max-width: calc(1200px + 10em);
|
||||
height: 5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.header .header-container .header-left {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container {
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container a {
|
||||
display: flex;
|
||||
color: #9b9b9b;
|
||||
border: none;
|
||||
display: flex;
|
||||
color: #9b9b9b;
|
||||
border: none;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container a img {
|
||||
height: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container a span {
|
||||
display: inline-block;
|
||||
margin: 2px 1ch 0 0;
|
||||
display: inline-block;
|
||||
margin: 2px 1ch 0 0;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container .auth0 {
|
||||
margin-left: 1ch;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
margin-left: 1ch;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
.header .header-container .header-right {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: space-between;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: space-between;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item {
|
||||
text-transform: uppercase;
|
||||
margin-left: 10px;
|
||||
text-transform: uppercase;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item button {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item.active a,
|
||||
.header .header-container .header-right .header-nav-item.active button {
|
||||
color: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.header .header-container .header-right a img {
|
||||
margin-top: -0.4rem;
|
||||
height: 28px;
|
||||
margin-top: -0.4rem;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.header .header-container .header-right .header-nav-item a,
|
||||
.header .header-container .header-right .header-nav-item button {
|
||||
transition: color 0.3s ease-in-out;
|
||||
display: block;
|
||||
padding: 20px 0;
|
||||
border: none;
|
||||
color: #9b9b9b;
|
||||
transition: color 0.3s ease-in-out;
|
||||
display: block;
|
||||
padding: 20px 0;
|
||||
border: none;
|
||||
color: #9b9b9b;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item:hover a,
|
||||
.header .header-container .header-right .header-nav-item:hover button {
|
||||
color: #fdfff5;
|
||||
color: #fdfff5;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.header {
|
||||
padding: 3em 5rem 0;
|
||||
}
|
||||
.header.top-banner-open {
|
||||
margin-top: 48px;
|
||||
}
|
||||
.header .header-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
.header .header-container .header-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item {
|
||||
margin-left: 26px;
|
||||
}
|
||||
.header {
|
||||
padding: 3em 5rem 0;
|
||||
}
|
||||
.header.top-banner-open {
|
||||
margin-top: 48px;
|
||||
}
|
||||
.header .header-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
.header .header-container .header-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item {
|
||||
margin-left: 26px;
|
||||
}
|
||||
}
|
||||
.button-dark {
|
||||
transition:
|
||||
border-color 0.3s ease-in-out,
|
||||
background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 1px solid #595b5c;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 1px solid #595b5c;
|
||||
margin: 2px;
|
||||
}
|
||||
.button-dark:hover {
|
||||
border-color: #fff;
|
||||
border-color: #fff;
|
||||
}
|
||||
.button-colorful {
|
||||
transition:
|
||||
border-color 0.3s ease-in-out,
|
||||
background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #d43aff;
|
||||
border: 1px solid #d43aff;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #d43aff;
|
||||
border: 1px solid #d43aff;
|
||||
}
|
||||
.button-colorful:hover {
|
||||
background-color: #c907ff;
|
||||
border-color: #c907ff;
|
||||
background-color: #c907ff;
|
||||
border-color: #c907ff;
|
||||
}
|
||||
.button-orange {
|
||||
transition:
|
||||
border-color 0.3s ease-in-out,
|
||||
background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #eb5424;
|
||||
border: 1px solid #eb5424;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #eb5424;
|
||||
border: 1px solid #eb5424;
|
||||
}
|
||||
.button-orange:hover {
|
||||
background-color: #ca3f12;
|
||||
border-color: #ca3f12;
|
||||
background-color: #ca3f12;
|
||||
border-color: #ca3f12;
|
||||
}
|
||||
.button-colorful:disabled {
|
||||
transition:
|
||||
border-color 0.3s ease-in-out,
|
||||
background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #9a9a9a;
|
||||
border: 1px solid #9a9a9a;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #9a9a9a;
|
||||
border: 1px solid #9a9a9a;
|
||||
}
|
||||
.hero-container {
|
||||
max-width: 795px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto 70px auto;
|
||||
max-width: 795px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto 70px auto;
|
||||
}
|
||||
.hero-container .hero-logo {
|
||||
margin-top: 88px;
|
||||
margin-bottom: 32px;
|
||||
margin-top: 88px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.hero-container .hero-subtitle {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
margin: 0 0 45px 0;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
margin: 0 0 45px 0;
|
||||
}
|
||||
.hero-container .hero-buttons-container {
|
||||
display: flex;
|
||||
display: flex;
|
||||
}
|
||||
.hero-container .hero-buttons-container button {
|
||||
margin: 0 8px;
|
||||
margin: 0 8px;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.hero-container {
|
||||
margin: 0 auto 140px auto;
|
||||
}
|
||||
.hero-container {
|
||||
margin: 0 auto 140px auto;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
color: white;
|
||||
letter-spacing: 0;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
color: white;
|
||||
letter-spacing: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.container .content {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.container .content .step-title {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 86px;
|
||||
opacity: 1;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 86px;
|
||||
opacity: 1;
|
||||
}
|
||||
.container .content .step-subtitle {
|
||||
position: relative;
|
||||
top: -5px;
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
position: relative;
|
||||
top: -5px;
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.container .content {
|
||||
margin-top: 120px;
|
||||
}
|
||||
.container .content {
|
||||
margin-top: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 680px) {
|
||||
.container {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
display: flex;
|
||||
width: calc(100% - 100px);
|
||||
padding: 0;
|
||||
}
|
||||
.container .content {
|
||||
max-width: 795px;
|
||||
padding-left: 116px;
|
||||
}
|
||||
.container .content .step-title {
|
||||
font-size: 36px;
|
||||
}
|
||||
.container {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
display: flex;
|
||||
width: calc(100% - 100px);
|
||||
padding: 0;
|
||||
}
|
||||
.container .content {
|
||||
max-width: 795px;
|
||||
}
|
||||
.container .content .step-title {
|
||||
font-size: 36px;
|
||||
}
|
||||
}
|
||||
.input-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px 0;
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
height: 73px;
|
||||
box-sizing: border-box;
|
||||
background-color: #2f2f2f;
|
||||
border-radius: 3px;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 10px 0;
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
height: 73px;
|
||||
box-sizing: border-box;
|
||||
background-color: #2f2f2f;
|
||||
border-radius: 3px;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
.input-box .label {
|
||||
text-transform: lowercase;
|
||||
margin: 0 1ch 0 0;
|
||||
margin: 0 1ch 0 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
.input-box .input {
|
||||
background-color: #494848;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
border: 3px solid #494848;
|
||||
width: 100%;
|
||||
max-width: 444px;
|
||||
font-size: 13px;
|
||||
background-color: #494848;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
border: 3px solid #494848;
|
||||
width: 100%;
|
||||
max-width: 444px;
|
||||
font-size: 13px;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.input-box {
|
||||
padding: 0 30px;
|
||||
margin: 32px 0;
|
||||
}
|
||||
.input-box {
|
||||
padding: 0 30px;
|
||||
}
|
||||
}
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: first baseline;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: first baseline;
|
||||
}
|
||||
@media (max-width: 680px) {
|
||||
.btn-container {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.btn-container p {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.btn-container {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.btn-container p {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
.warning {
|
||||
margin: 20px 0;
|
||||
padding: 1rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: rgb(255 228 230);
|
||||
border: 1px solid rgb(225 29 72);
|
||||
border-radius: 6px;
|
||||
color: rgb(225 29 72);
|
||||
font-size: 16px;
|
||||
margin: 20px 0;
|
||||
padding: 1rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: rgb(255 228 230);
|
||||
border: 1px solid rgb(225 29 72);
|
||||
border-radius: 6px;
|
||||
color: rgb(225 29 72);
|
||||
font-size: 16px;
|
||||
}
|
||||
.warning a {
|
||||
color: rgb(225 29 72);
|
||||
text-decoration: underline;
|
||||
color: rgb(225 29 72);
|
||||
text-decoration: underline;
|
||||
}
|
||||
.warning.hidden {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error {
|
||||
margin-top: 10rem;
|
||||
padding: 30px 40px;
|
||||
background: #2f3132;
|
||||
color: #fff;
|
||||
margin-top: 10rem;
|
||||
padding: 30px 40px;
|
||||
background: #2f3132;
|
||||
color: #fff;
|
||||
}
|
||||
.error p {
|
||||
margin: 0 0 1rem;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
.error p.intro {
|
||||
font-size: 1.3rem;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
.error .button-colorful {
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.error {
|
||||
padding: 65px 80px;
|
||||
}
|
||||
.error {
|
||||
padding: 65px 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-branding-container {
|
||||
color: white;
|
||||
font-weight: 300;
|
||||
margin-bottom: 73px;
|
||||
color: white;
|
||||
font-weight: 300;
|
||||
margin-bottom: 73px;
|
||||
}
|
||||
|
||||
.footer-branding-container .footer-branding {
|
||||
display: flex;
|
||||
width: 400px;
|
||||
display: flex;
|
||||
width: 400px;
|
||||
}
|
||||
.footer-branding-container .footer-branding {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
margin: 30px 0 0;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
margin: 30px 0 0;
|
||||
}
|
||||
.footer-branding-container .footer-branding .footer-crafted-by-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16px;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16px;
|
||||
color: white;
|
||||
}
|
||||
.footer-branding-container .footer-branding .footer-crafted-by-container span {
|
||||
display: inline-block;
|
||||
margin: 3px 1ch 0 0;
|
||||
display: inline-block;
|
||||
margin: 3px 1ch 0 0;
|
||||
}
|
||||
.footer-branding-container
|
||||
.footer-branding
|
||||
.footer-crafted-by-container
|
||||
.footer-branded-crafted-img {
|
||||
height: 28px;
|
||||
.footer-branding
|
||||
.footer-crafted-by-container
|
||||
.footer-branded-crafted-img {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.footer-branding-container .footer-branding .footer-copyright {
|
||||
color: #696969;
|
||||
letter-spacing: 0.5px;
|
||||
color: #696969;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.footer-container {
|
||||
width: 100%;
|
||||
color: white;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
color: white;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (min-width: 680px) {
|
||||
.footer-container {
|
||||
padding: 0;
|
||||
}
|
||||
.footer-container {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.simple-loader {
|
||||
--b: 20px; /* border thickness */
|
||||
--n: 15; /* number of dashes*/
|
||||
--g: 7deg; /* gap between dashes*/
|
||||
--c: #d43aff; /* the color */
|
||||
--b: 20px; /* border thickness */
|
||||
--n: 15; /* number of dashes*/
|
||||
--g: 7deg; /* gap between dashes*/
|
||||
--c: #d43aff; /* the color */
|
||||
|
||||
width: 40px; /* size */
|
||||
aspect-ratio: 1;
|
||||
border-radius: 50%;
|
||||
padding: 1px; /* get rid of bad outlines */
|
||||
background: conic-gradient(#0000, var(--c)) content-box;
|
||||
--_m: /* we use +/-1deg between colors to avoid jagged edges */ repeating-conic-gradient(
|
||||
#0000 0deg,
|
||||
#000 1deg calc(360deg / var(--n) - var(--g) - 1deg),
|
||||
#0000 calc(360deg / var(--n) - var(--g)) calc(360deg / var(--n))
|
||||
),
|
||||
radial-gradient(
|
||||
farthest-side,
|
||||
#0000 calc(98% - var(--b)),
|
||||
#000 calc(100% - var(--b))
|
||||
);
|
||||
-webkit-mask: var(--_m);
|
||||
mask: var(--_m);
|
||||
-webkit-mask-composite: destination-in;
|
||||
mask-composite: intersect;
|
||||
animation: load 1s infinite steps(var(--n));
|
||||
width: 40px; /* size */
|
||||
aspect-ratio: 1;
|
||||
border-radius: 50%;
|
||||
padding: 1px; /* get rid of bad outlines */
|
||||
background: conic-gradient(#0000, var(--c)) content-box;
|
||||
--_m: /* we use +/-1deg between colors to avoid jagged edges */ repeating-conic-gradient(
|
||||
#0000 0deg,
|
||||
#000 1deg calc(360deg / var(--n) - var(--g) - 1deg),
|
||||
#0000 calc(360deg / var(--n) - var(--g)) calc(360deg / var(--n))
|
||||
),
|
||||
radial-gradient(
|
||||
farthest-side,
|
||||
#0000 calc(98% - var(--b)),
|
||||
#000 calc(100% - var(--b))
|
||||
);
|
||||
-webkit-mask: var(--_m);
|
||||
mask: var(--_m);
|
||||
-webkit-mask-composite: destination-in;
|
||||
mask-composite: intersect;
|
||||
animation: load 1s infinite steps(var(--n));
|
||||
}
|
||||
@keyframes load {
|
||||
to {
|
||||
transform: rotate(1turn);
|
||||
}
|
||||
to {
|
||||
transform: rotate(1turn);
|
||||
}
|
||||
}
|
||||
|
||||
676
frontend/src/lib/css/styles.min.css
vendored
676
frontend/src/lib/css/styles.min.css
vendored
@@ -1,44 +1,46 @@
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url(https://fonts.gstatic.com/s/robotomono/v22/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_gPq_ROW9.ttf)
|
||||
format("truetype");
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url(https://fonts.gstatic.com/s/robotomono/v22/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_gPq_ROW9.ttf)
|
||||
format("truetype");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(https://fonts.gstatic.com/s/robotomono/v22/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_ROW9.ttf)
|
||||
format("truetype");
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(https://fonts.gstatic.com/s/robotomono/v22/L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_ROW9.ttf)
|
||||
format("truetype");
|
||||
}
|
||||
|
||||
html {
|
||||
padding: 0 30px;
|
||||
background-color: #000;
|
||||
color: #9b9b9b;
|
||||
font-family: Quicksand, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
padding: 0 30px;
|
||||
background-color: black;
|
||||
color: #9b9b9b;
|
||||
font-family: "Quicksand", sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
}
|
||||
body {
|
||||
max-width: 1200px;
|
||||
margin: 5em auto 0 auto;
|
||||
max-width: 1200px;
|
||||
margin: 5em auto 0 auto;
|
||||
}
|
||||
code,
|
||||
pre {
|
||||
display: inline;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-size: 16px;
|
||||
pre,
|
||||
code {
|
||||
display: inline;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: "Roboto Mono", monospace;
|
||||
color: #fff;
|
||||
border-style: none;
|
||||
height: 21px;
|
||||
font-size: 16px;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
color: white;
|
||||
border-style: none;
|
||||
height: 21px;
|
||||
font-size: 16px;
|
||||
}
|
||||
button {
|
||||
font-size: 16px;
|
||||
font-size: 16px;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
@@ -46,460 +48,466 @@ h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
h2 {
|
||||
margin: 0 0 45px 0;
|
||||
color: #fff;
|
||||
font-size: 36px;
|
||||
margin: 0 0 45px 0;
|
||||
color: #fff;
|
||||
font-size: 36px;
|
||||
}
|
||||
h3 {
|
||||
margin: 0 0 2rem 0;
|
||||
color: #fff;
|
||||
font-size: 32px;
|
||||
margin: 0 0 2rem 0;
|
||||
color: #fff;
|
||||
font-size: 32px;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 45px;
|
||||
line-height: 1.8;
|
||||
margin: 0 0 45px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
ul {
|
||||
margin: 0 0 32px;
|
||||
margin: 0 0 32px;
|
||||
}
|
||||
a {
|
||||
transition: border 0.2s ease-in-out;
|
||||
border-bottom: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
color: #00b7ef;
|
||||
transition: border 0.2s ease-in-out;
|
||||
border-bottom: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
color: #00b7ef;
|
||||
}
|
||||
a:hover {
|
||||
border-bottom-color: #00b7ef;
|
||||
border-bottom-color: #00b7ef;
|
||||
}
|
||||
li {
|
||||
line-height: 1.8;
|
||||
line-height: 1.8;
|
||||
}
|
||||
li strong {
|
||||
color: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
.image {
|
||||
width: 100%;
|
||||
margin: 0 0 32px;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
margin: 0 0 32px;
|
||||
padding: 0;
|
||||
}
|
||||
.image img {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.optanon-alert-box-wrapper {
|
||||
left: 0;
|
||||
left: 0;
|
||||
}
|
||||
.hidden {
|
||||
display: none !important;
|
||||
display: none !important;
|
||||
}
|
||||
.hide-mobile {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
body {
|
||||
margin: 8em auto 0 auto;
|
||||
}
|
||||
.hide-mobile {
|
||||
display: initial;
|
||||
}
|
||||
body {
|
||||
margin: 8em auto 0 auto;
|
||||
}
|
||||
.hide-mobile {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 3em 0 0;
|
||||
background: #000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 3em 0 0;
|
||||
background: black;
|
||||
}
|
||||
.header.top-banner-open {
|
||||
margin-top: 5px;
|
||||
transition: all 0.2s linear;
|
||||
margin-top: 5px;
|
||||
transition: all 0.2s linear;
|
||||
}
|
||||
.header .header-container {
|
||||
width: 100%;
|
||||
max-width: calc(1200px + 10em);
|
||||
height: 5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
max-width: calc(1200px + 10em);
|
||||
height: 5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.header .header-container .header-left {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container {
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container a {
|
||||
display: flex;
|
||||
color: #9b9b9b;
|
||||
border: none;
|
||||
display: flex;
|
||||
color: #9b9b9b;
|
||||
border: none;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container a img {
|
||||
height: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container a span {
|
||||
display: inline-block;
|
||||
margin: 2px 1ch 0 0;
|
||||
display: inline-block;
|
||||
margin: 2px 1ch 0 0;
|
||||
}
|
||||
.header .header-container .header-left .header-crafted-by-container .auth0 {
|
||||
margin-left: 1ch;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
margin-left: 1ch;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
.header .header-container .header-right {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: space-between;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: space-between;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item {
|
||||
text-transform: uppercase;
|
||||
margin-left: 10px;
|
||||
text-transform: uppercase;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item button {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item.active a,
|
||||
.header .header-container .header-right .header-nav-item.active button {
|
||||
color: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.header .header-container .header-right a img {
|
||||
margin-top: -0.4rem;
|
||||
height: 28px;
|
||||
margin-top: -0.4rem;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.header .header-container .header-right .header-nav-item a,
|
||||
.header .header-container .header-right .header-nav-item button {
|
||||
transition: color 0.3s ease-in-out;
|
||||
display: block;
|
||||
padding: 20px 0;
|
||||
border: none;
|
||||
color: #9b9b9b;
|
||||
transition: color 0.3s ease-in-out;
|
||||
display: block;
|
||||
padding: 20px 0;
|
||||
border: none;
|
||||
color: #9b9b9b;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item:hover a,
|
||||
.header .header-container .header-right .header-nav-item:hover button {
|
||||
color: #fdfff5;
|
||||
color: #fdfff5;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.header {
|
||||
padding: 3em 5rem 0;
|
||||
}
|
||||
.header.top-banner-open {
|
||||
margin-top: 48px;
|
||||
}
|
||||
.header .header-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
.header .header-container .header-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item {
|
||||
margin-left: 26px;
|
||||
}
|
||||
.header {
|
||||
padding: 3em 5rem 0;
|
||||
}
|
||||
.header.top-banner-open {
|
||||
margin-top: 48px;
|
||||
}
|
||||
.header .header-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
.header .header-container .header-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.header .header-container .header-right .header-nav-item {
|
||||
margin-left: 26px;
|
||||
}
|
||||
}
|
||||
.button-dark {
|
||||
transition:
|
||||
border-color 0.3s ease-in-out,
|
||||
background-color 0.3s ease-in-out;
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 1px solid #595b5c;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 1px solid #595b5c;
|
||||
margin: 2px;
|
||||
}
|
||||
.button-dark:hover {
|
||||
border-color: #fff;
|
||||
border-color: #fff;
|
||||
}
|
||||
.button-colorful {
|
||||
transition:
|
||||
border-color 0.3s ease-in-out,
|
||||
background-color 0.3s ease-in-out;
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #d43aff;
|
||||
border: 1px solid #d43aff;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #d43aff;
|
||||
border: 1px solid #d43aff;
|
||||
}
|
||||
.button-colorful:hover {
|
||||
background-color: #c907ff;
|
||||
border-color: #c907ff;
|
||||
background-color: #c907ff;
|
||||
border-color: #c907ff;
|
||||
}
|
||||
.button-orange {
|
||||
transition:
|
||||
border-color 0.3s ease-in-out,
|
||||
background-color 0.3s ease-in-out;
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #eb5424;
|
||||
border: 1px solid #eb5424;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #eb5424;
|
||||
border: 1px solid #eb5424;
|
||||
}
|
||||
.button-orange:hover {
|
||||
background-color: #ca3f12;
|
||||
border-color: #ca3f12;
|
||||
background-color: #ca3f12;
|
||||
border-color: #ca3f12;
|
||||
}
|
||||
.button-colorful:disabled {
|
||||
transition:
|
||||
border-color 0.3s ease-in-out,
|
||||
background-color 0.3s ease-in-out;
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #9a9a9a;
|
||||
border: 1px solid #9a9a9a;
|
||||
transition: border-color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
padding: 18px 28px;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
background-color: #9a9a9a;
|
||||
border: 1px solid #9a9a9a;
|
||||
}
|
||||
.hero-container {
|
||||
max-width: 795px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto 70px auto;
|
||||
max-width: 795px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto 70px auto;
|
||||
}
|
||||
.hero-container .hero-logo {
|
||||
margin-top: 88px;
|
||||
margin-bottom: 32px;
|
||||
margin-top: 88px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.hero-container .hero-subtitle {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
margin: 0 0 45px 0;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
margin: 0 0 45px 0;
|
||||
}
|
||||
.hero-container .hero-buttons-container {
|
||||
display: flex;
|
||||
display: flex;
|
||||
}
|
||||
.hero-container .hero-buttons-container button {
|
||||
margin: 0 8px;
|
||||
margin: 0 8px;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.hero-container {
|
||||
margin: 0 auto 140px auto;
|
||||
}
|
||||
.hero-container {
|
||||
margin: 0 auto 140px auto;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
color: #fff;
|
||||
letter-spacing: 0;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
color: white;
|
||||
letter-spacing: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.container .content {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.container .content .step-title {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 86px;
|
||||
opacity: 1;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 86px;
|
||||
opacity: 1;
|
||||
}
|
||||
.container .content .step-subtitle {
|
||||
position: relative;
|
||||
top: -5px;
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
position: relative;
|
||||
top: -5px;
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.container .content {
|
||||
margin-top: 120px;
|
||||
}
|
||||
.container .content {
|
||||
margin-top: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 680px) {
|
||||
.container {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
display: flex;
|
||||
width: calc(100% - 100px);
|
||||
padding: 0;
|
||||
}
|
||||
.container .content {
|
||||
max-width: 795px;
|
||||
padding-left: 116px;
|
||||
}
|
||||
.container .content .step-title {
|
||||
font-size: 36px;
|
||||
}
|
||||
.container {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
display: flex;
|
||||
width: calc(100% - 100px);
|
||||
padding: 0;
|
||||
}
|
||||
.container .content {
|
||||
max-width: 795px;
|
||||
}
|
||||
.container .content .step-title {
|
||||
font-size: 36px;
|
||||
}
|
||||
}
|
||||
.input-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px 0;
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
height: 73px;
|
||||
box-sizing: border-box;
|
||||
background-color: #2f2f2f;
|
||||
border-radius: 3px;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 10px 0;
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
height: 73px;
|
||||
box-sizing: border-box;
|
||||
background-color: #2f2f2f;
|
||||
border-radius: 3px;
|
||||
font-family: "Roboto Mono", monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
.input-box .label {
|
||||
text-transform: lowercase;
|
||||
margin: 0 1ch 0 0;
|
||||
margin: 0 1ch 0 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
.input-box .input {
|
||||
background-color: #494848;
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
border: 3px solid #494848;
|
||||
width: 100%;
|
||||
max-width: 444px;
|
||||
font-size: 13px;
|
||||
background-color: #494848;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
border: 3px solid #494848;
|
||||
width: 100%;
|
||||
max-width: 444px;
|
||||
font-size: 13px;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.input-box {
|
||||
padding: 0 30px;
|
||||
margin: 32px 0;
|
||||
}
|
||||
.input-box {
|
||||
padding: 0 30px;
|
||||
}
|
||||
}
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: first baseline;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: first baseline;
|
||||
}
|
||||
@media (max-width: 680px) {
|
||||
.btn-container {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.btn-container p {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.btn-container {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.btn-container p {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
.warning {
|
||||
margin: 20px 0;
|
||||
padding: 1rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: rgb(255 228 230);
|
||||
border: 1px solid rgb(225 29 72);
|
||||
border-radius: 6px;
|
||||
color: rgb(225 29 72);
|
||||
font-size: 16px;
|
||||
margin: 20px 0;
|
||||
padding: 1rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: rgb(255 228 230);
|
||||
border: 1px solid rgb(225 29 72);
|
||||
border-radius: 6px;
|
||||
color: rgb(225 29 72);
|
||||
font-size: 16px;
|
||||
}
|
||||
.warning a {
|
||||
color: rgb(225 29 72);
|
||||
text-decoration: underline;
|
||||
color: rgb(225 29 72);
|
||||
text-decoration: underline;
|
||||
}
|
||||
.warning.hidden {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error {
|
||||
margin-top: 10rem;
|
||||
padding: 30px 40px;
|
||||
background: #2f3132;
|
||||
color: #fff;
|
||||
margin-top: 10rem;
|
||||
padding: 30px 40px;
|
||||
background: #2f3132;
|
||||
color: #fff;
|
||||
}
|
||||
.error p {
|
||||
margin: 0 0 1rem;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
.error p.intro {
|
||||
font-size: 1.3rem;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
.error .button-colorful {
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
}
|
||||
@media (min-width: 680px) {
|
||||
.error {
|
||||
padding: 65px 80px;
|
||||
}
|
||||
.error {
|
||||
padding: 65px 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-branding-container {
|
||||
color: #fff;
|
||||
font-weight: 300;
|
||||
margin-bottom: 73px;
|
||||
color: white;
|
||||
font-weight: 300;
|
||||
margin-bottom: 73px;
|
||||
}
|
||||
|
||||
.footer-branding-container .footer-branding {
|
||||
display: flex;
|
||||
width: 400px;
|
||||
}
|
||||
.footer-branding-container .footer-branding {
|
||||
display: flex;
|
||||
width: 400px;
|
||||
}
|
||||
.footer-branding-container .footer-branding {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
margin: 30px 0 0;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
margin: 30px 0 0;
|
||||
}
|
||||
.footer-branding-container .footer-branding .footer-crafted-by-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16px;
|
||||
color: white;
|
||||
}
|
||||
.footer-branding-container .footer-branding .footer-crafted-by-container span {
|
||||
display: inline-block;
|
||||
margin: 3px 1ch 0 0;
|
||||
display: inline-block;
|
||||
margin: 3px 1ch 0 0;
|
||||
}
|
||||
.footer-branding-container
|
||||
.footer-branding
|
||||
.footer-crafted-by-container
|
||||
.footer-branded-crafted-img {
|
||||
height: 28px;
|
||||
.footer-branding
|
||||
.footer-crafted-by-container
|
||||
.footer-branded-crafted-img {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.footer-branding-container .footer-branding .footer-copyright {
|
||||
color: #696969;
|
||||
letter-spacing: 0.5px;
|
||||
color: #696969;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.footer-container {
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
color: white;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (min-width: 680px) {
|
||||
.footer-container {
|
||||
padding: 0;
|
||||
}
|
||||
.footer-container {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.simple-loader {
|
||||
--b: 20px;
|
||||
--n: 15;
|
||||
--g: 7deg;
|
||||
--c: #d43aff;
|
||||
width: 40px;
|
||||
aspect-ratio: 1;
|
||||
border-radius: 50%;
|
||||
padding: 1px;
|
||||
background: conic-gradient(#0000, var(--c)) content-box;
|
||||
--_m: repeating-conic-gradient(
|
||||
#0000 0deg,
|
||||
#000 1deg calc(360deg / var(--n) - var(--g) - 1deg),
|
||||
#0000 calc(360deg / var(--n) - var(--g)) calc(360deg / var(--n))
|
||||
),
|
||||
radial-gradient(
|
||||
farthest-side,
|
||||
#0000 calc(98% - var(--b)),
|
||||
#000 calc(100% - var(--b))
|
||||
);
|
||||
-webkit-mask: var(--_m);
|
||||
mask: var(--_m);
|
||||
-webkit-mask-composite: destination-in;
|
||||
mask-composite: intersect;
|
||||
animation: load 1s infinite steps(var(--n));
|
||||
--b: 20px; /* border thickness */
|
||||
--n: 15; /* number of dashes*/
|
||||
--g: 7deg; /* gap between dashes*/
|
||||
--c: #d43aff; /* the color */
|
||||
|
||||
width: 40px; /* size */
|
||||
aspect-ratio: 1;
|
||||
border-radius: 50%;
|
||||
padding: 1px; /* get rid of bad outlines */
|
||||
background: conic-gradient(#0000, var(--c)) content-box;
|
||||
--_m: /* we use +/-1deg between colors to avoid jagged edges */ repeating-conic-gradient(
|
||||
#0000 0deg,
|
||||
#000 1deg calc(360deg / var(--n) - var(--g) - 1deg),
|
||||
#0000 calc(360deg / var(--n) - var(--g)) calc(360deg / var(--n))
|
||||
),
|
||||
radial-gradient(
|
||||
farthest-side,
|
||||
#0000 calc(98% - var(--b)),
|
||||
#000 calc(100% - var(--b))
|
||||
);
|
||||
-webkit-mask: var(--_m);
|
||||
mask: var(--_m);
|
||||
-webkit-mask-composite: destination-in;
|
||||
mask-composite: intersect;
|
||||
animation: load 1s infinite steps(var(--n));
|
||||
}
|
||||
@keyframes load {
|
||||
to {
|
||||
transform: rotate(1turn);
|
||||
}
|
||||
to {
|
||||
transform: rotate(1turn);
|
||||
}
|
||||
}
|
||||
|
||||
BIN
frontend/src/lib/img/Avatar-f1.jpeg
Normal file
BIN
frontend/src/lib/img/Avatar-f1.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 188 KiB |
BIN
frontend/src/lib/img/Avatar-f2.jpeg
Normal file
BIN
frontend/src/lib/img/Avatar-f2.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
BIN
frontend/src/lib/img/Avatar-m1.jpeg
Normal file
BIN
frontend/src/lib/img/Avatar-m1.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 161 KiB |
BIN
frontend/src/lib/img/Avatar-m2.jpeg
Normal file
BIN
frontend/src/lib/img/Avatar-m2.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 KiB |
BIN
frontend/src/lib/img/Avatar-m3.jpeg
Normal file
BIN
frontend/src/lib/img/Avatar-m3.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 150 KiB |
BIN
frontend/src/lib/img/TeamAvatar.jpeg
Normal file
BIN
frontend/src/lib/img/TeamAvatar.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 207 KiB |
50
frontend/src/lib/locales/de.js
Normal file
50
frontend/src/lib/locales/de.js
Normal file
@@ -0,0 +1,50 @@
|
||||
export default {
|
||||
userStatus: {
|
||||
1: "Nicht verifiziert",
|
||||
2: "Verifiziert",
|
||||
3: "Aktiv",
|
||||
4: "Passiv",
|
||||
5: "Deaktiviert",
|
||||
},
|
||||
userRole: {
|
||||
0: "Mitglied",
|
||||
1: "Betrachter",
|
||||
4: "Bearbeiter",
|
||||
8: "Administrator",
|
||||
},
|
||||
unknown: "Unbekannt",
|
||||
notes: "Notizen",
|
||||
address: "Straße & Hausnummer",
|
||||
city: "Wohnort",
|
||||
zip_code: "PLZ",
|
||||
forgot_password: "Passwort vergessen?",
|
||||
password: "Passwort",
|
||||
password_repeat: "Passwort wiederholen",
|
||||
placeholder_password: "Passwort eingeben...",
|
||||
email: "Email",
|
||||
placeholder_email: "Emailadresse eingeben...",
|
||||
login: "Anmelden",
|
||||
user: "Nutzer",
|
||||
user_login: "Nutzer Anmeldung",
|
||||
user_edit: "Nutzer bearbeiten",
|
||||
profile: "Profil",
|
||||
membership: "Mitgliedschaft",
|
||||
bankaccount: "Kontodaten",
|
||||
status: "Status",
|
||||
start: "Beginn",
|
||||
end: "Ende",
|
||||
parent_member_id: "Hauptmitgliedsnr.",
|
||||
placeholder_parent_member_id: "Mitgliedsnr des Hauptmitglieds eingeben...",
|
||||
bank_account_holder: "Kontoinhaber",
|
||||
bank_name: "Name der Bank",
|
||||
iban: "IBAN",
|
||||
bic: "BIC",
|
||||
mandate_reference: "SEPA Mandat",
|
||||
placeholder_bank_account_holder: "Namen eingeben...",
|
||||
placeholder_iban: "IBAN eingeben..",
|
||||
placeholder_bic: "BIC eingeben(optional)...",
|
||||
placeholder_mandate_reference: "SEPA Mandatsreferenz eingeben..",
|
||||
required: "Eingabe benötigt",
|
||||
required_password: "Password zu kurz, mindestens 8 Zeichen",
|
||||
required_password_match: "Passwörter stimmen nicht überein!",
|
||||
};
|
||||
15
frontend/src/lib/locales/en.js
Normal file
15
frontend/src/lib/locales/en.js
Normal file
@@ -0,0 +1,15 @@
|
||||
export default {
|
||||
userStatus: {
|
||||
1: "Unverified",
|
||||
2: "Verified",
|
||||
3: "Active",
|
||||
4: "Passive",
|
||||
5: "Disabled",
|
||||
},
|
||||
userRole: {
|
||||
0: "Member",
|
||||
1: "Viewer",
|
||||
4: "Editor",
|
||||
8: "Admin",
|
||||
},
|
||||
};
|
||||
20
frontend/src/lib/utils/i18n.js
Normal file
20
frontend/src/lib/utils/i18n.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { register, init, getLocaleFromNavigator, locale } from "svelte-i18n";
|
||||
|
||||
function setupI18n() {
|
||||
register("en", () => import("../locales/en.js"));
|
||||
register("de", () => import("../locales/de.js"));
|
||||
|
||||
init({
|
||||
fallbackLocale: "de",
|
||||
initialLocale: getLocaleFromNavigator(),
|
||||
});
|
||||
}
|
||||
|
||||
setupI18n();
|
||||
|
||||
/**
|
||||
* @param {string} newLocale - The new locale to set
|
||||
*/
|
||||
export const changeLocale = (newLocale) => {
|
||||
locale.set(newLocale);
|
||||
};
|
||||
@@ -4,14 +4,27 @@
|
||||
import Transition from "$lib/components/Transition.svelte";
|
||||
import "$lib/css/styles.min.css";
|
||||
|
||||
import { waitLocale } from "svelte-i18n";
|
||||
import { onMount } from "svelte";
|
||||
import "$lib/utils/i18n.js";
|
||||
|
||||
/** @type {import('./$types').PageData} */
|
||||
export let data;
|
||||
|
||||
let ready = false;
|
||||
|
||||
onMount(async () => {
|
||||
await waitLocale();
|
||||
ready = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<Transition key={data.url} duration={600}>
|
||||
<Header />
|
||||
{#if ready}
|
||||
<Transition key={data.url} duration={600}>
|
||||
<Header />
|
||||
|
||||
<slot />
|
||||
<slot />
|
||||
|
||||
<Footer />
|
||||
</Transition>
|
||||
<Footer />
|
||||
</Transition>
|
||||
{/if}
|
||||
|
||||
@@ -4,16 +4,10 @@
|
||||
|
||||
<div class="hero-container">
|
||||
<!-- <div class="hero-logo"><img src={Developer} alt="Alexander Stölting" /></div> -->
|
||||
<h3 class="hero-subtitle subtitle">
|
||||
This application is the demonstration of a series of tutorials on
|
||||
session-based authentication using Go at the backend and JavaScript
|
||||
(SvelteKit) on the front-end.
|
||||
</h3>
|
||||
<h3 class="hero-subtitle subtitle">Backend vom Carsharing Zeug</h3>
|
||||
<div class="hero-buttons-container">
|
||||
<a
|
||||
class="button-dark"
|
||||
href="https://dev.to/sirneij/series/23239"
|
||||
data-learn-more>Learn more</a
|
||||
<a class="button-dark" href="https://tiny-bits.net/" data-learn-more
|
||||
>Auf zu Tiny Bits</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
131
frontend/src/routes/auth/about/[id]/+page.server.js
Normal file
131
frontend/src/routes/auth/about/[id]/+page.server.js
Normal file
@@ -0,0 +1,131 @@
|
||||
import { BASE_API_URI } from "$lib/utils/constants";
|
||||
import { formatError } from "$lib/utils/helpers";
|
||||
import { fail, redirect } from "@sveltejs/kit";
|
||||
|
||||
/** @type {import('./$types').PageServerLoad} */
|
||||
export async function load({ locals, params }) {
|
||||
// redirect user if not logged in
|
||||
if (!locals.user) {
|
||||
throw redirect(302, `/auth/login?next=/auth/about/${params.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {import('./$types').Actions} */
|
||||
export const actions = {
|
||||
/**
|
||||
*
|
||||
* @param request - The request object
|
||||
* @param fetch - Fetch object from sveltekit
|
||||
* @param cookies - SvelteKit's cookie object
|
||||
* @param locals - The local object, housing current user
|
||||
* @returns Error data or redirects user to the home page or the previous page
|
||||
*/
|
||||
updateUser: async ({ request, fetch, cookies, locals }) => {
|
||||
const formData = await request.formData();
|
||||
const firstName = String(formData.get("first_name"));
|
||||
const lastName = String(formData.get("last_name"));
|
||||
const phone = String(formData.get("phone"));
|
||||
const birthDate = String(formData.get("birth_date"));
|
||||
|
||||
const apiURL = `${BASE_API_URI}/backend/users/update/`;
|
||||
|
||||
const res = await fetch(apiURL, {
|
||||
method: "PATCH",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Cookie: `jwt=${cookies.get("jwt")}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
phone: phone,
|
||||
birth_date: birthDate,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const response = await res.json();
|
||||
const errors = formatError(response.error);
|
||||
return fail(400, { errors: errors });
|
||||
}
|
||||
|
||||
const response = await res.json();
|
||||
|
||||
locals.user = response;
|
||||
|
||||
if (locals.user.date_of_birth) {
|
||||
locals.user.date_of_birth = response["date_of_birth"].split("T")[0];
|
||||
}
|
||||
|
||||
throw redirect(303, `/auth/about/${response.id}`);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param request - The request object
|
||||
* @param fetch - Fetch object from sveltekit
|
||||
* @param cookies - SvelteKit's cookie object
|
||||
* @param locals - The local object, housing current user
|
||||
* @returns Error data or redirects user to the home page or the previous page
|
||||
*/
|
||||
uploadImage: async ({ request, fetch, cookies }) => {
|
||||
const formData = await request.formData();
|
||||
|
||||
/** @type {RequestInit} */
|
||||
const requestInitOptions = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Cookie: `jwt=${cookies.get("jwt")}`,
|
||||
},
|
||||
body: formData,
|
||||
};
|
||||
|
||||
const res = await fetch(`${BASE_API_URI}/file/upload/`, requestInitOptions);
|
||||
|
||||
if (!res.ok) {
|
||||
const response = await res.json();
|
||||
const errors = formatError(response.error);
|
||||
return fail(400, { errors: errors });
|
||||
}
|
||||
|
||||
const response = await res.json();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
thumbnail: response["s3_url"],
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param request - The request object
|
||||
* @param fetch - Fetch object from sveltekit
|
||||
* @param cookies - SvelteKit's cookie object
|
||||
* @param locals - The local object, housing current user
|
||||
* @returns Error data or redirects user to the home page or the previous page
|
||||
*/
|
||||
deleteImage: async ({ request, fetch, cookies }) => {
|
||||
const formData = await request.formData();
|
||||
|
||||
/** @type {RequestInit} */
|
||||
const requestInitOptions = {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
Cookie: `jwt=${cookies.get("jwt")}`,
|
||||
},
|
||||
body: formData,
|
||||
};
|
||||
|
||||
const res = await fetch(`${BASE_API_URI}/file/delete/`, requestInitOptions);
|
||||
|
||||
if (!res.ok) {
|
||||
const response = await res.json();
|
||||
const errors = formatError(response.error);
|
||||
return fail(400, { errors: errors });
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
thumbnail: "",
|
||||
};
|
||||
},
|
||||
};
|
||||
625
frontend/src/routes/auth/about/[id]/+page.svelte
Normal file
625
frontend/src/routes/auth/about/[id]/+page.svelte
Normal file
@@ -0,0 +1,625 @@
|
||||
<script>
|
||||
import ImageInput from "$lib/components/ImageInput.svelte";
|
||||
import InputField from "$lib/components/InputField.svelte";
|
||||
import SmallLoader from "$lib/components/SmallLoader.svelte";
|
||||
import Modal from "$lib/components/Modal.svelte";
|
||||
import Avatar from "$lib/img/TeamAvatar.jpeg";
|
||||
import { onMount } from "svelte";
|
||||
import { applyAction, enhance } from "$app/forms";
|
||||
import { page } from "$app/stores";
|
||||
import { receive, send } from "$lib/utils/helpers";
|
||||
import { t } from "svelte-i18n";
|
||||
|
||||
$: ({ user } = $page.data);
|
||||
|
||||
/** @typedef {{name: string, src: string}} Avatar */
|
||||
const avatarFiles = import.meta.glob("$lib/img/Avatar-*.jpeg", {
|
||||
eager: true,
|
||||
});
|
||||
/** @type{Avatar[]} */
|
||||
let avatars = [];
|
||||
|
||||
/**
|
||||
* @typedef {Object} FormData
|
||||
* @property {string} first_name
|
||||
* @property {string} last_name
|
||||
* @property {string} email
|
||||
* @property {string} [password]
|
||||
* @property {string} [password2]
|
||||
* @property {string} [phone]
|
||||
* @property {string} address
|
||||
* @property {string} zip_code
|
||||
* @property {string} city
|
||||
*/
|
||||
/**
|
||||
* @typedef {Object.<string, string>} ValidationErrors
|
||||
*/
|
||||
/**
|
||||
* @type {ValidationErrors}
|
||||
*/
|
||||
let validationErrors = {};
|
||||
|
||||
const TABS = ["profile", "membership", "bankaccount"];
|
||||
let activeTab = TABS[0];
|
||||
|
||||
let showModal = false,
|
||||
isUploading = false,
|
||||
isUpdating = false,
|
||||
showAvatars = false;
|
||||
const open = () => (showModal = true);
|
||||
const close = () => (showModal = false);
|
||||
const toggleAvatars = () => (showAvatars = !showAvatars);
|
||||
|
||||
onMount(() => {
|
||||
avatars = Object.entries(avatarFiles).map(([path, module]) => {
|
||||
if (typeof path !== "string") {
|
||||
throw new Error("Unexpected non-string path");
|
||||
}
|
||||
if (
|
||||
typeof module !== "object" ||
|
||||
module === null ||
|
||||
!("default" in module)
|
||||
) {
|
||||
throw new Error("Unexpected module format");
|
||||
}
|
||||
const src = module.default;
|
||||
if (typeof src !== "string") {
|
||||
throw new Error("Unexpected default export type");
|
||||
}
|
||||
return {
|
||||
name: path.split("/").pop()?.split(".")[0] ?? "Unknown",
|
||||
src: src,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
/** @type {import('./$types').ActionData} */
|
||||
export let form;
|
||||
|
||||
/**
|
||||
* Sets the active tab
|
||||
* @param {string} tab - The tab to set as active
|
||||
*/
|
||||
function setActiveTab(tab) {
|
||||
activeTab = tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates thek form data
|
||||
* @param {Object} data - The form data to validate
|
||||
* @returns {ValidationErrors} An object containing validation errors
|
||||
*/
|
||||
function validateForm(data) {
|
||||
/** @type {ValidationErrors} */
|
||||
let errors = {};
|
||||
|
||||
if ("first_name" in data && !String(data.first_name).trim()) {
|
||||
errors.first_name = $t("required");
|
||||
}
|
||||
if ("last_name" in data && !String(data.last_name).trim()) {
|
||||
errors.last_name = $t("required");
|
||||
}
|
||||
if (
|
||||
"email" in data &&
|
||||
(!data.email || !/^\S+@\S+\.\S+$/.test(String(data.email)))
|
||||
) {
|
||||
errors.email = $t("required");
|
||||
}
|
||||
if ("password" in data) {
|
||||
if (String(data.password).length < 8) {
|
||||
errors.password = $t("required_password");
|
||||
}
|
||||
if ("password2" in data && data.password !== data.password2) {
|
||||
errors.password2 = $t("required_password_match");
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/** @type {import('./$types').SubmitFunction} */
|
||||
const handleUpdate = async ({ form, formData, action, cancel }) => {
|
||||
/** @type {Object.<string, FormDataEntryValue>} */
|
||||
const fd = Object.fromEntries(formData);
|
||||
validationErrors = validateForm(fd);
|
||||
if (Object.keys(validationErrors).length > 0) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
isUpdating = true;
|
||||
return async ({ result }) => {
|
||||
isUpdating = false;
|
||||
if (result.type === "success" || result.type === "redirect") {
|
||||
validationErrors = {};
|
||||
close();
|
||||
} else if (result.type == "failure" && result.data?.errors) {
|
||||
/** @type {ValidationErrors} */
|
||||
validationErrors = {};
|
||||
// Assuming result.data.errors is an array of {error: string, id: string}
|
||||
result.data.errors.forEach(({ error, id }) => {
|
||||
validationErrors[id] = error;
|
||||
});
|
||||
}
|
||||
await applyAction(result);
|
||||
};
|
||||
};
|
||||
|
||||
/** @type {import('./$types').SubmitFunction} */
|
||||
const handleUpload = async () => {
|
||||
isUploading = true;
|
||||
return async ({ result }) => {
|
||||
isUploading = false;
|
||||
/** @type {any} */
|
||||
const res = result;
|
||||
if (result.type === "success" || result.type === "redirect") {
|
||||
user.thumbnail = res.data.thumbnail;
|
||||
}
|
||||
await applyAction(result);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="hero-container">
|
||||
<div class="hero-logo">
|
||||
<img
|
||||
src={user.thumbnail ? user.thumbnail : Avatar}
|
||||
alt={`${user.first_name} ${user.last_name}`}
|
||||
width="200"
|
||||
/>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
{#if user.status}
|
||||
<h3 class="hero-subtitle subtitle info-row">
|
||||
<span class="label">Status:</span>
|
||||
<span class="value block-value">
|
||||
<span
|
||||
>{$t(`userStatus.${user.status}`, {
|
||||
default: "unknown status",
|
||||
})}</span
|
||||
>
|
||||
<span
|
||||
>{$t(`userRole.${user.role_id}`, { default: "unknown role" })}</span
|
||||
>
|
||||
</span>
|
||||
</h3>
|
||||
{/if}
|
||||
<h3 class="hero-subtitle subtitle info-row">
|
||||
<span class="label">Name:</span>
|
||||
<span class="value">{`${user.first_name} ${user.last_name}`}</span>
|
||||
</h3>
|
||||
{#if user.email}
|
||||
<h3 class="hero-subtitle subtitle info-row">
|
||||
<span class="label">Email:</span>
|
||||
<span class="value">{user.email}</span>
|
||||
</h3>
|
||||
{/if}
|
||||
{#if user.address}
|
||||
<h3 class="hero-subtitle subtitle info-row">
|
||||
<span class="label">Adresse:</span>
|
||||
<span class="value block-value">
|
||||
<span>{user.address}</span>
|
||||
<span>{`${user.zip_code} ${user.city}`}</span>
|
||||
</span>
|
||||
</h3>
|
||||
{/if}
|
||||
{#if user.phone}
|
||||
<h3 class="hero-subtitle subtitle info-row">
|
||||
<span class="label">Telefon:</span>
|
||||
<span class="value">{user.phone}</span>
|
||||
</h3>
|
||||
{/if}
|
||||
{#if user.birth_date}
|
||||
<h3 class="hero-subtitle subtitle info-row">
|
||||
<span class="label">Geburtstag:</span>
|
||||
<span class="value">{user.birth_date}</span>
|
||||
</h3>
|
||||
{/if}
|
||||
{#if user.notes}
|
||||
<h3 class="hero-subtitle subtitle info-row">
|
||||
<span class="label">{$t("notes")}:</span>
|
||||
<span class="value">{user.notes}</span>
|
||||
</h3>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="hero-buttons-container">
|
||||
<button class="button-dark" on:click={open}>Ändern</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if showModal}
|
||||
<Modal on:close={close}>
|
||||
<div class="avatar-container">
|
||||
<form
|
||||
class="avatar-form"
|
||||
action="?/uploadImage"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
use:enhance={handleUpload}
|
||||
>
|
||||
<div class="current-avatar">
|
||||
<ImageInput
|
||||
avatar={user.thumbnail}
|
||||
fieldName="thumbnail"
|
||||
title="Nutzerbild auswählen"
|
||||
/>
|
||||
</div>
|
||||
<div class="avatar-buttons">
|
||||
{#if !user.thumbnail}
|
||||
{#if isUploading}
|
||||
<SmallLoader width={30} message={"Uploading..."} />
|
||||
{:else}
|
||||
<button class="button-dark" type="submit">Bild hochladen</button>
|
||||
{/if}
|
||||
{:else}
|
||||
<input
|
||||
type="hidden"
|
||||
hidden
|
||||
name="thumbnail_url"
|
||||
value={user.thumbnail}
|
||||
required
|
||||
/>
|
||||
{#if isUploading}
|
||||
<SmallLoader width={30} message={"Lösche..."} />
|
||||
{:else}
|
||||
<button
|
||||
class="button-dark"
|
||||
formaction="?/deleteImage"
|
||||
type="submit"
|
||||
>
|
||||
Bild löschen
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
<div class="avatar-buttons">
|
||||
<button class="button-dark" on:click={toggleAvatars}>
|
||||
{showAvatars ? "Abbrechen" : "Profilbild auswählen"}
|
||||
</button>
|
||||
</div>
|
||||
{#if showAvatars}
|
||||
<div class="avatar-selection">
|
||||
{#each avatars as avatar}
|
||||
<button
|
||||
class="avatar-option"
|
||||
on:click={() => {
|
||||
user.thumbnail = avatar.src;
|
||||
showAvatars = false;
|
||||
}}
|
||||
>
|
||||
<img src={avatar.src} alt={avatar.name} width="80" />
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<form
|
||||
class="content"
|
||||
action="?/updateUser"
|
||||
method="POST"
|
||||
use:enhance={handleUpdate}
|
||||
>
|
||||
<h1 class="step-title" style="text-align: center;">{$t("user_edit")}</h1>
|
||||
{#if form?.success}
|
||||
<h4
|
||||
class="step-subtitle warning"
|
||||
in:receive={{ key: Math.floor(Math.random() * 100) }}
|
||||
out:send={{ key: Math.floor(Math.random() * 100) }}
|
||||
>
|
||||
Um einen fehlerhaften upload Ihres Bildes zu vermeiden, clicke bitte
|
||||
auf den "Update" Button unten.
|
||||
</h4>
|
||||
{/if}
|
||||
{#if form?.errors}
|
||||
{#each form?.errors as error (error.id)}
|
||||
<h4
|
||||
class="step-subtitle warning"
|
||||
in:receive={{ key: error.id }}
|
||||
out:send={{ key: error.id }}
|
||||
>
|
||||
{error.error}
|
||||
</h4>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<input type="hidden" hidden name="thumbnail" value={user.thumbnail} />
|
||||
|
||||
<div class="button-container">
|
||||
{#each TABS as tab}
|
||||
<button
|
||||
type="button"
|
||||
class="button-dark"
|
||||
class:active={activeTab === tab}
|
||||
on:click={() => setActiveTab(tab)}
|
||||
>
|
||||
{$t(tab)}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{#if activeTab == "profile"}
|
||||
<div class="tab-content">
|
||||
<InputField
|
||||
name="password"
|
||||
type="password"
|
||||
label={$t("password")}
|
||||
placeholder={$t("placeholder_password")}
|
||||
/>
|
||||
<InputField
|
||||
name="password2"
|
||||
type="password"
|
||||
label={$t("password_repeat")}
|
||||
placeholder={$t("placeholder_password")}
|
||||
/>
|
||||
<InputField
|
||||
name="first_name"
|
||||
label={$t("first_name")}
|
||||
value={user.first_name}
|
||||
placeholder={$t("placeholder_first_name")}
|
||||
/>
|
||||
<InputField
|
||||
name="last_name"
|
||||
label={$t("last_name")}
|
||||
value={user.last_name}
|
||||
placeholder={$t("placeholder_last_name")}
|
||||
/>
|
||||
<InputField
|
||||
name="email"
|
||||
type="email"
|
||||
label={$t("email")}
|
||||
value={user.email}
|
||||
placeholder={$t("placeholder_email")}
|
||||
/>
|
||||
<InputField
|
||||
name="phone"
|
||||
type="tel"
|
||||
label={$t("phone")}
|
||||
value={user.phone || ""}
|
||||
placeholder={$t("placeholder_phone")}
|
||||
/>
|
||||
<InputField
|
||||
name="birth_date"
|
||||
type="date"
|
||||
label={$t("birth_date")}
|
||||
value={user.birth_date || ""}
|
||||
placeholder={$t("placeholder_birth_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="address"
|
||||
label={$t("address")}
|
||||
value={user.address || ""}
|
||||
placeholder={$t("placeholder_address")}
|
||||
/>
|
||||
<InputField
|
||||
name="zip_code"
|
||||
label={$t("zip_code")}
|
||||
value={user.zip_code || ""}
|
||||
placeholder={$t("placeholder_zip_code")}
|
||||
/>
|
||||
<InputField
|
||||
name="city"
|
||||
label={$t("city")}
|
||||
value={user.city || ""}
|
||||
placeholder={$t("placeholder_city")}
|
||||
/>
|
||||
</div>
|
||||
{:else if activeTab == "membership"}
|
||||
<div class="tab-content">
|
||||
<InputField
|
||||
name="membership_status"
|
||||
label={$t("status")}
|
||||
value={user.membership?.status || ""}
|
||||
/>
|
||||
<InputField
|
||||
name="membership_start_date"
|
||||
type="date"
|
||||
label={$t("start")}
|
||||
value={user.membership?.start_date || ""}
|
||||
placeholder={$t("placeholder_start_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="membership_end_date"
|
||||
type="date"
|
||||
label={$t("end")}
|
||||
value={user.membership?.end_date || ""}
|
||||
placeholder={$t("placeholder_end_date")}
|
||||
/>
|
||||
<InputField
|
||||
name="parent_member_id"
|
||||
type="number"
|
||||
label={$t("parent_member_id")}
|
||||
value={user.membership?.parent_member_id || ""}
|
||||
placeholder={$t("placeholder_parent_member_id")}
|
||||
/>
|
||||
</div>
|
||||
{:else if activeTab == "bankaccount"}
|
||||
<div class="tab-content">
|
||||
<InputField
|
||||
name="account_holder_name"
|
||||
label={$t("bank_account_holder")}
|
||||
value={user.bank_account?.account_holder_name || ""}
|
||||
placeholder={$t("placeholder_bank_account_holder")}
|
||||
/>
|
||||
<InputField
|
||||
name="bank"
|
||||
label={$t("bank_name")}
|
||||
value={user.bank_account?.bank || ""}
|
||||
placeholder={$t("placeholder_bank_name")}
|
||||
/>
|
||||
<InputField
|
||||
name="iban"
|
||||
label={$t("iban")}
|
||||
value={user.bank_account?.iban || ""}
|
||||
placeholder={$t("placeholder_iban")}
|
||||
/>
|
||||
<InputField
|
||||
name="bic"
|
||||
label={$t("bic")}
|
||||
value={user.bank_account?.bic || ""}
|
||||
placeholder={$t("placeholder_bic")}
|
||||
/>
|
||||
<InputField
|
||||
name="mandate_reference"
|
||||
label={$t("mandate_reference")}
|
||||
value={user.bank_account?.mandate_reference || ""}
|
||||
placeholder={$t("placeholder_mandate_reference")}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="button-container">
|
||||
{#if isUpdating}
|
||||
<SmallLoader width={30} message={"Aktualisiere..."} />
|
||||
{:else}
|
||||
<button type="button" class="button-dark" on:click={close}
|
||||
>Abbrechen</button
|
||||
>
|
||||
<button type="submit" class="button-dark">Bestätigen</button>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.tab-content {
|
||||
padding: 1rem;
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
.hero-container .hero-subtitle:not(:last-of-type) {
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
.hero-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 0.5rem 1rem;
|
||||
align-items: start;
|
||||
text-align: left;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.value {
|
||||
margin: 0;
|
||||
font-size: 1.2rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.block-value {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.hero-buttons-container {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.label,
|
||||
.value {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.avatar-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.current-avatar {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.avatar-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.avatar-buttons button {
|
||||
margin-top: 1.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.avatar-selection {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.avatar-option {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.avatar-option:hover,
|
||||
.avatar-option:focus {
|
||||
transform: scale(1.8);
|
||||
}
|
||||
|
||||
.avatar-option img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button-container button {
|
||||
flex: 1 1 0;
|
||||
min-width: 120px;
|
||||
max-width: calc(50%-5px);
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.button-container button {
|
||||
flex-basis: 100%;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,6 +2,7 @@
|
||||
import { applyAction, enhance } from "$app/forms";
|
||||
import { page } from "$app/stores";
|
||||
import { receive, send } from "$lib/utils/helpers";
|
||||
import { t } from "svelte-i18n";
|
||||
|
||||
/** @type {import('./$types').ActionData} */
|
||||
export let form;
|
||||
@@ -26,7 +27,7 @@
|
||||
action="?/login"
|
||||
use:enhance={handleLogin}
|
||||
>
|
||||
<h1 class="step-title">Login User</h1>
|
||||
<h1 class="step-title">{$t("user_login")}</h1>
|
||||
{#if form?.errors}
|
||||
{#each form?.errors as error (error.id)}
|
||||
<h4
|
||||
@@ -49,28 +50,45 @@
|
||||
value={$page.url.searchParams.get("next")}
|
||||
/>
|
||||
<div class="input-box">
|
||||
<span class="label">Email:</span>
|
||||
<span class="label">{$t("email")}:</span>
|
||||
<input
|
||||
class="input"
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Email address"
|
||||
placeholder="{$t('placeholder_email')} "
|
||||
/>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<span class="label">Password:</span>
|
||||
<input
|
||||
class="input"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
<a href="/auth/password/request-change" style="margin-left: 1rem;"
|
||||
>Forgot password?</a
|
||||
>
|
||||
<span class="label">{$t("password")}:</span>
|
||||
<div class="input-wrapper">
|
||||
<input
|
||||
class="input"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder={$t("placeholder_password")}
|
||||
/>
|
||||
<a href="/auth/password/request-change" class="forgot-password"
|
||||
>{$t("forgot_password")}?</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-container">
|
||||
<button class="button-dark">Login</button>
|
||||
<button class="button-dark">{$t("login")} </button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
width: 100%;
|
||||
max-width: 444px;
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user