1
This commit is contained in:
310
public/site-links-client.js
Normal file
310
public/site-links-client.js
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* 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 =
|
||||
'<div data-inapp-close style="' +
|
||||
MODAL_BACK +
|
||||
'"></div>' +
|
||||
'<div style="' +
|
||||
MODAL_PANEL +
|
||||
'">' +
|
||||
'<h3 id="inapp-modal-title" style="' +
|
||||
MODAL_TITLE +
|
||||
'"></h3>' +
|
||||
'<p id="inapp-modal-body" style="' +
|
||||
MODAL_BODY +
|
||||
'"></p>' +
|
||||
'<div style="' +
|
||||
MODAL_ACTIONS +
|
||||
'">' +
|
||||
'<button type="button" id="inapp-copy-apk" style="' +
|
||||
BTN +
|
||||
BTN_PRIMARY +
|
||||
'"></button>' +
|
||||
'<button type="button" id="inapp-try-chrome" style="' +
|
||||
BTN +
|
||||
'" hidden></button>' +
|
||||
'<button type="button" id="inapp-got-it" data-inapp-close style="' +
|
||||
BTN +
|
||||
'"></button>' +
|
||||
'</div></div>';
|
||||
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 =
|
||||
'<div data-app-soon-close style="' +
|
||||
MODAL_BACK +
|
||||
'"></div>' +
|
||||
'<div style="' +
|
||||
MODAL_PANEL +
|
||||
'">' +
|
||||
'<h3 id="app-soon-title" style="' +
|
||||
MODAL_TITLE +
|
||||
'"></h3>' +
|
||||
'<p id="app-soon-body" style="' +
|
||||
MODAL_BODY +
|
||||
'"></p>' +
|
||||
'<div style="' +
|
||||
MODAL_ACTIONS +
|
||||
'">' +
|
||||
'<button type="button" data-app-soon-close style="' +
|
||||
BTN +
|
||||
BTN_PRIMARY +
|
||||
'"></button>' +
|
||||
'</div></div>';
|
||||
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();
|
||||
})();
|
||||
@@ -3,14 +3,17 @@ import type { Translations } from '../i18n/translations'
|
||||
|
||||
export interface Props {
|
||||
t: Translations['download']
|
||||
siteLinks: Translations['siteLinks']
|
||||
}
|
||||
|
||||
const { t } = Astro.props
|
||||
const { t, siteLinks } = Astro.props
|
||||
const bgPattern = "/assets/cta-bg-pattern.svg";
|
||||
const talkproLogo = "/assets/cta-talkpro-logo.svg";
|
||||
const androidIcon = "/assets/cta-android-icon.svg";
|
||||
const appleIcon = "/assets/cta-apple-icon.svg";
|
||||
const phoneArt = "/assets/cta-phone-art.png";
|
||||
const defaultApkHref = "https://talkspro.xyz/download";
|
||||
const siteLinksJson = JSON.stringify(siteLinks);
|
||||
---
|
||||
|
||||
<section id="download" class="download-cta">
|
||||
@@ -35,7 +38,12 @@ const phoneArt = "/assets/cta-phone-art.png";
|
||||
</div>
|
||||
|
||||
<div class="store-badges">
|
||||
<div class="store-badge store-badge--android">
|
||||
<a
|
||||
class="store-badge store-badge--android store-badge--browser"
|
||||
href={defaultApkHref}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<div class="store-badge__icon-frame">
|
||||
<img alt={t.androidAlt} class="store-badge__android-icon" src={androidIcon} />
|
||||
</div>
|
||||
@@ -43,8 +51,12 @@ const phoneArt = "/assets/cta-phone-art.png";
|
||||
<p class="store-badge__platform">{t.android}</p>
|
||||
<p class="store-badge__label">{t.androidCta}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="store-badge store-badge--ios">
|
||||
</a>
|
||||
<a
|
||||
class="store-badge store-badge--ios store-badge--apple"
|
||||
href="#"
|
||||
data-app-soon="1"
|
||||
>
|
||||
<div class="store-badge__icon-frame">
|
||||
<img alt={t.appleAlt} class="store-badge__apple-icon" src={appleIcon} />
|
||||
</div>
|
||||
@@ -52,8 +64,13 @@ const phoneArt = "/assets/cta-phone-art.png";
|
||||
<p class="store-badge__platform">{t.ios}</p>
|
||||
<p class="store-badge__label">{t.iosCta}</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
id="site-links-meta"
|
||||
class="download-cta__links-meta"
|
||||
hidden
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="download-cta__phone">
|
||||
@@ -63,3 +80,5 @@ const phoneArt = "/assets/cta-phone-art.png";
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script type="application/json" id="site-links-i18n" set:html={siteLinksJson} />
|
||||
|
||||
@@ -11,6 +11,7 @@ const heroBg = "/assets/hero-bg.png";
|
||||
const phoneMockup = "/assets/hero-phone.png";
|
||||
const androidIcon = "/assets/cta-android-icon.svg";
|
||||
const appleIcon = "/assets/cta-apple-icon.svg";
|
||||
const defaultApkHref = "https://talkspro.xyz/download";
|
||||
---
|
||||
|
||||
<section id="hero" class="hero">
|
||||
@@ -39,7 +40,12 @@ const appleIcon = "/assets/cta-apple-icon.svg";
|
||||
{t.description}
|
||||
</p>
|
||||
<div class="hero__actions">
|
||||
<a href="#download" class="store-badge store-badge--android hero__store-badge">
|
||||
<a
|
||||
href={defaultApkHref}
|
||||
class="store-badge store-badge--android store-badge--browser hero__store-badge"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<div class="store-badge__icon-frame">
|
||||
<img alt={download.androidAlt} class="store-badge__android-icon" src={androidIcon} />
|
||||
</div>
|
||||
@@ -48,7 +54,11 @@ const appleIcon = "/assets/cta-apple-icon.svg";
|
||||
<p class="store-badge__label">{download.androidCta}</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#download" class="store-badge store-badge--ios hero__store-badge">
|
||||
<a
|
||||
href="#"
|
||||
class="store-badge store-badge--ios store-badge--apple hero__store-badge"
|
||||
data-app-soon="1"
|
||||
>
|
||||
<div class="store-badge__icon-frame">
|
||||
<img alt={download.appleAlt} class="store-badge__apple-icon" src={appleIcon} />
|
||||
</div>
|
||||
|
||||
@@ -281,6 +281,23 @@ export const translations = {
|
||||
appleAlt: "Apple",
|
||||
phoneAlt: "TalkPro on phone",
|
||||
},
|
||||
siteLinks: {
|
||||
linksMetaPrefix: "Store links file updated: ",
|
||||
linksMetaSuffix: " (GMT+8)",
|
||||
inapp_browser_title: "Open in your system browser",
|
||||
inapp_browser_body:
|
||||
"This page is opened inside an <strong>in-app browser</strong>. To download the APK, tap the <strong>menu (··· or ⋮)</strong> in the upper corner, then choose <strong>Open in default browser</strong>, <strong>Open in Safari</strong>, or <strong>Open in Chrome</strong>. Return here and tap the Android badge again—or paste the link you copied.",
|
||||
inapp_browser_body_ios:
|
||||
"You’re in <strong>WeChat’s built-in browser</strong> on iPhone or iPad. Apple and WeChat <strong>do not allow</strong> a website to jump to Safari automatically—this is normal. Tap <strong>···</strong> (top right) → <strong>Open in Safari</strong> or <strong>Open in default browser</strong>, then tap the Android badge again, or use <strong>Copy download link</strong> and paste it in Safari.",
|
||||
inapp_browser_copy: "Copy download link",
|
||||
inapp_browser_copied: "Copied",
|
||||
inapp_browser_got_it: "OK",
|
||||
inapp_browser_try_chrome: "Try opening in Chrome (Android)",
|
||||
app_store_soon_title: "Coming soon",
|
||||
app_store_soon_body:
|
||||
"The <strong>App Store</strong> download is still in development and is <strong>not available</strong> yet. Please use the <strong>Android</strong> download for now.",
|
||||
app_store_soon_ok: "OK",
|
||||
},
|
||||
footer: {
|
||||
logoAlt: "TalkPro",
|
||||
description:
|
||||
@@ -536,6 +553,23 @@ export const translations = {
|
||||
appleAlt: "Apple",
|
||||
phoneAlt: "手机上的 TalkPro",
|
||||
},
|
||||
siteLinks: {
|
||||
linksMetaPrefix: "Store links file updated: ",
|
||||
linksMetaSuffix: " (GMT+8)",
|
||||
inapp_browser_title: "请在系统浏览器中打开",
|
||||
inapp_browser_body:
|
||||
"当前页面在<strong>应用内置浏览器</strong>中打开,无法可靠下载 APK。请点击右上角<strong>「···」或「⋮」</strong>菜单,选择<strong>「在浏览器打开」「用默认浏览器打开」「在 Safari 打开」</strong>或<strong>「在 Chrome 打开」</strong>,在系统浏览器中再次点击 Android 徽章;或使用下方按钮<strong>复制链接</strong>,粘贴到系统浏览器地址栏打开。",
|
||||
inapp_browser_body_ios:
|
||||
"您正在 iPhone/iPad 的<strong>微信内置浏览器</strong>中。微信与 iOS <strong>不允许</strong>网页自动跳转到系统 Safari,这是系统限制,不是网站故障。请点击右上角<strong>「···」</strong>,选择<strong>「在 Safari 中打开」</strong>或<strong>「在默认浏览器中打开」</strong>,再在 Safari 里点 Android 徽章;或先<strong>复制下载链接</strong>,到 Safari 地址栏粘贴打开。",
|
||||
inapp_browser_copy: "复制下载链接",
|
||||
inapp_browser_copied: "已复制",
|
||||
inapp_browser_got_it: "知道了",
|
||||
inapp_browser_try_chrome: "尝试用 Chrome 打开(Android)",
|
||||
app_store_soon_title: "开发中",
|
||||
app_store_soon_body:
|
||||
"<strong>App Store</strong> 下载尚在开发与上架准备中,<strong>暂时未开放</strong>。请先使用 <strong>Android</strong> 下载。带来不便敬请谅解。",
|
||||
app_store_soon_ok: "知道了",
|
||||
},
|
||||
footer: {
|
||||
logoAlt: "TalkPro",
|
||||
description:
|
||||
@@ -699,6 +733,23 @@ export const translations = {
|
||||
appleAlt: "Apple",
|
||||
phoneAlt: "手機上的 TalkPro",
|
||||
},
|
||||
siteLinks: {
|
||||
linksMetaPrefix: "Store links file updated: ",
|
||||
linksMetaSuffix: " (GMT+8)",
|
||||
inapp_browser_title: "請在系統瀏覽器中開啟",
|
||||
inapp_browser_body:
|
||||
"目前頁面在<strong>應用程式內建瀏覽器</strong>中開啟,無法可靠下載 APK。請點選右上角<strong>「···」或「⋮」</strong>選單,選擇<strong>「在瀏覽器開啟」「用預設瀏覽器開啟」「在 Safari 開啟」</strong>或<strong>「在 Chrome 開啟」</strong>,在系統瀏覽器中再次點選 Android 徽章;或使用下方按鈕<strong>複製連結</strong>,貼到系統瀏覽器網址列開啟。",
|
||||
inapp_browser_body_ios:
|
||||
"您正在 iPhone/iPad 的<strong>微信內建瀏覽器</strong>中。微信與 iOS <strong>不允許</strong>網頁自動跳轉到系統 Safari,這是系統限制,不是網站故障。請點選右上角<strong>「···」</strong>,選擇<strong>「在 Safari 中開啟」</strong>或<strong>「在預設瀏覽器中開啟」</strong>,再在 Safari 裡點 Android 徽章;或先<strong>複製下載連結</strong>,到 Safari 網址列貼上開啟。",
|
||||
inapp_browser_copy: "複製下載連結",
|
||||
inapp_browser_copied: "已複製",
|
||||
inapp_browser_got_it: "知道了",
|
||||
inapp_browser_try_chrome: "嘗試用 Chrome 開啟(Android)",
|
||||
app_store_soon_title: "開發中",
|
||||
app_store_soon_body:
|
||||
"<strong>App Store</strong> 下載尚在開發與上架準備中,<strong>暫時未開放</strong>。請先使用 <strong>Android</strong> 下載。造成不便敬請見諒。",
|
||||
app_store_soon_ok: "知道了",
|
||||
},
|
||||
footer: {
|
||||
logoAlt: "TalkPro",
|
||||
description:
|
||||
|
||||
@@ -27,6 +27,7 @@ const {
|
||||
</head>
|
||||
<body class="bg-surface font-sans overflow-x-hidden">
|
||||
<slot />
|
||||
<script src="/site-links-client.js" defer></script>
|
||||
<script>
|
||||
(() => {
|
||||
const header = document.getElementById('site-header');
|
||||
|
||||
@@ -31,6 +31,6 @@ const t = getTranslations(lang)
|
||||
<UseCases t={t.useCases} />
|
||||
<Trust t={t.trust} />
|
||||
<!-- AppPreview section disabled per lead request. -->
|
||||
<DownloadCTA t={t.download} />
|
||||
<DownloadCTA t={t.download} siteLinks={t.siteLinks} />
|
||||
<Footer t={t.footer} />
|
||||
</Base>
|
||||
|
||||
@@ -24,6 +24,6 @@ const t = getTranslations(lang)
|
||||
<UseCases t={t.useCases} />
|
||||
<Trust t={t.trust} />
|
||||
<!-- AppPreview section disabled per lead request. -->
|
||||
<DownloadCTA t={t.download} />
|
||||
<DownloadCTA t={t.download} siteLinks={t.siteLinks} />
|
||||
<Footer t={t.footer} />
|
||||
</Base>
|
||||
|
||||
@@ -129,6 +129,21 @@
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
a.store-badge {
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.download-cta__links-meta {
|
||||
font-size: 13px;
|
||||
color: #7a726d;
|
||||
margin: 14px auto 0;
|
||||
max-width: min(1180px, calc(100% - 40px));
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.store-badge--android {
|
||||
background: #f28a4b;
|
||||
border: 1px solid #c5834e;
|
||||
|
||||
Reference in New Issue
Block a user