Frontend Sprint 3+4: Dog-Switcher, Health-Seite, Multi-Dog Tagebuch
- app.js: vollständiger Dog-Switcher (Avatar im Header/Sidebar, Quickpicker bei 3+ Hunden, setActiveDog, localStorage-Persistenz), iOS Ghost-Click Fix, Loading-Guard, Logout State Reset - index.html: Dog-Switcher HTML, Favicon-Links, Sidebar "+ Neu erstellen", Navigation Tab Karte → Gesundheit - health.js (neu): vollständiges Health-Frontend mit Tabs (Impfung, Entwurmung, Tierarzt, Medikament, Gewicht-Kurve, Allergie, Dokument), Ampel-System, KI-Zusammenfassung - dog-profile.js: "+ Weiteren Hund anlegen" Button + _openCreateModal(), Event-Delegation statt direkter Listener (kein Doppelaufruf) - diary.js: Dog-Picker im Formular, Avatar-Reihe auf Karten, Dog-Chips im Detail-Modal, dog_ids im API-Payload - poison.js: Erledigt-Dialog mit Grundauswahl (beseitigt/fehlerhaft/anderes) - api.js: health-Endpoints (list, create, update, delete, upload, ki) - ui.js: confirm() Fix (resolve vor close) - layout.css: Dog-Switcher Styles, scrollbare Sidebar-Nav, User-Item fix - components.css: Health-Styles, Diary Dog-Picker, Ampel-Punkte, Gewicht-SVG - icons/: Favicon-Set (ico, 16px, 32px, 180px, 192px, 512px)
This commit is contained in:
parent
6f48ec581d
commit
d8b9561fff
16 changed files with 1597 additions and 91 deletions
|
|
@ -441,6 +441,7 @@ textarea.form-control {
|
|||
padding: var(--space-4);
|
||||
backdrop-filter: blur(2px);
|
||||
animation: overlay-in var(--transition-normal) ease;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.modal-overlay { align-items: center; }
|
||||
|
|
@ -812,3 +813,409 @@ textarea.form-control {
|
|||
|
||||
/* Leaflet-Attribution ausblenden */
|
||||
.leaflet-control-attribution { display: none !important; }
|
||||
|
||||
/* ============================================================
|
||||
GESUNDHEIT
|
||||
============================================================ */
|
||||
|
||||
/* Header mit KI-Button */
|
||||
.health-header {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: var(--space-3) 0 var(--space-2);
|
||||
}
|
||||
|
||||
/* Tab-Leiste — Mobile: horizontal scrollbar, Desktop: umbrechen */
|
||||
.health-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-1) var(--space-1);
|
||||
padding-bottom: var(--space-2);
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
/* Auf sehr kleinen Screens: scrollen statt umbrechen */
|
||||
@media (max-width: 480px) {
|
||||
.health-tabs {
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
padding-right: var(--space-4);
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.health-tabs::-webkit-scrollbar { display: none; }
|
||||
}
|
||||
|
||||
.health-tab {
|
||||
flex-shrink: 0;
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border: 2px solid var(--c-border);
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--c-surface);
|
||||
color: var(--c-text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--weight-medium);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: all var(--transition-fast);
|
||||
touch-action: manipulation;
|
||||
}
|
||||
.health-tab.active {
|
||||
background: var(--c-primary);
|
||||
border-color: var(--c-primary);
|
||||
color: var(--c-text-inverse);
|
||||
}
|
||||
|
||||
/* Karten-Liste */
|
||||
.health-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
/* Einzelne Karte */
|
||||
.health-card {
|
||||
background: var(--c-surface);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-4);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
align-items: flex-start;
|
||||
transition: box-shadow var(--transition-fast), transform var(--transition-fast);
|
||||
}
|
||||
.health-card:active { transform: scale(0.985); }
|
||||
.health-card--inactive { opacity: 0.55; }
|
||||
|
||||
.health-card-body { flex: 1; min-width: 0; }
|
||||
.health-card-title { font-weight: var(--weight-semibold); margin-bottom: var(--space-1); }
|
||||
.health-card-meta { font-size: var(--text-sm); color: var(--c-text-secondary); }
|
||||
.health-card-next { font-size: var(--text-sm); font-weight: var(--weight-medium); margin-top: var(--space-1); }
|
||||
.health-card-note { font-size: var(--text-sm); color: var(--c-text-secondary); margin-top: var(--space-1); }
|
||||
|
||||
/* Ampel-Punkt (links an der Karte) */
|
||||
.health-card-ampel {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.ampel-green { background: #22c55e; }
|
||||
.ampel-yellow { background: #f59e0b; }
|
||||
.ampel-red { background: #ef4444; }
|
||||
.ampel-grey { background: var(--c-border); }
|
||||
|
||||
.ampel-text-green { color: #16a34a; }
|
||||
.ampel-text-yellow { color: #d97706; }
|
||||
.ampel-text-red { color: #dc2626; }
|
||||
|
||||
/* Gruppen-Label (z.B. "Aktuelle Medikamente") */
|
||||
.health-group-label {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--weight-semibold);
|
||||
color: var(--c-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: var(--space-3) 0 var(--space-1);
|
||||
}
|
||||
|
||||
/* Gewicht-Diagramm-Wrapper */
|
||||
.health-chart-wrap {
|
||||
background: var(--c-surface);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-4);
|
||||
margin-bottom: var(--space-4);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Dokument-Thumbnail und Icon */
|
||||
.health-doc-thumb {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
object-fit: cover;
|
||||
border-radius: var(--radius-sm);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.health-doc-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 2rem;
|
||||
background: var(--c-surface-2);
|
||||
border-radius: var(--radius-sm);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Detail-Dialog DL */
|
||||
.health-detail-dl {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: var(--space-1) var(--space-4);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
.health-detail-dl dt {
|
||||
color: var(--c-text-secondary);
|
||||
font-weight: var(--weight-medium);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.health-detail-dl dd { margin: 0; }
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
DOG SWITCHER
|
||||
Avatar-Leiste in Header (Mobile) + Sidebar-Logo (Desktop)
|
||||
------------------------------------------------------------ */
|
||||
|
||||
/* Aktiver (linker) Hund — primärer Ring */
|
||||
.dog-sw-active {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: var(--radius-full);
|
||||
overflow: hidden;
|
||||
background: var(--c-surface-2);
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
border: 2.5px solid var(--c-primary);
|
||||
transition: transform var(--transition-fast),
|
||||
box-shadow var(--transition-fast);
|
||||
}
|
||||
.dog-sw-active:hover {
|
||||
transform: scale(1.06);
|
||||
box-shadow: 0 0 0 3px var(--c-primary-subtle);
|
||||
}
|
||||
.dog-sw-active img { width:100%; height:100%; object-fit:cover; display:block; }
|
||||
.dog-sw-active span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
/* "Ban Yaro" Label — füllt den Zwischenraum */
|
||||
.dog-sw-title {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Gruppe der inaktiven Hunde (rechts) */
|
||||
.dog-sw-others {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative; /* Anker für Quickpicker-Dropdown */
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Inaktiver Hund-Avatar */
|
||||
.dog-sw-other {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: var(--radius-full);
|
||||
overflow: hidden;
|
||||
background: var(--c-surface-2);
|
||||
border: 2px solid var(--c-surface);
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: transform var(--transition-fast);
|
||||
position: relative;
|
||||
}
|
||||
.dog-sw-other:hover { transform: scale(1.12); }
|
||||
.dog-sw-other img { width:100%; height:100%; object-fit:cover; display:block; }
|
||||
.dog-sw-other span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Gestapelter Avatar-Stack (3+ Hunde) */
|
||||
.dog-sw-stack {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dog-sw-stack .dog-sw-other { margin-left: -9px; }
|
||||
.dog-sw-stack .dog-sw-other:first-child { margin-left: 0; }
|
||||
.dog-sw-stack .dog-sw-other--0 { z-index: 3; }
|
||||
.dog-sw-stack .dog-sw-other--1 { z-index: 2; }
|
||||
.dog-sw-stack .dog-sw-other--2 { z-index: 1; }
|
||||
.dog-sw-stack:hover .dog-sw-other { filter: brightness(1.05); }
|
||||
|
||||
/* +N Überlauf-Badge */
|
||||
.dog-sw-more {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--c-surface-2);
|
||||
border: 2px solid var(--c-surface);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 9px;
|
||||
font-weight: var(--weight-bold);
|
||||
color: var(--c-text-secondary);
|
||||
margin-left: -9px;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Quickpicker-Dropdown */
|
||||
.dog-quickpick {
|
||||
position: absolute;
|
||||
top: calc(100% + 10px);
|
||||
right: 0;
|
||||
background: var(--c-surface);
|
||||
border: 1px solid var(--c-border-light);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg);
|
||||
padding: var(--space-2);
|
||||
min-width: 170px;
|
||||
z-index: 600;
|
||||
}
|
||||
.dog-quickpick.hidden { display: none; }
|
||||
|
||||
.dog-qp-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--weight-medium);
|
||||
color: var(--c-text);
|
||||
transition: background var(--transition-fast);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.dog-qp-item:hover { background: var(--c-bg); }
|
||||
|
||||
.dog-qp-av {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: var(--radius-full);
|
||||
overflow: hidden;
|
||||
background: var(--c-surface-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dog-qp-av img { width:100%; height:100%; object-fit:cover; display:block; }
|
||||
.dog-qp-av span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* Sidebar: größerer aktiver Avatar */
|
||||
#sidebar-dog-switcher .dog-sw-active {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
DIARY — Multi-Dog (Hunde-Auswahl im Formular + Karten-Anzeige)
|
||||
------------------------------------------------------------ */
|
||||
|
||||
/* Avatar-Reihe in der Tagebuch-Karte */
|
||||
.diary-dog-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: -4px; /* überlappend via margin */
|
||||
margin-top: var(--space-2);
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.diary-dog-av {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: var(--radius-full);
|
||||
overflow: hidden;
|
||||
background: var(--c-surface-2);
|
||||
border: 1.5px solid var(--c-surface);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.diary-dog-av img { width:100%; height:100%; object-fit:cover; display:block; }
|
||||
.diary-dog-av span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Hunde-Chip in der Detail-Ansicht */
|
||||
.diary-detail-dogs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.diary-dog-chip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
padding: 3px 8px 3px 4px;
|
||||
background: var(--c-surface-2);
|
||||
border-radius: var(--radius-full);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--weight-medium);
|
||||
color: var(--c-text-secondary);
|
||||
}
|
||||
.diary-dog-chip .diary-dog-av {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/* Hunde-Picker im Formular */
|
||||
.diary-dog-picker {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.diary-dog-pick-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border: 1.5px solid var(--c-border-light);
|
||||
border-radius: var(--radius-full);
|
||||
cursor: pointer;
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--weight-medium);
|
||||
color: var(--c-text-secondary);
|
||||
transition: border-color var(--transition-fast),
|
||||
background var(--transition-fast),
|
||||
color var(--transition-fast);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
user-select: none;
|
||||
}
|
||||
.diary-dog-pick-item input { display: none; }
|
||||
|
||||
.diary-dog-pick-item .diary-dog-av {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.diary-dog-pick-item:hover {
|
||||
border-color: var(--c-primary);
|
||||
color: var(--c-text);
|
||||
}
|
||||
|
||||
.diary-dog-pick-item.checked {
|
||||
border-color: var(--c-primary);
|
||||
background: var(--c-primary-subtle);
|
||||
color: var(--c-primary-dark);
|
||||
font-weight: var(--weight-semibold);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,16 @@
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
/* Dog Switcher Container im Header */
|
||||
#header-dog-switcher {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
min-width: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.header-back {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -201,7 +211,7 @@
|
|||
background: var(--c-surface);
|
||||
border-right: 1px solid var(--c-border-light);
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
overflow: hidden; /* Sidebar selbst scrollt nicht */
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
|
|
@ -229,14 +239,31 @@
|
|||
color: var(--c-text);
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
flex: 1;
|
||||
padding: var(--space-4) var(--space-2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
.sidebar-add {
|
||||
padding: var(--space-4) var(--space-4) var(--space-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
flex: 1;
|
||||
padding: var(--space-2) var(--space-2) var(--space-4);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
overflow-y: auto;
|
||||
min-height: 0; /* wichtig: flex-child darf kleiner werden als Inhalt */
|
||||
/* Firefox */
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--c-primary) var(--c-surface);
|
||||
}
|
||||
.sidebar-nav::-webkit-scrollbar { width: 6px; }
|
||||
.sidebar-nav::-webkit-scrollbar-track { background: var(--c-surface); }
|
||||
.sidebar-nav::-webkit-scrollbar-thumb {
|
||||
background: var(--c-primary);
|
||||
border-radius: 3px;
|
||||
}
|
||||
.sidebar-nav::-webkit-scrollbar-thumb:hover { background: var(--c-primary-dark); }
|
||||
|
||||
.sidebar-section-label {
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--weight-semibold);
|
||||
|
|
@ -270,6 +297,12 @@
|
|||
color: var(--c-primary-dark);
|
||||
font-weight: var(--weight-semibold);
|
||||
}
|
||||
/* User-Eintrag bekommt nie den Active-Stil */
|
||||
.sidebar-item--user.active {
|
||||
background: transparent;
|
||||
color: var(--c-text-secondary);
|
||||
font-weight: var(--weight-medium);
|
||||
}
|
||||
.sidebar-item-icon {
|
||||
font-size: 18px;
|
||||
width: 24px;
|
||||
|
|
@ -291,11 +324,7 @@
|
|||
padding: 0 var(--space-1);
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
padding: var(--space-4) var(--space-2);
|
||||
border-top: 1px solid var(--c-border-light);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* sidebar-footer entfernt — Einstellungen/Konto sind jetzt Teil der scrollbaren Nav */
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
5. PAGE WRAPPER (inneres Layout der Seiten)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue