Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/(auth)/sign-in.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export default function SignIn() {
return (
<SafeAreaView style={[styles.fill, { backgroundColor: colors.bg }]}>
<View style={styles.hero}>
<View style={[styles.logo, { backgroundColor: colors.accent }]}>
<Icon name="sparkle" size={34} sw={1.8} stroke={colors.primaryDeep} />
<View style={[styles.logo, { backgroundColor: colors.primary }]}>
<Icon name="sparkle" size={34} sw={1.8} stroke={colors.onTint} />
</View>
<Text style={[styles.title, { color: colors.heading }]}>{t('auth.title')}</Text>
<Text style={[styles.subtitle, { color: colors.muted }]}>{t('auth.subtitle')}</Text>
Expand Down
12 changes: 5 additions & 7 deletions src/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const DOT_TONE: Record<'paid' | 'debt' | 'expected', DotTone> = {

export default function TodayScreen() {
const t = useT();
const { colors } = useTheme();
const { colors, radius } = useTheme();
const router = useRouter();

const { start, end } = dayBounds();
Expand Down Expand Up @@ -117,13 +117,13 @@ export default function TodayScreen() {
<View>
<SectionLabel>{t('today.next')}</SectionLabel>
{restToday.length === 0 ? (
<View style={[styles.emptyNext, { backgroundColor: colors.surface, borderColor: colors.hairline }]}>
<View style={[styles.emptyNext, { backgroundColor: colors.surface, borderColor: colors.hairline, borderRadius: radius.row }]}>
<Text style={[styles.emptyNextText, { color: colors.muted }]}>{t('today.nothingNext')}</Text>
</View>
) : (
<View style={styles.list}>
{restToday.map((l) => (
<View key={l.id} style={[styles.rowShell, { borderColor: colors.hairline, borderRadius: 16 }]}>
<View key={l.id} style={[styles.rowShell, { borderColor: colors.hairline, borderRadius: radius.row }]}>
<SwipeRow
leftActions={[
{
Expand Down Expand Up @@ -205,7 +205,7 @@ function NearestCard({
now: number;
}) {
const t = useT();
const { colors } = useTheme();
const { colors, radius } = useTheme();
const router = useRouter();

const m = minutesUntil(lesson.startsAt, now);
Expand Down Expand Up @@ -248,7 +248,7 @@ function NearestCard({
}}
accessibilityRole="button"
accessibilityLabel={t('common.contact')}
style={({ pressed }) => [styles.contactBtn, { backgroundColor: colors.primaryVlight, opacity: pressed ? 0.85 : 1 }]}>
style={({ pressed }) => [styles.contactBtn, { backgroundColor: colors.primaryVlight, borderRadius: radius.control, opacity: pressed ? 0.85 : 1 }]}>
<Icon name="phone" size={16} sw={1.8} stroke={colors.heading} />
<Text style={[styles.contactLabel, { color: colors.heading }]}>{t('common.contact')}</Text>
</Pressable>
Expand Down Expand Up @@ -284,7 +284,6 @@ const styles = StyleSheet.create({
justifyContent: 'center',
gap: 7,
paddingVertical: 10,
borderRadius: 12,
},
contactLabel: { fontSize: 14, fontWeight: '600' },

Expand All @@ -298,7 +297,6 @@ const styles = StyleSheet.create({

emptyNext: {
borderWidth: StyleSheet.hairlineWidth,
borderRadius: 16,
paddingVertical: 22,
paddingHorizontal: 16,
alignItems: 'center',
Expand Down
31 changes: 22 additions & 9 deletions src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import '@/lib/silence-rnw-warnings';

import { DarkTheme, DefaultTheme, Stack, ThemeProvider, useRouter, useSegments } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import { useEffect } from 'react';
import { useEffect, type ReactNode } from 'react';
import { Platform, View } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';

Expand Down Expand Up @@ -45,6 +46,16 @@ function useAuthGate() {
}, [session, segments, router]);
}

/** ADR-0010: on web, constrain the app to a centred ~430px mobile column with a bg surround. */
function WebFrame({ bg, children }: { bg: string; children: ReactNode }) {
if (Platform.OS !== 'web') return <>{children}</>;
return (
<View style={{ flex: 1, backgroundColor: bg, alignItems: 'center' }}>
<View style={{ flex: 1, width: '100%', maxWidth: 430, backgroundColor: bg }}>{children}</View>
</View>
);
}

function NavigationRoot() {
const { colors, scheme } = useTheme();
const t = useT();
Expand All @@ -68,14 +79,16 @@ function NavigationRoot() {
return (
<ThemeProvider value={navTheme}>
<StatusBar style={scheme === 'dark' ? 'light' : 'dark'} />
<Stack screenOptions={{ headerShown: false, contentStyle: { backgroundColor: colors.bg } }}>
<Stack.Screen name="(auth)" />
<Stack.Screen name="(tabs)" />
<Stack.Screen name="student" />
<Stack.Screen name="lesson" />
<Stack.Screen name="gallery" options={{ presentation: 'modal', headerShown: true, title: t('a11y.uiKit') }} />
<Stack.Screen name="+not-found" />
</Stack>
<WebFrame bg={colors.bg}>
<Stack screenOptions={{ headerShown: false, contentStyle: { backgroundColor: colors.bg } }}>
<Stack.Screen name="(auth)" />
<Stack.Screen name="(tabs)" />
<Stack.Screen name="student" />
<Stack.Screen name="lesson" />
<Stack.Screen name="gallery" options={{ presentation: 'modal', headerShown: true, title: t('a11y.uiKit') }} />
<Stack.Screen name="+not-found" />
</Stack>
</WebFrame>
</ThemeProvider>
);
}
16 changes: 7 additions & 9 deletions src/app/lesson/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function LessonCardScreen() {
const { id } = useLocalSearchParams<{ id: string }>();
const router = useRouter();
const t = useT();
const { colors } = useTheme();
const { colors, radius } = useTheme();
const dateLabel = useDateLabel();

const lesson = useLesson(id);
Expand Down Expand Up @@ -84,7 +84,7 @@ export default function LessonCardScreen() {
onPress={() => markLessonConducted(lesson)}
style={({ pressed }) => [
styles.action,
{ backgroundColor: colors.primary },
{ backgroundColor: colors.primary, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Icon name="check" size={18} sw={2} stroke={colors.onTint} />
Expand All @@ -96,7 +96,7 @@ export default function LessonCardScreen() {
onPress={() => setPayingOpen(true)}
style={({ pressed }) => [
styles.action,
{ backgroundColor: colors.stoneLight },
{ backgroundColor: colors.stoneLight, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Icon name="wallet" size={18} sw={1.8} stroke={colors.body} />
Expand All @@ -113,7 +113,7 @@ export default function LessonCardScreen() {
style={({ pressed }) => [
styles.action,
styles.actionGhost,
{ backgroundColor: colors.stoneLight },
{ backgroundColor: colors.stoneLight, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Icon name="refresh" size={17} sw={1.8} stroke={colors.body} />
Expand All @@ -125,7 +125,7 @@ export default function LessonCardScreen() {
style={({ pressed }) => [
styles.action,
styles.actionGhost,
{ backgroundColor: colors.dangerLight },
{ backgroundColor: colors.dangerLight, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Icon name="close" size={17} sw={2} stroke={colors.danger} />
Expand All @@ -152,7 +152,7 @@ export default function LessonCardScreen() {
}}
style={({ pressed }) => [
styles.payChoice,
{ backgroundColor: colors.stoneLight },
{ backgroundColor: colors.stoneLight, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Dot tone="green" />
Expand All @@ -165,7 +165,7 @@ export default function LessonCardScreen() {
}}
style={({ pressed }) => [
styles.payChoice,
{ backgroundColor: colors.stoneLight },
{ backgroundColor: colors.stoneLight, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Dot tone="red" />
Expand Down Expand Up @@ -248,7 +248,6 @@ const styles = StyleSheet.create({
justifyContent: 'center',
gap: 8,
paddingVertical: 14,
borderRadius: 14,
},
actionGhost: { flex: 1 },
actionLabel: { fontSize: 15, fontWeight: '600' },
Expand All @@ -259,7 +258,6 @@ const styles = StyleSheet.create({
gap: 10,
paddingVertical: 15,
paddingHorizontal: 16,
borderRadius: 14,
},
payChoiceLabel: { fontSize: 15, fontWeight: '600' },
pressed: { opacity: 0.85 },
Expand Down
21 changes: 13 additions & 8 deletions src/app/lesson/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function LessonFormScreen() {
const { studentId: preselect } = useLocalSearchParams<{ studentId?: string }>();
const router = useRouter();
const t = useT();
const { colors } = useTheme();
const { colors, radius } = useTheme();

const students = useStudents();
const subjects = useSubjects();
Expand Down Expand Up @@ -120,8 +120,11 @@ export default function LessonFormScreen() {
value={topic}
onChangeText={setTopic}
placeholder={t('lesson.topicPlaceholder')}
placeholderTextColor={colors.label3}
style={[styles.input, { color: colors.heading, backgroundColor: colors.elev, borderColor: colors.hairline }]}
placeholderTextColor={colors.muted}
style={[
styles.input,
{ borderRadius: radius.control, color: colors.heading, backgroundColor: colors.elev, borderColor: colors.hairline },
]}
/>
</FieldBlock>

Expand Down Expand Up @@ -157,8 +160,11 @@ export default function LessonFormScreen() {
}}
keyboardType="number-pad"
placeholder="0"
placeholderTextColor={colors.label3}
style={[styles.input, { color: colors.heading, backgroundColor: colors.elev, borderColor: colors.hairline }]}
placeholderTextColor={colors.muted}
style={[
styles.input,
{ borderRadius: radius.control, color: colors.heading, backgroundColor: colors.elev, borderColor: colors.hairline },
]}
/>
</FieldBlock>
</ScrollView>
Expand Down Expand Up @@ -244,15 +250,15 @@ function PickerField({
placeholder: string;
onPress: () => void;
}) {
const { colors } = useTheme();
const { colors, radius } = useTheme();
return (
<FieldBlock label={label}>
<Pressable
onPress={onPress}
style={({ pressed }) => [
styles.input,
styles.pickerRow,
{ backgroundColor: colors.elev, borderColor: colors.hairline },
{ borderRadius: radius.control, backgroundColor: colors.elev, borderColor: colors.hairline },
pressed && styles.pressed,
]}>
<Text style={[styles.pickerValue, { color: value ? colors.heading : colors.label3 }]} numberOfLines={1}>
Expand Down Expand Up @@ -283,7 +289,6 @@ const styles = StyleSheet.create({
fieldLabel: { fontSize: 13, fontWeight: '600', textTransform: 'uppercase', letterSpacing: 0.4 },
input: {
borderWidth: StyleSheet.hairlineWidth,
borderRadius: 12,
paddingHorizontal: 14,
paddingVertical: 12,
fontSize: 15,
Expand Down
32 changes: 16 additions & 16 deletions src/app/student/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const PAY_DOT: Record<PayStatus, DotTone> = {

export default function StudentCardScreen() {
const t = useT();
const { colors } = useTheme();
const { colors, radius } = useTheme();
const params = useLocalSearchParams<{ id: string }>();
const id = typeof params.id === 'string' ? params.id : (params.id?.[0] ?? '');

Expand Down Expand Up @@ -137,7 +137,7 @@ export default function StudentCardScreen() {
onPress={openContact}
style={({ pressed }) => [
styles.actionBtn,
{ backgroundColor: colors.surface, borderColor: colors.hairline },
{ backgroundColor: colors.surface, borderColor: colors.hairline, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Icon name="phone" size={18} stroke={colors.heading} />
Expand All @@ -148,7 +148,7 @@ export default function StudentCardScreen() {
style={({ pressed }) => [
styles.actionBtn,
styles.actionPrimary,
{ backgroundColor: colors.primary },
{ backgroundColor: colors.primary, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Icon name="plus" size={18} stroke={colors.onTint} />
Expand All @@ -159,7 +159,7 @@ export default function StudentCardScreen() {
</View>

{/* ── Data block ───────────────────────────────────────────── */}
<View style={[styles.dataCard, { backgroundColor: colors.surface, borderColor: colors.hairline }]}>
<View style={[styles.dataCard, { backgroundColor: colors.surface, borderColor: colors.hairline, borderRadius: radius.group }]}>
<DataRow label={t('field.subjects')} divider={false}>
{subjects.length > 0 ? (
<View style={styles.chips}>
Expand All @@ -168,7 +168,7 @@ export default function StudentCardScreen() {
))}
</View>
) : (
<Text style={[styles.value, { color: colors.label3 }]}>{t('common.none')}</Text>
<Text style={[styles.value, { color: colors.muted }]}>{t('common.none')}</Text>
)}
</DataRow>
<DataRow label={t('field.format')}>
Expand Down Expand Up @@ -203,7 +203,7 @@ export default function StudentCardScreen() {
))}
</View>
) : (
<Text style={[styles.empty, { color: colors.label3 }]}>{t('student.noUpcoming')}</Text>
<Text style={[styles.empty, { color: colors.muted }]}>{t('student.noUpcoming')}</Text>
)}

{/* ── Archive ──────────────────────────────────────────────── */}
Expand All @@ -212,7 +212,7 @@ export default function StudentCardScreen() {
disabled={isArchived}
style={({ pressed }) => [
styles.archiveBtn,
{ borderColor: colors.hairline },
{ borderColor: colors.hairline, borderRadius: radius.field },
pressed && !isArchived && styles.pressed,
]}>
<Icon name="archive" size={18} stroke={isArchived ? colors.label3 : colors.danger} />
Expand Down Expand Up @@ -301,13 +301,13 @@ function UpcomingRow({
onPress: () => void;
}) {
const t = useT();
const { colors } = useTheme();
const { colors, radius } = useTheme();
return (
<Pressable
onPress={onPress}
style={({ pressed }) => [
styles.lessonRow,
{ backgroundColor: colors.surface, borderColor: colors.hairline },
{ backgroundColor: colors.surface, borderColor: colors.hairline, borderRadius: radius.field },
pressed && styles.pressed,
]}>
<Text style={[styles.lessonTime, { color: colors.heading }]}>{hhmm(lesson.startsAt)}</Text>
Expand All @@ -329,11 +329,15 @@ function ContactAction({
label: string;
onPress: () => void;
}) {
const { colors } = useTheme();
const { colors, radius } = useTheme();
return (
<Pressable
onPress={onPress}
style={({ pressed }) => [styles.contactRow, pressed && { backgroundColor: colors.stoneLight }]}>
style={({ pressed }) => [
styles.contactRow,
{ borderRadius: radius.control },
pressed && { backgroundColor: colors.stoneLight },
]}>
<Icon name={icon} size={20} stroke={colors.heading} />
<Text style={[styles.contactLabel, { color: colors.heading }]}>{label}</Text>
</Pressable>
Expand Down Expand Up @@ -387,13 +391,12 @@ const styles = StyleSheet.create({
justifyContent: 'center',
gap: 8,
height: 48,
borderRadius: 14,
borderWidth: StyleSheet.hairlineWidth,
},
actionPrimary: { borderWidth: 0 },
actionLabel: { fontSize: 14.5, fontWeight: '600' },

dataCard: { borderRadius: 18, borderWidth: StyleSheet.hairlineWidth, paddingHorizontal: 14 },
dataCard: { borderWidth: StyleSheet.hairlineWidth, paddingHorizontal: 14 },
dataRow: { flexDirection: 'row', alignItems: 'flex-start', paddingVertical: 13, gap: 12 },
dataLabel: { width: 92, fontSize: 13.5, fontWeight: '500', paddingTop: 1 },
dataValue: { flex: 1, alignItems: 'flex-end' },
Expand All @@ -408,7 +411,6 @@ const styles = StyleSheet.create({
gap: 12,
paddingHorizontal: 14,
paddingVertical: 13,
borderRadius: 14,
borderWidth: StyleSheet.hairlineWidth,
},
lessonTime: { fontSize: 15, fontWeight: '700', minWidth: 44, fontVariant: ['tabular-nums'] },
Expand All @@ -421,7 +423,6 @@ const styles = StyleSheet.create({
justifyContent: 'center',
gap: 8,
height: 48,
borderRadius: 14,
borderWidth: StyleSheet.hairlineWidth,
marginTop: 4,
},
Expand All @@ -433,7 +434,6 @@ const styles = StyleSheet.create({
gap: 14,
paddingVertical: 15,
paddingHorizontal: 8,
borderRadius: 12,
},
contactLabel: { fontSize: 16, fontWeight: '500' },

Expand Down
Loading
Loading