diff --git a/database/migrations/20260901_add_route_activated_at.sql b/database/migrations/20260901_add_route_activated_at.sql new file mode 100644 index 0000000..1f5bde6 --- /dev/null +++ b/database/migrations/20260901_add_route_activated_at.sql @@ -0,0 +1,4 @@ +-- Wegwichtel editor support: route activation timestamp. +-- New routes remain unpublished while activated_at is NULL. +-- Run once against the SQLite database if the routes table does not already contain this column. +ALTER TABLE routes ADD COLUMN activated_at DATETIME NULL; diff --git a/docs/editor-merge-notes.md b/docs/editor-merge-notes.md new file mode 100644 index 0000000..b4ffb50 --- /dev/null +++ b/docs/editor-merge-notes.md @@ -0,0 +1,44 @@ +# Wegwichtel Streckeneditor - erste einfache Fassung + +Dieses Paket ergänzt die Oberfläche um einen einfachen Streckeneditor auf der Streckenauswahl. + +## Enthaltene Dateien + +- `public/index.html` + - neuer Abschnitt `Strecken verwalten` mit rundem Plus-Button + - neues Dialogfenster `#editor-dialog` + - Einbindung von `css/editor.css` und `js/editor-ui.js` +- `public/css/editor.css` + - eigenständige Editor-Styles, damit `app.css` nicht erneut ersetzt werden muss +- `public/js/editor-ui.js` + - Editor-Dialog, Streckenliste, Streckendetailformular, POI-Formular + - POI-Sortierung per Pfeil nach oben/unten + - Upload einer Audiodatei und beliebig vieler Bilder pro POI +- `database/migrations/20260901_add_route_activated_at.sql` + - ergänzt `routes.activated_at DATETIME NULL` + +## Datenbank + +Neue Strecken bleiben fachlich Entwürfe, solange `routes.activated_at` NULL ist. +Die Aktivierung wird in dieser Fassung nicht durch die Programmlogik gesetzt. + +SQLite-Migration einmalig ausführen, falls die Spalte noch nicht existiert: + +```sh +sqlite3 < database/migrations/20260901_add_route_activated_at.sql +``` + +## Erwartete API-Endpunkte + +Der Editor nutzt die vorhandene REST-Struktur der Anwendung: + +- `GET /api/routes` +- `GET /api/routes/:routeId` +- `POST /api/routes` +- `PUT /api/routes/:routeId` +- `POST /api/routes/:routeId/pois` +- `PUT /api/routes/:routeId/pois/:poiId` +- `POST /api/routes/:routeId/pois/:poiId/audio` +- `POST /api/routes/:routeId/pois/:poiId/images` + +Schreibende Zugriffe bleiben damit an die bestehende serverseitige Absicherung gebunden. diff --git a/public/css/editor.css b/public/css/editor.css new file mode 100644 index 0000000..9307cbc --- /dev/null +++ b/public/css/editor.css @@ -0,0 +1,229 @@ +.editor-entry-panel { + align-items: center; + background: rgba(255, 255, 255, .92); + border: 1px solid rgba(49, 93, 58, .22); + border-radius: 1.2rem; + box-shadow: 0 .5rem 1.4rem rgba(20, 40, 24, .08); + display: flex; + gap: 1rem; + justify-content: space-between; + margin-top: 1.4rem; + padding: 1rem; +} + +.editor-entry-panel h2, +.editor-entry-panel p { + margin: 0; +} + +.editor-entry-panel p { + color: #4e604f; + margin-top: .25rem; +} + +.editor-button, +.editor-round-button { + align-items: center; + background: #315d3a; + border: 0; + border-radius: 999px; + color: #fff; + display: inline-flex; + font-size: 1.8rem; + font-weight: 700; + height: 3rem; + justify-content: center; + line-height: 1; + min-width: 3rem; + padding: 0; +} + +.editor-button:focus-visible, +.editor-round-button:focus-visible, +.editor-primary-button:focus-visible, +.editor-secondary-button:focus-visible, +.editor-icon-button:focus-visible { + outline: .2rem solid #f2ca6b; + outline-offset: .15rem; +} + +.editor-dialog { + border: 0; + border-radius: 1.2rem; + box-shadow: 0 1.4rem 3rem rgba(20, 32, 22, .28); + max-height: min(90vh, 55rem); + max-width: min(92vw, 48rem); + padding: 0; + width: 48rem; +} + +.editor-dialog::backdrop { + background: rgba(21, 36, 24, .42); +} + +.editor-dialog-shell { + background: #f8f5eb; + color: #233326; + display: flex; + flex-direction: column; + gap: 1rem; + max-height: min(90vh, 55rem); + overflow-y: auto; + padding: 1rem; +} + +.editor-dialog-header, +.editor-toolbar { + align-items: center; + display: flex; + gap: .75rem; + justify-content: space-between; +} + +.editor-dialog-header h2, +.editor-toolbar h3 { + margin: 0; +} + +.editor-dialog-header h2, +.editor-toolbar-back h3 { + flex: 1 1 auto; + min-width: 0; +} + +#editor-close { + align-items: center; + background: #fff; + border: 1px solid rgba(49, 93, 58, .28); + border-radius: 999px; + color: #233326; + display: inline-flex; + font-size: 1.5rem; + height: 2.4rem; + justify-content: center; + margin-left: auto; + width: 2.4rem; +} + +.editor-status { + background: #fff8d7; + border: 1px solid rgba(125, 92, 21, .25); + border-radius: .8rem; + margin: 0; + padding: .7rem .85rem; +} + +.editor-view[hidden], +.editor-status[hidden] { + display: none; +} + +.editor-route-list, +.editor-poi-list { + display: flex; + flex-direction: column; + gap: .65rem; + list-style: none; + margin: 0; + padding: 0; +} + +.editor-poi-list { + counter-reset: editor-poi; +} + +.editor-route-item, +.editor-poi-item { + align-items: center; + background: #fff; + border: 1px solid rgba(49, 93, 58, .18); + border-radius: .9rem; + display: flex; + gap: .75rem; + justify-content: space-between; + padding: .75rem; +} + +.editor-route-item strong, +.editor-poi-item strong { + display: block; +} + +.editor-route-item small, +.editor-poi-item small, +.editor-muted { + color: #607160; +} + +.editor-form { + background: #fff; + border: 1px solid rgba(49, 93, 58, .18); + border-radius: .9rem; + display: flex; + flex-direction: column; + gap: .6rem; + padding: .9rem; +} + +.editor-form input, +.editor-form textarea { + border: 1px solid rgba(49, 93, 58, .35); + border-radius: .65rem; + font: inherit; + padding: .65rem .75rem; +} + +.editor-form textarea { + resize: vertical; +} + +.editor-coordinate-grid { + display: grid; + gap: .55rem; + grid-template-columns: minmax(0, 1fr); +} + +.editor-primary-button, +.editor-secondary-button, +.editor-icon-button { + border-radius: .75rem; + font: inherit; + min-height: 2.4rem; + padding: .55rem .85rem; +} + +.editor-primary-button { + background: #315d3a; + border: 1px solid #315d3a; + color: #fff; +} + +.editor-secondary-button, +.editor-icon-button { + background: #fff; + border: 1px solid rgba(49, 93, 58, .32); + color: #233326; +} + +.editor-icon-row { + display: flex; + flex: 0 0 auto; + gap: .35rem; +} + +.editor-icon-button { + align-items: center; + display: inline-flex; + justify-content: center; + min-width: 2.4rem; +} + +.editor-poi-toolbar { + margin-top: .5rem; +} + +@media (min-width: 42rem) { + .editor-coordinate-grid { + grid-template-columns: max-content minmax(0, 1fr); + } +} diff --git a/public/index.html b/public/index.html index 585b791..6907cc0 100644 --- a/public/index.html +++ b/public/index.html @@ -8,6 +8,7 @@ +
@@ -95,6 +96,16 @@
  • Routen werden geladen …

  • + +
    +
    +

    Strecken verwalten

    +

    Strecken, Stationen, Bilder und Audiodateien bearbeiten.

    +
    + +