Skip to content

apps/mobile UI 全面對齊 apps/web 窄螢幕樣式#14

Merged
Retsomm merged 2 commits into
mainfrom
dev
Jul 13, 2026
Merged

apps/mobile UI 全面對齊 apps/web 窄螢幕樣式#14
Retsomm merged 2 commits into
mainfrom
dev

Conversation

@Retsomm

@Retsomm Retsomm commented Jul 13, 2026

Copy link
Copy Markdown
Owner

新增共用設計系統(constants/theme.ts、NotchedView 缺角卡片、Button/XpBar/TabBarButton 元件)、載入 JetBrains Mono/Noto Sans TC 字型,逐畫面(Home/ChapterMap/Quiz/ QuestionCard/QuestionReview/CodeBlock/Notes/QuestionBook/Stats/Profile)比照網頁版 index.css 重寫顏色、字型、間距與底部 tab bar 樣式。成長史從卡片內展開改成彈窗顯示。

修復過程中一併解決:Profile 頁誤用 Themed View 導致卡片內出現蓋色黑底、捲動時內容與 系統狀態列重疊、成長史彈窗在 iOS 上無法捲動且會誤觸關閉(背景 Pressable 與卡片本體
改成手足關係,卡片內完全不使用 Pressable 包住 ScrollView)。使用者已在 iOS/Android 模擬器實測確認。

Summary by CodeRabbit

  • New Features

    • Added a refreshed mobile interface with consistent colors, typography, buttons, notched cards, icons, and progress bars.
    • Improved tab navigation with clearer active-state styling and safe-area support.
    • Added syntax highlighting to code examples.
    • Enhanced quiz, review, notes, chapter, home, and statistics screens with updated visuals and feedback.
    • Added improved profile growth-history display, statistics layout, and account controls.
  • Bug Fixes

    • Improved loading indicators and growth-history modal sizing, scrolling, and interaction behavior.

新增共用設計系統(constants/theme.ts、NotchedView 缺角卡片、Button/XpBar/TabBarButton
元件)、載入 JetBrains Mono/Noto Sans TC 字型,逐畫面(Home/ChapterMap/Quiz/
QuestionCard/QuestionReview/CodeBlock/Notes/QuestionBook/Stats/Profile)比照網頁版
index.css 重寫顏色、字型、間距與底部 tab bar 樣式。成長史從卡片內展開改成彈窗顯示。

修復過程中一併解決:Profile 頁誤用 Themed View 導致卡片內出現蓋色黑底、捲動時內容與
系統狀態列重疊、成長史彈窗在 iOS 上無法捲動且會誤觸關閉(背景 Pressable 與卡片本體
改成手足關係,卡片內完全不使用 Pressable 包住 ScrollView)。使用者已在 iOS/Android
模擬器實測確認。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
easy-learn Ready Ready Preview, Comment Jul 13, 2026 9:22am

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Retsomm, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d2ef69f9-a6b2-44c6-af60-f44f40e63578

📥 Commits

Reviewing files that changed from the base of the PR and between d93eb09 and 690f6d1.

📒 Files selected for processing (7)
  • apps/mobile/components/AccountHeader.tsx
  • apps/mobile/components/Icon.tsx
  • apps/mobile/components/NotchedView.tsx
  • apps/mobile/components/TabBarButton.tsx
  • apps/mobile/screens/ChapterMap.tsx
  • apps/mobile/screens/Stats.tsx
  • docs/rn-migration.md
📝 Walkthrough

Walkthrough

The mobile app adopts a shared theme and font system, adds reusable buttons, notched surfaces, icons, and XP bars, and updates navigation, profile, learning, quiz, statistics, and question-management screens to use the redesigned UI.

Changes

Mobile UI migration

