feat: Bit of frontend changes

This commit is contained in:
2025-11-29 13:38:17 +01:00
parent 7711bcc220
commit 4252fbcae0
9 changed files with 86 additions and 86 deletions

View File

@@ -31,9 +31,6 @@ Configure by setting up _/docker/.env_ (copy [/docker/.env.example](docker/.env.
(Please note that the _bind\_url_ should be left unconfigured as it is used in the [/docker/docker-compose.yml](docker/docker-compose.yml) config file. Otherwise the proxy-pass may break.) (Please note that the _bind\_url_ should be left unconfigured as it is used in the [/docker/docker-compose.yml](docker/docker-compose.yml) config file. Otherwise the proxy-pass may break.)
### Privacy policy
The website contains links to _privacy-policy.html_. You can (and should) set up this privacy policy page. Empty dummy files already exist in the [_docker/_](docker) and [_frontend/src/_](frontend/src) directories.
## API ## API
API-Documentation: [openapi.yml](openapi.yml) API-Documentation: [openapi.yml](openapi.yml)

View File

@@ -1,8 +1,4 @@
use std::{ use std::{collections::HashMap, io::Error};
collections::HashMap,
io::Error,
};
use log::{debug, error}; use log::{debug, error};
use serde::Deserialize; use serde::Deserialize;
use tokio::io::{AsyncBufReadExt, BufReader, BufWriter}; use tokio::io::{AsyncBufReadExt, BufReader, BufWriter};
@@ -113,6 +109,8 @@ pub async fn init<A: ToSocketAddrs>(
.await?; .await?;
tcp_stream_writer.flush().await?; tcp_stream_writer.flush().await?;
debug!("Sent login: '{}'", login_message.trim());
loop { loop {
let mut line = String::new(); let mut line = String::new();
@@ -131,7 +129,7 @@ pub async fn init<A: ToSocketAddrs>(
let current_timestamp = get_current_timestamp(); let current_timestamp = get_current_timestamp();
debug!("Got line: '{line}'"); debug!("Got line: '{}'", line.trim());
line_received_tx line_received_tx
.send(current_timestamp) .send(current_timestamp)

View File

@@ -20,4 +20,3 @@ services:
- "127.0.0.1:9000:8080" - "127.0.0.1:9000:8080"
volumes: volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./privacy-policy.html:/usr/share/nginx/html/privacy-policy.html:ro

View File

@@ -16,7 +16,7 @@ http {
server_name _; server_name _;
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' data:;"; add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' data:;";
add_header Permissions-Policy "geolocation=(), midi=(), camera=(), usb=(), payment=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), usb=(), interest-cohort=()"; add_header Permissions-Policy "geolocation=(self), midi=(), camera=(), usb=(), payment=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), usb=(), interest-cohort=()";
add_header Referer "no-referrer"; add_header Referer "no-referrer";
add_header Referrer-Policy "no-referrer"; add_header Referrer-Policy "no-referrer";
add_header Strict-Transport-Security "max-age=63072000" always; add_header Strict-Transport-Security "max-age=63072000" always;
@@ -26,10 +26,10 @@ http {
client_max_body_size 1; client_max_body_size 1;
access_log off;
error_log /dev/null emerg;
location /r/ { location /r/ {
# Do not log location data
access_log off;
error_log /dev/null emerg;
proxy_pass http://backend:9000/r/; proxy_pass http://backend:9000/r/;
} }
@@ -41,11 +41,6 @@ http {
gzip_types *; gzip_types *;
expires 1d; expires 1d;
location = /privacy-policy.html {
root /usr/share/nginx/html;
try_files /privacy-policy.html =404;
}
location / { location / {
proxy_pass http://frontend:80/; proxy_pass http://frontend:80/;
} }

View File

@@ -1 +0,0 @@
<!-- Fill this privacy policy. -->

View File

@@ -6,7 +6,7 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"copy-dependencies": "rm -rf dist && rsync -av --exclude='*.handlebars' src/ dist/ && cp node_modules/handlebars/dist/handlebars.min.js dist/ && cp node_modules/bootstrap/dist/js/bootstrap.min.js dist && cp node_modules/bootstrap/dist/js/bootstrap.min.js.map dist && cp node_modules/bootstrap/dist/css/bootstrap.min.css dist && cp node_modules/bootstrap/dist/css/bootstrap.min.css.map dist", "copy-dependencies": "rm -rf dist && rsync -av --exclude='*.handlebars' src/ dist/ && cp node_modules/handlebars/dist/handlebars.min.js dist/ && cp node_modules/bootstrap/dist/js/bootstrap.min.js dist && cp node_modules/bootstrap/dist/js/bootstrap.min.js.map dist && cp node_modules/bootstrap/dist/css/bootstrap.min.css dist && cp node_modules/bootstrap/dist/css/bootstrap.min.css.map dist",
"compile": "handlebars src/table.handlebars -f dist/table.handlebars.compiled.js", "compile": "handlebars src/table.handlebars -f dist/table.handlebars.dist.js",
"dev": "npm run copy-dependencies && npm run compile && cd dist && python3 -m http.server 8080" "dev": "npm run copy-dependencies && npm run compile && cd dist && python3 -m http.server 8080"
}, },
"keywords": [ "keywords": [

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="de">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
@@ -13,90 +13,81 @@
</head> </head>
<body> <body>
<nav class="navbar navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="#">
above_me
</a>
<div class="links">
<a href="privacy-policy.html">
Privacy policy
</a>
</div>
</div>
</nav>
<div class="container"> <div class="container">
<h3>See what's flying right above you!</h1> <div class="intro">
<div>
<p>
Klicke auf <i>Was fliegt über mir?</i> oder gebe hier spezifische Koordinaten und einen Suchradius
ein, um zu sehen, was in deiner Nähe gerade fliegt.
</p>
<p>
Die Daten dieser Webseite basieren auf den Services des
<a href="http://wiki.glidernet.org/" target="_blank">Open Glider Network</a>.
(Vielen Dank für eure offenen APIs! 😊)
</p>
</div>
<div class="button-container"> <div class="button-container">
<button type="button" class="btn btn-primary btn-lg" onclick="onClickWhatsAboveMe()" <button type="button" class="btn btn-primary btn-lg" onclick="onClickWhatsAboveMe()"
aria-describedby="whats-above-me-hint">What's above aria-describedby="whats-above-me-hint">Was fliegt über mir?</button>
me?</button>
<div id="whats-above-me-hint" class="form-text"> <div id="whats-above-me-hint" class="form-text">
By clicking this button you accept our <a href="privacy-policy.html">privacy policy</a> and also Mit Klick auf den Button wird deine aktuelle Position vom Browser übermittelt und es werden die
that Flugzeuge
your current position is sent to the webserver. in deiner Nähe abgefragt. Weder deine Position noch die Anfrage an den Server werden dabei geloggt
oder gespeichert.
</div> </div>
</div> </div>
<div class="alert alert-danger status-message" role="alert" id="no-position-available"> <div class="alert alert-danger status-message" role="alert" id="no-position-available">
Error. Position for your device could not be loaded. Please check if you gave permission to this site to Es ist ein Fehler aufgetreten: Dein Browser erlaubt der Webseite nicht, den Standort zu ermitteln.<br>
access your position. Prüfe die Webseitenberechtigungen und versuche es dann erneut.
</div> </div>
<div class="alert alert-danger status-message" role="alert" id="http-error"> <div class="alert alert-danger status-message" role="alert" id="http-error">
Error. Could not fetch data. Open the developer console for more information. Es ist ein Fehler aufgetreten: Die Daten konnten nicht geladen werden.<br>
(Öffne die Entwicklungskonsole für weitere Informationen.)
</div> </div>
<div class="alert alert-info status-message" role="alert" id="loading-position"> <div class="alert alert-info status-message" role="alert" id="loading-position">
Loading position... Position wird vom Browser angefragt…
</div> </div>
<div id="table-container" class="overflow-auto"></div> </div>
<div id="table-container" class="overflow-auto"></div>
<p> <form>
Either click <i>What's above me?</i> to automatically fetch your location <div class="mb-3">
or enter specific coordinates and range and see whats flying above you right now. <label for="latitude" class="form-label">Breitengrad (Latitude)</label>
</p> <input class="form-control" type="number" name="latitude" id="latitude" placeholder="48.858222"
<p> min="-90" max="90" step=".000000001">
This site works with data provided by the </div>
<a href="http://wiki.glidernet.org/" target="_blank">Open Glider Network</a>. <div class="mb-3">
(Thank you for your open data & APIs! 😊) <label for="longitude" class="form-label">Längengrad (Longitude)</label>
</p> <input class="form-control" type="number" name="longitude" id="longitude" placeholder="2.2945"
min="-180" max="180" step=".000000001">
<form> </div>
<div class="mb-3"> <div class="mb-3">
<label for="latitude" class="form-label">Latitude</label> <label for="range" class="form-label">Range</label>
<input class="form-control" type="number" name="latitude" id="latitude" placeholder="48.858222" <input class="form-control" type="number" name="range" id="range" min="1" max="20" value="20"
min="-90" max="90" step=".000000001"> placeholder="1 - 20 km" aria-describedby="range-help" step="1">
<div id="range-help" class="form-text">
Suchradius (in <i>km</i>) um die angegebenen Koordinaten.
</div> </div>
<div class="mb-3"> </div>
<label for="longitude" class="form-label">Longitude</label> <div class="mb-3 button-container">
<input class="form-control" type="number" name="longitude" id="longitude" placeholder="2.2945" <button type="submit" class="btn btn-primary" aria-describedby="submit-hint">Was fliegt hier?</button>
min="-180" max="180" step=".000000001"> <div id="submit-hint" class="form-text">
Mit Klick auf <i>Was fliegt hier?</i> werden die Flugzeuge für die angegebenen Koordinaten
abgefragt.
Weder die Koordinaten noch die Anfrage an den Server werden dabei geloggt oder gespeichert.
</div> </div>
<div class="mb-3"> </div>
<label for="range" class="form-label">Range</label> </form>
<input class="form-control" type="number" name="range" id="range" min="1" max="20" value="20"
placeholder="1 - 20 km" aria-describedby="range-help" step="1">
<div id="range-help" class="form-text">
Range (in <i>km</i>) around given coordinates that should be filtered for.
</div>
</div>
<div class="mb-3 button-container">
<button type="submit" class="btn btn-primary" aria-describedby="submit-hint">Submit</button>
<div id="submit-hint" class="form-text">
By clicking this button you accept our <a href="privacy-policy.html">privacy policy</a> and also
that the given position is sent to the webserver.
</div>
</div>
</form>
</div> </div>
<script src="bootstrap.min.js"></script> <script src="bootstrap.min.js"></script>
<script src="handlebars.min.js"></script> <script src="handlebars.min.js"></script>
<script src="table.handlebars.compiled.js"></script> <script src="table.handlebars.dist.js"></script>
<script src="main.js"></script> <script src="main.js"></script>
</body> </body>

View File

@@ -1 +0,0 @@
<!-- Fill this privacy policy. -->

View File

@@ -1,5 +1,26 @@
nav { html, body {
margin-bottom: 3%; width: 100%;
height: 100%;
}
.container {
display: grid;
height: 100%;
width: 100%;
grid-template-columns: 100%;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"intro"
"table"
"form";
padding-top: 5%;
}
.intro {
grid-area: intro;
} }
.button-container { .button-container {
@@ -10,6 +31,7 @@ nav {
} }
form { form {
grid-area: form;
margin-top: 12.5%; margin-top: 12.5%;
} }
@@ -32,7 +54,7 @@ form .button-container {
} }
#table-container { #table-container {
margin: 5% 0; grid-area: table;
white-space: nowrap; white-space: nowrap;
} }