diff --git a/web/website/src/components/Download.astro b/web/website/src/components/Download.astro
index c8fdaf4..aaacdc3 100644
--- a/web/website/src/components/Download.astro
+++ b/web/website/src/components/Download.astro
@@ -7,11 +7,17 @@ interface Props { t: T }
const { t } = Astro.props;
// href 缺省 = 未接入下载 → 禁用「敬请期待」占位。
-// iOS/iPad 目前仅「测试版」(TestFlight 公开链接,需美区 Apple ID);「正式版」(App Store)敬请期待。
-const plats: { icon: string; name: string; ver: string; href?: string; badge?: string; note?: string }[] = [
- { icon: 'smartphone', name: 'iOS', ver: 'iOS 15+', href: SITE.downloads.ios, badge: t('dl.beta'), note: t('dl.us_id') },
- { icon: 'tablet', name: 'iPad', ver: 'iPadOS 15+', href: SITE.downloads.ios, badge: t('dl.beta'), note: t('dl.us_id') },
- { icon: 'smartphone', name: 'iOS / iPad', ver: 'App Store', badge: t('dl.stable') },
+// iOS/iPad 合成一张卡、两个按钮:「测试版」(TestFlight 公开链接) 现已可装,
+// 「正式版」(App Store) 禁用,按钮内带「?」——悬浮提示「美区即将上线,需美区 Apple ID」。
+type Action = { label: string; href?: string; hint?: string };
+const plats: { icon: string; name: string; ver: string; href?: string; badge?: string; note?: string; actions?: Action[] }[] = [
+ {
+ icon: 'smartphone', name: 'iOS / iPad', ver: 'iOS / iPadOS 15+',
+ actions: [
+ { label: t('dl.beta'), href: SITE.downloads.ios },
+ { label: t('dl.stable'), hint: `${t('dl.us_soon')} · ${t('dl.us_id')}` },
+ ],
+ },
{ icon: 'smartphone', name: 'Android', ver: 'Android 9+', href: SITE.downloads.android },
{ icon: 'laptop', name: 'macOS', ver: 'macOS 12+', href: SITE.downloads.macos },
{ icon: 'monitor', name: 'Windows', ver: 'Win 10/11', href: SITE.downloads.windows },
@@ -35,7 +41,24 @@ const plats: { icon: string; name: string; ver: string; href?: string; badge?: s
{p.note && ?}
{p.ver}
- {p.href ? (
+ {p.actions ? (
+
+ {p.actions.map((a) => (
+ a.href ? (
+
{a.label}
+ ) : (
+
+ {a.label}
+ {a.hint && (
+
+ ?{a.hint}
+
+ )}
+
+ )
+ ))}
+
+ ) : p.href ? (
{t('dl.get')}
) : (
{t('dl.soon')}
@@ -56,9 +79,45 @@ const plats: { icon: string; name: string; ver: string; href?: string; badge?: s
font-family: var(--font-mono); letter-spacing: .02em;
}
.dl .q {
+ position: relative;
display: inline-flex; align-items: center; justify-content: center;
width: 16px; height: 16px; border-radius: 50%;
- font-size: 11px; font-weight: 700; cursor: help;
+ font-size: 11px; font-weight: 700; cursor: default;
background: var(--bg-subtle); color: var(--fg3);
}
+ /* 自定义提示气泡:走设计 token,悬浮/聚焦「?」时上浮显示,带小箭头。 */
+ .dl .q .tip {
+ position: absolute; bottom: calc(100% + 9px); left: 50%;
+ transform: translateX(-50%) translateY(4px);
+ width: max-content; max-width: 210px; white-space: normal;
+ padding: 8px 11px; border-radius: var(--radius-md, 10px);
+ background: var(--fg1); color: var(--bg);
+ font-family: var(--font-sans); font-size: 12px; font-weight: 500;
+ line-height: 1.45; text-align: center; letter-spacing: 0;
+ box-shadow: var(--shadow-md, 0 6px 20px rgba(45,30,20,.18));
+ opacity: 0; visibility: hidden; pointer-events: none; z-index: 20;
+ transition: opacity var(--dur-base, .18s) var(--ease-out, ease),
+ transform var(--dur-base, .18s) var(--ease-out, ease),
+ visibility var(--dur-base, .18s);
+ }
+ .dl .q .tip::after {
+ content: ""; position: absolute; top: 100%; left: 50%;
+ transform: translateX(-50%);
+ border: 5px solid transparent; border-top-color: var(--fg1);
+ }
+ .dl .q:hover .tip, .dl .q:focus-visible .tip {
+ opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0);
+ }
+ /* iOS/iPad 单卡双按钮:测试版(实心 accent 可点)+ 正式版(描边禁用,内含「?」悬浮提示)。 */
+ .dl .btns { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 2px; }
+ .dl .b2 {
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px;
+ padding: 8px 15px; border-radius: 999px; line-height: 1.15;
+ font-size: 13px; font-weight: 600; text-decoration: none;
+ border: 1px solid var(--accent); color: var(--accent);
+ }
+ .dl .b2.beta { background: var(--accent); color: var(--fg-on-accent); border-color: var(--accent); }
+ /* 禁用态:不导航(本就是 span)+ 默认光标,但不禁用指针事件——否则内含「?」的 title 悬浮失效。 */
+ .dl .b2.disabled { border-color: var(--border); color: var(--fg3); cursor: default; }
+ .dl .b2 .q { background: transparent; border: 1px solid var(--border); }
diff --git a/web/website/src/i18n/strings.ts b/web/website/src/i18n/strings.ts
index bc25a9a..ffb4ba2 100644
--- a/web/website/src/i18n/strings.ts
+++ b/web/website/src/i18n/strings.ts
@@ -140,6 +140,7 @@ export const STRINGS: Record> = {
'dl.beta': { zh: '测试版', en: 'Beta', ja: 'ベータ版', ko: '베타', ru: 'Бета', es: 'Beta' },
'dl.stable': { zh: '正式版', en: 'Stable', ja: '正式版', ko: '정식판', ru: 'Релиз', es: 'Estable' },
'dl.us_id': { zh: '需美区 Apple ID', en: 'Requires a US Apple ID', ja: '米国 Apple ID が必要', ko: '미국 Apple ID 필요', ru: 'Нужен Apple ID (США)', es: 'Requiere un Apple ID de EE. UU.' },
+ 'dl.us_soon': { zh: '美区即将上线', en: 'Coming to US App Store', ja: '米国 App Store で近日公開', ko: '미국 App Store 출시 예정', ru: 'Скоро в App Store (США)', es: 'Pronto en App Store (EE. UU.)' },
'docs.eyebrow': { zh: '文档', en: 'Docs', ja: 'ドキュメント', ko: '문서', ru: 'Документация', es: 'Documentación' },
'docs.h': { zh: '需要帮助?都在这里', en: 'Need help? It’s all here', ja: 'お困りですか?すべてここに', ko: '도움이 필요하세요? 모두 여기에', ru: 'Нужна помощь? Всё здесь', es: '¿Necesitas ayuda? Todo está aquí' },