Skip to content

Commit 843cf17

Browse files
fix(mobile): embed fonts and render project favicons reliably (#3823)
Co-authored-by: codex <codex@users.noreply.github.com>
1 parent ca1e08b commit 843cf17

64 files changed

Lines changed: 444 additions & 837 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/mobile/app.config.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ function resolveAppVariant(value: string | undefined): AppVariant {
6363

6464
const variant = VARIANT_CONFIG[APP_VARIANT];
6565

66+
const dmSansFonts = {
67+
regular: "@expo-google-fonts/dm-sans/400Regular/DMSans_400Regular.ttf",
68+
medium: "@expo-google-fonts/dm-sans/500Medium/DMSans_500Medium.ttf",
69+
bold: "@expo-google-fonts/dm-sans/700Bold/DMSans_700Bold.ttf",
70+
} as const;
71+
72+
// These aliases match the fonts' PostScript names on iOS. Register the same
73+
// names on Android so React Native and the native composer use one set of
74+
// family names without waiting for runtime font loading.
75+
6676
const config: ExpoConfig = {
6777
name: variant.appName,
6878
slug: "t3-code",
@@ -121,7 +131,30 @@ const config: ExpoConfig = {
121131
favicon: "./assets/favicon.png",
122132
},
123133
plugins: [
124-
"expo-font",
134+
[
135+
"expo-font",
136+
{
137+
ios: {
138+
fonts: [dmSansFonts.regular, dmSansFonts.medium, dmSansFonts.bold],
139+
},
140+
android: {
141+
fonts: [
142+
{
143+
fontFamily: "DMSans-Regular",
144+
fontDefinitions: [{ path: dmSansFonts.regular, weight: 400 }],
145+
},
146+
{
147+
fontFamily: "DMSans-Medium",
148+
fontDefinitions: [{ path: dmSansFonts.medium, weight: 500 }],
149+
},
150+
{
151+
fontFamily: "DMSans-Bold",
152+
fontDefinitions: [{ path: dmSansFonts.bold, weight: 700 }],
153+
},
154+
],
155+
},
156+
},
157+
],
125158
"expo-secure-store",
126159
"expo-sqlite",
127160
["@clerk/expo", { theme: "./clerk-theme.json" }],

apps/mobile/global.css

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
/* Inputs */
5252
--color-input: #ffffff;
5353
--color-input-border: rgba(0, 0, 0, 0.1);
54+
--color-sidebar-search: rgba(118, 118, 128, 0.12);
5455
--color-placeholder: #a3a3a3;
5556

5657
/* Icons */
@@ -144,6 +145,7 @@
144145
/* Inputs */
145146
--color-input: #141414;
146147
--color-input-border: rgba(255, 255, 255, 0.08);
148+
--color-sidebar-search: rgba(118, 118, 128, 0.24);
147149
--color-placeholder: #8e8e93;
148150

149151
/* Icons */
@@ -194,9 +196,10 @@
194196

195197
/* ─── Typography ────────────────────────────────────────────────────── */
196198
@theme {
197-
--font-sans: "DMSans_400Regular";
198-
--font-medium: "DMSans_500Medium";
199-
--font-bold: "DMSans_700Bold";
199+
/* Keep these native family names aligned with app.config.ts. */
200+
--font-sans: "DMSans-Regular";
201+
--font-medium: "DMSans-Medium";
202+
--font-bold: "DMSans-Bold";
200203

201204
/* Keep this scale aligned with src/lib/typography.ts for native style props. */
202205
--text-3xs: 11px;
@@ -221,14 +224,14 @@
221224

222225
/* ─── Custom utilities ──────────────────────────────────────────────── */
223226
@utility font-t3-medium {
224-
font-family: "DMSans_500Medium";
227+
font-family: var(--font-medium);
225228
}
226229

227230
@utility font-t3-bold {
228-
font-family: "DMSans_700Bold";
231+
font-family: var(--font-bold);
229232
}
230233

231234
@utility font-t3-extrabold {
232-
font-family: "DMSans_700Bold";
235+
font-family: var(--font-bold);
233236
font-weight: 800;
234237
}

apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
300300
skillText: "#a21caf",
301301
fileTint: "#737373"
302302
)
303-
private var fontFamily = "DMSans_400Regular"
303+
private var fontFamily = "DMSans-Regular"
304304
private var fontSize: CGFloat = 14
305305
private var lineHeight: CGFloat = 20
306306
private var contentInsetVertical: CGFloat = 0
@@ -608,7 +608,7 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
608608
iconImage: UIImage?,
609609
style: ComposerChipStyle
610610
) -> UIImage {
611-
let font = UIFont(name: "DMSans_500Medium", size: max(12, fontSize - 2))
611+
let font = UIFont(name: "DMSans-Medium", size: max(12, fontSize - 2))
612612
?? UIFont.systemFont(ofSize: max(12, fontSize - 2), weight: .medium)
613613
let fallbackIcon = UIImage(
614614
systemName: iconName,

apps/mobile/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"scripts": {
77
"dev": "expo start --clear",
88
"dev:client": "APP_VARIANT=development expo start --dev-client --scheme t3code-dev --clear",
9-
"dev:client:preview": "eas env:exec preview 'EXPO_NO_DOTENV=1 APP_VARIANT=preview expo start --dev-client --scheme t3code-preview --clear'",
9+
"dev:client:preview": "eas env:exec preview 'EXPO_NO_DOTENV=1 APP_VARIANT=preview expo start --dev-client --scheme t3code-preview --clear --lan'",
1010
"start": "expo start",
1111
"start:dev": "APP_VARIANT=development expo start",
1212
"start:preview": "APP_VARIANT=preview expo start",
@@ -80,6 +80,7 @@
8080
"expo-font": "~56.0.7",
8181
"expo-glass-effect": "~56.0.4",
8282
"expo-haptics": "~56.0.3",
83+
"expo-image": "~56.0.11",
8384
"expo-image-picker": "~56.0.18",
8485
"expo-linking": "~56.0.14",
8586
"expo-network": "~56.0.5",

apps/mobile/src/App.tsx

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
1-
import {
2-
DMSans_400Regular,
3-
DMSans_500Medium,
4-
DMSans_700Bold,
5-
useFonts,
6-
} from "@expo-google-fonts/dm-sans";
71
import * as Linking from "expo-linking";
82
import * as SplashScreen from "expo-splash-screen";
3+
import { useEffect } from "react";
94
import { StatusBar, useColorScheme } from "react-native";
105
import { GestureHandlerRootView } from "react-native-gesture-handler";
116
import { KeyboardProvider } from "react-native-keyboard-controller";
127
import { SafeAreaProvider } from "react-native-safe-area-context";
138
import { createStaticNavigation, DarkTheme, DefaultTheme } from "@react-navigation/native";
149

1510
import { RegistryContext } from "@effect/atom-react";
16-
import { useEffect } from "react";
1711
import { CloudAuthProvider } from "./features/cloud/CloudAuthProvider";
1812
import { AppearancePreferencesProvider } from "./features/settings/appearance/AppearancePreferencesProvider";
1913
import { RootStack } from "./Stack";
@@ -29,17 +23,12 @@ const appLinking = {
2923
const Navigation = createStaticNavigation(RootStack);
3024

3125
export default function App() {
32-
const [fontsLoaded] = useFonts({
33-
DMSans_400Regular,
34-
DMSans_500Medium,
35-
DMSans_700Bold,
36-
});
3726
const colorScheme = useColorScheme();
3827
const statusBarBg = useThemeColor("--color-status-bar");
3928

4029
useEffect(() => {
41-
if (fontsLoaded) SplashScreen.hide();
42-
}, [fontsLoaded]);
30+
SplashScreen.hide();
31+
}, []);
4332

4433
return (
4534
<RegistryContext.Provider value={appAtomRegistry}>

apps/mobile/src/components/AppText.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
type TextInputProps as RNTextInputProps,
55
type TextProps as RNTextProps,
66
} from "react-native";
7-
import { useThemeColor } from "../lib/useThemeColor";
87

98
import { cn } from "../lib/cn";
109

@@ -18,7 +17,7 @@ export function AppText({ className, ...props }: AppTextProps) {
1817
return <RNText className={cn("font-sans text-foreground", className)} {...props} />;
1918
}
2019

21-
export type AppTextInputProps = RNTextInputProps & {
20+
export type AppTextInputProps = Omit<RNTextInputProps, "placeholderTextColor"> & {
2221
readonly className?: string;
2322
readonly ref?: React.Ref<RNTextInput>;
2423
};
@@ -27,22 +26,15 @@ export type AppTextInputProps = RNTextInputProps & {
2726
* Thin wrapper around RN TextInput with default input styling.
2827
* Uses Uniwind className — no manual style parsing.
2928
*/
30-
export function AppTextInput({
31-
className,
32-
placeholderTextColor,
33-
ref,
34-
...props
35-
}: AppTextInputProps) {
36-
const placeholderColor = useThemeColor("--color-placeholder");
37-
29+
export function AppTextInput({ className, ref, ...props }: AppTextInputProps) {
3830
return (
3931
<RNTextInput
4032
ref={ref}
4133
className={cn(
4234
"min-h-13.5 rounded-2xl border border-input-border bg-input px-3.5 py-3 font-sans text-base text-foreground",
4335
className,
4436
)}
45-
placeholderTextColor={placeholderTextColor ?? placeholderColor}
37+
placeholderTextColorClassName="accent-placeholder"
4638
{...props}
4739
/>
4840
);

apps/mobile/src/components/BrandMark.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,9 @@ export function BrandMark(props: { readonly compact?: boolean; readonly stageLab
2222
/>
2323
<View className="gap-1">
2424
<View className="flex-row items-center gap-2">
25-
<Text className="text-lg font-t3-bold text-foreground" style={{ letterSpacing: -0.4 }}>
26-
T3 Code
27-
</Text>
25+
<Text className="text-lg font-t3-bold tracking-[-0.4px] text-foreground">T3 Code</Text>
2826
<View className="rounded-full bg-subtle px-2 py-1">
29-
<Text
30-
className="text-3xs font-t3-bold uppercase text-foreground-muted"
31-
style={{ letterSpacing: 1.1 }}
32-
>
27+
<Text className="text-3xs font-t3-bold tracking-[1.1px] uppercase text-foreground-muted">
3328
{stageLabel}
3429
</Text>
3530
</View>

apps/mobile/src/components/ComposerAttachmentStrip.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ export function ComposerAttachmentStrip(props: ComposerAttachmentStripProps) {
3939
horizontal
4040
showsHorizontalScrollIndicator={false}
4141
keyboardShouldPersistTaps="always"
42-
style={{ flexGrow: 0 }}
42+
className="grow-0"
4343
>
44-
<View style={{ flexDirection: "row", gap: 10 }}>
44+
<View className="flex-row gap-2.5">
4545
{props.attachments.map((image) => (
4646
<View
4747
key={image.id}
48+
className="relative"
4849
style={{
49-
position: "relative",
5050
paddingTop: removeButtonGutter,
5151
paddingRight: removeButtonGutter,
5252
}}
@@ -66,16 +66,10 @@ export function ComposerAttachmentStrip(props: ComposerAttachmentStripProps) {
6666
/>
6767
</Pressable>
6868
<Pressable
69+
className="absolute h-[22px] w-[22px] items-center justify-center rounded-[11px] bg-black/55"
6970
style={{
70-
position: "absolute",
7171
top: removeButtonPlacement === "gutter" ? 0 : 4,
7272
right: removeButtonPlacement === "gutter" ? 0 : 4,
73-
width: 22,
74-
height: 22,
75-
borderRadius: 11,
76-
backgroundColor: "rgba(0,0,0,0.55)",
77-
alignItems: "center",
78-
justifyContent: "center",
7973
}}
8074
hitSlop={6}
8175
onPress={() => props.onRemove(image.id)}

apps/mobile/src/components/ComposerToolbarTrigger.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,9 @@ export function ComposerToolbarRow(props: {
3131
}) {
3232
return (
3333
<View
34+
className="flex-row items-center gap-1.5"
3435
style={[
3536
{
36-
alignItems: "center",
37-
flexDirection: "row",
38-
gap: 6,
3937
paddingBottom: props.paddingBottom ?? 8,
4038
paddingHorizontal: props.paddingHorizontal ?? 6,
4139
paddingTop: props.paddingTop ?? 8,
@@ -89,7 +87,7 @@ export function ComposerToolbarScroller(props: {
8987
}, []);
9088

9189
return (
92-
<View className="min-w-0 flex-1" style={{ position: "relative" }}>
90+
<View className="relative min-w-0 flex-1">
9391
<ScrollView
9492
horizontal
9593
keyboardShouldPersistTaps="always"

apps/mobile/src/components/GlassSafeAreaView.tsx

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,12 @@ export function GlassSafeAreaView({
3939
style={{ borderRadius: 0, backgroundColor: "transparent" }}
4040
>
4141
<View
42-
style={{
43-
flexDirection: "row",
44-
alignItems: "center",
45-
paddingHorizontal: 20,
46-
paddingTop: headerPaddingTop,
47-
paddingBottom: 16,
48-
gap: 10,
49-
}}
42+
className="flex-row items-center gap-2.5 px-5 pb-4"
43+
style={{ paddingTop: headerPaddingTop }}
5044
>
51-
<View style={{ alignItems: "flex-start", justifyContent: "center" }}>{leftSlot}</View>
52-
<View
53-
style={{ flex: 1, alignItems: "center", justifyContent: "center", overflow: "hidden" }}
54-
>
55-
{centerSlot}
56-
</View>
57-
<View style={{ alignItems: "flex-end", justifyContent: "center" }}>{rightSlot}</View>
45+
<View className="items-start justify-center">{leftSlot}</View>
46+
<View className="flex-1 items-center justify-center overflow-hidden">{centerSlot}</View>
47+
<View className="items-end justify-center">{rightSlot}</View>
5848
</View>
5949
</GlassSurface>
6050
</View>

0 commit comments

Comments
 (0)