Initial UI outline

This commit is contained in:
30hours 2024-02-01 14:50:24 +00:00
parent 0b7f5aa839
commit e3b7d91312
9 changed files with 218 additions and 0 deletions

16
Dockerfile Normal file
View file

@ -0,0 +1,16 @@
FROM python:3.9-slim
WORKDIR /app
COPY src /app
# install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# make port 5000 available to the world outside this container
EXPOSE 5000
# define environment variable
ENV FLASK_APP=main.py
# run Gunicorn instead of the default Flask development server
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "main:app"]

12
docker-compose.yml Normal file
View file

@ -0,0 +1,12 @@
version: '3'
services:
3lips:
restart: always
build: .
image: 3lips
ports:
- 49156:5000
network_mode: bridge
container_name: 3lips

43
src/main.py Normal file
View file

@ -0,0 +1,43 @@
# main.py
from flask import Flask, render_template, request, jsonify, send_from_directory
import os
app = Flask(__name__)
# store state data
servers = [
{"name": "radar4", "url": "radar4.30hours.dev"},
{"name": "radar5", "url": "radar5.30hours.dev"}
]
associators = [
{"name": "ADSB Associator", "id": "adsb-associator"}
]
coordregs = [
{"name": "Ellipse 2D Conic Intersection", "id": "ellipse-2d-conic-int"}
]
@app.route("/")
def index():
return render_template("index.html", servers=servers, \
associators=associators, coordregs=coordregs)
# serve static files from the /app/public folder
@app.route('/public/<path:file>')
def serve_static(file):
base_dir = os.path.abspath(os.path.dirname(__file__))
public_folder = os.path.join(base_dir, 'public')
return send_from_directory(public_folder, file)
@app.route("/api")
def api():
urls = request.args.getlist("url")
data = [{"url": url} for url in urls]
return jsonify(data)
@app.route("/map")
def map_page():
return render_template("map.html")
if __name__ == "__main__":
app.run(debug=True)

19
src/public/js/index.js Normal file
View file

@ -0,0 +1,19 @@
function toggle_button(button) {
button.classList.toggle('active');
var pressed = button.getAttribute('aria-pressed') === 'false' ? 'true' : 'false';
button.setAttribute('aria-pressed', pressed);
// fix button states
if (pressed === 'true') {
button.classList.add("btn-success");
button.classList.remove("btn-secondary");
} else {
button.classList.add("btn-secondary");
button.classList.remove("btn-success");
}
// Set the value to server.url when the button is pressed
var serverUrl = button.getAttribute('server-url');
button.value = pressed === 'true' ? serverUrl : '';
console.log(button.value);
}

File diff suppressed because one or more lines are too long

6
src/public/lib/bootstrap-5.2.3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
src/requirements.txt Normal file
View file

@ -0,0 +1,2 @@
Flask==3.0.1
gunicorn==21.2.0

99
src/templates/index.html Normal file
View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3lips</title>
<!-- load lib js -->
<script src="./public/lib/bootstrap-5.2.3.min.js"></script>
<!-- load lib css -->
<link rel="stylesheet" href="./public/lib/bootstrap-5.2.3.min.css">
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
input, select {
margin-bottom: 10px;
}
.custom-location-fields {
display: none;
}
.calculator-form {
max-width: 600px;
margin: 0 auto;
}
body .jumbotron h1 {
font-family: 'Helvetica', sans-serif !important;
font-weight: bold;
font-size: 3.5rem !important;
}
@media (min-width: 768px) {
body .jumbotron h1 {
font-family: 'Helvetica', sans-serif !important;
font-weight: bold;
font-size: 5rem !important;
}
}
</style>
</head>
<body style="background-color:#f78c58;">
<div class="container-md">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="jumbotron">
<h1 class="display-4 text-center">3lips</h1>
<p class="lead">Coordinate registration for multi-static radar using ellipse intersections. Requires input of <a href="https://github.com/30hours/blah2" target="_blank">blah2</a> servers, and choice of algorithm for association and coordinate registration. This program exposes an API endpoint to generate geographic coordinates and a <a href="https://github.com/CesiumGS/cesium" target="_blank">Cesium</a> map for display.</p>
<p class="lead">See <a href="https://github.com/30hours/3lips" target="_blank">github.com/30hours/3lips</a> for more details.</p>
</div>
<div class="calculator-form">
<form action="/api" method="get">
<div class="mb-3">
<label class="form-label fw-bold">Servers:</label>
{% for server in servers %}
<button type="button" class="btn btn-success toggle-button active w-100 mb-1" data-toggle="button" aria-pressed="true" server-url="{{ server.url }}" onclick="toggle_button(this)">{{ server.name }}</button>
<input type="hidden" name="url" value="{{ server.url }}">
{% endfor %}
</div>
<div class="mb-3">
<label class="form-label fw-bold">Associator:</label>
<select class="form-select" name="associator">
{% for associator in associators %}
<option value="{{ associator.id }}">{{ associator.name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label fw-bold">Coordinate Registration:</label>
<select class="form-select" name="associator">
{% for coordreg in coordregs %}
<option value="{{ coordreg.id }}">{{ coordreg.name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-1">
<label class="form-label fw-bold">Run:</label>
<button type="submit" class="btn btn-dark w-100">API</button>
</div>
</form>
</div>
<div class="mb-3">
<button class="btn btn-dark w-100">Map</button>
</div>
</div>
</div>
</div>
<script src="/public/js/index.js"></script>
</body>
</html>

15
src/templates/map.html Normal file
View file

@ -0,0 +1,15 @@
<!-- templates/map.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Map Page</title>
</head>
<body>
<h1>Map Page</h1>
<!-- Your map-related content goes here -->
</body>
</html>