Layer / File(s) Summary
Theme and reusable UI foundation
apps/mobile/constants/*, apps/mobile/components/Button.tsx, apps/mobile/components/NotchedView.tsx, apps/mobile/components/XpBar.tsx, apps/mobile/components/TabBarButton.tsx, apps/mobile/app/_layout.tsx, apps/mobile/package.json
Adds shared colors, fonts, layout constants, Google Font loading, reusable buttons, notched SVG surfaces, XP bars, and custom tab controls.
Shared content component updates
apps/mobile/components/AccountHeader.tsx, CodeBlock.tsx, GrowthHistory.tsx, Mascot.tsx, QuestionCard.tsx
Applies the theme to shared components, adds syntax highlighting, and replaces inline progress and action controls with reusable components.
Navigation and profile flow
apps/mobile/app/(tabs)/*, apps/mobile/app/(tabs)/_layout.tsx
Updates tab icons, tab styling, loading indicators, profile actions, statistics layout, and the growth-history overlay behavior.
Learning screen redesigns
apps/mobile/screens/{Home,ChapterMap,Notes,QuestionBook,QuestionReview,Quiz}.tsx
Updates learning cards, buttons, question states, chapter visuals, quiz results, and typography using theme tokens and shared components.
Stats behavior and migration record
apps/mobile/screens/Stats.tsx, docs/rn-migration.md
Replaces chart colors with theme values, improves heatmap scrolling timing, and documents the Phase 7 migration and modal/native-dependency changes.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: aligning apps/mobile UI with apps/web narrow-screen styles.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (4)
apps/mobile/screens/Stats.tsx (2)

326-326: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use colors.optionBorder instead of hardcoded 'rgba(95, 240, 224, 0.18)'.

Three style definitions use the literal 'rgba(95, 240, 224, 0.18)' which is exactly colors.optionBorder in theme.ts. Replacing them with the token keeps the migration consistent and avoids drift if the web value changes.

♻️ Proposed fix
 // Line 326 — heatmapCard
-    borderColor: 'rgba(95, 240, 224, 0.18)',
+    borderColor: colors.optionBorder,

 // Line 395 — miniChartPair
-    borderColor: 'rgba(95, 240, 224, 0.18)',
+    borderColor: colors.optionBorder,

 // Line 458 — chapterCard
-    borderColor: 'rgba(95, 240, 224, 0.18)',
+    borderColor: colors.optionBorder,

Also applies to: 395-395, 458-458

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/mobile/screens/Stats.tsx` at line 326, Replace the hardcoded rgba border
color in all three affected style definitions with the existing
colors.optionBorder theme token, including the occurrences near the referenced
styles. Preserve the surrounding style properties unchanged.

289-289: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding theme tokens for remaining hardcoded cyan/primary opacity values.

tileLabel (line 289), tileWideLabel (line 294), and sectionTitle (line 313) use hardcoded rgba(95, 240, 224, …) / rgba(255, 180, 84, …) strings at specific opacities that don't map to existing theme.ts tokens. If these are deliberate one-off values, a brief inline comment would clarify intent; if they recur elsewhere, adding tokens (e.g. cyanFaint, primaryFaint) would prevent future drift.

Also applies to: 294-294, 313-313

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/mobile/screens/Stats.tsx` at line 289, Update the Stats styling for
tileLabel, tileWideLabel, and sectionTitle to avoid unexplained hardcoded
cyan/primary opacity values: reuse shared theme tokens if equivalent values
exist, or add appropriately named tokens such as cyanFaint and primaryFaint in
theme.ts and reference them. If these remain deliberate one-off values, add
concise inline comments documenting their intent.
docs/rn-migration.md (1)

515-522: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a language specifier to the fenced code block.

The code block showing the modal structure lacks a language tag, which triggers markdownlint MD040 and prevents syntax highlighting in renderers.

♻️ Proposed fix
-    ```
+    ```tsx
     <View modalRoot>                         {/* 純容器,不接觸控 */}
       <Pressable modalBackdrop onPress={close} />  {/* 鋪滿全螢幕,負責變暗+點擊關閉 */}
       <View modalCardWrap pointerEvents="box-none">  {/* 鋪滿全螢幕、flex-end 對齊,
                                                             自己不接觸控只負責排版 */}
         <View modalCard>...header/ScrollView...</View>
       </View>
     </View>
     ```
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/rn-migration.md` around lines 515 - 522, Update the fenced code block
containing the modal structure in the migration documentation to specify the TSX
language, using the ```tsx fence while preserving the example content unchanged.

Source: Linters/SAST tools

apps/mobile/screens/ChapterMap.tsx (1)

8-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid the unsafe cast; narrow the type instead.

STATUS_COLOR is cast to Record<IconName, string> but only covers 3 of the ~28 IconName values. It's safe today because statusIcon (Line 40) is only ever one of those 3, but the cast removes TypeScript's ability to catch a future mismatch between the two.

♻️ Proposed narrowing
-const STATUS_COLOR: Record<IconName, string> = {
+type LevelStatusIcon = 'lock' | 'check-circle' | 'play';
+
+const STATUS_COLOR: Record<LevelStatusIcon, string> = {
   lock: colors.locked,
   'check-circle': colors.cyan,
   play: colors.primary,
-} as Record<IconName, string>;
+};

And at the usage site:

-        const statusIcon: IconName = locked ? 'lock' : record ? 'check-circle' : 'play';
+        const statusIcon: LevelStatusIcon = locked ? 'lock' : record ? 'check-circle' : 'play';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/mobile/screens/ChapterMap.tsx` around lines 8 - 12, Replace the unsafe
full Record<IconName, string> cast on STATUS_COLOR with a narrowed type that
requires only the three mapped icon keys. Update the statusIcon usage to use
that narrowed key type so TypeScript preserves mismatch detection if the allowed
status icons change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/mobile/components/AccountHeader.tsx`:
- Around line 376-378: Update the name input style near the fontFamily
declaration to remove the conflicting fontWeight value and rely on
fonts.sans.medium, or use fonts.sans.bold if the intended weight is 700. Keep
the font size and other styling unchanged.

In `@apps/mobile/components/Icon.tsx`:
- Around line 79-87: Update the Icon component’s destructuring to default the
fill prop to "none", ensuring omitted fill values are forwarded explicitly as
none to the selected ICONS[name] component while preserving caller-provided
fills.

In `@apps/mobile/components/NotchedView.tsx`:
- Around line 11-32: Update buildPoints and the surrounding SVG sizing in
NotchedView so bordered polygons do not place their stroke on the canvas edge.
Inset all vertices by the border width or expand the SVG canvas by the required
stroke margin, while preserving the existing notch geometry and ensuring
QuestionCard’s borderWidth={1} renders at full thickness.

In `@apps/mobile/components/TabBarButton.tsx`:
- Around line 13-19: Update the Pressable configuration in TabBarButton so
function-valued style props retain Pressable’s callback contract: provide a
top-level style callback, invoke style(state) when style is a function, and
combine its result with styles.base and the focused active style. Preserve
direct style values and existing rest/accessibility behavior.

---

Nitpick comments:
In `@apps/mobile/screens/ChapterMap.tsx`:
- Around line 8-12: Replace the unsafe full Record<IconName, string> cast on
STATUS_COLOR with a narrowed type that requires only the three mapped icon keys.
Update the statusIcon usage to use that narrowed key type so TypeScript
preserves mismatch detection if the allowed status icons change.

In `@apps/mobile/screens/Stats.tsx`:
- Line 326: Replace the hardcoded rgba border color in all three affected style
definitions with the existing colors.optionBorder theme token, including the
occurrences near the referenced styles. Preserve the surrounding style
properties unchanged.
- Line 289: Update the Stats styling for tileLabel, tileWideLabel, and
sectionTitle to avoid unexplained hardcoded cyan/primary opacity values: reuse
shared theme tokens if equivalent values exist, or add appropriately named
tokens such as cyanFaint and primaryFaint in theme.ts and reference them. If
these remain deliberate one-off values, add concise inline comments documenting
their intent.

In `@docs/rn-migration.md`:
- Around line 515-522: Update the fenced code block containing the modal
structure in the migration documentation to specify the TSX language, using the
```tsx fence while preserving the example content unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f6063053-5be3-4629-933f-bd388a4d2f5e

