feat: Hilfe-Button in Topbar mit kompletter Anleitung
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 1s
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 1s
❓-Button oben rechts öffnet ein Vollbild-Modal mit:
- Auftragsfindung und Suche
- Fotos aufnehmen (Kamera/Galerie), Hinweis auf Entwurf-Akkumulation
- Skizzen-Editor (Pen/Pfeil/Rect/Ellipse, Undo, speichern)
- Sprachnotizen aufnehmen + abspielen
- Berichte finalisieren + Status-Erklärung
- Offline-Modus + Status-Badge-Legende
- Installation auf Home-Screen (Android + iOS)
- Einstellungen
Service Worker v4.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
This commit is contained in:
parent
bd9580bd46
commit
3f1b462105
4 changed files with 181 additions and 2 deletions
60
app.css
60
app.css
|
|
@ -438,3 +438,63 @@ body {
|
|||
.audio-item audio { width: 100%; flex-basis: 100%; }
|
||||
|
||||
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
|
||||
|
||||
/* Hilfe-Modal */
|
||||
.help-modal .help-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 20px;
|
||||
color: #e0e0e0;
|
||||
max-width: 780px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: #1a1a1f;
|
||||
}
|
||||
.help-modal h2 {
|
||||
color: #7aa2f7;
|
||||
margin: 0 0 20px;
|
||||
font-size: 22px;
|
||||
}
|
||||
.help-modal section {
|
||||
background: #25252b;
|
||||
border-radius: 10px;
|
||||
padding: 14px 18px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.help-modal section h3 {
|
||||
color: #7aa2f7;
|
||||
font-size: 16px;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
.help-modal p { margin: 6px 0; line-height: 1.5; font-size: 14px; }
|
||||
.help-modal ul { margin: 6px 0 6px 20px; padding: 0; }
|
||||
.help-modal li { margin: 4px 0; font-size: 14px; line-height: 1.5; }
|
||||
.help-modal strong { color: #fff; }
|
||||
.help-modal .tip {
|
||||
background: rgba(122, 162, 247, 0.1);
|
||||
border-left: 3px solid #7aa2f7;
|
||||
padding: 10px 12px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.help-modal .status-badge-help {
|
||||
background: #2a2a30;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 12px;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
.help-modal .help-footer {
|
||||
margin-top: 24px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #333;
|
||||
text-align: center;
|
||||
opacity: 0.6;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* help-btn in Topbar kleiner machen */
|
||||
#help-btn { font-size: 18px; padding: 4px 8px; }
|
||||
|
|
|
|||
120
app.js
120
app.js
|
|
@ -428,13 +428,131 @@ router.on('/settings', async () => {
|
|||
};
|
||||
});
|
||||
|
||||
/* Bottom nav */
|
||||
/* Bottom nav + Hilfe-Button */
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.querySelectorAll('#bottom-nav button').forEach(b => {
|
||||
b.addEventListener('click', () => router.go('#/' + b.dataset.route));
|
||||
});
|
||||
const helpBtn = document.getElementById('help-btn');
|
||||
if (helpBtn) helpBtn.addEventListener('click', openHelpModal);
|
||||
});
|
||||
|
||||
function openHelpModal() {
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'fullscreen-modal help-modal';
|
||||
modal.innerHTML = `
|
||||
<div class="fs-header">
|
||||
<button class="icon-btn" id="help-close">✕</button>
|
||||
<div class="fs-title">❓ Hilfe / Anleitung</div>
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="help-body">
|
||||
<h2>📋 So funktioniert die Baustelle-App</h2>
|
||||
|
||||
<section>
|
||||
<h3>1. Aufträge finden</h3>
|
||||
<p>Im Reiter <strong>Aufträge</strong> siehst du alle offenen Aufträge, die dir zugewiesen sind.
|
||||
Oben kannst du per Suchfeld nach Auftragsnummer oder Kundenname filtern.</p>
|
||||
<p>Auf einen Auftrag tippen → Detail-Ansicht mit Kunde, Adresse, Telefon.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>2. Fotos aufnehmen</h3>
|
||||
<p>Im Auftrag-Detail:</p>
|
||||
<ul>
|
||||
<li><strong>📷 Foto aufnehmen</strong> — öffnet direkt die Kamera</li>
|
||||
<li><strong>📂 Aus Galerie wählen</strong> — mehrere Bilder auf einmal möglich</li>
|
||||
</ul>
|
||||
<p>Die Bilder werden automatisch auf 2000px verkleinert und hochgeladen.
|
||||
Sie landen in einem <strong>Entwurf-Bericht</strong>, der automatisch zum Auftrag angelegt wird.</p>
|
||||
<p class="tip">💡 Alle weiteren Fotos werden an denselben Entwurf angehängt —
|
||||
du hast also einen Bericht mit mehreren Seiten, bis du ihn finalisierst.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>3. Fotos bearbeiten (Skizzen)</h3>
|
||||
<p>Tippe auf ein hochgeladenes Foto im Grid → <strong>Vollbild-Ansicht</strong>.</p>
|
||||
<ul>
|
||||
<li><strong>✏️ (oben)</strong> öffnet den Skizzen-Editor</li>
|
||||
<li><strong>🗑️ (oben)</strong> löscht das Foto</li>
|
||||
</ul>
|
||||
<p>Im Skizzen-Editor:</p>
|
||||
<ul>
|
||||
<li>✏️ Stift (Freihand)</li>
|
||||
<li>↗ Pfeil mit Spitze (von Start bis Ende ziehen)</li>
|
||||
<li>▭ Rechteck</li>
|
||||
<li>○ Ellipse</li>
|
||||
<li>Farbe + Linienstärke rechts daneben</li>
|
||||
<li>↶ Undo / 🗑 Alles zurücksetzen</li>
|
||||
</ul>
|
||||
<p>Oben rechts <strong>✓</strong> → Skizze wird als eigenständige neue Bericht-Seite gespeichert.
|
||||
Das Original-Foto bleibt unverändert.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>4. Sprachnotizen</h3>
|
||||
<p><strong>🎙 Sprachnotiz aufnehmen</strong> im Auftrag-Detail:</p>
|
||||
<ul>
|
||||
<li>Aufnahme starten, reden</li>
|
||||
<li>Stopp → Vorhören</li>
|
||||
<li>Senden → Audio landet im Auftrags-Anhang</li>
|
||||
</ul>
|
||||
<p>Unter der Foto-Liste erscheint eine eigene Sektion „🎙 Sprachnotizen" mit Play-Button je Eintrag.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>5. Berichte finalisieren</h3>
|
||||
<p>Im Reiter <strong>Berichte</strong> siehst du alle deine Berichte mit Status.</p>
|
||||
<ul>
|
||||
<li><span class="status-draft">Entwurf</span> — kannst du noch erweitern</li>
|
||||
<li><span class="status-final">Final</span> — PDF wurde erzeugt, der Bericht ist eingefroren</li>
|
||||
</ul>
|
||||
<p>Bericht öffnen → <strong>📑 Bericht finalisieren</strong> → erzeugt das PDF und legt es
|
||||
unter „Verknüpfte Dokumente" des Auftrags ab. In Dolibarr siehst du den Bericht dann direkt beim Auftrag.</p>
|
||||
<p class="tip">💡 Wenn du nach dem Finalisieren neue Fotos machst, wird automatisch ein
|
||||
<strong>neuer</strong> Entwurf angelegt. Der finalisierte bleibt unberührt.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>6. Offline arbeiten</h3>
|
||||
<p>Die App funktioniert auch ohne Internet:</p>
|
||||
<ul>
|
||||
<li>Fotos werden in einer lokalen Warteschlange gespeichert</li>
|
||||
<li>Sobald wieder Empfang da ist, werden sie automatisch hochgeladen</li>
|
||||
<li>Oben rechts siehst du den Status: <span class="status-badge-help">🟢 online</span>,
|
||||
<span class="status-badge-help">🟡 N</span> (N Uploads werden synchronisiert),
|
||||
<span class="status-badge-help">🔴 N</span> (offline, N warten)</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>7. Auf dem Handy installieren</h3>
|
||||
<p>So wird die PWA zur echten App:</p>
|
||||
<ul>
|
||||
<li><strong>Android/Chrome:</strong> Menü → „Zum Startbildschirm hinzufügen"</li>
|
||||
<li><strong>iPhone/Safari:</strong> Teilen-Symbol → „Zum Home-Bildschirm"</li>
|
||||
</ul>
|
||||
<p>Danach startet sie wie eine normale App, ohne Browser-Leiste.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>8. Einstellungen</h3>
|
||||
<p>Im Reiter <strong>⚙️</strong>:</p>
|
||||
<ul>
|
||||
<li>🔄 Offline-Queue manuell synchronisieren</li>
|
||||
<li>🚪 Abmelden</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<div class="help-footer">
|
||||
<p>Baustelle PWA v1.0 · Fragen? → Eddy</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(modal);
|
||||
modal.querySelector('#help-close').onclick = () => modal.remove();
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
<header id="topbar">
|
||||
<button id="back-btn" class="icon-btn" style="display:none">←</button>
|
||||
<h1 id="page-title">Baustelle</h1>
|
||||
<button id="help-btn" class="icon-btn" title="Hilfe">❓</button>
|
||||
<span id="status-badge">🟢</span>
|
||||
</header>
|
||||
|
||||
|
|
|
|||
2
sw.js
2
sw.js
|
|
@ -4,7 +4,7 @@
|
|||
* - API-Calls: network-first, kein offline-cache (da auth-pflichtig)
|
||||
*/
|
||||
|
||||
const CACHE = 'baustelle-v3';
|
||||
const CACHE = 'baustelle-v4';
|
||||
const SHELL = [
|
||||
'./',
|
||||
'./index.html',
|
||||
|
|
|
|||
Loading…
Reference in a new issue