feat(mobile): UI rework P1-P6 — 5 pages Expo SDK 54 (mocks only)#2
Open
simlirette wants to merge 74 commits into
Open
feat(mobile): UI rework P1-P6 — 5 pages Expo SDK 54 (mocks only)#2simlirette wants to merge 74 commits into
simlirette wants to merge 74 commits into
Conversation
- Remove blue sport-label row (was rendered separately with accent color) - Move sport icon into header row beside 'SÉANCE DU JOUR' label - Zone badge now extracts short format: 'Zone 1 (60–74%)' → 'Z1' - Duration + zone merged into single meta line with '·' separator - Stub titles francisés: 'Easy Run Z1' → 'Course facile', 'Muscu — Upper Pull' → 'Musculation haut du corps' - Tests updated to match new structure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
State mapping: green→ok, yellow→warn, red→zoneRed (from design tokens). Previously colors were hardcoded per metric type regardless of value. Label 'Récup.' renamed to 'Strain' (technical sport science term, per design decision — consistent with clinical tone of agent outputs). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace classic expo-router Tabs with NativeTabs from expo-router/unstable-native-tabs. iOS: UITabBarController with systemChromeMaterial blur (liquid glass). Android: Material 3 bottom navigation. Web: Radix UI fallback built into expo-router, no Platform.OS branch needed. SF Symbols: house/house.fill, heart/heart.fill, bolt/bolt.fill, person/person.fill. tintColor: colors.accent (#3B74C9). UI-RULES-MOBILE.md: Rule 9 SF Symbols exception, Rule 14 tech terms in EN, MetricRow state-based color mapping, metric token table updated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add babel-preset-expo and babel plugins to public-hoist-pattern in .npmrc - Explicit router.appRoot in babel.config.js to force transform injection - Resolves expo-router crash on Expo Go (SDK 54) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove missing asset refs from app.json (icon/splash/adaptive-icon pending design phase) - Pin lightningcss to 1.28.2 via pnpm.overrides to fix react-native-css crash - Unblocks expo start bundle completion on iOS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add react@19.1.0 and react-dom@19.1.0 to pnpm.overrides - Resolves "Cannot read property 'useContext' of null" from duplicate React instances between apps/mobile (19.1.0) and packages/ui-mobile (19.2.4) - Unblocks ThemeProvider runtime on iOS Expo Go Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Run expo install to match react-native-svg and other native packages with versions embedded in Expo Go SDK 54 - Add extraNodeModules to metro.config.js to force singleton native packages (react, react-native, react-native-svg, reanimated, etc.) to resolve from apps/mobile/node_modules only - Resolves "RNSVGCircle must be a function (received undefined)" crash on Home screen caused by pnpm creating two Metro module IDs for the same native package Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Set disableHierarchicalLookup: true in metro.config.js — prevents Metro from walking into packages/ui-mobile/node_modules when resolving native packages; forces all resolution through apps/mobile/node_modules → single file path → single module ID → single native binding - Add react-native-svg@15.12.1 to pnpm.overrides to pin version - Remove incorrect extraNodeModules approach (checked after nodeModulesPaths, so it never intercepted pnpm virtual store symlinks) - Restore newArchEnabled: true (Expo Go always runs New Arch regardless) - Root cause: pnpm creates separate virtual store entries per peer-dep context (peer#bb03 for apps/mobile, peer#0d2d for ui-mobile); Metro bundled both → RNSVGCircle native binding registered once → second JS instance undefined Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
disableHierarchicalLookup:true broke resolution of transitive deps (whatwg-fetch) that only exist in pnpm virtual store sub-paths. Switch to resolveRequest which is surgical — intercepts only the singleton native packages, leaves all other resolution untouched. Fakes originModulePath to apps/mobile/package.json so Metro's hierarchical lookup starts at apps/mobile/node_modules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace Clinical Blue (#3B74C9) with Amber/Terracotta (#B8552E light, #D97A52 dark) across all accent/primary/ring token fields. Update RGB channels and rgba() derived values. shadcn.dark gets #D97A52, shadcn.light and top-level get #B8552E. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PRIMARY constant in logo.tsx: #5b5fef → #B8552E. BRAND.md: update wordmark, design aesthetic section, logo spec, and absolute rule to reflect amber/terracotta canonical accent. Also corrects dark bg reference from #08080e to #131210 (warm near-black). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tailwind.config.js: accent/primary #3B74C9 → #B8552E, primary-dim rgba updated to amber RGB channels. app.json: splash backgroundColor #5b5fef → #131210 (warm near-black) for imperceptible transition into dark UI — no brand flash on launch. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Button.tsx JSDoc: Clinical Blue → Amber. README usage example: #5b5fef → #B8552E. Circle.test.tsx + Icon.test.tsx: arbitrary test color #5b5fef → #B8552E (tests remain behaviorally identical — color prop is passed through, not asserted against a specific value). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
frontend/UI-RULES.md is the single source of truth for design rules (both web and mobile). The mobile-specific file was an outdated fork containing obsolete color references (#5b5fef, #3B74C9). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rule 3 forbidden-hex comment: replace #5b5fef (purged) with #3B74C9 (also obsolete) as the illustrative bad example. No logic change. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lime (#C8FF4D) supprimé définitivement. Amber (#B8552E light / #D97A52 dark) est l'accent unique pour tous les CTAs y compris "Démarrer" et "Set terminé". - todays session/SPEC.md: remplacer lime par amber dans palette + CTA labels - homedashboard/SPEC.md: tab bar V1 = 4 onglets (Métriques = V2) - frontend/UI-RULES.md: retirer section "Accent action session — Lime électrique" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-auth deps - @gorhom/bottom-sheet — Training History drawer + HITL sheet - expo-blur — HITL sheet backdrop BlurView - react-native-draggable-flatlist — HITL type 3 réordonnage - expo-apple-authentication — Auth Apple Sign In Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ar Training
Fonts:
- _layout.tsx: Inter + SpaceMono → Space Grotesk 400/500/600/700
- typography.ts: fontSans + RN fontFamily constants, Space Grotesk
Tokens:
- colors.ts: add accentDark (#D97A52), physio {green/yellow/red} light+dark
- zoneRed: #ef4444 (cold) → #B64536 (terracotta warm, cohérent amber)
- zoneCritical: #dc2626 → #9C3020
Tab bar:
- 4 onglets: Accueil | Entraînement | Coach | Profil (Métriques = V2)
- Check-in hors tab bar: (tabs)/check-in.tsx → app/check-in.tsx (route non-tab)
- Ajout (tabs)/training.tsx placeholder
- Home: router.push('/check-in') au lieu de '/(tabs)/check-in'
Plan docs:
- docs/ui-rework-diagnostic.md
- docs/ui-rework-plan.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Caps, wordmark Replace Inter with Space Grotesk across all variants. New variants: heroNumber (72px/500/tabular), heroPace (80px/700/tracking-3), heroLarge (40px/700), pageTitle, stepTitle, sectionTitle, wordmark, navBar, metric, bodyBold, smallCaps. Back-compat aliases preserved. tabular prop added for forcing fontVariant on any variant. Debug screen: app/_debug/text-showcase.tsx Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…error state - Animated floating label: translateY -18 + scale 0.76 (150ms ease) - Border: 1px neutral → 1.5px accent on focus, -0.5px margin compensation - Password toggle via showToggle prop (text Voir/Masquer) - Inline error in physio.red below input - peerDep: react-native-reanimated >=3.0.0 added to ui-mobile - Debug screen: app/_debug/inputs-showcase.tsx Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ents, SegmentedControl Button: - Variants: primary (amber), secondary (surfaceAlt), ghost (accent border), apple (black/white) - Radius 12px, height 54px, disabled opacity 0.4, heavyHaptic prop - Pressable (not TouchableOpacity), accessibilityRole button HeroNumber: - Sizes: xl (40px/700), xxl (72px/500), pace (80px/700) - tabular-nums, optional unit label, accepts string|number ProgressSegments: - Thin 3px segments for onboarding (5 total) - Instantaneous swap, no transition SegmentedControl: - 2-4 options, active pill on surfaceAlt container - radius 10 container / 8 active Text: style prop → StyleProp<TextStyle> (was TextStyle) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…trix Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full chat UI matching design spec. No reanimated/gorhom deps (Expo Go SDK 54 safe). - Chat conversation: HC bubbles (avatar, left), user bubbles (right), summary card - Typing indicator: 3-dot animated fade via RN Animated.Value loop - Quick reply chips: horizontal ScrollView - Input bar: TextInput + send button (accent when text present) - HITL bottom sheet: Animated.Value spring slide-up, BlurView (expo-blur) + dim backdrop - Question type 1 — single: numbered rows, selected = dark pill + bold + arrow - Question type 2 — multi: checkboxes, count in footer, "Autre chose" input - Question type 3 — rank: ↑↓ buttons (no draggable-flatlist needed) - Summary card: right-aligned, accent border, Q&A entries - "Reprendre les questions" button if sheet dismissed without answering - Auto-open sheet after 900ms; coach reply + typing indicator after submit - Chat-specific color tokens (light/dark) matching SPEC.md palette - useSafeAreaInsets for top/bottom padding Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Avoids hardcoded hex in components. Used by HomeSessionCard CTA footer. - accentText: '#FAFAF7' (warm off-white, readable on amber CTA) - accentTextDark: '#161412' (warm charcoal, readable on dark amber CTA) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rich mock data matching design spec (dashboard.jsx DATA.*): - normal: Readiness 78, Course 52min, Allure/FC/TSS targets - ideal: Readiness 92, Vélo 2h10, Puissance/NP/TSS targets - recovery: Readiness 45, Récupération active (no targets) Includes typed HomeDashData, DashState, nextDashState() cycle helper. Avatar tap in HomeScreen will cycle between states without rebuild. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full redesign matching docs/design/homedashboard/ screenshots. Layout: - Header: greeting + date small-caps + avatar "SR" (tap = cycle 3 DEV states) - ReadinessRingHome: 160px, semantic color (green ≥80 / amber 60-79 / red <60) + delta "+X vs hier" in ring color - MetricsStrip: 3-col text card (Nutrition kcal/target + progress bar, Strain display value + semantic color, Sommeil duration + score) - HomeSessionCard: discipline + brief + targets row (Allure/FC/TSS or Puissance/NP/TSS) + full-width CTA footer (accent or ghost for recovery) - CognitiveLoadBar: 24 segments, semantic color, at bottom of scroll Removed: MetricRow, SessionCard, CognitiveLoadDial, ReadinessStatusBadge (flagged as deletion candidates in docs/p6-home-plan.md) Tokens: colors.accentText / colors.accentTextDark (Commit 0) — 0 hex inline SDK 54 safe: no reanimated, no @gorhom Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ostatique Bug 3 polish: drop "CHARGE COGNITIVE" label + "7j" badge from CognitiveLoadBar header — clutters the section without adding information. Change "Charge allostatique" from textMuted to foreground color for better hierarchy. Remove unused cogHeader + cogTitle styles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bug 1 polish: ring value font too dominant on device (72px covers ~48% of ring diameter). Reduce to 52px (33% of outer ring), proportional letterSpacing -2.5 and lineHeight 58. First iteration — sub-commit allowed in 52-60px range after Expo Go test without new plan cycle. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…IN col
Bug 2 polish: explicit newline caused 3-line orphan on small screens.
Remove hard newline, let text wrap naturally, cap with numberOfLines={2}.
Fallback (widening STRAIN col flex) not needed — natural wrap with cap is clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…stats Bug 4 polish: single-line row (weekLabel left + summary right) replaced with 2-line stacked layout. L1: "SEMAINE DU 13 AVRIL" (full month, foreground). L2: "7 SÉANCES - 7H05 TOT. - 381 CHARGE" (dash separator, TOT. suffix, uppercase, textMuted). SpaceGrotesk_600SemiBold L1, _400Regular L2. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bug 6 polish: reverts regression that replaced NativeTabs with standard Tabs using an incorrect "SDK 55 only" comment. NativeTabs is available on SDK 54 via expo-router/unstable-native-tabs (confirmed commit e2d1810, build dir present). 4 tabs: index/training/chat/profile. SF Symbols: house.fill, calendar.circle.fill, message.fill, person.fill. tintColor: colors.accent (amber). blurEffect: systemChromeMaterial. 0 hex inline. Label+Icon as Trigger children (not sub-components — API corrected vs e2d1810 draft). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bug 5 polish: HITL rank type now supports real drag-and-drop via PanResponder. Row follows finger in real-time (translateY = gs.dy, native driver). Multi-slot swap in one drag: Math.round(dy / ROW_HEIGHT). Haptics.Light on pickup, Haptics.Medium on successful swap (zero haptic if no swap). Spring reset after release (damping 20, stiffness 300). Shadow + zIndex=10 on dragging row. GripDots (2×3 dots) right-aligned replaces ↑↓ arrows. Hint updated to "GLISSE POUR RÉORDONNER". Expo Go SDK 54 safe: no reanimated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add p6-polish-diagnostic.md (v2, 4 corrections: branch confirm, NativeTabs reopened, Bug 4 verbatim, Bug 1 pixel measurement). Add p6-polish-plan.md (6 atomic commits, real PanResponder drag spec for Bug 5). Update state.md: P6 polish ✅ 6/6 commits, NativeTabs API notes, calendar.fill correction. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Correct 2 stale entries claiming NativeTabs is SDK 55 only (it's available in SDK 54 expo-router v6). Append P6 polish [saved] entry: NativeTabs API, calendar.fill invalidity, PanResponder drag pattern, 52px ring first iteration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… clipping Bug 1 polish #2: Space Grotesk Medium 22px has tall ascenders that clip without an explicit lineHeight. Default RN line height (~24px) insufficient. 30px = 1.36x ratio gives full ascender clearance without extra whitespace. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…llision Bug 2 polish #2: when isRecovery, long title + duration share one row causing overlap. Conditional layout: recovery=column (title L1, duration L2 at 13px textMuted), non-recovery=existing row layout unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…HT 49pt) Bug 3 polish #2: NativeTabs is a native UITabBarController that does not provide BottomTabBarHeightContext, so useBottomTabBarHeight() would throw. Manual paddingBottom = safeArea.bottom + 49 + 8 applied inline on inputWrap, replacing static paddingBottom:8. Chips and TextInput now fully visible above tab bar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ooks) Bug 4 polish #2: crash "Rendered more hooks than during previous render" caused by useState + useRef inside if(q.type==='rank') conditional. When navigating between questions of different types, hook count changed between renders. Fix: draggingIndex (useState) and dragY (useRef) moved to top level of QuestionBody, always initialised. ROW_HEIGHT constant promoted to module level as RANK_ROW_HEIGHT. Conditionals now only read from pre-existing state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HITLSheet container paddingBottom was insetBottom + 16 (~50pt), only covering the home indicator. Added TAB_BAR_HEIGHT (49pt) so footer buttons clear the NativeTabs translucent bar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
InputBar paddingBottom was static (bottom + 49 + 8 ≈ 91pt), causing a gap above the keyboard when KAV pushed the layout up. Now dynamic: - Keyboard closed: bottom + TAB_BAR_HEIGHT + 8 (clears NativeTabs) - Keyboard open: bottom + 8 (glued to keyboard top) Uses keyboardWillShow/Hide (iOS) and keyboardDidShow/Hide (Android) via Keyboard.addListener for cross-platform support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
keyboardVerticalOffset={insets.top + 56} over-compensated by ~103pt.
RN KAV formula: paddingBottom = KAV_bottom - keyboard_screenY + offset.
Since KAV extends to screen bottom and RN already measures its own frame,
offset must be 0. Previous value created a structural gap equal to the offset.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keyboard height on iOS includes the home indicator area (~34pt). Using bottom+8 when keyboard open kept a 34pt gap. Now uses 8pt only. Keyboard closed stays bottom+TAB_BAR_HEIGHT+8 to clear NativeTabs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s, SDK 54 constraints)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Résumé technique
Rework complet de l'app mobile Expo (SDK 54) depuis un scaffold Vague 1.
5 pages livrées et testées manuellement sur iPhone via Expo Go SDK 54.
Toutes les pages utilisent des mocks locaux — pas de wiring backend dans cette PR.
SDK downgrade 55→54 nécessaire pour compatibilité binaire Expo Go (reanimated worklets
absents du binaire SDK 54, remplacés par
Animated.Value+PanResponder).Pages livrées ✅
/(auth)/login,/(auth)/signup,/(auth)/forgot-password/onboardingAnimated.Value/(tabs)//(tabs)/training/(tabs)/chatPages placeholder (non bloquantes) 🚧
/session/live) — route non créée/metric/[id])/nutrition)/(tabs)/profile) — scaffold vide/connectors)Ce qui N'est PAS dans cette PR
apps/mobile/src/mocks/)handleLogin/handleSignup=// TODO: real auth call)Checklist QA manuelle (Expo Go iPhone)
Avant merge, valider sur device physique iOS (iPhone + Expo Go SDK 54):
Navigation
Home Dashboard
Coach Chat
Training History
Auth
Screenshots à attacher manuellement
Stack technique
expo-router/unstable-native-tabs(iOS liquid glass, SDK 54 OK)Animated.Value+PanResponder(reanimated absent SDK 54 Expo Go)expo-font@gorhom/bottom-sheet+expo-blur@resilio/design-tokens(0 hex inline)apps/mobile/src/mocks/Pre-existing issues (out of scope)
packages/ui-web/src/theme/ThemeProvider.tsx:25(@ts-expect-errordevenue inutile, confirmé présent sur main)