feat: integrate theme and i18n across all screens

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Millian Lamiaux
2026-02-21 00:05:14 +01:00
parent f17125e231
commit f80798069b
17 changed files with 3127 additions and 2402 deletions

View File

@@ -1,13 +1,14 @@
/**
* GlassCard - Liquid Glass Container
* iOS 18.4 inspired glassmorphism
* iOS 18.4 inspired glassmorphism — theme-aware
*/
import { ReactNode } from 'react'
import { ReactNode, useMemo } from 'react'
import { StyleSheet, View, ViewStyle } from 'react-native'
import { BlurView } from 'expo-blur'
import { DARK, GLASS, SHADOW, BORDER } from '../constants/colors'
import { useThemeColors } from '../theme'
import type { ThemeColors } from '../theme/types'
import { RADIUS } from '../constants/borderRadius'
type GlassVariant = 'base' | 'elevated' | 'inset' | 'tinted'
@@ -20,34 +21,38 @@ interface GlassCardProps {
blurIntensity?: number
}
const variantStyles: Record<GlassVariant, ViewStyle> = {
base: {
backgroundColor: GLASS.BASE.backgroundColor,
borderColor: GLASS.BASE.borderColor,
borderWidth: GLASS.BASE.borderWidth,
},
elevated: {
backgroundColor: GLASS.ELEVATED.backgroundColor,
borderColor: GLASS.ELEVATED.borderColor,
borderWidth: GLASS.ELEVATED.borderWidth,
},
inset: {
backgroundColor: GLASS.INSET.backgroundColor,
borderColor: GLASS.INSET.borderColor,
borderWidth: GLASS.INSET.borderWidth,
},
tinted: {
backgroundColor: GLASS.TINTED.backgroundColor,
borderColor: GLASS.TINTED.borderColor,
borderWidth: GLASS.TINTED.borderWidth,
},
function getVariantStyles(colors: ThemeColors): Record<GlassVariant, ViewStyle> {
return {
base: {
backgroundColor: colors.glass.base.backgroundColor,
borderColor: colors.glass.base.borderColor,
borderWidth: colors.glass.base.borderWidth,
},
elevated: {
backgroundColor: colors.glass.elevated.backgroundColor,
borderColor: colors.glass.elevated.borderColor,
borderWidth: colors.glass.elevated.borderWidth,
},
inset: {
backgroundColor: colors.glass.inset.backgroundColor,
borderColor: colors.glass.inset.borderColor,
borderWidth: colors.glass.inset.borderWidth,
},
tinted: {
backgroundColor: colors.glass.tinted.backgroundColor,
borderColor: colors.glass.tinted.borderColor,
borderWidth: colors.glass.tinted.borderWidth,
},
}
}
const shadowStyles: Record<GlassVariant, ViewStyle> = {
base: SHADOW.sm,
elevated: SHADOW.md,
inset: {},
tinted: SHADOW.sm,
function getShadowStyles(colors: ThemeColors): Record<GlassVariant, ViewStyle> {
return {
base: colors.shadow.sm,
elevated: colors.shadow.md,
inset: {},
tinted: colors.shadow.sm,
}
}
export function GlassCard({
@@ -55,17 +60,22 @@ export function GlassCard({
variant = 'base',
style,
hasBlur = true,
blurIntensity = GLASS.BLUR_MEDIUM,
blurIntensity,
}: GlassCardProps) {
const colors = useThemeColors()
const variantStyles = useMemo(() => getVariantStyles(colors), [colors])
const shadowStyles = useMemo(() => getShadowStyles(colors), [colors])
const glassStyle = variantStyles[variant]
const shadowStyle = shadowStyles[variant]
const intensity = blurIntensity ?? colors.glass.blurMedium
if (hasBlur) {
return (
<View style={[styles.container, glassStyle, shadowStyle, style]}>
<BlurView
intensity={blurIntensity}
tint="dark"
intensity={intensity}
tint={colors.glass.blurTint}
style={StyleSheet.absoluteFill}
/>
<View style={styles.content}>{children}</View>

View File

@@ -3,10 +3,11 @@
* Reusable wrapper for each onboarding screen — progress bar, animation, layout
*/
import { useRef, useEffect } from 'react'
import { useRef, useEffect, useMemo } from 'react'
import { View, StyleSheet, Animated, Dimensions } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { DARK, BRAND, TEXT } from '../constants/colors'
import { useThemeColors, BRAND } from '../theme'
import type { ThemeColors } from '../theme/types'
import { SPACING, LAYOUT } from '../constants/spacing'
import { DURATION, EASE } from '../constants/animations'
@@ -19,6 +20,8 @@ interface OnboardingStepProps {
}
export function OnboardingStep({ step, totalSteps, children }: OnboardingStepProps) {
const colors = useThemeColors()
const styles = useMemo(() => createStyles(colors), [colors])
const insets = useSafeAreaInsets()
const slideAnim = useRef(new Animated.Value(SCREEN_WIDTH)).current
const fadeAnim = useRef(new Animated.Value(0)).current
@@ -83,26 +86,28 @@ export function OnboardingStep({ step, totalSteps, children }: OnboardingStepPro
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: DARK.BASE,
},
progressTrack: {
height: 3,
backgroundColor: DARK.SURFACE,
marginHorizontal: LAYOUT.SCREEN_PADDING,
borderRadius: 2,
overflow: 'hidden',
},
progressFill: {
height: '100%',
backgroundColor: BRAND.PRIMARY,
borderRadius: 2,
},
content: {
flex: 1,
paddingHorizontal: LAYOUT.SCREEN_PADDING,
paddingTop: SPACING[8],
},
})
function createStyles(colors: ThemeColors) {
return StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.bg.base,
},
progressTrack: {
height: 3,
backgroundColor: colors.bg.surface,
marginHorizontal: LAYOUT.SCREEN_PADDING,
borderRadius: 2,
overflow: 'hidden',
},
progressFill: {
height: '100%',
backgroundColor: BRAND.PRIMARY,
borderRadius: 2,
},
content: {
flex: 1,
paddingHorizontal: LAYOUT.SCREEN_PADDING,
paddingTop: SPACING[8],
},
})
}

View File

@@ -1,10 +1,10 @@
/**
* TabataFit StyledText
* Unified text component — replaces 5 local copies
* Unified text component — uses theme for default color
*/
import { Text as RNText, TextStyle, StyleProp } from 'react-native'
import { TEXT } from '../constants/colors'
import { useThemeColors } from '../theme'
type FontWeight = 'regular' | 'medium' | 'semibold' | 'bold'
@@ -28,17 +28,20 @@ export function StyledText({
children,
size = 17,
weight = 'regular',
color = TEXT.PRIMARY,
color,
style,
numberOfLines,
}: StyledTextProps) {
const colors = useThemeColors()
const resolvedColor = color ?? colors.text.primary
return (
<RNText
style={[
{
fontSize: size,
fontWeight: WEIGHT_MAP[weight],
color,
color: resolvedColor,
},
style,
]}