UX: Installationsanleitung mobile-first, alle Plattformen — SW by-v443, APP_VER 422

Alle 5 Fälle abgedeckt: Android+Prompt (Button), Android ohne Prompt (Chrome-Schritte),
iOS Safari (Teilen-Menü), iOS non-Safari (Hinweis + Link kopieren), Desktop (Tabs
Android/iOS). Steps mit Icon statt Zahl. Link-kopieren-Button für manuelle Fälle.
This commit is contained in:
rene 2026-04-27 18:22:10 +02:00
parent e62d94546b
commit 9cb4a16cc2
3 changed files with 102 additions and 25 deletions

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung. Router, State-Management, Navigation, Initialisierung.
============================================================ */ ============================================================ */
const APP_VER = '421'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VER = '422'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const App = (() => { const App = (() => {

View file

@ -231,56 +231,112 @@ window.Page_welcome = (() => {
const isIOS = /iPad|iPhone|iPod/.test(ua) && !window.MSStream; const isIOS = /iPad|iPhone|iPod/.test(ua) && !window.MSStream;
const isSafari = /^((?!chrome|android).)*safari/i.test(ua); const isSafari = /^((?!chrome|android).)*safari/i.test(ua);
const isAndroid = /android/i.test(ua); const isAndroid = /android/i.test(ua);
const isMobile = isIOS || isAndroid;
const hasPrompt = !!App.getInstallPrompt(); const hasPrompt = !!App.getInstallPrompt();
if ((isAndroid || hasPrompt) && hasPrompt) { // Android: Browser hat Install-Prompt bereit (Chrome, Edge, Samsung Internet neu)
if (hasPrompt) {
return ` return `
<p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-3);line-height:1.5"> <p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-3);line-height:1.5">
Kein App Store nötig direkt installieren. Kein App Store nötig direkt auf den Home-Bildschirm.
</p> </p>
<button class="btn btn-primary" id="install-android-btn" style="width:100%"> <button class="btn btn-primary" id="install-android-btn" style="width:100%;margin-bottom:var(--space-2)">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg> <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg>
Ban Yaro installieren Ban Yaro installieren
</button>`; </button>`;
} }
// iOS Safari: Teilen-Menü
if (isIOS && isSafari) { if (isIOS && isSafari) {
return ` return `
<p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-4);line-height:1.5"> <p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-4);line-height:1.5">
Auf iPhone/iPad installieren: So kommt Ban Yaro auf deinen Home-Bildschirm:
</p> </p>
${_steps([ ${_steps([
['1', 'Teilen-Symbol <svg class="ph-icon" style="width:14px;height:14px;vertical-align:-2px"><use href="/icons/phosphor.svg#share"></use></svg> in Safari tippen'], ['share', 'Tippe unten in Safari auf das <strong>Teilen-Symbol</strong> <svg class="ph-icon" style="width:14px;height:14px;vertical-align:-2px"><use href="/icons/phosphor.svg#share"></use></svg>'],
['2', '<strong>„Zum Home-Bildschirm"</strong> wählen'], ['rows-plus-top', 'Wähle <strong>„Zum Home-Bildschirm"</strong> aus der Liste'],
['3', 'Rechts oben <strong>„Hinzufügen"</strong> tippen'], ['check', 'Tippe oben rechts auf <strong>„Hinzufügen"</strong>'],
])} ])}
<p style="font-size:var(--text-xs);color:var(--c-text-muted);margin:var(--space-3) 0 0"> <p style="font-size:var(--text-xs);color:var(--c-text-muted);margin:var(--space-4) 0 0">
Nur in Safari verfügbar, nicht in anderen Browsern. Funktioniert nur in Safari nicht in Chrome oder Firefox auf iOS.
</p>`; </p>`;
} }
// iOS, aber nicht Safari (Chrome, Firefox, etc.)
if (isIOS && !isSafari) {
return `
<p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-4);line-height:1.5">
Auf dem iPhone geht die Installation nur über <strong>Safari</strong>.
</p>
${_steps([
['safari-logo', 'Öffne <strong>Safari</strong> auf deinem iPhone'],
['arrow-square-in','Gib <strong>banyaro.app</strong> in die Adressleiste ein'],
['share', 'Tippe auf das Teilen-Symbol und wähle <strong>„Zum Home-Bildschirm"</strong>'],
])}
<button class="btn btn-ghost btn-sm" id="install-copy-btn"
style="margin-top:var(--space-3);width:100%">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#copy"></use></svg>
Link kopieren
</button>`;
}
// Android ohne Prompt (Firefox, älterer Samsung Browser, etc.)
if (isAndroid) {
return `
<p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-4);line-height:1.5">
Am einfachsten geht es mit <strong>Chrome</strong>:
</p>
${_steps([
['arrow-square-in', 'Öffne <strong>banyaro.app</strong> in Chrome'],
['dots-three-circle','Tippe auf das <strong>Menü ⋮</strong> oben rechts'],
['download-simple', 'Wähle <strong>„App installieren"</strong> oder<br>„Zum Startbildschirm hinzufügen"'],
])}
<button class="btn btn-ghost btn-sm" id="install-copy-btn"
style="margin-top:var(--space-3);width:100%">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#copy"></use></svg>
Link kopieren
</button>`;
}
// Desktop — beide Plattformen zeigen
return ` return `
<p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-4);line-height:1.5"> <div style="display:flex;gap:var(--space-2);margin-bottom:var(--space-4)">
In Chrome oder Edge installieren: <button class="btn btn-sm" id="inst-tab-android"
</p> style="flex:1;background:var(--c-primary);color:#fff;border:none">
${_steps([ Android
['1', 'Seite in <strong>Chrome</strong> oder <strong>Edge</strong> öffnen'], </button>
['2', 'Installations-Symbol in der Adressleiste klicken'], <button class="btn btn-sm btn-ghost" id="inst-tab-ios" style="flex:1">
['3', 'Bestätigen — fertig!'], iPhone / iPad
])}`; </button>
</div>
<div id="inst-panel-android">
${_steps([
['arrow-square-in', 'Öffne <strong>banyaro.app</strong> in Chrome oder Edge'],
['monitor', 'Klicke auf das <strong>Installations-Symbol</strong> in der Adressleiste'],
['check', 'Bestätigen — fertig!'],
])}
</div>
<div id="inst-panel-ios" style="display:none">
${_steps([
['arrow-square-in', 'Öffne <strong>banyaro.app</strong> in Safari auf dem iPhone'],
['share', 'Tippe auf das <strong>Teilen-Symbol</strong> <svg class="ph-icon" style="width:14px;height:14px;vertical-align:-2px"><use href="/icons/phosphor.svg#share"></use></svg>'],
['rows-plus-top', 'Wähle <strong>„Zum Home-Bildschirm"</strong> → <strong>„Hinzufügen"</strong>'],
])}
</div>`;
} }
function _steps(list) { function _steps(list) {
return ` return `
<ol style="margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:var(--space-3)"> <ol style="margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:var(--space-3)">
${list.map(([num, text]) => ` ${list.map(([icon, text]) => `
<li style="display:flex;gap:var(--space-3);align-items:flex-start"> <li style="display:flex;gap:var(--space-3);align-items:flex-start">
<div style="width:24px;height:24px;border-radius:50%;flex-shrink:0; <div style="width:32px;height:32px;border-radius:var(--radius-md);flex-shrink:0;
background:var(--c-primary);color:#fff;font-size:var(--text-xs); background:var(--c-surface-2);display:flex;align-items:center;justify-content:center">
font-weight:var(--weight-bold);display:flex;align-items:center;justify-content:center"> <svg class="ph-icon" style="width:16px;height:16px;color:var(--c-primary)" aria-hidden="true">
${num} <use href="/icons/phosphor.svg#${icon}"></use>
</svg>
</div> </div>
<span style="font-size:var(--text-sm);color:var(--c-text);line-height:1.5;padding-top:2px">${text}</span> <span style="font-size:var(--text-sm);color:var(--c-text);line-height:1.5;padding-top:6px">${text}</span>
</li> </li>
`).join('')} `).join('')}
</ol>`; </ol>`;
@ -301,6 +357,27 @@ window.Page_welcome = (() => {
} }
}); });
_container.querySelector('#install-copy-btn')?.addEventListener('click', async () => {
await navigator.clipboard.writeText('https://banyaro.app');
UI.toast.success('Link kopiert!');
});
// Desktop-Tabs Android / iOS
_container.querySelector('#inst-tab-android')?.addEventListener('click', () => {
_container.querySelector('#inst-panel-android').style.display = '';
_container.querySelector('#inst-panel-ios').style.display = 'none';
_container.querySelector('#inst-tab-android').style.cssText += ';background:var(--c-primary);color:#fff;border:none';
_container.querySelector('#inst-tab-ios').className = 'btn btn-sm btn-ghost';
_container.querySelector('#inst-tab-ios').style.cssText = 'flex:1';
});
_container.querySelector('#inst-tab-ios')?.addEventListener('click', () => {
_container.querySelector('#inst-panel-android').style.display = 'none';
_container.querySelector('#inst-panel-ios').style.display = '';
_container.querySelector('#inst-tab-ios').style.cssText += ';background:var(--c-primary);color:#fff;border:none';
_container.querySelector('#inst-tab-android').className = 'btn btn-sm btn-ghost';
_container.querySelector('#inst-tab-android').style.cssText = 'flex:1';
});
_container.querySelector('#welcome-register-btn')?.addEventListener('click', () => App.navigate('settings')); _container.querySelector('#welcome-register-btn')?.addEventListener('click', () => App.navigate('settings'));
_container.querySelector('#welcome-login-btn')?.addEventListener('click', () => App.navigate('settings')); _container.querySelector('#welcome-login-btn')?.addEventListener('click', () => App.navigate('settings'));

View file

@ -3,7 +3,7 @@
Offline-Cache + Push Notifications + Tile-Cache Offline-Cache + Push Notifications + Tile-Cache
============================================================ */ ============================================================ */
const CACHE_VERSION = 'by-v442'; const CACHE_VERSION = 'by-v443';
const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten