From 7f6d0425d5e976a07552b3492db6de2ffd4fdbbf Mon Sep 17 00:00:00 2001 From: Florian Zumpe Date: Sun, 27 Sep 2026 21:50:52 +0200 Subject: [PATCH] image handling update for route creation --- examples/presentation-route.json | 4 +- public/css/bootstrap.css | 20 +- public/css/editor.css | 81 +++++--- public/images/icons/route-management.svg | 6 +- public/index.html | 53 ++--- public/js/app.js | 26 +-- public/js/bootstrap-loader.js | 21 ++ public/js/editor-ui.js | 230 +++++++++++++++------ public/js/local-routes.js | 245 ++++++++++++++++++++--- public/js/slideshow.js | 2 +- scripts/upload-presentation-route.sh | 2 +- test/bootstrap-start-ui.test.js | 15 ++ test/editor-ui.test.js | 103 ++++++++-- test/local-routes.test.js | 196 +++++++++++++++++- test/presentation-route.test.js | 2 +- test/route-selection-ui.test.js | 7 +- 16 files changed, 831 insertions(+), 182 deletions(-) diff --git a/examples/presentation-route.json b/examples/presentation-route.json index 4f44e92..71de53c 100644 --- a/examples/presentation-route.json +++ b/examples/presentation-route.json @@ -12,7 +12,7 @@ }, { "title": "Wiesenblick", - "description": "Ein Beispiel-Trackpunkt für Texte, Bilder und Audio.", + "description": "Ein Beispiel-Streckenpunkt für Texte, Bilder und Audio.", "lat": 50.58109, "lon": 10.43384, "triggerRadiusM": 25, @@ -20,7 +20,7 @@ }, { "title": "Waldrand", - "description": "Zweiter Beispiel-Trackpunkt der Demo-Strecke.", + "description": "Zweiter Beispiel-Streckenpunkt der Demo-Strecke.", "lat": 50.58082, "lon": 10.43546, "triggerRadiusM": 25, diff --git a/public/css/bootstrap.css b/public/css/bootstrap.css index 0f54449..2aa9920 100644 --- a/public/css/bootstrap.css +++ b/public/css/bootstrap.css @@ -236,7 +236,25 @@ line-height: 1.2; } -#bootstrap-screen .privacy-summary { +#bootstrap-screen +.android-browser-hint { + margin: .8rem 0 0; + padding: .75rem .9rem; + border: 1px solid #cbdccf; + border-radius: .85rem; + background: #eef7f1; + color: #24462b; + font-size: .9rem; + line-height: 1.35; +} + +.android-browser-hint[data-browser="other"] { + border-color: #e3c98c; + background: #fff8e8; + color: #694d14; +} + +.privacy-summary { display: grid; gap: .65rem; margin: .85rem 0 0; diff --git a/public/css/editor.css b/public/css/editor.css index cc16491..2cccfc9 100644 --- a/public/css/editor.css +++ b/public/css/editor.css @@ -3,31 +3,30 @@ top: calc(env(safe-area-inset-top) + .45rem); right: calc(max(.65rem, env(safe-area-inset-right)) + var(--icon-button-size) + .5rem); z-index: 10000; + display: flex; + align-items: flex-start; + gap: .4rem; } -.route-control-button, -.route-control-button.ui-button { +.route-control-summary { display: grid; - width: min(13rem, calc(100vw - var(--icon-button-size) - 5.2rem)); - min-width: 0; + width: min(13rem, calc(100vw - (var(--icon-button-size) * 2) - 6rem)); min-height: var(--icon-button-size); box-sizing: border-box; + align-content: center; gap: .08rem; - margin: 0; padding: .35rem .75rem; overflow: hidden; - border: 2px solid rgba(255, 255, 255, .9); - border-radius: 999px; - background: #24462b; + border: 1px solid rgba(255, 255, 255, .72); + border-radius: .9rem; + background: rgba(36, 70, 43, .94); color: #fff; - box-shadow: 0 .15rem .55rem rgba(0, 0, 0, .28); - text-align: left; - cursor: pointer; - touch-action: manipulation; + box-shadow: 0 .15rem .55rem rgba(0, 0, 0, .22); + pointer-events: none; } -.route-control-button strong, -.route-control-button small { +.route-control-summary strong, +.route-control-summary small { display: block; min-width: 0; overflow: hidden; @@ -35,17 +34,44 @@ white-space: nowrap; } -.route-control-button strong { +.route-control-summary strong { font-size: .9rem; line-height: 1.1; } -.route-control-button small { +.route-control-summary small { color: rgba(255, 255, 255, .86); font-size: .68rem; line-height: 1.1; } +.route-control-button, +.route-control-button.ui-button { + display: grid; + place-items: center; + width: var(--icon-button-size); + min-width: var(--icon-button-size); + height: var(--icon-button-size); + min-height: var(--icon-button-size); + box-sizing: border-box; + margin: 0; + padding: .45rem; + overflow: hidden; + border: 2px solid rgba(255, 255, 255, .9); + border-radius: 50%; + background: #24462b; + color: #fff; + box-shadow: 0 .15rem .55rem rgba(0, 0, 0, .28); + cursor: pointer; + touch-action: manipulation; +} + +.route-control-button img { + display: block; + width: 100%; + height: 100%; +} + .route-control-button:focus-visible, .route-control-button.ui-button:focus-visible { outline: .2rem solid #fff; @@ -142,7 +168,7 @@ .route-control-actions { display: grid; - grid-template-columns: auto minmax(0, 1fr); + grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; margin-top: .85rem; padding-top: .75rem; @@ -172,14 +198,7 @@ display: inline-flex; justify-content: center; min-height: 2.75rem; - min-width: 2.75rem; - padding: .5rem; -} - -.editor-button img { - display: block; - height: 1.65rem; - width: 1.65rem; + padding: .55rem .85rem; } .editor-media-actions { @@ -511,6 +530,11 @@ resize: vertical; } +.editor-gpx-group { + display: grid; + gap: .6rem; +} + .editor-secondary-button, .editor-icon-button { background: #fff; @@ -559,11 +583,8 @@ right: calc(max(.5rem, env(safe-area-inset-right)) + var(--icon-button-size) + .35rem); } - .route-control-button, - .route-control-button.ui-button { - width: min(10.5rem, calc(100vw - var(--icon-button-size) - 4.7rem)); - padding-right: .55rem; - padding-left: .55rem; + .route-control-summary { + width: min(10.5rem, calc(100vw - (var(--icon-button-size) * 2) - 5rem)); } .route-control-dropdown { diff --git a/public/images/icons/route-management.svg b/public/images/icons/route-management.svg index 6f4e871..eec053a 100644 --- a/public/images/icons/route-management.svg +++ b/public/images/icons/route-management.svg @@ -1,5 +1,5 @@ - - - + + + diff --git a/public/index.html b/public/index.html index 7efda82..2932be0 100644 --- a/public/index.html +++ b/public/index.html @@ -91,6 +91,8 @@ + +

