Feature: Tagebuch Ort/POI, Foto/Video-Edit, Modal-UX, iOS-Fixes
Tagebuch — Ort/POI (DayOne-ähnlich):
- diary.location_name Spalte, DiaryCreate/Update mit gps_lat/lon/location_name
- GET /api/dogs/{id}/diary/nearby: Overpass + Nominatim (vor {entry_id}-Route)
- Mini-Karte im Edit-Formular: Leaflet lazy, Edit-Modus, SVG-Pin
- Meilenstein-Toggle: Button statt Checkbox, Filter in Toolbar
- Datenmigration: 97 Ort-Einträge aus text → location_name
Tagebuch — Foto/Video:
- Foto/Video im Edit: Ersetzen + Löschen, DELETE media endpoint
- Media-Picker: Kamera/Mediathek/Datei Buttons
- Video-Wiedergabe (<video controls> in Detail + Edit)
Modal-UX (alle Edit-Karten vereinheitlicht):
- Footer-Pattern: [Speichern vollbreit] / [Löschen][Abbrechen]
- diary, dog-profile, events, health, places, walks, settings, sitting
- Löschen aus Detail-Modal → Edit-Form verschoben
iOS Mobile-Fixes:
- Auto-Zoom: input/select/textarea font-size 16px !important
- Scroll-Through: html.modal-open + touch-action:none auf Overlay
- Kein position:fixed mehr auf body (kein Scroll-Sprung)
PWA & Icons:
- icon-512-any.png + icon-192-any.png (quadratisch, maskable)
- manifest.json: purpose any/maskable getrennt
- Gesundheits-Icon: syringe → first-aid
Import-Fix:
- _HTMLStripper überspringt video/audio/script → kein "Video nicht gefunden" mehr
This commit is contained in:
parent
88912e2746
commit
f8d354749d
19 changed files with 963 additions and 198 deletions
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '133'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '164'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
|
||||
const App = (() => {
|
||||
|
||||
|
|
@ -417,8 +417,13 @@ const App = (() => {
|
|||
}
|
||||
|
||||
_updateNotifBadge();
|
||||
// Badge alle 60s aktualisieren
|
||||
setInterval(_updateNotifBadge, 60_000);
|
||||
|
||||
const pendingInvite = sessionStorage.getItem('pending_invite');
|
||||
if (pendingInvite) {
|
||||
sessionStorage.removeItem('pending_invite');
|
||||
_handleInvite(pendingInvite);
|
||||
}
|
||||
}
|
||||
|
||||
async function _updateNotifBadge() {
|
||||
|
|
@ -670,15 +675,23 @@ const App = (() => {
|
|||
history.replaceState(null, '', '/');
|
||||
return;
|
||||
}
|
||||
const ok = await UI.modal.confirm(
|
||||
`<strong>${UI.escape(info.owner_name)}</strong> möchte das Profil von
|
||||
<strong>${UI.escape(info.dog_name)}</strong> mit dir teilen
|
||||
(${info.role === 'editor' ? 'Lesen & Schreiben' : 'Nur lesen'}).
|
||||
Möchtest du die Einladung annehmen?`
|
||||
);
|
||||
|
||||
if (!state.user) {
|
||||
sessionStorage.setItem('pending_invite', token);
|
||||
history.replaceState(null, '', '/');
|
||||
navigate('settings', false);
|
||||
UI.toast.info('Bitte melde dich an, um die Einladung anzunehmen.');
|
||||
return;
|
||||
}
|
||||
|
||||
const ok = await UI.modal.confirm({
|
||||
message: `<strong>${UI.escape(info.owner_name)}</strong> möchte das Profil von
|
||||
<strong>${UI.escape(info.dog_name)}</strong> mit dir teilen
|
||||
(${info.role === 'editor' ? 'Lesen & Schreiben' : 'Nur lesen'}).
|
||||
Möchtest du die Einladung annehmen?`,
|
||||
});
|
||||
if (!ok) { history.replaceState(null, '', '/'); return; }
|
||||
await API.sharing.accept(token);
|
||||
// Hundeliste neu laden
|
||||
state.dogs = await API.dogs.list();
|
||||
const newDog = state.dogs.find(d => d.name === info.dog_name);
|
||||
if (newDog) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue