Untere Leiste fest am unteren Rand [deploy]
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 13s
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 13s
Eddy: „ja mach die Leiste unten mal fest". Sie stand seit v1.0.0 am Seitenende — in einem Auftrag unter allen Fotos und Dokumenten, also praktisch nie im Bild. - #bottom-nav: position sticky, bottom 0, feste Höhe --nav-h (56 px). - „Geteiltes ablegen" klebt genau darüber, der FAB sitzt darüber. - Banner mit Teilen-Symbol statt Emoji und „2 Fotos und 1 Video" statt „3 Bilder". Im Android-Emulator gemessen: Leiste oben wie gescrollt am Rand, Banner und FAB ohne Überlappung. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
afc6ca7046
commit
47cd91193e
4 changed files with 29 additions and 9 deletions
|
|
@ -20,7 +20,7 @@ Mobile Progressive Web App für die Baustellen-Doku — Foto-Upload, Sprach- und
|
||||||
- ✅ Auftragsdetail mit Kunde, Adresse, Telefon (Click-to-Call)
|
- ✅ Auftragsdetail mit Kunde, Adresse, Telefon (Click-to-Call)
|
||||||
- ✅ **Neuer Auftrag** (FAB): Kunde per Suche/Zuletzt-verwendet wählen, dann **Ihr Zeichen** (Pflicht), **Auftragsbeschreibung** (optional), **Geplanter Liefertermin** (Datum + Uhrzeit) und Checkbox **Auftrag direkt freigeben**. Kunden-Defaults (Zahlungsbedingung/Zahlart, Ansprechpartner) werden übernommen. Bei „direkt freigeben" wird der Auftrag **ohne Position** validiert — die Leistungen kommen aus dem Stundenzettel. (Bis Bericht 1.3.1 hängte das Backend hier eine Std-Lohn-Zeile mit Menge 1 an; die verfälschte den Auftragswert, stand als offene Restmenge in der Lieferauflistung und im Kunden-PDF.)
|
- ✅ **Neuer Auftrag** (FAB): Kunde per Suche/Zuletzt-verwendet wählen, dann **Ihr Zeichen** (Pflicht), **Auftragsbeschreibung** (optional), **Geplanter Liefertermin** (Datum + Uhrzeit) und Checkbox **Auftrag direkt freigeben**. Kunden-Defaults (Zahlungsbedingung/Zahlart, Ansprechpartner) werden übernommen. Bei „direkt freigeben" wird der Auftrag **ohne Position** validiert — die Leistungen kommen aus dem Stundenzettel. (Bis Bericht 1.3.1 hängte das Backend hier eine Std-Lohn-Zeile mit Menge 1 an; die verfälschte den Auftragswert, stand als offene Restmenge in der Lieferauflistung und im Kunden-PDF.)
|
||||||
|
|
||||||
**Aussehen:** Knöpfe tragen farbige Symbole statt Emojis (`icon()` in app.js, Material Icons; Farben je Symbol in app.css `.ikon-<name>`) — Emojis erscheinen je nach Handy als Kästchen. Große Knöpfe: weißes Symbol im farbigen runden Feld, linksbündig (Symbole in einer Spalte, Text darunter bündig); kleine Knöpfe: farbiges Symbol. Untere Leiste: farbiges Symbol über dem Wort. Überschriften fett in normaler Schreibweise, ohne Versalien und ohne Emoji (ROADMAP Punkt 12).
|
**Aussehen:** Knöpfe tragen farbige Symbole statt Emojis (`icon()` in app.js, Material Icons; Farben je Symbol in app.css `.ikon-<name>`) — Emojis erscheinen je nach Handy als Kästchen. Große Knöpfe: weißes Symbol im farbigen runden Feld, linksbündig (Symbole in einer Spalte, Text darunter bündig); kleine Knöpfe: farbiges Symbol. Untere Leiste: farbiges Symbol über dem Wort, klebt fest am unteren Rand (wie die Kopfzeile oben). Überschriften fett in normaler Schreibweise, ohne Versalien und ohne Emoji (ROADMAP Punkt 12).
|
||||||
|
|
||||||
**Foto- und Video-Upload**
|
**Foto- und Video-Upload**
|
||||||
- ✅ Live-Kamera-Modal (getUserMedia): bleibt für Serien-Aufnahmen offen — Auslöser + Filmstreifen mit Upload-Status je Foto (💾 gesichert → ⏳ lädt hoch → ✓ fertig), Front-/Rückkamera-Umschaltung (nur bei zwei Kameras), Fehlschuss löschbar
|
- ✅ Live-Kamera-Modal (getUserMedia): bleibt für Serien-Aufnahmen offen — Auslöser + Filmstreifen mit Upload-Status je Foto (💾 gesichert → ⏳ lädt hoch → ✓ fertig), Front-/Rückkamera-Umschaltung (nur bei zwei Kameras), Fehlschuss löschbar
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,12 @@ Anlass: der 🔄-Wechselknopf erschien als blaues Kästchen („den hässlichen
|
||||||
- [x] ✅ Titel der Vollbild-Ansichten und Abschnitts-Überschriften ohne Emoji (reiner Text).
|
- [x] ✅ Titel der Vollbild-Ansichten und Abschnitts-Überschriften ohne Emoji (reiner Text).
|
||||||
- Bewusst gelassen: Zustandsanzeige 🟢/🟡/🔴 (Farbe ist dort die Aussage), Stempel im Skizzen-Editor (werden so ins Bild
|
- Bewusst gelassen: Zustandsanzeige 🟢/🟡/🔴 (Farbe ist dort die Aussage), Stempel im Skizzen-Editor (werden so ins Bild
|
||||||
gezeichnet), Bilder in leeren Listen, Emojis in Meldungen.
|
gezeichnet), Bilder in leeren Listen, Emojis in Meldungen.
|
||||||
- [ ] Offen, nicht angefasst: Die untere Leiste steht seit v1.0.0 am **Seitenende** statt fest unten (`#app` nur
|
- [x] ✅ 20.10.2026 (Eddy: „ja mach die Leiste unten mal fest"): Die untere Leiste stand seit v1.0.0 am **Seitenende**
|
||||||
`min-height: 100dvh`, `#main` wächst mit) — bei langen Listen erst nach Scrollen erreichbar. Wenn gewünscht:
|
(`#app` nur `min-height`, die Seite wächst mit) — in einem Auftrag unter allen Fotos und Dokumenten, Eddy kannte sie
|
||||||
Leiste fest unten, dabei FAB und „Geteiltes ablegen"-Leiste (Punkt 8) mit hochrücken.
|
gar nicht. Jetzt `position: sticky; bottom: 0` wie die Kopfzeile oben, feste Höhe `--nav-h: 56px`; „Geteiltes
|
||||||
|
ablegen" klebt genau darüber (`bottom: var(--nav-h)`), der FAB (fixed 68 px) darüber. Im Emulator gemessen: Leiste
|
||||||
|
729–786 bei 785 px Fensterhöhe, oben wie gescrollt; Banner 688–730, FAB 618–674 — nichts überlappt. Banner mit
|
||||||
|
Teilen-Symbol statt 📤 und „2 Fotos und 1 Video" statt „3 Bilder".
|
||||||
|
|
||||||
## 11. Videos aufnehmen (gewünscht 2026-10-19)
|
## 11. Videos aufnehmen (gewünscht 2026-10-19)
|
||||||
|
|
||||||
|
|
|
||||||
18
app.css
18
app.css
|
|
@ -63,20 +63,31 @@ body {
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Untere Leiste klebt am unteren Rand wie die Kopfzeile oben (Eddy 20.10.2026: „mach die Leiste
|
||||||
|
unten mal fest"). Bis dahin stand sie seit v1.0.0 am Seitenende — in einem Auftrag unter allen
|
||||||
|
Fotos und Dokumenten, praktisch nie im Bild. Feste Hoehe (--nav-h), damit die Leiste
|
||||||
|
„Geteiltes ablegen" genau darueber kleben kann; der FAB (fixed, 68px) liegt schon darueber. */
|
||||||
|
:root { --nav-h: 56px; }
|
||||||
#bottom-nav {
|
#bottom-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
background: #25252b;
|
background: #25252b;
|
||||||
border-top: 1px solid #333;
|
border-top: 1px solid #333;
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 30;
|
||||||
}
|
}
|
||||||
#bottom-nav button {
|
#bottom-nav button {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: #888;
|
color: #888;
|
||||||
padding: 8px 2px;
|
height: var(--nav-h);
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 6px 2px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
justify-content: center;
|
||||||
/* Symbol ueber dem Wort, wie in Handy-Apps ueblich (vorher bunte Emojis) */
|
/* Symbol ueber dem Wort, wie in Handy-Apps ueblich (vorher bunte Emojis) */
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -1698,7 +1709,7 @@ body {
|
||||||
* (fixed, bottom 68px) liegt darüber und wird nicht mehr verdeckt. */
|
* (fixed, bottom 68px) liegt darüber und wird nicht mehr verdeckt. */
|
||||||
.shared-banner {
|
.shared-banner {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0;
|
bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px)); /* direkt ueber der festen Leiste */
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
@ -1713,6 +1724,9 @@ body {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.shared-banner:active { filter: brightness(0.95); }
|
.shared-banner:active { filter: brightness(0.95); }
|
||||||
|
/* Symbol in Schriftfarbe (dunkel auf hellblau) — die Teilen-Farbe waere hier unsichtbar */
|
||||||
|
.shared-banner { display: flex; align-items: center; justify-content: center; gap: 8px; }
|
||||||
|
.shared-banner .ikon { color: inherit; }
|
||||||
/* Solange die Leiste da ist, sitzt der FAB eine Leistenhöhe höher — sonst ragt er hinein */
|
/* Solange die Leiste da ist, sitzt der FAB eine Leistenhöhe höher — sonst ragt er hinein */
|
||||||
body.hat-geteiltes .fab { bottom: calc(112px + env(safe-area-inset-bottom, 0px)); }
|
body.hat-geteiltes .fab { bottom: calc(112px + env(safe-area-inset-bottom, 0px)); }
|
||||||
|
|
||||||
|
|
|
||||||
9
app.js
9
app.js
|
|
@ -1982,11 +1982,12 @@ router.on('/settings', async () => {
|
||||||
* bleiben in IndexedDB liegen; ohne diesen Hinweis wuerde sie niemand je wiederfinden. */
|
* bleiben in IndexedDB liegen; ohne diesen Hinweis wuerde sie niemand je wiederfinden. */
|
||||||
async function checkPendingShare() {
|
async function checkPendingShare() {
|
||||||
if (document.getElementById('shared-banner')) return;
|
if (document.getElementById('shared-banner')) return;
|
||||||
let n = 0, notiz = false;
|
let n = 0, notiz = false, dateien = [];
|
||||||
try {
|
try {
|
||||||
const p = await idb.get('shared_payload');
|
const p = await idb.get('shared_payload');
|
||||||
if (p) {
|
if (p) {
|
||||||
n = (p.files || []).length;
|
dateien = p.files || [];
|
||||||
|
n = dateien.length;
|
||||||
notiz = !!((p.title || '').trim() || (p.text || '').trim() || (p.url || '').trim());
|
notiz = !!((p.title || '').trim() || (p.text || '').trim() || (p.url || '').trim());
|
||||||
} else {
|
} else {
|
||||||
const alt = await idb.get('shared_files'); // altes Format
|
const alt = await idb.get('shared_files'); // altes Format
|
||||||
|
|
@ -2004,7 +2005,9 @@ async function checkPendingShare() {
|
||||||
const b = document.createElement('button');
|
const b = document.createElement('button');
|
||||||
b.id = 'shared-banner';
|
b.id = 'shared-banner';
|
||||||
b.className = 'shared-banner';
|
b.className = 'shared-banner';
|
||||||
b.textContent = '📤 Geteiltes ablegen' + (n ? ' (' + n + ' Bild' + (n > 1 ? 'er' : '') + ')' : ' (Notiz)');
|
// Videos koennen seit 19.10.2026 mitkommen — daher „2 Fotos und 1 Video" statt „3 Bilder"
|
||||||
|
const was = n ? medienText(dateien.length ? dateien.map(f => ({ mime: f.type || '' })) : new Array(n).fill({})) : 'Notiz';
|
||||||
|
b.innerHTML = icon('teilen', 20) + '<span>Geteiltes ablegen (' + escapeHtml(was) + ')</span>';
|
||||||
b.addEventListener('click', () => { location.href = 'share.html'; });
|
b.addEventListener('click', () => { location.href = 'share.html'; });
|
||||||
// Als Leiste in die App-Spalte direkt über die Navigation (Eddy: „unten am Rand, nicht auf den
|
// Als Leiste in die App-Spalte direkt über die Navigation (Eddy: „unten am Rand, nicht auf den
|
||||||
// Aufträgen") — vorher schwebte der Knopf fest über der Liste und verdeckte Einträge und den FAB
|
// Aufträgen") — vorher schwebte der Knopf fest über der Liste und verdeckte Einträge und den FAB
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue