Initial commit

This commit is contained in:
Thomas Klaehn 2023-01-30 13:29:26 +01:00
commit f8b2047cff
33 changed files with 2787 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/node_modules/
/public/build/
.DS_Store
__debug_bin

16
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/main.go",
"preLaunchTask": "npm: build - svelte"
}
]
}

14
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,14 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build",
"path": "svelte",
"group": "build",
"problemMatcher": [],
"label": "npm: build - svelte",
"detail": "vite build"
}
]
}

12
config/config.json Normal file
View File

@ -0,0 +1,12 @@
{
"outer_gate": {
"state": 1,
"open_time": 4,
"close_time": 2
},
"inner_gate": {
"state": 1,
"open_time": 2,
"close_time": 2
}
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module webserver
go 1.19

0
go.sum Normal file
View File

145
main.go Normal file
View File

@ -0,0 +1,145 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
)
const (
OPENED uint = 1
CLOSED uint = 2
CLOSING uint = 3
OPENING uint = 4
)
type gate struct {
State uint `json:"state"`
OpenTime uint `json:"open_time"`
CloseTime uint `json:"close_time"`
}
type config struct {
InnerGate gate `json:"inner_gate"`
OuterGate gate `json:"outer_gate"`
}
var (
logger log.Logger = *log.Default()
config_path string
cache_inner_gate = gate{
State: 1,
OpenTime: 2,
CloseTime: 2,
}
cache_outer_gate = gate{
State: 1,
OpenTime: 4,
CloseTime: 2,
}
config_cache = config{
InnerGate: cache_inner_gate,
OuterGate: cache_outer_gate,
}
)
func read_config() {
data, err := os.ReadFile(config_path)
if err != nil {
logger.Printf("Unable to read %s", config_path)
return
}
err = json.Unmarshal(data, &config_cache)
if err != nil {
logger.Print("Unable to evaluate config data")
return
}
}
func api_handler_gates(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-type", "application/json; charset=utf-8;")
if r.Method == "GET" {
res, err := json.Marshal(config_cache)
if err != nil {
res = json.RawMessage(`{"error": "` + err.Error() + `"}`)
w.WriteHeader(http.StatusInternalServerError)
w.Write(res)
return
}
w.WriteHeader(http.StatusOK)
w.Write(res)
} else if r.Method == "PATCH" {
var tmp config
payload, _ := io.ReadAll(r.Body)
err := json.Unmarshal(payload, &tmp)
if err != nil {
logger.Print(err)
}
logger.Print(r.Body)
} else {
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
func api_handler_gates_outer(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
res, err := json.Marshal(map[string]uint{"state": config_cache.OuterGate.State})
if err != nil {
res = json.RawMessage(`{"error": "` + err.Error() + `"}`)
w.WriteHeader(http.StatusInternalServerError)
w.Write(res)
return
}
w.WriteHeader(http.StatusOK)
w.Write(res)
} else if r.Method == "PATCH" {
var tmp config
payload, _ := io.ReadAll(r.Body)
err := json.Unmarshal(payload, &tmp)
if err != nil {
res := json.RawMessage(`{"error": "` + err.Error() + `"}`)
w.WriteHeader(http.StatusInternalServerError)
w.Write(res)
return
}
if tmp.OuterGate.State == 1 {
config_cache.OuterGate.State = 3 // Schliessen => Schliesst
} else if tmp.OuterGate.State == 2 {
config_cache.OuterGate.State = 4 // Oeffnen => Oeffnet
}
// FIXME: add real gate handling
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
func main() {
flag.StringVar(&config_path, "c", "./config/config.json", "Specify path to find the config file. Default is ./config/config.json")
flag.Parse()
read_config()
// API routes
// Serve files from static folder
http.Handle("/", http.FileServer(http.Dir("./svelte/build")))
// Serve api
http.HandleFunc("/gates", api_handler_gates)
http.HandleFunc("/gates/outer", api_handler_gates_outer)
port := ":5000"
fmt.Println("Server is running on port" + port)
// Start server on port specified above
log.Fatal(http.ListenAndServe(port, nil))
}

10
svelte/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
.vercel
.output

1
svelte/.npmrc Normal file
View File

@ -0,0 +1 @@
engine-strict=true

38
svelte/README.md Normal file
View File

@ -0,0 +1,38 @@
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

1592
svelte/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
svelte/package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "my-app",
"version": "0.0.1",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@sveltejs/adapter-static": "next",
"@sveltejs/kit": "next",
"svelte": "^3.46.0",
"vite": "^3.1.0"
},
"type": "module",
"dependencies": {
"@fontsource/fira-mono": "^4.5.0"
}
}

12
svelte/src/app.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/haus.svg"/>
<meta name="viewport" content="width=device-width"/>
%sveltekit.head%
</head>
<body>
<div>%sveltekit.body%</div>
</body>
</html>

566
svelte/src/css/style.css Normal file
View File

@ -0,0 +1,566 @@
html,
body {
margin: 0;
padding: 0;
font-size: 18px !important;
font-family: 'Muli', arial, verdana, helvetica, sans-serif;
font-weight: 300;
font-style: normal;
height: 100%;
color: #b6b6b6;
background: #282929;
}
body {
display: flex;
flex-direction: column;
}
.modalbg {
background: rgba(0, 0, 0, 0.6);
height: 100%;
width: 100%;
position: fixed;
top: 0px;
z-index: 999;
overflow-x: hidden;
overflow-y: auto;
color: white;
}
a {
outline: none;
color: #b6b6b6;
text-decoration-line: none;
}
li {
list-style: none;
}
.content {
padding: 10rem 0;
margin: 2%;
}
section {
margin: auto 0;
align-items: center;
text-align: center;
}
section h1 {
margin: 20px auto;
font-size: 2rem;
}
section h2 {
font-size: 1.4rem;
}
table {
margin: auto;
}
td p {
margin: 0;
}
td.left {
text-align: right;
font-weight: 700;
width: 33%;
padding: 5px;
vertical-align: text-top;
}
td.right {
text-align: left;
}
td.input {
text-align: left;
width: 65%;
outline: none;
vertical-align: text-top;
}
form {
font-size: 1.2rem;
}
td select {
width: 51%;
outline: none;
width: 62%;
outline: none;
margin-left: 2%;
}
td input {
width: 60%;
outline: none;
}
td textarea {
text-align: left;
}
td input span {
font-size: 1.0rem;
outline: none;
border: none;
background: none;
}
select,
input {
border: 1px #999999 solid;
background-color: #f6f6f6;
padding: 2px 4px 2px 4px;
margin: 0 0 0.5rem 0;
color: #b6b6b6 !important;
font-size: 1.0rem;
border-radius: 8px;
outline: none;
}
td div input {
color: #b6b6b6 !important;
border: none;
background: none;
}
textarea {
border-radius: 10px;
width: 98%;
height: 10rem;
position: relative;
resize: none;
outline: none;
margin-left: 2%;
}
header {
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
background-color: #282929;
}
/*logo placement*/
header figure {
float: left;
color: #b6b6b6;
}
header figure.logo {
position: absolute;
right: 0px;
top: -15px;
}
/*Navigation*/
.header {
background-color: #282929;
/*position: fixed;*/
width: 100%;
z-index: 510;
}
.header ul {
margin: 0;
padding: 0;
list-style: none;
overflow: hidden;
/* background-color: #282929; */
background-color: transparent;
}
.header li a {
display: block;
padding: 30px 5px 10px 5px;
font-size: 1.5rem;
border-right: 1px solid #282929;
text-decoration: none;
/* background: rgba(255, 255, 255, 0.9) */
background-color: #282929;
}
.header li a:hover,
.header .menu-btn:hover {
background-color: #282929;
}
.header .logo {
display: block;
float: left;
font-size: 2em;
padding: 5px;
text-decoration: none;
}
/* menu */
.header .menu {
clear: both;
max-height: 0;
transition: max-height .2s ease-out;
}
/* menu icon */
.header .menu-icon {
cursor: pointer;
float: right;
margin: 2%;
padding: 10px 20px;
position: relative;
user-select: none;
}
.header .menu-icon .nav-icon {
background: #000;
display: block;
height: 5px;
position: relative;
transition: background .2s ease-out;
width: 30px;
}
.header .menu-icon .nav-icon:before,
.header .menu-icon .nav-icon:after {
background: #000;
content: '';
display: block;
height: 100%;
position: absolute;
transition: all .2s ease-out;
width: 100%;
}
.header .menu-icon .nav-icon:before {
top: 20px;
}
.header .menu-icon .nav-icon:after {
top: 10px;
}
/* menu btn */
.header .menu-btn {
display: none;
}
.header .menu-btn:checked~.menu {
max-height: 1200px;
}
.header .menu-btn:checked~.menu-icon .nav-icon {
background: transparent;
}
.header .menu-btn:checked~.menu-icon .nav-icon:before {
transform: rotate(-45deg);
top: 0;
}
.header .menu-btn:checked~.menu-icon .nav-icon:after {
transform: rotate(45deg);
top: 0;
}
/* menu content - larger screen*/
@media (min-width: 1132px) {
.header li {
float: left;
}
.header li a {
padding: 20px 15px 5px 0px;
font-size: 1rem;
border: none;
}
.header .menu {
clear: none;
float: right;
max-height: none;
}
.header .menu-icon {
display: none;
}
}
/* smaller screen*/
@media (max-width: 924px) {
.header li {
padding: 30px 5px 10px 5px;
}
.header li a {
font-size: 1.2rem;
}
}
#overlay {
position: absolute;
display: none;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999;
background-color: rgba(0, 0, 0, 0.5);
/*dim the background*/
}
.update-container {
display: flex;
align-items: center;
justify-content: center;
}
#update-plain {
position: relative;
}
#update-overlay {
position: absolute;
z-index: 502;
transform-origin: 50% 50%;
transition: transform 1.00s;
}
address {
text-align: center;
margin-top: 5px;
}
address table {
margin: 0 auto;
width: 100%;
font-style: normal;
}
address td {
width: 50%;
}
input[type="submit" i] {
margin: 0px 0 6px 0;
vertical-align: middle;
position: relative;
font-size: 16px;
font-weight: bold;
width: auto;
height: 45px;
z-index: 200;
width: 65%;
outline: none;
}
input[type="submit"] {
border-radius: 30px;
background: #282929;
border: 1px solid #d2d2d2;
-webkit-transition: all 1s;
transition: all 1s;
margin-top: 2%;
margin-left: 2%;
outline: none;
z-index: auto;
}
input[type="submit" i]:hover {
background-color: #f6f6f6;
color: #282929;
outline: none;
}
input[type="file"] {
border-radius: 10px;
margin: 1%;
width: 390px;
margin-left: 45px;
margin-right: 28px;
outline: none;
}
input {
border-radius: 10px;
background: #282929;
margin-left: 2%;
outline: none;
}
.confi table td.input {
padding: 1px 0px 10px 0px;
outline: none;
}
.confi table td.left {
padding: 0px 25px 0px 0px;
}
.content #uploadbutton {
width: 400px;
outline: none;
}
footer {
background-color: #f6f6f6;
padding: 1px 50px 1px 0px;
text-align: center;
text-decoration: none;
font-size: 0.8rem;
bottom: 0;
width: 100%;
position: fixed;
}
footer nav :hover {
color: #b6b6b6;
font-weight: 600;
}
footer td p {
text-align: left;
padding-left: 40%;
}
/* upload loader animation*/
.loader {
display: flex;
justify-content: center;
align-items: center;
width: 100px;
height: 100px;
background: transparent;
margin: 30px auto 0 auto;
border: solid 10px #b6b6b6;
border-top: solid 10px #c2d100;
border-radius: 50%;
opacity: 0;
}
.loader.active {
animation: loading 4s ease-in-out;
animation-fill-mode: forwards;
}
@keyframes loading {
5% {
opacity: 1;
border-color: #b6b6b6;
}
15% {
opacity: 1;
border-color: #c2d100;
}
30% {
opacity: 1;
transform: rotate(180deg);
border-color: #b6b6b6;
}
45% {
opacity: 1;
border-color: #c2d100;
}
60% {
opacity: 1;
transform: rotate(180deg);
border-color: #b6b6b6;
}
70% {
opacity: 1;
border-color: #c2d100;
}
85% {
opacity: 1;
transform: rotate(180deg);
border-color: #c2d100;
}
90% {
opacity: 1;
transform: rotate(1080deg);
border-color: #c2d100;
}
99% {
opacity: 1;
transform: rotate(1080deg);
border-color: #c2d100;
}
100% {
opacity: 1;
transform: rotate(1080deg);
border-color: #282929;
}
}
/*Chrome runable slider*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
input[type='range'] {
overflow: hidden;
/* Standard */
width: calc(99.9% - 1.5px);
-webkit-appearance: none;
background-color: transparent;
margin: 0 0 0;
}
input[type='range']::-webkit-slider-runnable-track {
height: fit-content;
/* -webkit-appearance: none; */
color: #C2D100;
/* margin-top: -5px; */
}
input[type='range']::-webkit-slider-thumb {
width: 20px;
-webkit-appearance: none;
height: 20px;
cursor: ew-resize;
border-radius: 5px;
background: #292659;
box-shadow: -1080px 10px 10px 1080px #C1D10A;
}
input:focus {
outline: none;
border-color: #C1D10A;
}
}
/** FF*/
input[type="range"]::-moz-range-progress {
background-color: #C1D10A;
}
input[type="range"]::-moz-range-track {
background-color: transparent;
}
/* IE*/
input[type="range"]::-ms-fill-lower {
background-color: #C1D10A;
}
input[type="range"]::-ms-fill-upper {
background-color: #C1D10A;
}