📥 Commits

Reviewing files that changed from the base of the PR and between 3604caa and d93eb09.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (28)
  • apps/mobile/app/(tabs)/_layout.tsx
  • apps/mobile/app/(tabs)/index.tsx
  • apps/mobile/app/(tabs)/notes.tsx
  • apps/mobile/app/(tabs)/profile.tsx
  • apps/mobile/app/(tabs)/stats.tsx
  • apps/mobile/app/_layout.tsx
  • apps/mobile/components/AccountHeader.tsx
  • apps/mobile/components/Button.tsx
  • apps/mobile/components/CodeBlock.tsx
  • apps/mobile/components/GrowthHistory.tsx
  • apps/mobile/components/Icon.tsx
  • apps/mobile/components/Mascot.tsx
  • apps/mobile/components/NotchedView.tsx
  • apps/mobile/components/QuestionCard.tsx
  • apps/mobile/components/TabBarButton.tsx
  • apps/mobile/components/Themed.tsx
  • apps/mobile/components/XpBar.tsx
  • apps/mobile/constants/Colors.ts
  • apps/mobile/constants/theme.ts
  • apps/mobile/package.json
  • apps/mobile/screens/ChapterMap.tsx
  • apps/mobile/screens/Home.tsx
  • apps/mobile/screens/Notes.tsx
  • apps/mobile/screens/QuestionBook.tsx
  • apps/mobile/screens/QuestionReview.tsx
  • apps/mobile/screens/Quiz.tsx
  • apps/mobile/screens/Stats.tsx
  • docs/rn-migration.md

Comment thread apps/mobile/components/AccountHeader.tsx Outdated
Comment thread apps/mobile/components/Icon.tsx
Comment thread apps/mobile/components/NotchedView.tsx Outdated
Comment thread apps/mobile/components/TabBarButton.tsx Outdated
…yle callback

- AccountHeader nameInput 移除跟 fontFamily 衝突的 fontWeight
- Icon fill 預設 'none',明確轉發給底層圖示元件
- NotchedView 邊框寬度轉成頂點內縮,避免 stroke 被畫布邊界裁掉一半
- TabBarButton 支援函式型 style prop,保留 Pressable 的 callback 用法
- ChapterMap STATUS_COLOR 改用窄化型別取代不安全的型別轉型
- Stats.tsx 重複的 rgba border 色改用 colors.optionBorder token
- rn-migration.md 補上程式碼區塊的 tsx 語言標記

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Retsomm
Retsomm merged commit df6744d into main Jul 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant