Initial Commit
This commit is contained in:
commit
b499bd0890
9 changed files with 347 additions and 0 deletions
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
8
.idea/CheitMaps.iml
generated
Normal file
8
.idea/CheitMaps.iml
generated
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.11" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/CheitMaps.iml" filepath="$PROJECT_DIR$/.idea/CheitMaps.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
198
main.py
Normal file
198
main.py
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# backend/main.py
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
|
from fastapi.responses import HTMLResponse
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
from fastapi.templating import Jinja2Templates
|
||||||
|
import uvicorn
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
# Mount static folder to serve images, PDFs, JS if needed
|
||||||
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||||
|
|
||||||
|
# Set up template rendering
|
||||||
|
templates = Jinja2Templates(directory="templates")
|
||||||
|
|
||||||
|
# Sample map data
|
||||||
|
|
||||||
|
MapsFolder = Path('./static/maps')
|
||||||
|
|
||||||
|
maps = [
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "DaisyRevedins",
|
||||||
|
"latitude": 44.480829598869185,
|
||||||
|
"longitude": 11.352026314262476,
|
||||||
|
'stem': 'San Mamolo-JoNotte',
|
||||||
|
"description": "From the grass to the church while visiting the Hospital"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "CastelWeak",
|
||||||
|
"latitude": 44.49959787027563,
|
||||||
|
"longitude": 11.27473782212433,
|
||||||
|
'stem': 'Casteldebole_2024_05_15',
|
||||||
|
"description": "Totally Flat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "Golinelli",
|
||||||
|
"latitude": 44.50847170695366,
|
||||||
|
"longitude": 11.308195638402232,
|
||||||
|
"stem": "Norwegian Sprint",
|
||||||
|
"description": "Jo Noche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "SwordVille",
|
||||||
|
"latitude": 44.49119622583157,
|
||||||
|
"longitude": 11.308122673834362,
|
||||||
|
"stem": "A3-Pellegrino",
|
||||||
|
"description": "San Pellegrino night"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "Small Heaven",
|
||||||
|
"latitude": 44.375066657656234,
|
||||||
|
"longitude": 11.247854195489277,
|
||||||
|
"stem": "Piccolo Paradiso_small",
|
||||||
|
"description": "Fucked Dogs & Owners"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"name": "Marzab8",
|
||||||
|
"latitude": 44.340876557519195,
|
||||||
|
"longitude": 11.208385117204514,
|
||||||
|
"stem": "Marzabotto-O-Training",
|
||||||
|
"description": "Marzabotto Greto Fiume"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"name": "Bazzano",
|
||||||
|
"latitude": 44.506688577284855,
|
||||||
|
"longitude": 11.084856756615434,
|
||||||
|
'stem': 'Pro Mel',
|
||||||
|
"description": "Bazzano Pro Mel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"name": "Battindarno",
|
||||||
|
'coord': (44.495505920730935, 11.288849376526782),
|
||||||
|
'stem': 'JoNotte.2022.1',
|
||||||
|
"description": "Battindarno 2022-1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"name": "Daisy Gardens",
|
||||||
|
"latitude": 44.480829598869185,
|
||||||
|
"longitude": 11.3525,
|
||||||
|
'stem': 'Revedinmargherita',
|
||||||
|
"description": "Giardini e Revedin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"name": "Pontecchio",
|
||||||
|
"coord": (44.431200464913914, 11.269902531675038),
|
||||||
|
'stem': 'Pontecchio_night bo 2020',
|
||||||
|
"description": "Occhio al custode di villa Grifone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"name": "Sasso Marconi",
|
||||||
|
"coord": (44.398978299870166, 11.25642430653767),
|
||||||
|
'stem': 'night_bo_13_02_20',
|
||||||
|
"description": "Cà de Testi e Sasso"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"name": "Croce e Funivia",
|
||||||
|
"coord": (44.48620778951313, 11.283029683468458),
|
||||||
|
'stem': '1802',
|
||||||
|
"description": "Da Casalatch alla Funivia"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"name": "CastelWeakRiverBank",
|
||||||
|
"coord": (44.50400435370321, 11.283098136577783),
|
||||||
|
'stem': '11 febbraio',
|
||||||
|
"description": "Casteldebole e lungo fiume"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 14,
|
||||||
|
"name": "ZanardiPark",
|
||||||
|
"coord": (44.48890188652948, 11.28842972160338),
|
||||||
|
'stem': 'ParcoZanardi',
|
||||||
|
"description": "Parco Zanardi, Casalatch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 15,
|
||||||
|
"name": "The Monster",
|
||||||
|
"coord": (44.47603075768931, 11.262382357503611),
|
||||||
|
'stem': 'EremoELITE',
|
||||||
|
"description": "Eremo di Tizzano / Mostro"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 16,
|
||||||
|
"name": "Villa Angeletti",
|
||||||
|
"coord": (44.510693796692124, 11.333109723632031),
|
||||||
|
'stem': 'Night BO Villa Angeletti-Night 1',
|
||||||
|
"description": "Villa Angeletti 2020"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 17,
|
||||||
|
"name": "Navile",
|
||||||
|
"coord": (44.536246247660856, 11.354504683188482),
|
||||||
|
'stem': 'NightBO_Navile_20022020',
|
||||||
|
"description": "Navile, Nightbo 2020"
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
for m in maps:
|
||||||
|
if 'stem' in m:
|
||||||
|
base = m['stem']
|
||||||
|
m['pdf'] = f'/static/maps/{base}.pdf'
|
||||||
|
for suffix in ('.jpg', '.png'):
|
||||||
|
fn = MapsFolder / f'{base}_small{suffix}'
|
||||||
|
if fn.is_file():
|
||||||
|
m['thumbnail'] = f'/static/maps/{fn.name}'
|
||||||
|
fn = MapsFolder / f'{base}_big{suffix}'
|
||||||
|
if fn.is_file():
|
||||||
|
m['full_size'] = f'/static/maps/{fn.name}'
|
||||||
|
|
||||||
|
if 'coord' in m:
|
||||||
|
lat, long = m.get('coord')
|
||||||
|
m['latitude'] = lat
|
||||||
|
m['longitude'] = long
|
||||||
|
|
||||||
|
|
||||||
|
# Serve the main map page
|
||||||
|
@app.get("/", response_class=HTMLResponse)
|
||||||
|
async def index(request: Request):
|
||||||
|
return templates.TemplateResponse("index.html", {"request": request})
|
||||||
|
|
||||||
|
|
||||||
|
# JSON endpoint to get map data
|
||||||
|
@app.get("/api/maps")
|
||||||
|
async def get_maps():
|
||||||
|
return maps
|
||||||
|
|
||||||
|
|
||||||
|
# Detailed map page
|
||||||
|
@app.get("/map/{map_id}", response_class=HTMLResponse)
|
||||||
|
async def map_detail(request: Request, map_id: int):
|
||||||
|
map_data = next((m for m in maps if m["id"] == map_id), None)
|
||||||
|
if not map_data:
|
||||||
|
return HTMLResponse(content="Map not found", status_code=404)
|
||||||
|
return templates.TemplateResponse("map_detail.html", {"request": request, "map": map_data})
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
uvicorn.run(app, host="127.0.0.1", port=8000)
|
82
templates/index.html
Normal file
82
templates/index.html
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<!-- backend/templates/index.html -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Orienteering Map Viewer</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
|
||||||
|
<style>
|
||||||
|
#map { height: 100vh; margin: 0; }
|
||||||
|
.popup-img { width: 250px; cursor: pointer; }
|
||||||
|
body, html {
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title-overlay {
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
z-index: 1000;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="map"></div>
|
||||||
|
<div id="title-overlay">Super Cheit Orienteering Maps<img src="/static/face.jog" style="width: 50px;" />
|
||||||
|
</div>
|
||||||
|
<div id="map"></div>
|
||||||
|
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
|
||||||
|
<script>
|
||||||
|
const map = L.map('map'); // Initialize without setting center and zoom yet
|
||||||
|
const flag = L.icon({ iconUrl: '/static/O_Flag_.svg', iconSize: [64, 80] , iconAnchor: [32, 79]})
|
||||||
|
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© OpenStreetMap contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
fetch("/api/maps")
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(maps => {
|
||||||
|
const bounds = [];
|
||||||
|
|
||||||
|
maps.forEach(m => {
|
||||||
|
const latlng = [m.latitude, m.longitude];
|
||||||
|
bounds.push(latlng);
|
||||||
|
|
||||||
|
const marker = L.marker(latlng, {icon: flag}).addTo(map);
|
||||||
|
const popup = `
|
||||||
|
<strong>${m.name}</strong><br>
|
||||||
|
${m.description}<br>
|
||||||
|
<img class="popup-img" src="${m.thumbnail}" onclick="window.location='/map/${m.id}'" />
|
||||||
|
`;
|
||||||
|
marker.bindPopup(popup);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bounds.length > 0) {
|
||||||
|
map.fitBounds(bounds, { padding: [50, 50] });
|
||||||
|
} else {
|
||||||
|
// Fallback if no maps
|
||||||
|
map.setView([45, 9], 5); // Default view
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
29
templates/map_detail.html
Normal file
29
templates/map_detail.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<!-- backend/templates/map_detail.html -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{ map.name }}</title>
|
||||||
|
<style>
|
||||||
|
body, html {
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{{ map.name }}</h1>
|
||||||
|
<p>{{ map.description }}</p>
|
||||||
|
<br>
|
||||||
|
<a href="{{ map.pdf }}" download>Download PDF</a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<a href="https://www.google.com/maps?q={{ map.latitude }},{{ map.longitude }} "target="_blank">Parking Lot coordinates</a>
|
||||||
|
<br><br>
|
||||||
|
<a href="/">← Back to Map</a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<img src="{{ map.full_size }}" style="width: 100vw;" />
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Reference in a new issue