View File

@ -0,0 +1,14 @@
export const handle = async ({ event, resolve }) => {
let userid = event.cookies.get('userid');
if (!userid) {
// if this is the first time the user has visited this app,
// set a cookie so that we recognise them when they return
userid = crypto.randomUUID();
event.cookies.set('userid', userid, { path: '/' });
}
event.locals.userid = userid;
return resolve(event);
};

View File

@ -0,0 +1,27 @@
<script>
import perinetLogo from '../../static/perinet-logo.png'
import favicon from '../../static/favicon.png'
</script>
<header class="header">
<!-- <a href="https://www.perinet.io" target="_blank" class="logo">
<img src={perinetLogo} alt="Perinet Logo" width="180">
</a>
<link rel="shortcut icon" type="image/png" href={favicon} /> -->
<input class="menu-btn" type="checkbox" id="menu-btn" />
<!-- <label class="menu-icon" for="menu-btn"><span class="nav-icon"></span></label> -->
<ul class="menu">
<li><a href="/">Home</a></li>
<li><a href="/chicken">Chicken</a></li>
<!-- <li><a href="/Information">Information</a></li>
<li><a href="/Configuration">Configuration</a></li>
<li><a href="/Security">Security</a></li>
<li><a href="/FirmwareUpdate">Firmware update</a></li>
<li><a href="/APIDocumentation">API documentation</a></li>
<li><a href="https://docs.perinet.io" target="_blank">Online documentation</a></li> -->
</ul>
</header>

