From c04b69a11f02bf16131f8190cf4d372dafcd737c Mon Sep 17 00:00:00 2001 From: neodk2004 Date: Sun, 6 Sep 2026 21:10:49 +0200 Subject: [PATCH] fix(mobile): dark mode on auth screens + RepostCard, expand .easignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sign-in/sign-up and RepostCard used the static (light-only) color tokens instead of useTheme() — in dark mode the login screen kept a light background with light-theme-colored text baked in, and RepostCard's text color was hardcoded independent of its (already theme-aware) surrounding background, both landing on illegible low-contrast text. Same bug class as earlier dark-mode fixes this session, converted the same way (useTheme() + makeStyles(colors)). Also add a root-level .easignore (EAS Build's archive root may resolve above mobile/ for monorepo purposes) excluding backend/tooling directories the mobile app never needs at build or runtime (.claude, .impeccable, .planning, docker, prisma — the last is only a type-only dependency via mobile's tRPC router import, erased before Metro bundles anything). --- .easignore | 24 +++++++++++++++++ mobile/.easignore | 1 + mobile/app/(auth)/sign-in.tsx | 36 ++++++++++++++----------- mobile/app/(auth)/sign-up.tsx | 36 ++++++++++++++----------- mobile/src/components/RepostCard.tsx | 39 ++++++++++++++++------------ 5 files changed, 90 insertions(+), 46 deletions(-) create mode 100644 .easignore diff --git a/.easignore b/.easignore new file mode 100644 index 0000000..68dac04 --- /dev/null +++ b/.easignore @@ -0,0 +1,24 @@ +# In case EAS Build's archive root resolves to this repo root rather than +# mobile/ (it has its own .easignore too) — these are backend/tooling +# directories the mobile app never needs at build or runtime. mobile/'s +# only link to this repo is a `import type` (tRPC router shape) that's +# erased before Metro ever bundles anything, so none of this needs to be +# present for a build to succeed. + +.claude +.impeccable +.planning +docker + +# Type-only dependency of mobile/'s tRPC import chain — needed for local +# `tsc` checks, never bundled into the app (type-only imports are erased +# before Metro sees them). +prisma + +# Already excluded from git; listed here too since .easignore isn't +# strictly limited to git-tracked files. +pentest-ai-agents +scaffold-tmp +node_modules +.next +.git diff --git a/mobile/.easignore b/mobile/.easignore index 567c90c..14a64a0 100644 --- a/mobile/.easignore +++ b/mobile/.easignore @@ -15,6 +15,7 @@ .idea .expo .vscode +.claude # Never needed — EAS installs dependencies itself on the build worker. node_modules diff --git a/mobile/app/(auth)/sign-in.tsx b/mobile/app/(auth)/sign-in.tsx index 1e4ba28..5ffd53e 100644 --- a/mobile/app/(auth)/sign-in.tsx +++ b/mobile/app/(auth)/sign-in.tsx @@ -1,11 +1,12 @@ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { View, Text, Pressable, StyleSheet } from "react-native"; import { useSignIn } from "@clerk/expo"; import { useRouter } from "expo-router"; import { useTranslation } from "react-i18next"; import { Button } from "../../src/components/Button"; import { TextField } from "../../src/components/TextField"; -import { colors, typography } from "../../src/theme/tokens"; +import { useTheme } from "../../src/context/ThemeContext"; +import { getTypography, type ColorTokens, type Typography } from "../../src/theme/tokens"; /** * Minimal email/password sign-in. Social sign-in is still follow-up work; @@ -24,6 +25,8 @@ export default function SignInScreen() { const { t } = useTranslation(); const { signIn, fetchStatus } = useSignIn(); const router = useRouter(); + const { colors } = useTheme(); + const styles = useMemo(() => makeStyles(colors), [colors]); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); const [code, setCode] = useState(""); @@ -117,16 +120,19 @@ export default function SignInScreen() { ); } -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: "center", - padding: 24, - gap: 12, - backgroundColor: colors.porchWhite, - }, - title: { ...typography.headline, marginBottom: 16 }, - hint: { ...typography.body, color: colors.quietGray, marginBottom: 8 }, - error: { ...typography.body, color: colors.alertRed }, - link: { ...typography.body, color: colors.marigoldDeep, textAlign: "center", marginTop: 8 }, -}); +function makeStyles(colors: ColorTokens) { + const typography: Typography = getTypography(colors); + return StyleSheet.create({ + container: { + flex: 1, + justifyContent: "center", + padding: 24, + gap: 12, + backgroundColor: colors.porchWhite, + }, + title: { ...typography.headline, marginBottom: 16 }, + hint: { ...typography.body, color: colors.quietGray, marginBottom: 8 }, + error: { ...typography.body, color: colors.alertRed }, + link: { ...typography.body, color: colors.marigoldDeep, textAlign: "center", marginTop: 8 }, + }); +} diff --git a/mobile/app/(auth)/sign-up.tsx b/mobile/app/(auth)/sign-up.tsx index 53937b9..de02437 100644 --- a/mobile/app/(auth)/sign-up.tsx +++ b/mobile/app/(auth)/sign-up.tsx @@ -1,11 +1,12 @@ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { View, Text, Pressable, StyleSheet } from "react-native"; import { useSignUp } from "@clerk/expo"; import { useRouter } from "expo-router"; import { useTranslation } from "react-i18next"; import { Button } from "../../src/components/Button"; import { TextField } from "../../src/components/TextField"; -import { colors, typography } from "../../src/theme/tokens"; +import { useTheme } from "../../src/context/ThemeContext"; +import { getTypography, type ColorTokens, type Typography } from "../../src/theme/tokens"; /** * Email/password sign-up — the mobile app's other half of sign-in.tsx (that @@ -21,6 +22,8 @@ export default function SignUpScreen() { const { t } = useTranslation(); const { signUp, fetchStatus } = useSignUp(); const router = useRouter(); + const { colors } = useTheme(); + const styles = useMemo(() => makeStyles(colors), [colors]); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); const [code, setCode] = useState(""); @@ -114,16 +117,19 @@ export default function SignUpScreen() { ); } -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: "center", - padding: 24, - gap: 12, - backgroundColor: colors.porchWhite, - }, - title: { ...typography.headline, marginBottom: 16 }, - hint: { ...typography.body, color: colors.quietGray, marginBottom: 8 }, - error: { ...typography.body, color: colors.alertRed }, - link: { ...typography.body, color: colors.marigoldDeep, textAlign: "center", marginTop: 8 }, -}); +function makeStyles(colors: ColorTokens) { + const typography: Typography = getTypography(colors); + return StyleSheet.create({ + container: { + flex: 1, + justifyContent: "center", + padding: 24, + gap: 12, + backgroundColor: colors.porchWhite, + }, + title: { ...typography.headline, marginBottom: 16 }, + hint: { ...typography.body, color: colors.quietGray, marginBottom: 8 }, + error: { ...typography.body, color: colors.alertRed }, + link: { ...typography.body, color: colors.marigoldDeep, textAlign: "center", marginTop: 8 }, + }); +} diff --git a/mobile/src/components/RepostCard.tsx b/mobile/src/components/RepostCard.tsx index dd0a859..351e25f 100644 --- a/mobile/src/components/RepostCard.tsx +++ b/mobile/src/components/RepostCard.tsx @@ -1,3 +1,4 @@ +import { useMemo } from "react"; import { View, Text, Pressable, StyleSheet, useWindowDimensions } from "react-native"; import { useRouter } from "expo-router"; import { useTranslation } from "react-i18next"; @@ -5,7 +6,8 @@ import { Image } from "expo-image"; import { PawPrint, Video, Trophy } from "lucide-react-native"; import { PetAvatar } from "./PetAvatar"; import { getMediaUrl } from "../lib/media-url"; -import { colors, typography, radii } from "../theme/tokens"; +import { useTheme } from "../context/ThemeContext"; +import { getTypography, radii, type ColorTokens, type Typography } from "../theme/tokens"; import type { PostCardPost } from "./PostCard"; type Props = { @@ -25,6 +27,8 @@ export function RepostCard({ post }: Props) { const { t } = useTranslation(); const router = useRouter(); const { width } = useWindowDimensions(); + const { colors } = useTheme(); + const styles = useMemo(() => makeStyles(colors), [colors]); const cardWidth = width - 32; const originalPost = post.repost?.originalPost; @@ -72,18 +76,21 @@ export function RepostCard({ post }: Props) { ); } -const styles = StyleSheet.create({ - card: { gap: 8 }, - attribution: { flexDirection: "row", alignItems: "center", gap: 6 }, - attributionText: { ...typography.label, textTransform: "none", letterSpacing: 0, color: colors.quietGray }, - header: { flexDirection: "row", alignItems: "center", gap: 8 }, - name: { ...typography.body, fontFamily: typography.title.fontFamily }, - caption: { ...typography.body }, - placeholder: { - aspectRatio: 1.2, - borderRadius: radii.md, - backgroundColor: colors.ink, - alignItems: "center", - justifyContent: "center", - }, -}); +function makeStyles(colors: ColorTokens) { + const typography: Typography = getTypography(colors); + return StyleSheet.create({ + card: { gap: 8 }, + attribution: { flexDirection: "row", alignItems: "center", gap: 6 }, + attributionText: { ...typography.label, textTransform: "none", letterSpacing: 0, color: colors.quietGray }, + header: { flexDirection: "row", alignItems: "center", gap: 8 }, + name: { ...typography.body, fontFamily: typography.title.fontFamily }, + caption: { ...typography.body }, + placeholder: { + aspectRatio: 1.2, + borderRadius: radii.md, + backgroundColor: colors.ink, + alignItems: "center", + justifyContent: "center", + }, + }); +}