Cookies: Diese Anwendung setzt derzeit keine Cookies und verwendet weder Werbung noch Tracking.

- @@ -198,7 +201,7 @@
Länge
–
Höhenmeter
–
-
POIs
–
+
Streckenpunkte
–
Routensteuerung @@ -213,7 +216,7 @@
-

Stationen

+

Streckenpunkte

    @@ -222,7 +225,7 @@ -

    Station

    +

    Streckenpunkt

    @@ -244,7 +247,7 @@

    - +
    @@ -252,7 +255,7 @@

    - Richtung zum nächsten POI + Richtung zum nächsten Streckenpunkt –

    @@ -291,7 +294,7 @@

    3. Standortdaten

    Die Standortfreigabe ist freiwillig. Sie wird benötigt, um nahe Routen vorzuschlagen und während einer gestarteten Route Entfernungen und Richtungen zu berechnen. Die Anwendung verarbeitet die laufende Position im Browser. Sie legt daraus keinen serverseitigen Standortverlauf an.

    4. Lokaler Streckenfortschritt

    -

    Nach ausdrücklicher Aktivierung speichert die Anwendung ein JSON-Objekt im Local Storage dieses Browsers. Es enthält die aktuell ausgewählte Strecke, besuchte und angesehene Stationen, abgespielte Audioeinträge, den Routenstatus sowie Zeitstempel. Diese Angaben bleiben auf dem verwendeten Gerät und werden nicht mit dem Server synchronisiert.

    +

    Nach ausdrücklicher Aktivierung speichert die Anwendung ein JSON-Objekt im Local Storage dieses Browsers. Es enthält die aktuell ausgewählte Strecke, besuchte und angesehene Streckenpunkte, abgespielte Audioeinträge, den Routenstatus sowie Zeitstempel. Diese Angaben bleiben auf dem verwendeten Gerät und werden nicht mit dem Server synchronisiert.

    Gespeicherte Streckendaten werden beim nächsten Öffnen entfernt, sobald ihre letzte Aktualisierung mindestens 24 Stunden zurückliegt. Beim Ausschalten der Funktion werden die Streckendaten sofort gelöscht.

    5. Lokale Streckenentwürfe

    -

    Neu angelegte Strecken werden zunächst ausschließlich im Local Storage dieses Browsers gespeichert. Die GPX-Daten enthalten den Streckenverlauf und die POI-Koordinaten. Ergänzende JSON-Daten ordnen den POIs Texte, Audiodateien und Bilder zu. Medien werden dafür als lokale Browserdaten gespeichert.

    +

    Neu angelegte Strecken werden zunächst ausschließlich im Local Storage dieses Browsers gespeichert. Die GPX-Daten enthalten den Streckenverlauf und die Koordinaten der Streckenpunkte. Ergänzende JSON-Daten ordnen den Streckenpunkten Texte und Medienreferenzen zu. Bilder und Audiodateien werden platzsparend im lokalen Browser-Medienspeicher gespeichert.

    Lokale Streckenentwürfe sind bewusst von der freiwilligen Fortschrittsspeicherung getrennt. Sie werden nicht durch die 24-Stunden-Bereinigung entfernt und beim Ausschalten der Fortschrittsspeicherung nicht gelöscht. Sie verbleiben im Browser, bis sie ausdrücklich gelöscht werden oder die Browserdaten entfernt werden. Eine Übertragung an den Server erfolgt nur nach ausdrücklicher Betätigung des Upload-Buttons im Editor.

    6. Cookies und Tracking

    Die Anwendung setzt derzeit keine Cookies. Sie verwendet keine Reichweitenmessung, keine personalisierte Werbung und keine Trackingdienste. Eine technisch notwendige Local-Storage-Einstellung merkt sich lediglich, ob die freiwillige Speicherung des Streckenfortschritts aktiviert wurde.

    @@ -366,7 +369,7 @@

    Local Storage

    Der Browser kann auf Wunsch Streckenfortschritte lokal speichern. Verwendet werden die Schlüssel wegwichtel.privacy.v1 für die gewählte Einstellung und wegwichtel.route-progress.v1 für die freiwilligen Streckendaten. Die Streckendaten werden nach 24 Stunden bereinigt oder beim Ausschalten sofort entfernt.

    -

    Lokale Streckenentwürfe werden getrennt davon unter wegwichtel.local-routes.v1.* gespeichert. Pro Entwurf werden GPX- und JSON-Daten vorgehalten; Bilder und Audiodateien liegen als Bestandteil der lokalen JSON-Daten im Browser. Diese Entwürfe werden nicht nach 24 Stunden bereinigt und sind nicht vom Schalter für den Streckenfortschritt abhängig. Durch Mediendateien kann das Speicherlimit des Browsers vergleichsweise schnell erreicht werden. Eine Serverübertragung erfolgt ausschließlich nach ausdrücklicher Betätigung des Upload-Buttons im Editor.

    +

    Lokale Streckenentwürfe werden getrennt davon unter wegwichtel.local-routes.v1.* gespeichert. Pro Entwurf werden GPX- und JSON-Daten im Local Storage vorgehalten; Bilder und Audiodateien liegen getrennt davon im lokalen Browser-Medienspeicher (IndexedDB). Diese Entwürfe werden nicht nach 24 Stunden bereinigt und sind nicht vom Schalter für den Streckenfortschritt abhängig. Durch Mediendateien kann das Speicherlimit des Browsers vergleichsweise schnell erreicht werden. Eine Serverübertragung erfolgt ausschließlich nach ausdrücklicher Betätigung des Upload-Buttons im Editor.