View File

@ -0,0 +1,13 @@
<script>
import Header from '$lib/Header.svelte';
// import Footer from '$lib/Footer.svelte';
import '../css/style.css'
</script>
<Header />
<main>
<slot />
</main>
<!-- <Footer/> -->

View File

@ -0,0 +1 @@
export const prerender = true;

View File

@ -0,0 +1,15 @@
<script>
import icon from "../../static/haus.svg"
</script>
<svelte:head>
<title>Home</title>
<meta name="description" content="Home"/>
</svelte:head>
<section id='content_id' class='content'>
<figure>
<img src={icon} alt="Home" width=150/>
</figure>
<h1>Home</h1>
</section>

View File

@ -0,0 +1 @@
export const prerender = true;

View File

@ -0,0 +1,152 @@
<script>
import { bind, onMount } from "svelte/internal";
import icon from "../../../static/hahn.svg"
// base api url
let backend_url = "http://localhost:5000/gates";
let value_state_outer = "";
let value_open_times_outer = "";
let value_close_times_outer = "";
let options_state = [
{id: 1, text: "Schließen" }, // means "is open"
{id: 2, text: "Öffnen" },
{id: 3, text: "Schließt..." },
{id: 4, text: "Öffnet..." },
];
let options_open = [
{id: 1, text: "Sonnenaufgang"},
{id: 2, text: "08:00"},
{id: 3, text: "09:00"},
{id: 4, text: "10:00"},
{id: 5, text: "11:00"},
{id: 6, text: "12:00"}
];
let options_close = [
{id: 1, text: "Sonnenuntergang"},
{id: 2, text: "Sonnenuntergang + 30min"},
{id: 3, text: "16:00"},
{id: 4, text: "16:30"},
{id: 5, text: "17:00"},
{id: 6, text: "17:30"},
{id: 7, text: "18:00"},
{id: 8, text: "18:30"},
{id: 9, text: "19:00"},
{id: 10, text: "19:30"},
{id: 11, text: "20:00"},
{id: 12, text: "20:30"},
{id: 13, text: "21:00"},
{id: 14, text: "21:30"},
{id: 15, text: "22:00"},
];
function get_next_state(state) {
if(state == 1) {
return 2;
}
if(state == 2) {
return 1;
}
}
function handle_button_outer(event) {
console.log(value_state_outer)
for( var i = 0; i < options_state.length; i++) {
if(options_state[i].text == value_state_outer) {
fetch(backend_url + "/outer", {
method: "PATCH",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
outer_gate: {state: get_next_state(options_state[i].id)}
})
})
.then(response => response.json())
// .then(result => console.log(result))
break;
}
}
}
function handle_open_times_outer() {
alert(value_open_times_outer);
}
function handle_close_times_outer() {
alert(value_close_times_outer);
}
function set_state_outer(index) {
for( var i = 0; i < options_state.length; i++) {
if(options_state[i].id == index) {
value_state_outer = options_state[i].text;
break;
}
}
}
function get_gates() {
fetch(backend_url)
.then(response => response.json())
.then(data => {
set_state_outer(data.outer_gate.state)
}).catch(error => {
console.log(error);
return [];
});
}
setInterval(() => {
get_gates();
}, 1000)
onMount(async () => {
get_gates();
});
</script>
<svelte:head>
<title>Chicken</title>
<meta name="description" content="Chicken"/>
</svelte:head>
<section id='content_id' class='content'>
<figure>
<img src={icon} alt="Chicken" width=150/>
</figure>
<h1>Chicken</h1>
<hr>
<table>
<tr>
<td class="left">
<h2>Außenklappe</h2>
</td>
<td>
<input type="submit" enabled id="button_outer" value={value_state_outer} style="margin-left:55px;width:200px" on:click={(event) => handle_button_outer(event)}/>
</td>
</tr>
<tr>
<td class="left">Öffnen:</td>
<td class="input">
<select style="margin-left:55px;width:250px;" bind:value={value_open_times_outer} on:change={handle_open_times_outer}>
{#each options_open as option}
<option value={option}>{option.text}</option>
{/each}
</select>
</td>
</tr>
<tr>
<td class="left">Schließen:</td>
<td class="input">
<select style="margin-left:55px;width:250px;" bind:value={value_close_times_outer} on:change={handle_close_times_outer}>
{#each options_close as option}
<option value={option}>{option.text}</option>
{/each}
</select>
</td>
</tr>
</table>
<hr>
</section>

Binary file not shown.

BIN
svelte/static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

79
svelte/static/hahn.svg Normal file
View File

@ -0,0 +1,79 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1280.000000pt" height="1210.000000pt" viewBox="0 0 1280.000000 1210.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.15, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,1210.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M11345 12075 c-49 -33 -58 -44 -146 -173 -39 -57 -77 -106 -85 -109
-27 -10 -63 7 -141 69 -121 96 -179 128 -233 128 -98 0 -285 -84 -384 -172
-79 -70 -152 -176 -166 -241 -23 -110 22 -257 116 -373 l33 -41 -82 -7 c-331
-28 -656 -105 -851 -203 -314 -157 -535 -430 -726 -893 -73 -179 -139 -389
-235 -750 -105 -391 -159 -559 -229 -705 -102 -213 -292 -470 -496 -675 -155
-155 -294 -265 -550 -435 -640 -426 -839 -521 -1245 -596 -211 -40 -362 -31
-623 37 -333 86 -415 126 -722 350 -415 303 -681 451 -1005 559 -264 88 -490
121 -770 112 -536 -19 -1152 -196 -1560 -450 -532 -330 -957 -995 -1129 -1762
-37 -167 -54 -286 -83 -591 -36 -383 -38 -796 -5 -1012 35 -222 114 -439 255
-702 53 -100 75 -129 167 -221 171 -171 395 -307 579 -349 91 -21 457 -64 495
-58 16 3 13 10 -21 53 -22 28 -102 115 -178 195 -304 320 -424 526 -519 891
-33 125 -46 221 -72 519 l-6 75 72 -140 c149 -290 218 -384 305 -421 104 -43
165 9 219 188 26 85 31 116 60 365 20 165 35 190 36 58 2 -343 21 -830 35
-915 20 -123 77 -301 118 -370 95 -158 210 -120 281 92 13 40 52 233 85 428
189 1104 245 1410 261 1439 24 46 33 23 26 -66 -8 -90 -18 -520 -16 -653 1
-41 9 -97 18 -125 19 -57 39 -65 104 -46 49 15 142 101 161 150 9 21 62 212
117 423 118 446 184 676 210 733 l18 40 1 -45 c1 -57 -22 -155 -99 -410 -112
-375 -145 -530 -156 -740 -17 -335 71 -805 187 -993 111 -180 323 -392 481
-481 114 -63 258 -84 258 -36 0 27 -60 214 -134 420 -106 295 -129 389 -151
630 -27 283 -17 718 21 945 34 205 186 705 213 705 9 0 -3 -116 -23 -210 -46
-229 -67 -495 -67 -870 0 -562 54 -984 161 -1257 29 -74 56 -122 63 -112 2 2
26 96 54 209 49 202 94 329 136 391 25 36 74 76 82 67 4 -3 13 -70 21 -149 19
-185 39 -290 71 -362 50 -112 234 -253 424 -324 91 -34 242 -63 256 -50 4 4
-14 94 -40 200 -60 248 -72 354 -51 455 5 23 6 22 34 -17 16 -22 49 -51 72
-63 38 -20 58 -23 163 -23 l120 0 58 -111 c63 -121 78 -134 151 -134 34 0 60
11 127 51 125 76 117 76 191 17 99 -80 135 -93 253 -92 105 1 161 15 216 55
17 12 31 20 33 18 1 -2 15 -33 29 -68 66 -153 185 -323 326 -461 97 -94 199
-167 223 -157 7 2 49 91 92 196 l79 192 22 -27 c12 -15 53 -83 90 -151 80
-144 129 -197 288 -310 59 -42 107 -80 107 -83 0 -4 -16 -116 -35 -250 -19
-134 -35 -244 -35 -245 0 -1 -36 8 -80 21 -103 30 -177 42 -320 53 -87 6 -133
15 -190 37 -65 24 -89 28 -185 28 -100 1 -115 -1 -165 -26 -30 -15 -74 -47
-98 -71 l-43 -44 75 -5 c58 -4 90 -12 141 -37 72 -36 105 -72 157 -175 62
-122 72 -129 226 -146 72 -8 124 -22 222 -60 71 -28 134 -50 140 -50 47 0 -99
-104 -190 -135 -105 -36 -238 -107 -397 -214 -159 -106 -239 -181 -291 -273
-82 -144 -96 -325 -35 -449 18 -35 45 -77 62 -93 l30 -28 45 89 c71 142 108
176 226 203 111 26 228 81 357 167 45 31 87 52 93 48 6 -4 32 -39 57 -79 74
-117 114 -163 193 -229 136 -114 233 -167 306 -167 14 0 44 -15 67 -34 77 -62
90 -65 248 -63 126 2 151 -1 202 -20 73 -28 175 -95 260 -174 37 -34 70 -59
74 -56 3 4 6 73 7 154 1 138 -1 153 -27 228 -19 53 -25 81 -17 83 13 5 195
125 252 167 34 25 39 26 74 15 l37 -13 60 67 c176 197 266 160 575 -233 62
-79 130 -156 150 -171 91 -66 140 -152 163 -287 6 -37 13 -69 14 -71 5 -6 148
29 173 42 42 22 108 98 123 142 21 62 16 143 -15 228 -16 42 -32 79 -37 82
-21 13 -7 23 19 13 15 -6 83 -24 151 -40 209 -50 213 -55 246 -282 9 -62 18
-114 20 -116 2 -2 52 23 111 55 71 39 113 69 125 89 46 75 64 293 34 408 -40
152 -137 262 -311 350 -29 15 -132 54 -229 87 -202 69 -238 86 -361 168 -134
90 -174 135 -203 223 -13 41 -39 108 -58 149 -26 58 -42 119 -69 265 -40 220
-85 430 -114 529 l-20 69 98 93 c257 242 366 531 395 1044 l2 44 190 164 c479
414 733 657 1026 982 418 464 613 726 765 1025 115 228 163 396 211 735 25
178 24 730 0 950 -46 400 -108 725 -222 1154 -25 92 -45 175 -45 183 0 9 14
31 30 50 46 51 101 169 171 363 l63 175 2 240 c0 187 4 256 18 315 9 41 19 84
21 95 4 21 5 21 167 -7 90 -15 190 -27 223 -28 72 0 167 23 205 50 l27 19 102
-69 101 -68 17 31 c11 21 17 55 17 97 0 58 -5 76 -51 170 -61 125 -106 187
-215 297 l-81 83 38 82 c38 81 39 87 43 212 5 159 -9 247 -54 342 -36 76 -109
166 -155 189 -38 20 -125 19 -244 -4 -57 -11 -104 -16 -109 -11 -5 5 7 45 28
94 59 137 50 223 -26 262 -62 32 -143 4 -293 -100 -44 -31 -85 -56 -92 -56 -9
0 -12 37 -10 153 2 140 0 155 -20 194 -28 52 -69 82 -125 89 -36 5 -50 1 -83
-21z m-2875 -9705 c30 -183 56 -273 113 -390 28 -58 52 -107 54 -110 1 -3 -29
-20 -68 -38 -206 -97 -249 -254 -143 -519 l29 -72 50 56 c54 62 122 99 201
110 45 6 48 5 35 -10 -7 -9 -64 -55 -126 -102 -129 -97 -174 -143 -211 -216
l-26 -52 -31 57 c-49 92 -198 221 -336 291 -73 37 -137 55 -193 55 -27 0 -48
2 -48 5 0 2 12 40 26 82 31 92 29 174 -5 241 l-21 42 21 62 c11 35 30 135 41
223 11 88 21 160 22 161 0 0 58 19 129 42 141 47 310 120 402 175 33 19 61 34
62 33 1 -1 11 -58 23 -126z m-454 -1530 c38 -17 106 -38 151 -45 75 -12 143
-43 143 -63 0 -7 -16 -115 -26 -170 l-5 -34 -31 46 c-16 25 -57 71 -91 101
-53 48 -66 55 -102 55 -53 0 -180 63 -209 103 -18 24 -19 29 -6 38 24 16 103
2 176 -31z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

29
svelte/static/haus.svg Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1280.000000pt" height="1210.000000pt" viewBox="0 0 1280.000000 1210.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.15, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,1210.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M5699 11502 c-371 -328 -1786 -1580 -3144 -2782 -1359 -1201 -2489
-2203 -2512 -2225 l-41 -40 329 -370 c181 -203 333 -371 338 -373 6 -2 949
828 2098 1844 1148 1017 2434 2154 2857 2529 423 374 773 680 777 680 5 0
1291 -1135 2859 -2523 1568 -1388 2857 -2525 2864 -2528 7 -3 122 119 267 283
140 158 289 327 332 375 l78 87 -1038 918 c-571 505 -1882 1665 -2913 2578
-1031 912 -1998 1768 -2149 1902 -214 190 -277 240 -288 232 -9 -8 -17 -8 -26
-1 -10 8 -171 -129 -688 -586z"/>
<path d="M1910 10089 l0 -1201 108 98 c59 53 418 378 798 721 l691 623 6 347
c4 190 7 406 7 480 l0 133 -805 0 -805 0 0 -1201z"/>
<path d="M4875 8574 c-836 -740 -1845 -1632 -2242 -1982 l-722 -637 0 -2875
c-1 -2870 -1 -2875 20 -2920 29 -64 84 -117 146 -140 53 -20 80 -20 1478 -20
l1425 0 2 1277 c3 1272 3 1278 24 1323 26 58 76 108 134 134 45 21 49 21 1260
21 1211 0 1215 0 1260 -21 58 -26 108 -76 134 -134 21 -45 21 -51 24 -1322 l2
-1278 1425 0 c1398 0 1425 0 1478 20 62 23 117 76 146 140 21 45 21 51 20
2920 l0 2875 -831 735 c-457 404 -1360 1202 -2007 1775 -1658 1467 -1645 1455
-1651 1455 -3 0 -689 -606 -1525 -1346z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -0,0 +1 @@
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 566.93 629.92"><defs><style>.cls-1{fill:#c2d100;}.cls-2{fill:#2c2b5a;stroke:#2c2b5a;stroke-width:5.31px;}.cls-2,.cls-4{stroke-miterlimit:10;}.cls-3{fill:#2b2a59;}.cls-4{fill:none;stroke:#2b2a59;stroke-width:10.63px;}</style></defs><path class="cls-1" d="M317.59,621.73s-34.13,18.43-68.25,0L34.12,498S0,476.9,0,437.4V192.52S0,150.39,34.12,132L249.34,8.19s34.12-18.43,68.25,0L532.81,132s34.12,18.44,34.12,60.57V437.4s0,39.5-34.12,60.57Z"/><g id="periNODE"><path class="cls-2" d="M373.25,334.38c21.36,4.51,41.57,31.1,54,71.08,6.88,22.18,14.21,37.33,23.84,49.27A39.27,39.27,0,0,0,465,466.18c3.85,1.88,4.46,2,9.41,2s5.45-.11,9.63-2.15c8.59-4.24,17.84-15.25,25.38-30.28a208.35,208.35,0,0,0,9.8-23.35l.94-2.86h8.48c7.71,0,8.48.11,8.48.94,0,1.7-5.4,16.9-8.59,24.22-12.28,28.24-28,45.58-45.37,50.1A46.76,46.76,0,0,1,466,485a53.67,53.67,0,0,1-15.91-7.71c-15.3-11.39-29.51-35.56-38.37-65.29-6.34-21.31-17-41.41-27.15-51.54-9.79-9.74-19.32-11.89-29.67-6.77-11.84,5.84-24.67,25.22-33.75,51.15l-1.54,4.4-8.59.17c-7.38.11-8.53,0-8.53-.72a69.68,69.68,0,0,1,2.25-7.6c9.36-28,23.4-50.21,38.16-60.34a47.92,47.92,0,0,1,14.31-6.38A43.47,43.47,0,0,1,373.25,334.38Z"/><path class="cls-3" d="M123.67,123.2v21.25a1.54,1.54,0,0,1,.64.1L194.73,185a2,2,0,0,1,.85,1.72V267a4.11,4.11,0,0,1-1.07,2.44l-69.73,40.1a6.41,6.41,0,0,1-1.94.37,1.54,1.54,0,0,1-.64-.1L52.43,269.69c-.62-.54-1.5-1.55-1.5-2.08v-80.4a6.94,6.94,0,0,1,.52-2l.08-.05,70.58-40.59c.16,0,1.17-.15,1.56-.15V123.2m0,0A27,27,0,0,0,112,125.9L41,166.76c-11.27,6.09-11.27,20-11.27,20v80.85c0,13,11.27,20,11.27,20L112,328.46a22.55,22.55,0,0,0,10.85,2.7,27,27,0,0,0,11.68-2.7l71.06-40.86c11.26-7,11.26-20,11.26-20V186.76a23.42,23.42,0,0,0-11.26-20L134.52,125.9A22.44,22.44,0,0,0,123.67,123.2Z"/><line class="cls-4" x1="393.98" y1="112.27" x2="141.22" y2="550.06"/></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 708.66 708.66"><defs><style>.cls-1{fill:#c2d100;}.cls-2{fill:#292659;}.cls-3{fill:#c1d00e;}</style></defs><path class="cls-1" d="M400.36,22.71s-44-25.4-88,0L91.28,150.36s-44,25.4-44,76.2V481.85s0,50.81,44,76.2L312.36,685.7s44,25.4,88,0L621.45,558.05s44-25.39,44-76.2V226.56s0-50.8-44-76.2L400.36,22.71Z"/><path class="cls-2" d="M397.25,329.78v-28c0-21.82-17.46-39.58-38.93-39.58S319.38,280,319.38,301.78v28H292.79V449.51H423.85V329.78Zm-66.48-28a27.55,27.55,0,1,1,55.09,0v28H330.77Z"/><path class="cls-3" d="M352.62,392.76v20.68H364V392.75a13.29,13.29,0,1,0-11.39,0Z"/><path class="cls-2" d="M540.55,246.53c-.22-11.57-.44-22.51-.44-33.08a15.14,15.14,0,0,0-15.3-15c-65.43,0-115.25-18.44-156.77-58a15.53,15.53,0,0,0-21.34,0c-41.52,39.6-91.33,58-156.76,58a15.15,15.15,0,0,0-15.3,15c0,10.58-.21,21.51-.44,33.09-2.09,107.69-5,255.18,178.16,317.42a15.54,15.54,0,0,0,10,0C545.52,501.72,542.65,354.22,540.55,246.53ZM357.37,533.87c-157-55.95-154.68-178.5-152.57-286.76.13-6.5.25-12.8.33-19,61.29-2.53,110.29-20.74,152.24-56.58,42,35.84,91,54.05,152.25,56.58.09,6.17.21,12.47.34,19C512.06,355.36,514.44,477.92,357.37,533.87Z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg id="Nachtrag" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 708.66 708.66"><defs><style>.cls-1{fill:#c3d205;}.cls-2{fill:#2a2459;}</style></defs><path class="cls-1" d="M387.82,689.7s-37.2,20.1-74.41,0l-234.67-135s-37.21-23-37.21-66v-267s0-45.94,37.21-66L313.41,20.71s37.21-20.1,74.41,0l234.68,135s37.2,20.09,37.2,66v267s0,43.07-37.2,66l-234.68,135Z"/><path class="cls-2" d="M540.34,249.13c0,12.51-.26,25,.06,37.52.26,10.28-3.4,16.12-15.58,16-28.05-.28-56.12,0-84.18-.08-4,0-9.14,1.1-11.06-3.41s2.71-6.92,5.24-9.87c.87-1,2-1.88,2.92-2.84,26.1-26.13,26.26-26.37-6-46.24-45.6-28.06-94.14-30.34-142-7.91-48.28,22.63-73.61,61.14-75.74,112.53-.38,9.2,6,22-5.92,26.91-12.75,5.26-27.7,2.95-41.53,1-9.3-1.29-8-9.53-8.44-15.91-6-86.38,57.26-167.22,148-186.66,66.36-14.23,127.35-1.66,178.1,42,15.37,13.22,24,11.16,34.89-2a50.26,50.26,0,0,1,7.47-6.93c3.06-2.43,5.94-6.75,10.6-4.35,4.22,2.18,3.09,6.94,3.13,10.73C540.45,222.8,540.36,236,540.34,249.13Z"/><path class="cls-2" d="M157.81,462.76c0-12.51.26-25-.06-37.52-.26-10.28,3.39-16.11,15.57-16,28.06.29,56.13,0,84.19.08,4,0,9.13-1.09,11.05,3.42s-2.7,6.92-5.23,9.87c-.88,1-2,1.87-2.93,2.84-26.09,26.12-26.26,26.36,6,46.23,45.6,28.07,94.15,30.34,142,7.92C456.68,457,482,418.47,484.14,367.07c.38-9.2-6-22,5.92-26.91,12.75-5.25,27.7-3,41.52-1,9.31,1.29,8,9.52,8.44,15.91,6,86.37-57.26,167.21-148,186.66-66.36,14.22-127.36,1.66-178.1-42-15.38-13.22-24-11.15-34.89,2a50.9,50.9,0,0,1-7.48,6.94c-3.06,2.43-5.93,6.75-10.6,4.34-4.22-2.17-3.09-6.94-3.13-10.73C157.7,489.09,157.79,475.92,157.81,462.76Z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

12
svelte/svelte.config.js Normal file
View File

@ -0,0 +1,12 @@
import adapter from '@sveltejs/adapter-static';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter({
fallback: "200.html"
})
}
};
export default config;

7
svelte/vite.config.js Normal file
View File

@ -0,0 +1,7 @@
import { sveltekit } from '@sveltejs/kit/vite';
const config = {
plugins: [sveltekit()]
};
export default config;