diff --git a/.changeset/viewport-qa-layout-hotfix.md b/.changeset/viewport-qa-layout-hotfix.md new file mode 100644 index 000000000..b38f6f2ca --- /dev/null +++ b/.changeset/viewport-qa-layout-hotfix.md @@ -0,0 +1,5 @@ +--- +'@app/ratewise': patch +--- + +修復 360×800 與 320×568 裝置上 CTA 與 bottom nav 重疊、匯率文字與 RateSelector 重疊,以及加入歷史按鈕觸控目標不足 44px 的問題 diff --git a/apps/ratewise/src/components/AppLayout.tsx b/apps/ratewise/src/components/AppLayout.tsx index b34238642..a85ec2c6f 100644 --- a/apps/ratewise/src/components/AppLayout.tsx +++ b/apps/ratewise/src/components/AppLayout.tsx @@ -232,7 +232,7 @@ export function AppLayout() { ref={mainRef} data-scroll-container="main" tabIndex={0} - className="flex-1 min-h-0 min-w-0 w-full relative overflow-y-auto overflow-x-hidden pb-[calc(56px+env(safe-area-inset-bottom,0px))] md:pb-0 [-webkit-overflow-scrolling:touch] overscroll-y-contain" + className={`flex-1 min-h-0 min-w-0 w-full relative overflow-y-auto overflow-x-hidden ${navigationTokens.mainScroll.paddingBottomClass} [-webkit-overflow-scrolling:touch] overscroll-y-contain`} > { expect(screen.getByRole('main')).toHaveAttribute('tabindex', '0'); }); + + it('主要滾動區域應保留 bottom nav 留白並含 narrow 360px 加值', () => { + render( + + + }> + 內容} /> + + + , + ); + + const main = screen.getByRole('main'); + expect(main.className).toContain(navigationTokens.mainScroll.paddingBottomClass); + }); }); diff --git a/apps/ratewise/src/config/design-tokens.test.ts b/apps/ratewise/src/config/design-tokens.test.ts index 20e166a23..445764cda 100644 --- a/apps/ratewise/src/config/design-tokens.test.ts +++ b/apps/ratewise/src/config/design-tokens.test.ts @@ -266,6 +266,22 @@ describe('Design Token System - BDD', () => { expect(singleConverterLayoutTokens.rateCard.chartHeight).toContain('compact:h-16'); expect(singleConverterLayoutTokens.rateCard.rateTypeContainer).toContain('absolute'); expect(singleConverterLayoutTokens.rateCard.rateTypeButton).toContain('px-'); + expect(singleConverterLayoutTokens.rateCard.infoPadding).toContain('micro:pt-10'); + expect(singleConverterLayoutTokens.rateCard.infoPadding).toContain('nano:pt-10'); + expect(singleConverterLayoutTokens.addToHistory.className).toContain('micro:min-h-11'); + expect(singleConverterLayoutTokens.addToHistory.className).toContain('nano:min-h-11'); + }); + }); + + describe('🟢 GREEN: 導覽 main 滾動留白 Token', () => { + it('應該導出 narrow 360px 額外 bottom padding', async () => { + const { navigationTokens } = await import('./design-tokens'); + + expect(navigationTokens.mainScroll.paddingBottomClass).toContain( + 'pb-[calc(56px+env(safe-area-inset-bottom,0px))]', + ); + expect(navigationTokens.mainScroll.paddingBottomClass).toContain('max-[360px]:pb-[calc(84px'); + expect(navigationTokens.mainScroll.paddingBottomClass).toContain('md:pb-0'); }); }); diff --git a/apps/ratewise/src/config/design-tokens.ts b/apps/ratewise/src/config/design-tokens.ts index dd93f1086..ce57548c8 100644 --- a/apps/ratewise/src/config/design-tokens.ts +++ b/apps/ratewise/src/config/design-tokens.ts @@ -475,6 +475,15 @@ export const navigationTokens = { bottom: 'pb-safe-bottom', }, }, + + /** + * 行動版 main 滾動區底部留白(fixed bottom nav 上方可捲動空間) + * narrow 額外 +28px:Galaxy S21 360×800 QA 曾見 CTA 與 bottom nav 重疊 + */ + mainScroll: { + paddingBottomClass: + 'pb-[calc(56px+env(safe-area-inset-bottom,0px))] max-[360px]:pb-[calc(84px+env(safe-area-inset-bottom,0px))] md:pb-0', + }, } as const; /** @@ -689,9 +698,9 @@ export const singleConverterLayoutTokens = { /** 卡片底部間距 */ cardSpacing: 'mb-3 compact:mb-2.5 short:mb-2 tiny:mb-1.5 micro:mb-1.5 nano:mb-1', - /** 匯率資訊區內距 - 保持充足空間感 */ + /** 匯率資訊區內距 - micro/nano 頂部 ≥40px,避免 RateSelector 與匯率文字重疊 */ infoPadding: - 'pt-12 pb-6 compact:pt-10 compact:pb-5 short:pt-8 short:pb-4 tiny:pt-6 tiny:pb-3 micro:pt-5 micro:pb-2.5 nano:pt-4 nano:pb-2', + 'pt-12 pb-6 compact:pt-10 compact:pb-5 short:pt-8 short:pb-4 tiny:pt-6 tiny:pb-3 micro:pt-10 micro:pb-2.5 nano:pt-10 nano:pb-2', /** 匯率類型按鈕容器定位 */ rateTypeContainer: @@ -778,9 +787,10 @@ export const singleConverterLayoutTokens = { glowHidden: 'short:hidden', }, - /** 加入歷史按鈕 - 線性縮減 */ + /** 加入歷史按鈕 - micro/nano 維持 WCAG 44px 最小觸控高度 */ addToHistory: { - className: 'py-3.5 compact:py-3 short:py-2.5 tiny:py-2 micro:py-1.5 nano:py-1.5', + className: + 'py-3.5 compact:py-3 short:py-2.5 tiny:py-2 micro:min-h-11 micro:py-2 nano:min-h-11 nano:py-2', }, } as const; diff --git a/docs/dev/002_development_reward_penalty_log.md b/docs/dev/002_development_reward_penalty_log.md index a855d3447..d36628b55 100644 --- a/docs/dev/002_development_reward_penalty_log.md +++ b/docs/dev/002_development_reward_penalty_log.md @@ -2,7 +2,7 @@ > 版本:outline-v2-ultra > 原則:每筆只保留日期、ID、原因、解法。 -> 本次分數變化:+1(reward 1、penalty 0、neutral 0)|累計總分:+80 +> 本次分數變化:+1(reward 1、penalty 0、neutral 0)|累計總分:+81 ## 新增模板(4 行) @@ -13,6 +13,11 @@ ## 條目(新→舊) +- 日期:2026-06-28 +- ID:reward-viewport-qa-layout-hotfix +- 原因:10 裝置 QA 矩陣在 Galaxy S21 360×800 與 iPhone SE 320×568 出現 CTA 與 bottom nav 重疊、匯率文字蓋住 RateSelector、CTA 觸控高度僅 38px +- 解法:design-tokens SSOT 調整 infoPadding/addToHistory min-h-11,AppLayout narrow 360px 額外 bottom padding +28px + - 日期:2026-06-28 - ID:reward-pwa-https-cold-start-manifest-regression - 原因:#447 已改絕對 HTTPS start_url,但 SW seo-files-cache 以 SWR 快取舊 manifest(相對 start_url),冷啟動仍觸發 HTTPS-First 警告