60 lines
2.7 KiB
JavaScript
60 lines
2.7 KiB
JavaScript
/* Kundenansicht neu (P2): Hinweis "WEBklar als App" (Logik aus app.js renderInstallOffers). Chrome/Android per Installationsdialog,
|
||
iPhone über Teilen und Zum Home-Bildschirm. Kein DOM-Zugriff beim Import. */
|
||
|
||
import { h } from './dom.js'
|
||
|
||
const SCHLUESSEL = 'kb-install-dismissed'
|
||
|
||
/** Zeigen nur auf dem Handy, nicht installiert, mit Installationsdialog oder iOS und nicht ausgeblendet. */
|
||
export function installAngebot({ appLayout, standalone, canPrompt, ios, dismissed }) {
|
||
const zeigen = Boolean(appLayout) && !standalone && Boolean(canPrompt || ios) && !dismissed
|
||
return { zeigen, art: zeigen ? (canPrompt ? 'prompt' : 'ios') : null }
|
||
}
|
||
|
||
export function baueInstallHinweis({ art, onInstall, onDismiss }) {
|
||
const text = art === 'prompt'
|
||
? 'Mit einem Tipp auf deinem Homescreen – ohne App-Store.'
|
||
: 'Tippe auf „Teilen“ und dann auf „Zum Home-Bildschirm“.'
|
||
return h('div', { class: 'kn-install', role: 'region', 'aria-label': 'WEBklar als App' },
|
||
h('div', { class: 'kn-install-text' }, h('strong', null, 'WEBklar als App'), h('span', null, text)),
|
||
art === 'prompt' ? h('button', { type: 'button', class: 'kn-knopf', on: { click: () => onInstall?.() } }, 'Installieren') : null,
|
||
h('button', { type: 'button', class: 'kn-textknopf', 'aria-label': 'Hinweis ausblenden', on: { click: () => onDismiss?.() } }, '×'))
|
||
}
|
||
|
||
const quellen = new WeakMap()
|
||
|
||
/** Je Fenster genau eine Quelle: merkt den Installationsdialog (beforeinstallprompt), räumt bei appinstalled. */
|
||
export function starteInstallQuelle(win = window) {
|
||
if (quellen.has(win)) return quellen.get(win)
|
||
const nav = win.navigator ?? {}
|
||
const ios = /iphone|ipad|ipod/i.test(nav.userAgent ?? '') || (nav.platform === 'MacIntel' && nav.maxTouchPoints > 1)
|
||
let angebot = null
|
||
const hoerer = []
|
||
const melde = () => { for (const fn of [...hoerer]) fn() }
|
||
const quelle = {
|
||
ios,
|
||
standalone: () => Boolean(typeof win.matchMedia === 'function' && win.matchMedia('(display-mode: standalone)')?.matches) || nav.standalone === true,
|
||
kannPrompt: () => angebot !== null,
|
||
async installiere() {
|
||
const p = angebot
|
||
if (!p) return
|
||
angebot = null
|
||
try { await p.prompt() } catch { /* abgebrochen */ }
|
||
melde()
|
||
},
|
||
beiAenderung(fn) { hoerer.push(fn) },
|
||
}
|
||
win.addEventListener('beforeinstallprompt', (ev) => { ev.preventDefault?.(); angebot = ev; melde() })
|
||
win.addEventListener('appinstalled', () => { angebot = null; melde() })
|
||
quellen.set(win, quelle)
|
||
return quelle
|
||
}
|
||
|
||
export function istAusgeblendet() {
|
||
try { return localStorage.getItem(SCHLUESSEL) === '1' } catch { return false }
|
||
}
|
||
|
||
export function merkeAusgeblendet() {
|
||
try { localStorage.setItem(SCHLUESSEL, '1') } catch { /* ohne Speicher wird der Hinweis wieder gezeigt */ }
|
||
}
|