From 4ef8ae37b0d64278e6a01c066362a814612694cb Mon Sep 17 00:00:00 2001 From: Arne Baeumler Date: Sun, 7 Jun 2026 12:26:16 +0200 Subject: [PATCH] feat: add map-based web interface --- README.md | 15 ++ package-lock.json | 50 ++++ src/server/request-handler.ts | 443 ++++++++++++++++++++++++++++++++-- 3 files changed, 491 insertions(+), 17 deletions(-) create mode 100644 package-lock.json diff --git a/README.md b/README.md index 8b47bca..0ab8616 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,14 @@ Web-App für Foto-Uploads, EXIF-Positionen und Kartenanzeige. +## Aktueller Prototyp + +- Startseite mit Kartenansicht auf OpenStreetMap +- Marker für Beispieldaten +- Hover-Popup mit Thumbnail +- Klick öffnet Vollbildansicht +- Upload-Bereich als Platzhalter für den nächsten Schritt + ## Zielbild - Fotos per Webinterface hochladen @@ -18,3 +26,10 @@ Web-App für Foto-Uploads, EXIF-Positionen und Kartenanzeige. - `src/domain/` fachliche Modelle - `src/features/` Anwendungslogik nach Bereichen +## Start + +```bash +npm install +npm run build +npm start +``` diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..375135d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,50 @@ +{ + "name": "mapy-mg", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mapy-mg", + "version": "0.1.0", + "devDependencies": { + "@types/node": "^22.0.0", + "typescript": "^5.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@types/node": { + "version": "22.19.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.20.tgz", + "integrity": "sha512-6tELRwSDYWW9EdZhbeZmYGZ1/7Djkt+Ah3/ScEYT9cDord7UJzasR/4D3VONg9tQI5CDp+/CZC1AXj2pCFOvpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/src/server/request-handler.ts b/src/server/request-handler.ts index b195b77..5300738 100644 --- a/src/server/request-handler.ts +++ b/src/server/request-handler.ts @@ -1,21 +1,430 @@ import type { IncomingMessage, ServerResponse } from "node:http"; -export function createRequestHandler() { - return async function handleRequest(_req: IncomingMessage, res: ServerResponse) { - res.statusCode = 200; - res.setHeader("content-type", "application/json; charset=utf-8"); - res.end( - JSON.stringify({ - name: "mapy-mg", - status: "ok", - features: [ - "photo upload", - "EXIF location extraction", - "map markers", - "route preview" - ] - }) - ); - }; +const demoPhotos = [ + { + id: "1", + name: "berlin-brandenburg-gate.jpg", + lat: 52.516275, + lon: 13.377704, + capturedAt: "2026-06-07T08:20:00Z", + thumb: + "https://images.unsplash.com/photo-1467269204594-9661b134dd2b?auto=format&fit=crop&w=200&q=60" + }, + { + id: "2", + name: "museum-island.jpg", + lat: 52.5169, + lon: 13.4015, + capturedAt: "2026-06-07T08:42:00Z", + thumb: + "https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?auto=format&fit=crop&w=200&q=60" + }, + { + id: "3", + name: "alexanderplatz.jpg", + lat: 52.521918, + lon: 13.413215, + capturedAt: "2026-06-07T09:05:00Z", + thumb: + "https://images.unsplash.com/photo-1494526585095-c41746248156?auto=format&fit=crop&w=200&q=60" + } +] as const; + +function htmlPage(): string { + const points = JSON.stringify(demoPhotos); + + return ` + + + + + mapy-mg + + + + +
+
+

mapy-mg

+

Fotos hochladen, Positionen sichtbar machen und Wege grob nachzeichnen.

+
+
OpenStreetMap + Leaflet · Prototyp
+
+ +
+ + +
+
Marker per Hover -> Thumbnail, Klick -> Vollbild
+
+
+
+ + + + + + +`; } +export function createRequestHandler() { + return async function handleRequest(req: IncomingMessage, res: ServerResponse) { + const url = new URL(req.url ?? "/", "http://localhost"); + + if (url.pathname === "/health") { + res.statusCode = 200; + res.setHeader("content-type", "application/json; charset=utf-8"); + res.end(JSON.stringify({ status: "ok" })); + return; + } + + res.statusCode = 200; + res.setHeader("content-type", "text/html; charset=utf-8"); + res.end(htmlPage()); + }; +}