Sprint 12+13: Tagebuch Day-One-Redesign, Notiz-Feature, Icon-Fixes, SW by-v405
Tagebuch:
- Day-One-Listenansicht: Wochentag + Tageszahl + Meta-Zeile (Zeit/Ort/Wetter)
- 4 Ansichten: Liste, Medien-Mosaik, Kalender (mit Sprungbuttons), Karte (GPS-Marker)
- Detail-Ansicht inline im Content-Bereich (kein Fullscreen-Overlay mehr)
- Hero-Bild vollständig sichtbar (object-fit:contain), Lightbox mit Safe-Area
- 2-Spalten-Layout Desktop: Text + Leaflet-Karte + POI-Liste
- EXIF-GPS-Extraktion bei Foto-Upload, historisches Wetter via Archive-API
- NoteStation-Import: Fotos in diary_media (80 Einträge migriert, 94 Medien)
- Stats-Endpoints: /diary/stats, /diary/calendar, /diary/locations
Notiz-Feature:
- Generische notes-Tabelle (parent_type + parent_id + meta_json)
- 📝-Button in 8 Bereichen, Notizblock-Seite mit KI-Analyse
- KI-Toggle in Einstellungen, notes_ki_enabled in User-Profil
Icons & Design:
- fill:currentColor Fix für welcome/onboarding/friends.js
- --c-icon Variable, --c-text-muted Dark Mode aufgehellt
- 15+ neue Phosphor-Icons aus lokaler Kopie
- CSS Network-First im SW, Cache-Control-Middleware
Infrastruktur:
- Wiki-Anreicherungs-Scheduler-Jobs entfernt (abgeschlossen)
- auth.py: notes_ki_enabled + is_social_media im User-Response
This commit is contained in:
parent
95f91fdc00
commit
553e9e7854
35 changed files with 4558 additions and 370 deletions
|
|
@ -136,6 +136,12 @@ window.Page_sitting = (() => {
|
|||
<div class="sitting-card-side">
|
||||
<div class="sitting-price">${s.preis_pro_tag > 0 ? s.preis_pro_tag.toFixed(0) + ' €/Tag' : 'Preis anfragen'}</div>
|
||||
<div class="sitting-dogs">max. ${s.max_hunde} Hund${s.max_hunde !== 1 ? 'e' : ''}</div>
|
||||
${_state.user ? `<button class="btn-icon sit-note-btn"
|
||||
data-sit-note-id="${s.id}"
|
||||
data-sit-note-label="${UI.escHtml(s.sitter_name + ' ' + (s.datum || ''))}"
|
||||
title="Notiz" style="color:var(--c-text-muted);margin-top:var(--space-1)"
|
||||
onclick="event.stopPropagation()">
|
||||
${UI.icon('note-pencil')}</button>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -704,6 +710,19 @@ window.Page_sitting = (() => {
|
|||
return;
|
||||
}
|
||||
|
||||
// Notiz-Button auf Sitter-Karte
|
||||
const noteBtn = e.target.closest('.sit-note-btn');
|
||||
if (noteBtn) {
|
||||
e.stopPropagation();
|
||||
_openNoteModal(
|
||||
'sitting',
|
||||
parseInt(noteBtn.dataset.sitNoteId),
|
||||
noteBtn.dataset.sitNoteLabel,
|
||||
null
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sitter-Karte
|
||||
const sitterCard = e.target.closest('[data-sit-id]');
|
||||
if (sitterCard && !e.target.closest('button')) {
|
||||
|
|
@ -741,6 +760,59 @@ window.Page_sitting = (() => {
|
|||
} catch (e) { UI.toast(e.message, 'error'); }
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Notiz-Modal (Custom DOM — kein UI.modal um Konflikte zu vermeiden)
|
||||
// ----------------------------------------------------------
|
||||
async function _openNoteModal(parentType, parentId, parentLabel, locationName) {
|
||||
let existingNote = null;
|
||||
try { existingNote = await API.notes.get(parentType, String(parentId)); } catch {}
|
||||
|
||||
const ovl = document.createElement('div');
|
||||
ovl.style.cssText = 'position:fixed;inset:0;z-index:1200;background:rgba(0,0,0,0.55);display:flex;align-items:flex-end;justify-content:center';
|
||||
ovl.innerHTML = `
|
||||
<div style="width:100%;max-width:600px;background:var(--c-surface);border-radius:var(--radius-lg) var(--radius-lg) 0 0;
|
||||
padding:var(--space-4);box-sizing:border-box;max-height:80vh;display:flex;flex-direction:column">
|
||||
<div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-3)">
|
||||
<svg class="ph-icon" aria-hidden="true" style="color:var(--c-primary)"><use href="/icons/phosphor.svg#note-pencil"></use></svg>
|
||||
<span style="font-weight:600;flex:1"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz — ${UI.escape(parentLabel)}</span>
|
||||
<button id="sit-note-close" style="background:none;border:none;cursor:pointer;color:var(--c-text-muted);padding:4px">
|
||||
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#x"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<textarea id="sit-note-text" rows="5"
|
||||
style="width:100%;box-sizing:border-box;padding:var(--space-3);
|
||||
border:1.5px solid var(--c-border);border-radius:var(--radius-md);
|
||||
font-size:var(--text-sm);font-family:inherit;
|
||||
background:var(--c-bg);color:var(--c-text);resize:vertical;flex:1"
|
||||
placeholder="Deine Notiz zu diesem Sitter…">${UI.escape(existingNote?.text || '')}</textarea>
|
||||
<div style="display:flex;gap:var(--space-2);margin-top:var(--space-3)">
|
||||
<button id="sit-note-cancel" class="btn btn-secondary flex-1">Abbrechen</button>
|
||||
<button id="sit-note-save" class="btn btn-primary flex-1">Speichern</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(ovl);
|
||||
|
||||
const close = () => ovl.remove();
|
||||
ovl.querySelector('#sit-note-close')?.addEventListener('click', close);
|
||||
ovl.querySelector('#sit-note-cancel')?.addEventListener('click', close);
|
||||
ovl.addEventListener('click', e => { if (e.target === ovl) close(); });
|
||||
|
||||
ovl.querySelector('#sit-note-save')?.addEventListener('click', async () => {
|
||||
const text = ovl.querySelector('#sit-note-text')?.value?.trim() || '';
|
||||
const payload = { text, parent_label: parentLabel, location_name: locationName || null };
|
||||
try {
|
||||
if (existingNote?.id) {
|
||||
await API.notes.update(existingNote.id, payload);
|
||||
} else {
|
||||
await API.notes.create(parentType, String(parentId), payload);
|
||||
}
|
||||
UI.toast.success('Notiz gespeichert.');
|
||||
close();
|
||||
} catch (err) { UI.toast.error(err.message || 'Fehler beim Speichern.'); }
|
||||
});
|
||||
}
|
||||
|
||||
return { init, refresh };
|
||||
|
||||
})();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue