/** * Mirrors talkpro static site: /api/site-links, APK default, in-app + App Store modals. * Strings come from #site-links-i18n (JSON) rendered by DownloadCTA.astro. */ (function () { const DEFAULT_APK = 'https://talkspro.xyz/download'; let apkDownloadUrl = DEFAULT_APK; function getApkDownloadUrl() { return apkDownloadUrl; } function getI18n() { const el = document.getElementById('site-links-i18n'); if (!el || !el.textContent.trim()) return {}; try { return JSON.parse(el.textContent); } catch { return {}; } } function detectInAppBrowser() { const ua = navigator.userAgent || ''; if (/MicroMessenger/i.test(ua)) return 'wechat'; try { if (typeof window.WeixinJSBridge !== 'undefined') return 'wechat'; } catch { /* ignore */ } if (/QQ\//i.test(ua) && /MQQBrowser/i.test(ua)) return 'qq'; if (/Weibo/i.test(ua)) return 'weibo'; return ''; } function isIOSDevice() { const ua = navigator.userAgent || ''; if (/iPhone|iPad|iPod/i.test(ua)) return true; if (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) return true; return false; } function isAndroidDevice() { const ua = navigator.userAgent || ''; return /Android/i.test(ua) && !isIOSDevice(); } const MODAL_WRAP = 'position:fixed;inset:0;z-index:10050;display:flex;align-items:center;justify-content:center;padding:16px;box-sizing:border-box;'; const MODAL_BACK = 'position:absolute;inset:0;background:rgba(0,0,0,.45);cursor:pointer;'; const MODAL_PANEL = 'position:relative;max-width:420px;width:100%;margin:auto;padding:20px 22px;border-radius:12px;background:#fff;color:#1a1a1a;font:15px/1.45 system-ui,-apple-system,sans-serif;box-shadow:0 12px 40px rgba(0,0,0,.18);'; const MODAL_TITLE = 'margin:0 0 10px;font-size:18px;font-weight:700;line-height:1.25;'; const MODAL_BODY = 'margin:0 0 18px;font-size:14px;color:#444;'; const MODAL_ACTIONS = 'display:flex;flex-wrap:wrap;gap:10px;justify-content:flex-end;'; const BTN = 'cursor:pointer;border-radius:8px;padding:10px 14px;font-size:14px;font-weight:600;border:1px solid #ccc;background:#f5f5f5;color:#1a1a1a;'; const BTN_PRIMARY = 'border-color:#1a6cff;background:#1a6cff;color:#fff;'; function initInAppBrowserModal() { if (document.getElementById('inapp-browser-modal')) return; const wrap = document.createElement('div'); wrap.id = 'inapp-browser-modal'; wrap.setAttribute('role', 'dialog'); wrap.setAttribute('aria-modal', 'true'); wrap.setAttribute('aria-hidden', 'true'); wrap.style.cssText = MODAL_WRAP + 'display:none;'; wrap.innerHTML = '
' + '
' + '

' + '

' + '
' + '' + '' + '' + '
'; document.body.appendChild(wrap); const close = () => { wrap.style.display = 'none'; wrap.setAttribute('aria-hidden', 'true'); }; wrap.querySelectorAll('[data-inapp-close]').forEach((el) => { el.addEventListener('click', close); }); const i18n = () => getI18n(); document.getElementById('inapp-copy-apk').addEventListener('click', async () => { const btn = document.getElementById('inapp-copy-apk'); const dict = i18n(); const done = dict.inapp_browser_copied || 'Copied'; try { await navigator.clipboard.writeText(getApkDownloadUrl()); const prev = btn.textContent; btn.textContent = done; setTimeout(() => { btn.textContent = dict.inapp_browser_copy || prev; }, 1600); } catch { window.prompt(dict.inapp_browser_copy || 'Copy', getApkDownloadUrl()); } }); document.getElementById('inapp-try-chrome').addEventListener('click', () => { const enc = encodeURIComponent(getApkDownloadUrl()); const intent = getApkDownloadUrl().replace(/^https:/i, 'intent:') + '#Intent;' + 'scheme=https;action=android.intent.action.VIEW;category=android.intent.category.BROWSABLE;' + 'package=com.android.chrome;S.browser_fallback_url=' + enc + ';end'; window.location.href = intent; }); } function openInAppBrowserModal() { const modal = document.getElementById('inapp-browser-modal'); if (!modal) return; const dict = getI18n(); const tryChrome = modal.querySelector('#inapp-try-chrome'); const showChrome = isAndroidDevice() && !!detectInAppBrowser(); if (tryChrome) { tryChrome.hidden = !showChrome; tryChrome.setAttribute('aria-hidden', showChrome ? 'false' : 'true'); } modal.style.display = 'flex'; modal.setAttribute('aria-hidden', 'false'); const titleEl = modal.querySelector('#inapp-modal-title'); const bodyEl = modal.querySelector('#inapp-modal-body'); if (titleEl) titleEl.textContent = dict.inapp_browser_title || ''; if (bodyEl) { const iosWechat = isIOSDevice() && detectInAppBrowser() === 'wechat'; const bodyKey = iosWechat ? 'inapp_browser_body_ios' : 'inapp_browser_body'; bodyEl.innerHTML = dict[bodyKey] || dict.inapp_browser_body || ''; } const copyBtn = modal.querySelector('#inapp-copy-apk'); const gotBtn = modal.querySelector('#inapp-got-it'); if (copyBtn) copyBtn.textContent = dict.inapp_browser_copy || ''; if (tryChrome) tryChrome.textContent = dict.inapp_browser_try_chrome || ''; if (gotBtn) gotBtn.textContent = dict.inapp_browser_got_it || 'OK'; } function initAppStoreSoonModal() { if (document.getElementById('app-store-soon-modal')) return; const wrap = document.createElement('div'); wrap.id = 'app-store-soon-modal'; wrap.setAttribute('role', 'dialog'); wrap.setAttribute('aria-modal', 'true'); wrap.setAttribute('aria-hidden', 'true'); wrap.style.cssText = MODAL_WRAP + 'display:none;'; wrap.innerHTML = '
' + '
' + '

' + '

' + '
' + '' + '
'; document.body.appendChild(wrap); const close = () => { wrap.style.display = 'none'; wrap.setAttribute('aria-hidden', 'true'); }; wrap.querySelectorAll('[data-app-soon-close]').forEach((el) => { el.addEventListener('click', close); }); } function openAppStoreSoonModal() { const modal = document.getElementById('app-store-soon-modal'); if (!modal) return; const dict = getI18n(); const tEl = modal.querySelector('#app-soon-title'); const bEl = modal.querySelector('#app-soon-body'); const ok = modal.querySelector('button[data-app-soon-close]'); if (tEl) tEl.textContent = dict.app_store_soon_title || ''; if (bEl) bEl.innerHTML = dict.app_store_soon_body || ''; if (ok) ok.textContent = dict.app_store_soon_ok || 'OK'; modal.style.display = 'flex'; modal.setAttribute('aria-hidden', 'false'); } function bindBrowserDownloadLinks() { document.querySelectorAll('a.store-badge--browser').forEach((a) => { const openForInApp = (e) => { if (!detectInAppBrowser()) return; e.preventDefault(); e.stopPropagation(); openInAppBrowserModal(); }; a.addEventListener('click', openForInApp); a.addEventListener( 'touchend', (e) => { if (!detectInAppBrowser()) return; e.preventDefault(); openInAppBrowserModal(); }, { passive: false } ); }); } function bindAppStoreAppleBadges() { document.querySelectorAll('a.store-badge--apple[data-app-soon]').forEach((a) => { const stopAndOpen = (e) => { e.preventDefault(); e.stopPropagation(); openAppStoreSoonModal(); }; a.addEventListener('click', stopAndOpen); a.addEventListener( 'touchend', (e) => { e.preventDefault(); e.stopPropagation(); openAppStoreSoonModal(); }, { passive: false } ); }); } function loadSiteLinksThenBind() { if (window.location.protocol === 'file:') { bindBrowserDownloadLinks(); bindAppStoreAppleBadges(); return; } fetch('/api/site-links', { credentials: 'same-origin' }) .then((r) => { if (!r.ok) throw new Error('bad status'); return r.json(); }) .then((j) => { const apk = String(j.apk_download_url || '').trim(); const ios = String(j.app_store_url || '').trim(); if (apk.startsWith('https://')) apkDownloadUrl = apk; document.querySelectorAll('a.store-badge--browser').forEach((a) => { if (apk.startsWith('https://')) a.setAttribute('href', apk); }); document.querySelectorAll('a.store-badge--apple').forEach((a) => { if (ios.startsWith('https://')) { a.setAttribute('href', ios); a.removeAttribute('data-app-soon'); a.setAttribute('rel', 'noopener noreferrer'); a.setAttribute('target', '_blank'); } }); const meta = document.getElementById('site-links-meta'); if (meta) { const dict = getI18n(); const u = String(j.updated_at || '').trim(); if (u) { meta.textContent = (dict.linksMetaPrefix || 'Store links file updated: ') + u + (dict.linksMetaSuffix || ' (GMT+8)'); meta.hidden = false; } else { meta.hidden = true; } } }) .catch(() => { /* keep defaults */ }) .finally(() => { bindBrowserDownloadLinks(); bindAppStoreAppleBadges(); }); } initInAppBrowserModal(); initAppStoreSoonModal(); loadSiteLinksThenBind(); })();