authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-19 16:49:35-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-19 16:49:35-07:00
loge29ad7604b1597e3a741868c85ffd76bca84fa7f
tree197f7e2849ae141cce69265514e9312a589a1fa9
parentcdaba7fa8b9c94dba783b7161e265a6db03b3d93
signature Signed by PGP key B5690EEEBB952194

Unify mobile typography tokens across the app (#3162)

Co-authored-by: codex <codex@users.noreply.github.com>

59 files changed, 415 insertions(+), 289 deletions(-)

apps/mobile/.swiftlint.yml+1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1included:1included:
2 - ios/T3Code2 - ios/T3Code
3 - modules/t3-composer-editor/ios
3 - modules/t3-terminal/ios4 - modules/t3-terminal/ios
4 - modules/t3-review-diff/ios5 - modules/t3-review-diff/ios
56
apps/mobile/global.css+21-1
...@@ -192,11 +192,31 @@...@@ -192,11 +192,31 @@
192 }192 }
193}193}
194194
195/* ─── Font family ───────────────────────────────────────────────────── */195/* ─── Typography ────────────────────────────────────────────────────── */
196@theme {196@theme {
197 --font-sans: "DMSans_400Regular";197 --font-sans: "DMSans_400Regular";
198 --font-medium: "DMSans_500Medium";198 --font-medium: "DMSans_500Medium";
199 --font-bold: "DMSans_700Bold";199 --font-bold: "DMSans_700Bold";
200
201 /* Keep this scale aligned with src/lib/typography.ts for native style props. */
202 --text-3xs: 10px;
203 --text-3xs--line-height: 13px;
204 --text-2xs: 11px;
205 --text-2xs--line-height: 15px;
206 --text-xs: 12px;
207 --text-xs--line-height: 16px;
208 --text-sm: 13px;
209 --text-sm--line-height: 18px;
210 --text-base: 15px;
211 --text-base--line-height: 22px;
212 --text-lg: 17px;
213 --text-lg--line-height: 22px;
214 --text-xl: 20px;
215 --text-xl--line-height: 26px;
216 --text-2xl: 24px;
217 --text-2xl--line-height: 30px;
218 --text-3xl: 28px;
219 --text-3xl--line-height: 34px;
200}220}
201221
202/* ─── Custom utilities ──────────────────────────────────────────────── */222/* ─── Custom utilities ──────────────────────────────────────────────── */
apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift+27-4
...@@ -275,8 +275,8 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {...@@ -275,8 +275,8 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
275 fileTint: "#737373"275 fileTint: "#737373"
276 )276 )
277 private var fontFamily = "DMSans_400Regular"277 private var fontFamily = "DMSans_400Regular"
278 private var fontSize: CGFloat = 15278 private var fontSize: CGFloat = 14
279 private var lineHeight: CGFloat = 22279 private var lineHeight: CGFloat = 20
280 private var contentInsetVertical: CGFloat = 0280 private var contentInsetVertical: CGFloat = 0
281 private var shouldAutoFocus = false281 private var shouldAutoFocus = false
282 private var didAutoFocus = false282 private var didAutoFocus = false
...@@ -460,9 +460,19 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {...@@ -460,9 +460,19 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
460 guard !isApplyingControlledValue else {460 guard !isApplyingControlledValue else {
461 return461 return
462 }462 }
463 restoreBaseTypingAttributes()
463 emitSelection()464 emitSelection()
464 }465 }
465466
467 public func textView(
468 _ textView: UITextView,
469 shouldChangeTextIn range: NSRange,
470 replacementText text: String
471 ) -> Bool {
472 restoreBaseTypingAttributes()
473 return true
474 }
475
466 public func textViewDidBeginEditing(_ textView: UITextView) {476 public func textViewDidBeginEditing(_ textView: UITextView) {
467 onComposerFocus()477 onComposerFocus()
468 }478 }
...@@ -484,6 +494,7 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {...@@ -484,6 +494,7 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
484 let targetSelection = requestedSelection ?? previousSelection494 let targetSelection = requestedSelection ?? previousSelection
485 requestedSelection = nil495 requestedSelection = nil
486 textView.selectedRange = displayRange(for: targetSelection)496 textView.selectedRange = displayRange(for: targetSelection)
497 restoreBaseTypingAttributes()
487 isApplyingControlledValue = false498 isApplyingControlledValue = false
488 updatePlaceholderVisibility()499 updatePlaceholderVisibility()
489 emitContentSizeIfNeeded()500 emitContentSizeIfNeeded()
...@@ -556,7 +567,12 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {...@@ -556,7 +567,12 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
556 size: image.size,567 size: image.size,
557 baselineOffset: baselineOffset568 baselineOffset: baselineOffset
558 )569 )
559 return NSAttributedString(attachment: attachment)570 let attributedAttachment = NSMutableAttributedString(attachment: attachment)
571 attributedAttachment.addAttributes(
572 baseAttributes(),
573 range: NSRange(location: 0, length: attributedAttachment.length)
574 )
575 return attributedAttachment
560 }576 }
561577
562 private func renderChip(578 private func renderChip(
...@@ -660,11 +676,18 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {...@@ -660,11 +676,18 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
660 let font = UIFont(name: fontFamily, size: fontSize)676 let font = UIFont(name: fontFamily, size: fontSize)
661 ?? UIFont.systemFont(ofSize: fontSize)677 ?? UIFont.systemFont(ofSize: fontSize)
662 textView.font = font678 textView.font = font
663 textView.typingAttributes = baseAttributes()679 restoreBaseTypingAttributes()
664 placeholderLabel.font = font680 placeholderLabel.font = font
665 setNeedsLayout()681 setNeedsLayout()
666 }682 }
667683
684 private func restoreBaseTypingAttributes() {
685 guard textView.markedTextRange == nil else {
686 return
687 }
688 textView.typingAttributes = baseAttributes()
689 }
690
668 private func applyTheme() {691 private func applyTheme() {
669 textView.textColor = UIColor(composerHex: theme.text) ?? .label692 textView.textColor = UIColor(composerHex: theme.text) ?? .label
670 placeholderLabel.textColor = UIColor(composerHex: theme.placeholder) ?? .placeholderText693 placeholderLabel.textColor = UIColor(composerHex: theme.placeholder) ?? .placeholderText
apps/mobile/src/app/+not-found.tsx+2-2
...@@ -21,7 +21,7 @@ export default function NotFoundRoute() {...@@ -21,7 +21,7 @@ export default function NotFoundRoute() {
21 }}21 }}
22 style={[{ flex: 1 }, screenBgStyle]}22 style={[{ flex: 1 }, screenBgStyle]}
23 >23 >
24 <Text className="text-[28px] font-t3-bold text-foreground" selectable>24 <Text className="text-3xl font-t3-bold text-foreground" selectable>
25 Route not found25 Route not found
26 </Text>26 </Text>
27 <Link href="/" asChild>27 <Link href="/" asChild>
...@@ -35,7 +35,7 @@ export default function NotFoundRoute() {...@@ -35,7 +35,7 @@ export default function NotFoundRoute() {
35 primaryBgStyle,35 primaryBgStyle,
36 ]}36 ]}
37 >37 >
38 <Text className="text-[16px] font-t3-bold text-primary-foreground">Return home</Text>38 <Text className="text-base font-t3-bold text-primary-foreground">Return home</Text>
39 </Pressable>39 </Pressable>
40 </Link>40 </Link>
41 </ScrollView>41 </ScrollView>
apps/mobile/src/app/connections/index.tsx+1-1
...@@ -85,7 +85,7 @@ export default function ConnectionsRouteScreen() {...@@ -85,7 +85,7 @@ export default function ConnectionsRouteScreen() {
85 type="monochrome"85 type="monochrome"
86 />86 />
87 </View>87 </View>
88 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">88 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
89 No environments connected yet.{"\n"}Tap{" "}89 No environments connected yet.{"\n"}Tap{" "}
90 <Text className="font-t3-bold text-foreground">+</Text> to add one.90 <Text className="font-t3-bold text-foreground">+</Text> to add one.
91 </Text>91 </Text>
apps/mobile/src/app/connections/new.tsx+5-5
...@@ -171,7 +171,7 @@ export default function ConnectionsNewRouteScreen() {...@@ -171,7 +171,7 @@ export default function ConnectionsNewRouteScreen() {
171 className="items-center gap-3 rounded-[24px] bg-card px-5 py-8"171 className="items-center gap-3 rounded-[24px] bg-card px-5 py-8"
172 style={{ borderCurve: "continuous" }}172 style={{ borderCurve: "continuous" }}
173 >173 >
174 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">174 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
175 Camera permission is required to scan a QR code.175 Camera permission is required to scan a QR code.
176 </Text>176 </Text>
177 <ConnectionSheetButton177 <ConnectionSheetButton
...@@ -189,7 +189,7 @@ export default function ConnectionsNewRouteScreen() {...@@ -189,7 +189,7 @@ export default function ConnectionsNewRouteScreen() {
189 <View collapsable={false} className="gap-4 rounded-[24px] bg-card p-4">189 <View collapsable={false} className="gap-4 rounded-[24px] bg-card p-4">
190 <View collapsable={false} className="gap-1.5">190 <View collapsable={false} className="gap-1.5">
191 <Text191 <Text
192 className="text-[11px] font-t3-bold uppercase text-foreground-muted"192 className="text-2xs font-t3-bold uppercase text-foreground-muted"
193 style={{ letterSpacing: 0.8 }}193 style={{ letterSpacing: 0.8 }}
194 >194 >
195 Host195 Host
...@@ -202,13 +202,13 @@ export default function ConnectionsNewRouteScreen() {...@@ -202,13 +202,13 @@ export default function ConnectionsNewRouteScreen() {
202 placeholderTextColor={placeholderColor}202 placeholderTextColor={placeholderColor}
203 value={hostInput}203 value={hostInput}
204 onChangeText={handleHostChange}204 onChangeText={handleHostChange}
205 className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-[15px] text-foreground"205 className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-base text-foreground"
206 />206 />
207 </View>207 </View>
208208
209 <View collapsable={false} className="gap-1.5">209 <View collapsable={false} className="gap-1.5">
210 <Text210 <Text
211 className="text-[11px] font-t3-bold uppercase text-foreground-muted"211 className="text-2xs font-t3-bold uppercase text-foreground-muted"
212 style={{ letterSpacing: 0.8 }}212 style={{ letterSpacing: 0.8 }}
213 >213 >
214 Pairing code214 Pairing code
...@@ -220,7 +220,7 @@ export default function ConnectionsNewRouteScreen() {...@@ -220,7 +220,7 @@ export default function ConnectionsNewRouteScreen() {
220 placeholderTextColor={placeholderColor}220 placeholderTextColor={placeholderColor}
221 value={codeInput}221 value={codeInput}
222 onChangeText={handleCodeChange}222 onChangeText={handleCodeChange}
223 className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-[15px] text-foreground"223 className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-base text-foreground"
224 />224 />
225 </View>225 </View>
226226
apps/mobile/src/app/new/index.tsx+5-7
...@@ -129,10 +129,10 @@ export default function NewTaskRoute() {...@@ -129,10 +129,10 @@ export default function NewTaskRoute() {
129 {items.length === 0 ? (129 {items.length === 0 ? (
130 <View collapsable={false} className="items-center gap-3 rounded-[24px] bg-card px-6 py-8">130 <View collapsable={false} className="items-center gap-3 rounded-[24px] bg-card px-6 py-8">
131 {projectEmptyState.loading ? <ActivityIndicator color={accentColor} /> : null}131 {projectEmptyState.loading ? <ActivityIndicator color={accentColor} /> : null}
132 <Text className="text-center text-[17px] font-t3-bold text-foreground">132 <Text className="text-center text-lg font-t3-bold text-foreground">
133 {projectEmptyState.title}133 {projectEmptyState.title}
134 </Text>134 </Text>
135 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">135 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
136 {projectEmptyState.detail}136 {projectEmptyState.detail}
137 </Text>137 </Text>
138 {!catalogState.hasReadyEnvironment ? (138 {!catalogState.hasReadyEnvironment ? (
...@@ -140,7 +140,7 @@ export default function NewTaskRoute() {...@@ -140,7 +140,7 @@ export default function NewTaskRoute() {
140 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"140 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
141 onPress={() => router.push("/connections/new")}141 onPress={() => router.push("/connections/new")}
142 >142 >
143 <Text className="text-[13px] font-t3-bold text-primary-foreground">143 <Text className="text-sm font-t3-bold text-primary-foreground">
144 Add environment144 Add environment
145 </Text>145 </Text>
146 </Pressable>146 </Pressable>
...@@ -149,7 +149,7 @@ export default function NewTaskRoute() {...@@ -149,7 +149,7 @@ export default function NewTaskRoute() {
149 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"149 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
150 onPress={() => router.push("/new/add-project")}150 onPress={() => router.push("/new/add-project")}
151 >151 >
152 <Text className="text-[13px] font-t3-bold text-primary-foreground">152 <Text className="text-sm font-t3-bold text-primary-foreground">
153 Add new project153 Add new project
154 </Text>154 </Text>
155 </Pressable>155 </Pressable>
...@@ -197,9 +197,7 @@ export default function NewTaskRoute() {...@@ -197,9 +197,7 @@ export default function NewTaskRoute() {
197 />197 />
198 </View>198 </View>
199 <View className="flex-1">199 <View className="flex-1">
200 <Text className="text-[16px] leading-[21px] font-t3-bold">200 <Text className="text-base leading-[21px] font-t3-bold">{item.title}</Text>
201 {item.title}
202 </Text>
203 </View>201 </View>
204 <SymbolView202 <SymbolView
205 name="chevron.right"203 name="chevron.right"
apps/mobile/src/app/settings/environments.tsx+11-11
...@@ -111,7 +111,7 @@ export default function SettingsEnvironmentsRouteScreen() {...@@ -111,7 +111,7 @@ export default function SettingsEnvironmentsRouteScreen() {
111 type="monochrome"111 type="monochrome"
112 />112 />
113 </View>113 </View>
114 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">114 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
115 No environments connected yet.{"\n"}Tap{" "}115 No environments connected yet.{"\n"}Tap{" "}
116 <Text className="font-t3-bold text-foreground">+</Text> to add one.116 <Text className="font-t3-bold text-foreground">+</Text> to add one.
117 </Text>117 </Text>
...@@ -160,7 +160,7 @@ function ConfiguredCloudEnvironmentRows(props: {...@@ -160,7 +160,7 @@ function ConfiguredCloudEnvironmentRows(props: {
160 return (160 return (
161 <View collapsable={false} className="mt-5 gap-3">161 <View collapsable={false} className="mt-5 gap-3">
162 <View className="flex-row items-center justify-between px-1">162 <View className="flex-row items-center justify-between px-1">
163 <Text className="text-[13px] font-t3-bold uppercase text-foreground-muted">T3 Cloud</Text>163 <Text className="text-sm font-t3-bold uppercase text-foreground-muted">T3 Cloud</Text>
164 <Pressable164 <Pressable
165 accessibilityRole="button"165 accessibilityRole="button"
166 disabled={controller.relayDiscovery.isRefreshing}166 disabled={controller.relayDiscovery.isRefreshing}
...@@ -204,16 +204,16 @@ function ConfiguredCloudEnvironmentRows(props: {...@@ -204,16 +204,16 @@ function ConfiguredCloudEnvironmentRows(props: {
204 ) : controller.relayDiscovery.isRefreshing ? (204 ) : controller.relayDiscovery.isRefreshing ? (
205 <View collapsable={false} className="items-center gap-3 rounded-[24px] bg-card p-6">205 <View collapsable={false} className="items-center gap-3 rounded-[24px] bg-card p-6">
206 <ActivityIndicator color={iconColor} />206 <ActivityIndicator color={iconColor} />
207 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">207 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
208 Loading linked cloud environments.208 Loading linked cloud environments.
209 </Text>209 </Text>
210 </View>210 </View>
211 ) : controller.relayDiscovery.error ? (211 ) : controller.relayDiscovery.error ? (
212 <View collapsable={false} className="gap-3 rounded-[24px] bg-card p-5">212 <View collapsable={false} className="gap-3 rounded-[24px] bg-card p-5">
213 <Text className="text-[15px] font-t3-bold text-foreground">213 <Text className="text-base font-t3-bold text-foreground">
214 Could not load T3 Cloud environments214 Could not load T3 Cloud environments
215 </Text>215 </Text>
216 <Text className="text-[13px] leading-[18px] text-foreground-muted">216 <Text className="text-sm leading-[18px] text-foreground-muted">
217 {controller.relayDiscovery.error}217 {controller.relayDiscovery.error}
218 </Text>218 </Text>
219 {controller.relayDiscovery.errorTraceId ? (219 {controller.relayDiscovery.errorTraceId ? (
...@@ -222,7 +222,7 @@ function ConfiguredCloudEnvironmentRows(props: {...@@ -222,7 +222,7 @@ function ConfiguredCloudEnvironmentRows(props: {
222 </View>222 </View>
223 ) : (223 ) : (
224 <View collapsable={false} className="rounded-[24px] bg-card p-5">224 <View collapsable={false} className="rounded-[24px] bg-card p-5">
225 <Text className="text-[14px] leading-[20px] text-foreground-muted">225 <Text className="text-sm leading-[20px] text-foreground-muted">
226 No additional linked cloud environments.226 No additional linked cloud environments.
227 </Text>227 </Text>
228 </View>228 </View>
...@@ -361,7 +361,7 @@ function CloudEnvironmentRowShell(props: {...@@ -361,7 +361,7 @@ function CloudEnvironmentRowShell(props: {
361 <View className="min-w-0 flex-row items-center gap-2">361 <View className="min-w-0 flex-row items-center gap-2">
362 <ConnectionStatusDot state={props.connectionState} pulse={shouldPulse} size={7} />362 <ConnectionStatusDot state={props.connectionState} pulse={shouldPulse} size={7} />
363 <Text363 <Text
364 className="min-w-0 flex-shrink text-[16px] font-t3-bold leading-[21px] text-foreground"364 className="min-w-0 flex-shrink text-base font-t3-bold leading-[21px] text-foreground"
365 numberOfLines={1}365 numberOfLines={1}
366 >366 >
367 {props.label}367 {props.label}
...@@ -370,7 +370,7 @@ function CloudEnvironmentRowShell(props: {...@@ -370,7 +370,7 @@ function CloudEnvironmentRowShell(props: {
370 {props.connectionError ? (370 {props.connectionError ? (
371 <Text371 <Text
372 aria-hidden372 aria-hidden
373 className={cn("absolute left-0 right-0 text-[12px] leading-[16px]", statusClassName)}373 className={cn("absolute left-0 right-0 text-xs leading-[16px]", statusClassName)}
374 onTextLayout={onMeasuredErrorTextLayout}374 onTextLayout={onMeasuredErrorTextLayout}
375 style={{ opacity: 0, zIndex: -1 }}375 style={{ opacity: 0, zIndex: -1 }}
376 >376 >
...@@ -384,7 +384,7 @@ function CloudEnvironmentRowShell(props: {...@@ -384,7 +384,7 @@ function CloudEnvironmentRowShell(props: {
384 className="min-w-0 flex-row items-start gap-1"384 className="min-w-0 flex-row items-start gap-1"
385 >385 >
386 <Text386 <Text
387 className={cn("min-w-0 flex-1 text-[12px] leading-[16px]", statusClassName)}387 className={cn("min-w-0 flex-1 text-xs leading-[16px]", statusClassName)}
388 numberOfLines={isErrorExpanded ? undefined : 1}388 numberOfLines={isErrorExpanded ? undefined : 1}
389 >389 >
390 {statusText}390 {statusText}
...@@ -394,7 +394,7 @@ function CloudEnvironmentRowShell(props: {...@@ -394,7 +394,7 @@ function CloudEnvironmentRowShell(props: {
394 <Text394 <Text
395 accessibilityHint="Copies the trace ID"395 accessibilityHint="Copies the trace ID"
396 accessibilityRole="button"396 accessibilityRole="button"
397 className={cn("text-[12px] leading-[16px] underline", statusClassName)}397 className={cn("text-xs leading-[16px] underline", statusClassName)}
398 onLongPress={(event) => {398 onLongPress={(event) => {
399 event.stopPropagation();399 event.stopPropagation();
400 copyTextWithHaptic(errorTraceId);400 copyTextWithHaptic(errorTraceId);
...@@ -446,7 +446,7 @@ function CopyTraceIdButton(props: { readonly traceId: string }) {...@@ -446,7 +446,7 @@ function CopyTraceIdButton(props: { readonly traceId: string }) {
446 className="self-start flex-row items-center gap-1.5 rounded-full bg-subtle px-3 py-2 active:opacity-70"446 className="self-start flex-row items-center gap-1.5 rounded-full bg-subtle px-3 py-2 active:opacity-70"
447 >447 >
448 <SymbolView name="doc.on.doc" size={12} tintColor={iconColor} type="monochrome" />448 <SymbolView name="doc.on.doc" size={12} tintColor={iconColor} type="monochrome" />
449 <Text className="text-[12px] font-t3-bold text-foreground">Copy trace ID</Text>449 <Text className="text-xs font-t3-bold text-foreground">Copy trace ID</Text>
450 </Pressable>450 </Pressable>
451 );451 );
452}452}
apps/mobile/src/app/settings/index.tsx+7-7
...@@ -346,7 +346,7 @@ function ConfiguredSettingsRouteScreen() {...@@ -346,7 +346,7 @@ function ConfiguredSettingsRouteScreen() {
346 onPress={openAccount}346 onPress={openAccount}
347 />347 />
348 </SettingsSection>348 </SettingsSection>
349 <Text className="px-2 text-[13px] leading-[18px] text-foreground-muted">349 <Text className="px-2 text-sm leading-[18px] text-foreground-muted">
350 T3 Code works locally without signing in. Cloud features are optional.350 T3 Code works locally without signing in. Cloud features are optional.
351 </Text>351 </Text>
352 </View>352 </View>
...@@ -389,7 +389,7 @@ type SymbolName = ComponentProps<typeof SymbolView>["name"];...@@ -389,7 +389,7 @@ type SymbolName = ComponentProps<typeof SymbolView>["name"];
389function SettingsSection(props: { readonly title: string; readonly children: ReactNode }) {389function SettingsSection(props: { readonly title: string; readonly children: ReactNode }) {
390 return (390 return (
391 <View className="gap-2">391 <View className="gap-2">
392 <Text className="px-2 text-[13px] font-t3-medium text-foreground-muted">{props.title}</Text>392 <Text className="px-2 text-sm font-t3-medium text-foreground-muted">{props.title}</Text>
393 <View393 <View
394 className="overflow-hidden rounded-[28px] bg-card"394 className="overflow-hidden rounded-[28px] bg-card"
395 style={{ borderCurve: "continuous" }}395 style={{ borderCurve: "continuous" }}
...@@ -413,8 +413,8 @@ function AppSettingsSection() {...@@ -413,8 +413,8 @@ function AppSettingsSection() {
413 type="monochrome"413 type="monochrome"
414 weight="regular"414 weight="regular"
415 />415 />
416 <Text className="flex-1 text-[17px] text-foreground">Version</Text>416 <Text className="flex-1 text-lg text-foreground">Version</Text>
417 <Text className="text-[17px] text-foreground-muted">Alpha</Text>417 <Text className="text-lg text-foreground-muted">Alpha</Text>
418 </View>418 </View>
419 </SettingsSection>419 </SettingsSection>
420 );420 );
...@@ -444,13 +444,13 @@ function SettingsRow(props: {...@@ -444,13 +444,13 @@ function SettingsRow(props: {
444 style={{ opacity: props.disabled ? 0.45 : 1 }}444 style={{ opacity: props.disabled ? 0.45 : 1 }}
445 >445 >
446 <SymbolView name={props.icon} size={22} tintColor={icon} type="monochrome" weight="regular" />446 <SymbolView name={props.icon} size={22} tintColor={icon} type="monochrome" weight="regular" />
447 <Text className="shrink-0 text-[17px] text-foreground" numberOfLines={1}>447 <Text className="shrink-0 text-lg text-foreground" numberOfLines={1}>
448 {props.label}448 {props.label}
449 </Text>449 </Text>
450 <View className="min-w-0 flex-1 items-end">450 <View className="min-w-0 flex-1 items-end">
451 {props.value ? (451 {props.value ? (
452 <Text452 <Text
453 className="max-w-[180px] text-right text-[16px] text-foreground-muted"453 className="max-w-[180px] text-right text-base text-foreground-muted"
454 ellipsizeMode="middle"454 ellipsizeMode="middle"
455 numberOfLines={1}455 numberOfLines={1}
456 >456 >
...@@ -502,7 +502,7 @@ function SettingsSwitchRow(props: {...@@ -502,7 +502,7 @@ function SettingsSwitchRow(props: {
502 style={{ opacity: props.disabled ? 0.45 : 1 }}502 style={{ opacity: props.disabled ? 0.45 : 1 }}
503 >503 >
504 <SymbolView name={props.icon} size={22} tintColor={icon} type="monochrome" weight="regular" />504 <SymbolView name={props.icon} size={22} tintColor={icon} type="monochrome" weight="regular" />
505 <Text className="flex-1 text-[17px] text-foreground">{props.label}</Text>505 <Text className="flex-1 text-lg text-foreground">{props.label}</Text>
506 <Switch506 <Switch
507 disabled={props.disabled}507 disabled={props.disabled}
508 ios_backgroundColor={track}508 ios_backgroundColor={track}
apps/mobile/src/components/AppText.tsx+1-1
...@@ -40,7 +40,7 @@ export function AppTextInput({...@@ -40,7 +40,7 @@ export function AppTextInput({
40 <RNTextInput40 <RNTextInput
41 ref={ref}41 ref={ref}
42 className={cn(42 className={cn(
43 "min-h-[54px] rounded-2xl border border-input-border bg-input px-3.5 py-3 font-sans text-[15px] text-foreground",43 "min-h-[54px] rounded-2xl border border-input-border bg-input px-3.5 py-3 font-sans text-base text-foreground",
44 className,44 className,
45 )}45 )}
46 placeholderTextColor={placeholderTextColor ?? placeholderColor}46 placeholderTextColor={placeholderTextColor ?? placeholderColor}
apps/mobile/src/components/BrandMark.tsx+3-6
...@@ -22,15 +22,12 @@ export function BrandMark(props: { readonly compact?: boolean; readonly stageLab...@@ -22,15 +22,12 @@ export function BrandMark(props: { readonly compact?: boolean; readonly stageLab
22 />22 />
23 <View className="gap-1">23 <View className="gap-1">
24 <View className="flex-row items-center gap-2">24 <View className="flex-row items-center gap-2">
25 <Text25 <Text className="text-lg font-t3-bold text-foreground" style={{ letterSpacing: -0.4 }}>
26 className="text-[17px] font-t3-bold text-foreground"
27 style={{ letterSpacing: -0.4 }}
28 >
29 T3 Code26 T3 Code
30 </Text>27 </Text>
31 <View className="rounded-full bg-subtle px-2 py-1">28 <View className="rounded-full bg-subtle px-2 py-1">
32 <Text29 <Text
33 className="text-[10px] font-t3-bold uppercase text-foreground-muted"30 className="text-3xs font-t3-bold uppercase text-foreground-muted"
34 style={{ letterSpacing: 1.1 }}31 style={{ letterSpacing: 1.1 }}
35 >32 >
36 {stageLabel}33 {stageLabel}
...@@ -38,7 +35,7 @@ export function BrandMark(props: { readonly compact?: boolean; readonly stageLab...@@ -38,7 +35,7 @@ export function BrandMark(props: { readonly compact?: boolean; readonly stageLab
38 </View>35 </View>
39 </View>36 </View>
40 {!compact ? (37 {!compact ? (
41 <Text className="text-[12px] font-medium text-foreground-muted">38 <Text className="text-xs font-medium text-foreground-muted">
42 Mobile control surface for your live coding environments39 Mobile control surface for your live coding environments
43 </Text>40 </Text>
44 ) : null}41 ) : null}
apps/mobile/src/components/ComposerToolbarTrigger.tsx+1-1
...@@ -223,7 +223,7 @@ export function ComposerToolbarButton(props: {...@@ -223,7 +223,7 @@ export function ComposerToolbarButton(props: {
223 {props.label ? (223 {props.label ? (
224 <Text224 <Text
225 className={cn(225 className={cn(
226 "shrink text-center text-[13px] font-t3-bold",226 "shrink text-center text-sm font-t3-bold",
227 variant === "primary"227 variant === "primary"
228 ? props.disabled228 ? props.disabled
229 ? "text-foreground-muted"229 ? "text-foreground-muted"
apps/mobile/src/components/ControlPill.tsx+1-1
...@@ -48,7 +48,7 @@ export function ControlPill(props: {...@@ -48,7 +48,7 @@ export function ControlPill(props: {
48 : "bg-subtle",48 : "bg-subtle",
49 );49 );
50 const labelClassName = cn(50 const labelClassName = cn(
51 "text-center text-[12px] font-t3-bold",51 "text-center text-xs font-t3-bold",
52 variant === "primary"52 variant === "primary"
53 ? props.disabled53 ? props.disabled
54 ? "text-foreground-muted"54 ? "text-foreground-muted"
apps/mobile/src/components/EmptyState.tsx+1-3
...@@ -19,9 +19,7 @@ export function EmptyState(props: {...@@ -19,9 +19,7 @@ export function EmptyState(props: {
19 className="mt-4 self-start rounded-full bg-primary px-4 py-2.5 active:opacity-70"19 className="mt-4 self-start rounded-full bg-primary px-4 py-2.5 active:opacity-70"
20 onPress={props.onAction}20 onPress={props.onAction}
21 >21 >
22 <Text className="text-[13px] font-t3-bold text-primary-foreground">22 <Text className="text-sm font-t3-bold text-primary-foreground">{props.actionLabel}</Text>
23 {props.actionLabel}
24 </Text>
25 </Pressable>23 </Pressable>
26 ) : null}24 ) : null}
27 </View>25 </View>
apps/mobile/src/components/ErrorBanner.tsx+1-1
...@@ -4,7 +4,7 @@ import { AppText as Text } from "./AppText";...@@ -4,7 +4,7 @@ import { AppText as Text } from "./AppText";
4export function ErrorBanner(props: { readonly message: string }) {4export function ErrorBanner(props: { readonly message: string }) {
5 return (5 return (
6 <View className="rounded-2xl border border-rose-300/70 bg-rose-100/80 px-3.5 py-3 dark:border-rose-400/28 dark:bg-rose-500/12">6 <View className="rounded-2xl border border-rose-300/70 bg-rose-100/80 px-3.5 py-3 dark:border-rose-400/28 dark:bg-rose-500/12">
7 <Text className="font-t3-medium text-[13px] leading-[18px] text-rose-700 dark:text-rose-300">7 <Text className="font-t3-medium text-sm leading-[18px] text-rose-700 dark:text-rose-300">
8 {props.message}8 {props.message}
9 </Text>9 </Text>
10 </View>10 </View>
apps/mobile/src/components/StatusPill.tsx+1-1
...@@ -26,7 +26,7 @@ export function StatusPill(...@@ -26,7 +26,7 @@ export function StatusPill(
26 <Text26 <Text
27 className={cn(27 className={cn(
28 "font-t3-bold",28 "font-t3-bold",
29 size === "compact" ? "text-[11px]" : "text-xs",29 size === "compact" ? "text-2xs" : "text-xs",
30 props.textClassName,30 props.textClassName,
31 )}31 )}
32 >32 >
apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx+11-9
...@@ -147,14 +147,14 @@ function ProjectGroupLabel(props: {...@@ -147,14 +147,14 @@ function ProjectGroupLabel(props: {
147 workspaceRoot={props.project.workspaceRoot}147 workspaceRoot={props.project.workspaceRoot}
148 />148 />
149 <Text149 <Text
150 className="flex-1 text-[12px] font-t3-medium uppercase text-foreground-muted"150 className="flex-1 text-xs font-t3-medium uppercase text-foreground-muted"
151 numberOfLines={1}151 numberOfLines={1}
152 style={{ letterSpacing: 0.5 }}152 style={{ letterSpacing: 0.5 }}
153 >153 >
154 {props.project.title}154 {props.project.title}
155 </Text>155 </Text>
156 {props.environmentLabel ? (156 {props.environmentLabel ? (
157 <Text className="max-w-[42%] text-[11px] text-foreground-tertiary" numberOfLines={1}>157 <Text className="max-w-[42%] text-2xs text-foreground-tertiary" numberOfLines={1}>
158 {props.environmentLabel}158 {props.environmentLabel}
159 </Text>159 </Text>
160 ) : null}160 ) : null}
...@@ -265,13 +265,13 @@ function ArchivedThreadRow(props: {...@@ -265,13 +265,13 @@ function ArchivedThreadRow(props: {
265 <View className="min-w-0 flex-1 gap-1">265 <View className="min-w-0 flex-1 gap-1">
266 <View className="flex-row items-center gap-2">266 <View className="flex-row items-center gap-2">
267 <Text267 <Text
268 className="min-w-0 flex-1 text-[15px] font-t3-bold leading-[20px] text-foreground"268 className="min-w-0 flex-1 text-base font-t3-bold leading-[20px] text-foreground"
269 numberOfLines={1}269 numberOfLines={1}
270 >270 >
271 {props.thread.title}271 {props.thread.title}
272 </Text>272 </Text>
273 <Text273 <Text
274 className="text-[12px] text-foreground-tertiary"274 className="text-xs text-foreground-tertiary"
275 style={{ fontVariant: ["tabular-nums"] }}275 style={{ fontVariant: ["tabular-nums"] }}
276 >276 >
277 {timestamp}277 {timestamp}
...@@ -286,7 +286,7 @@ function ArchivedThreadRow(props: {...@@ -286,7 +286,7 @@ function ArchivedThreadRow(props: {
286 type="monochrome"286 type="monochrome"
287 />287 />
288 <Text288 <Text
289 className="min-w-0 flex-1 text-[11px] text-foreground-tertiary"289 className="min-w-0 flex-1 text-2xs text-foreground-tertiary"
290 numberOfLines={1}290 numberOfLines={1}
291 style={{ fontFamily: "monospace" }}291 style={{ fontFamily: "monospace" }}
292 >292 >
...@@ -314,10 +314,12 @@ function ArchivedThreadRow(props: {...@@ -314,10 +314,12 @@ function ArchivedThreadRow(props: {
314function ArchiveError(props: { readonly message: string; readonly onRetry: () => void }) {314function ArchiveError(props: { readonly message: string; readonly onRetry: () => void }) {
315 return (315 return (
316 <View className="rounded-[20px] border border-danger-border bg-danger p-4">316 <View className="rounded-[20px] border border-danger-border bg-danger p-4">
317 <Text className="font-t3-bold text-danger-foreground">Could not load every archive</Text>317 <Text className="text-base font-t3-bold text-danger-foreground">
318 <Text className="mt-1 text-[13px] leading-[18px] text-foreground-muted">{props.message}</Text>318 Could not load every archive
319 </Text>
320 <Text className="mt-1 text-sm leading-[18px] text-foreground-muted">{props.message}</Text>
319 <Pressable className="mt-3 self-start active:opacity-60" onPress={props.onRetry}>321 <Pressable className="mt-3 self-start active:opacity-60" onPress={props.onRetry}>
320 <Text className="text-[13px] font-t3-bold text-danger-foreground">Try again</Text>322 <Text className="text-sm font-t3-bold text-danger-foreground">Try again</Text>
321 </Pressable>323 </Pressable>
322 </View>324 </View>
323 );325 );
...@@ -386,7 +388,7 @@ export function ArchivedThreadsScreen(props: {...@@ -386,7 +388,7 @@ export function ArchivedThreadsScreen(props: {
386 {isInitialLoad ? (388 {isInitialLoad ? (
387 <View className="items-center py-16">389 <View className="items-center py-16">
388 <ActivityIndicator color={refreshTint} />390 <ActivityIndicator color={refreshTint} />
389 <Text className="mt-3 text-[13px] text-foreground-muted">Loading archive…</Text>391 <Text className="mt-3 text-sm text-foreground-muted">Loading archive…</Text>
390 </View>392 </View>
391 ) : props.groups.length === 0 ? (393 ) : props.groups.length === 0 ? (
392 <EmptyState394 <EmptyState
apps/mobile/src/features/cloud/CloudWaitlistEnrollment.tsx+8-12
...@@ -2,6 +2,7 @@ import { useWaitlist } from "@clerk/expo";...@@ -2,6 +2,7 @@ import { useWaitlist } from "@clerk/expo";
2import { ActivityIndicator, Pressable, StyleSheet, Text, TextInput, View } from "react-native";2import { ActivityIndicator, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
3import { useState } from "react";3import { useState } from "react";
44
5import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
5import { useThemeColor } from "../../lib/useThemeColor";6import { useThemeColor } from "../../lib/useThemeColor";
67
7export function CloudWaitlistEnrollment(props: { readonly onSignIn: () => void }) {8export function CloudWaitlistEnrollment(props: { readonly onSignIn: () => void }) {
...@@ -141,12 +142,11 @@ function useCloudWaitlistColors() {...@@ -141,12 +142,11 @@ function useCloudWaitlistColors() {
141const styles = StyleSheet.create({142const styles = StyleSheet.create({
142 body: {143 body: {
143 fontFamily: "DMSans_400Regular",144 fontFamily: "DMSans_400Regular",
144 fontSize: 15,145 ...MOBILE_TYPOGRAPHY.body,
145 lineHeight: 21,
146 },146 },
147 buttonText: {147 buttonText: {
148 fontFamily: "DMSans_700Bold",148 fontFamily: "DMSans_700Bold",
149 fontSize: 16,149 fontSize: MOBILE_TYPOGRAPHY.body.fontSize,
150 },150 },
151 content: {151 content: {
152 gap: 18,152 gap: 18,
...@@ -156,8 +156,7 @@ const styles = StyleSheet.create({...@@ -156,8 +156,7 @@ const styles = StyleSheet.create({
156 },156 },
157 error: {157 error: {
158 fontFamily: "DMSans_400Regular",158 fontFamily: "DMSans_400Regular",
159 fontSize: 13,159 ...MOBILE_TYPOGRAPHY.footnote,
160 lineHeight: 18,
161 },160 },
162 field: {161 field: {
163 gap: 8,162 gap: 8,
...@@ -167,15 +166,14 @@ const styles = StyleSheet.create({...@@ -167,15 +166,14 @@ const styles = StyleSheet.create({
167 borderRadius: 16,166 borderRadius: 16,
168 borderWidth: 1,167 borderWidth: 1,
169 fontFamily: "DMSans_400Regular",168 fontFamily: "DMSans_400Regular",
170 fontSize: 17,169 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
171 minHeight: 54,170 minHeight: 54,
172 paddingHorizontal: 16,171 paddingHorizontal: 16,
173 paddingVertical: 14,172 paddingVertical: 14,
174 },173 },
175 label: {174 label: {
176 fontFamily: "DMSans_700Bold",175 fontFamily: "DMSans_700Bold",
177 fontSize: 13,176 ...MOBILE_TYPOGRAPHY.footnote,
178 lineHeight: 18,
179 },177 },
180 primaryButton: {178 primaryButton: {
181 alignItems: "center",179 alignItems: "center",
...@@ -196,13 +194,11 @@ const styles = StyleSheet.create({...@@ -196,13 +194,11 @@ const styles = StyleSheet.create({
196 },194 },
197 signInText: {195 signInText: {
198 fontFamily: "DMSans_700Bold",196 fontFamily: "DMSans_700Bold",
199 fontSize: 15,197 ...MOBILE_TYPOGRAPHY.body,
200 lineHeight: 21,
201 },198 },
202 title: {199 title: {
203 fontFamily: "DMSans_700Bold",200 fontFamily: "DMSans_700Bold",
204 fontSize: 20,201 ...MOBILE_TYPOGRAPHY.title,
205 lineHeight: 26,
206 textAlign: "center",202 textAlign: "center",
207 },203 },
208});204});
apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx+9-12
...@@ -76,19 +76,16 @@ export function ConnectionEnvironmentRow(props: {...@@ -76,19 +76,16 @@ export function ConnectionEnvironmentRow(props: {
76 />76 />
7777
78 <View className="flex-1 gap-0.5">78 <View className="flex-1 gap-0.5">
79 <Text79 <Text className="text-base font-t3-bold leading-[21px] text-foreground" numberOfLines={1}>
80 className="text-[16px] font-t3-bold leading-[21px] text-foreground"
81 numberOfLines={1}
82 >
83 {props.environment.environmentLabel}80 {props.environment.environmentLabel}
84 </Text>81 </Text>
85 <Text className="text-[12px] leading-[16px] text-foreground-muted" numberOfLines={1}>82 <Text className="text-xs leading-[16px] text-foreground-muted" numberOfLines={1}>
86 {props.environment.displayUrl}83 {props.environment.displayUrl}
87 </Text>84 </Text>
88 {statusLabel ? (85 {statusLabel ? (
89 <Text86 <Text
90 className={cn(87 className={cn(
91 "text-[12px] leading-[16px]",88 "text-xs leading-[16px]",
92 hasConnectionFailure ? "text-rose-500 dark:text-rose-400" : "text-foreground-muted",89 hasConnectionFailure ? "text-rose-500 dark:text-rose-400" : "text-foreground-muted",
93 )}90 )}
94 numberOfLines={props.expanded ? undefined : 1}91 numberOfLines={props.expanded ? undefined : 1}
...@@ -137,14 +134,14 @@ export function ConnectionEnvironmentRow(props: {...@@ -137,14 +134,14 @@ export function ConnectionEnvironmentRow(props: {
137 className="gap-3 px-4 pb-4"134 className="gap-3 px-4 pb-4"
138 >135 >
139 {props.environment.isRelayManaged ? (136 {props.environment.isRelayManaged ? (
140 <Text className="text-[13px] leading-[18px] text-foreground-muted">137 <Text className="text-sm leading-[18px] text-foreground-muted">
141 Managed by T3 Cloud. Tunnel details update automatically.138 Managed by T3 Cloud. Tunnel details update automatically.
142 </Text>139 </Text>
143 ) : (140 ) : (
144 <>141 <>
145 <View className="gap-1.5">142 <View className="gap-1.5">
146 <Text143 <Text
147 className="text-[11px] font-t3-bold uppercase text-foreground-muted"144 className="text-2xs font-t3-bold uppercase text-foreground-muted"
148 style={{ letterSpacing: 0.8 }}145 style={{ letterSpacing: 0.8 }}
149 >146 >
150 Label147 Label
...@@ -156,13 +153,13 @@ export function ConnectionEnvironmentRow(props: {...@@ -156,13 +153,13 @@ export function ConnectionEnvironmentRow(props: {
156 placeholderTextColor={placeholderColor}153 placeholderTextColor={placeholderColor}
157 value={label}154 value={label}
158 onChangeText={setLabel}155 onChangeText={setLabel}
159 className="rounded-[14px] border border-input-border bg-input px-4 py-3 text-[15px] text-foreground"156 className="rounded-[14px] border border-input-border bg-input px-4 py-3 text-base text-foreground"
160 />157 />
161 </View>158 </View>
162159
163 <View className="gap-1.5">160 <View className="gap-1.5">
164 <Text161 <Text
165 className="text-[11px] font-t3-bold uppercase text-foreground-muted"162 className="text-2xs font-t3-bold uppercase text-foreground-muted"
166 style={{ letterSpacing: 0.8 }}163 style={{ letterSpacing: 0.8 }}
167 >164 >
168 URL165 URL
...@@ -175,7 +172,7 @@ export function ConnectionEnvironmentRow(props: {...@@ -175,7 +172,7 @@ export function ConnectionEnvironmentRow(props: {
175 placeholderTextColor={placeholderColor}172 placeholderTextColor={placeholderColor}
176 value={url}173 value={url}
177 onChangeText={setUrl}174 onChangeText={setUrl}
178 className="rounded-[14px] border border-input-border bg-input px-4 py-3 text-[15px] text-foreground"175 className="rounded-[14px] border border-input-border bg-input px-4 py-3 text-base text-foreground"
179 />176 />
180 </View>177 </View>
181 </>178 </>
...@@ -189,7 +186,7 @@ export function ConnectionEnvironmentRow(props: {...@@ -189,7 +186,7 @@ export function ConnectionEnvironmentRow(props: {
189 >186 >
190 <SymbolView name="checkmark" size={13} tintColor={primaryFg} type="monochrome" />187 <SymbolView name="checkmark" size={13} tintColor={primaryFg} type="monochrome" />
191 <Text188 <Text
192 className="text-[12px] font-t3-bold uppercase text-primary-foreground"189 className="text-xs font-t3-bold uppercase text-primary-foreground"
193 style={{ letterSpacing: 0.8 }}190 style={{ letterSpacing: 0.8 }}
194 >191 >
195 Save192 Save
apps/mobile/src/features/connection/ConnectionSheetButton.tsx+1-1
...@@ -104,7 +104,7 @@ export function ConnectionSheetButton(props: {...@@ -104,7 +104,7 @@ export function ConnectionSheetButton(props: {
104 type="monochrome"104 type="monochrome"
105 />105 />
106 <Text106 <Text
107 className="text-[12px] font-t3-bold uppercase"107 className="text-xs font-t3-bold uppercase"
108 style={{ color: colors.textColor, letterSpacing: 0.8 }}108 style={{ color: colors.textColor, letterSpacing: 0.8 }}
109 >109 >
110 {props.label}110 {props.label}
apps/mobile/src/features/connection/EnvironmentConnectionNotice.tsx+3-3
...@@ -73,10 +73,10 @@ export function EnvironmentConnectionNotice(props: {...@@ -73,10 +73,10 @@ export function EnvironmentConnectionNotice(props: {
73 />73 />
74 )}74 )}
7575
76 <Text className="text-center text-[17px] font-t3-bold leading-[22px] text-foreground">76 <Text className="text-center text-lg font-t3-bold leading-[22px] text-foreground">
77 {noticeTitle(props.connection.phase, props.environmentLabel)}77 {noticeTitle(props.connection.phase, props.environmentLabel)}
78 </Text>78 </Text>
79 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">79 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
80 {noticeDetail(props.connection.phase, props.resourceName, props.connection.error)}80 {noticeDetail(props.connection.phase, props.resourceName, props.connection.error)}
81 {props.connection.traceId ? (81 {props.connection.traceId ? (
82 <>82 <>
...@@ -99,7 +99,7 @@ export function EnvironmentConnectionNotice(props: {...@@ -99,7 +99,7 @@ export function EnvironmentConnectionNotice(props: {
99 className="mt-1 rounded-full bg-subtle px-4 py-2.5 active:opacity-70"99 className="mt-1 rounded-full bg-subtle px-4 py-2.5 active:opacity-70"
100 onPress={props.onRetry}100 onPress={props.onRetry}
101 >101 >
102 <Text className="text-[13px] font-t3-bold text-foreground">Retry now</Text>102 <Text className="text-sm font-t3-bold text-foreground">Retry now</Text>
103 </Pressable>103 </Pressable>
104 ) : null}104 ) : null}
105 </View>105 </View>
apps/mobile/src/features/files/FileMarkdownPreview.tsx+3-4
...@@ -7,6 +7,7 @@ import {...@@ -7,6 +7,7 @@ import {
7} from "react-native-nitro-markdown";7} from "react-native-nitro-markdown";
8import { Linking, ScrollView, Text as NativeText, View } from "react-native";8import { Linking, ScrollView, Text as NativeText, View } from "react-native";
99
10import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
10import { useThemeColor } from "../../lib/useThemeColor";11import { useThemeColor } from "../../lib/useThemeColor";
11import {12import {
12 hasNativeSelectableMarkdownText,13 hasNativeSelectableMarkdownText,
...@@ -72,8 +73,7 @@ function useMarkdownPreviewStyles(): MarkdownPreviewStyles {...@@ -72,8 +73,7 @@ function useMarkdownPreviewStyles(): MarkdownPreviewStyles {
72 text: {73 text: {
73 color: body,74 color: body,
74 fontFamily: "DMSans_400Regular",75 fontFamily: "DMSans_400Regular",
75 fontSize: 15,76 ...MOBILE_TYPOGRAPHY.body,
76 lineHeight: 22,
77 },77 },
78 heading: {78 heading: {
79 color: strong,79 color: strong,
...@@ -123,8 +123,7 @@ function useMarkdownPreviewStyles(): MarkdownPreviewStyles {...@@ -123,8 +123,7 @@ function useMarkdownPreviewStyles(): MarkdownPreviewStyles {
123 skillTextColor: codeText,123 skillTextColor: codeText,
124 quoteMarkerColor: blockquoteBorder,124 quoteMarkerColor: blockquoteBorder,
125 dividerColor: horizontalRule,125 dividerColor: horizontalRule,
126 fontSize: 15,126 ...MOBILE_TYPOGRAPHY.body,
127 lineHeight: 22,
128 fontFamily: "DMSans_400Regular",127 fontFamily: "DMSans_400Regular",
129 headingFontFamily: "DMSans_700Bold",128 headingFontFamily: "DMSans_700Bold",
130 boldFontFamily: "DMSans_700Bold",129 boldFontFamily: "DMSans_700Bold",
apps/mobile/src/features/files/FileTreeBrowser.tsx+6-8
...@@ -64,7 +64,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {...@@ -64,7 +64,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {
64 <PierreEntryIcon path={node.path} kind={node.kind} size={17} />64 <PierreEntryIcon path={node.path} kind={node.kind} size={17} />
65 <Text65 <Text
66 className={cn(66 className={cn(
67 "min-w-0 flex-1 text-[14px] leading-[19px]",67 "min-w-0 flex-1 text-sm leading-[19px]",
68 selected ? "font-t3-bold text-foreground" : "font-t3-medium text-foreground-secondary",68 selected ? "font-t3-bold text-foreground" : "font-t3-medium text-foreground-secondary",
69 )}69 )}
70 numberOfLines={1}70 numberOfLines={1}
...@@ -72,7 +72,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {...@@ -72,7 +72,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {
72 {node.name}72 {node.name}
73 </Text>73 </Text>
74 {node.kind === "directory" ? (74 {node.kind === "directory" ? (
75 <Text className="text-[11px] font-t3-medium text-foreground-tertiary">75 <Text className="text-2xs font-t3-medium text-foreground-tertiary">
76 {node.children.length}76 {node.children.length}
77 </Text>77 </Text>
78 ) : null}78 ) : null}
...@@ -142,10 +142,8 @@ export function FileTreeBrowser(props: {...@@ -142,10 +142,8 @@ export function FileTreeBrowser(props: {
142 <View className="flex-1 bg-sheet">142 <View className="flex-1 bg-sheet">
143 {props.error && props.entries.length === 0 ? (143 {props.error && props.entries.length === 0 ? (
144 <View className="px-4 py-5">144 <View className="px-4 py-5">
145 <Text className="text-[13px] font-t3-bold text-foreground">Files unavailable</Text>145 <Text className="text-sm font-t3-bold text-foreground">Files unavailable</Text>
146 <Text className="mt-1 text-[12px] leading-[18px] text-foreground-muted">146 <Text className="mt-1 text-xs leading-[18px] text-foreground-muted">{props.error}</Text>
147 {props.error}
148 </Text>
149 </View>147 </View>
150 ) : (148 ) : (
151 <FlatList149 <FlatList
...@@ -174,8 +172,8 @@ export function FileTreeBrowser(props: {...@@ -174,8 +172,8 @@ export function FileTreeBrowser(props: {
174 <ActivityIndicator size="small" />172 <ActivityIndicator size="small" />
175 ) : (173 ) : (
176 <>174 <>
177 <Text className="text-[13px] font-t3-bold text-foreground">No files found</Text>175 <Text className="text-sm font-t3-bold text-foreground">No files found</Text>
178 <Text className="mt-1 text-[12px] leading-[18px] text-foreground-muted">176 <Text className="mt-1 text-xs leading-[18px] text-foreground-muted">
179 {props.searchQuery.trim().length > 0177 {props.searchQuery.trim().length > 0
180 ? "Try a different search."178 ? "Try a different search."
181 : "The workspace file index is empty."}179 : "The workspace file index is empty."}
apps/mobile/src/features/files/SourceFileSurface.tsx+15-9
...@@ -18,6 +18,7 @@ import {...@@ -18,6 +18,7 @@ import {
18} from "../review/reviewDiffRendering";18} from "../review/reviewDiffRendering";
19import type { ReviewHighlightedToken } from "../review/shikiReviewHighlighter";19import type { ReviewHighlightedToken } from "../review/shikiReviewHighlighter";
20import { cn } from "../../lib/cn";20import { cn } from "../../lib/cn";
21import { MOBILE_CODE_SURFACE } from "../../lib/typography";
21import {22import {
22 buildNativeSourceRows,23 buildNativeSourceRows,
23 buildNativeSourceTokens,24 buildNativeSourceTokens,
...@@ -28,8 +29,8 @@ import {...@@ -28,8 +29,8 @@ import {
28} from "./nativeSourceFileAdapter";29} from "./nativeSourceFileAdapter";
29import { sourceHighlightAtom } from "./sourceHighlightingState";30import { sourceHighlightAtom } from "./sourceHighlightingState";
3031
31const SOURCE_LINE_HEIGHT = 24;32const SOURCE_LINE_HEIGHT = MOBILE_CODE_SURFACE.rowHeight;
32const SOURCE_LINE_NUMBER_WIDTH = 58;33const SOURCE_LINE_NUMBER_WIDTH = MOBILE_CODE_SURFACE.gutterWidth;
33const NATIVE_SOURCE_STYLE_JSON = JSON.stringify(NATIVE_SOURCE_STYLE);34const NATIVE_SOURCE_STYLE_JSON = JSON.stringify(NATIVE_SOURCE_STYLE);
3435
35interface SourceFileSurfaceProps {36interface SourceFileSurfaceProps {
...@@ -56,10 +57,12 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {...@@ -56,10 +57,12 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {
56 style={{ minHeight: SOURCE_LINE_HEIGHT }}57 style={{ minHeight: SOURCE_LINE_HEIGHT }}
57 >58 >
58 <NativeText59 <NativeText
59 className="select-none pr-3 text-right text-[11px] leading-[24px] text-foreground-tertiary"60 className="select-none pr-3 text-right text-foreground-tertiary"
60 style={{61 style={{
61 width: SOURCE_LINE_NUMBER_WIDTH,62 width: SOURCE_LINE_NUMBER_WIDTH,
62 fontFamily: REVIEW_MONO_FONT_FAMILY,63 fontFamily: REVIEW_MONO_FONT_FAMILY,
64 fontSize: MOBILE_CODE_SURFACE.lineNumberFontSize,
65 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
63 }}66 }}
64 >67 >
65 {props.index + 1}68 {props.index + 1}
...@@ -67,8 +70,13 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {...@@ -67,8 +70,13 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {
67 <NativeText70 <NativeText
68 selectable71 selectable
69 numberOfLines={1}72 numberOfLines={1}
70 className="text-[13px] font-medium leading-[24px] text-foreground"73 className="font-normal text-foreground"
71 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY, minWidth: 320 }}74 style={{
75 fontFamily: REVIEW_MONO_FONT_FAMILY,
76 fontSize: MOBILE_CODE_SURFACE.fontSize,
77 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
78 minWidth: 320,
79 }}
72 >80 >
73 {props.tokens && props.tokens.length > 081 {props.tokens && props.tokens.length > 0
74 ? (() => {82 ? (() => {
...@@ -80,7 +88,7 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {...@@ -80,7 +88,7 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {
80 const fontWeight =88 const fontWeight =
81 token.fontStyle !== null && (token.fontStyle & 2) === 289 token.fontStyle !== null && (token.fontStyle & 2) === 2
82 ? ("700" as const)90 ? ("700" as const)
83 : ("500" as const);91 : ("400" as const);
84 const fontStyle =92 const fontStyle =
85 token.fontStyle !== null && (token.fontStyle & 1) === 193 token.fontStyle !== null && (token.fontStyle & 1) === 1
86 ? ("italic" as const)94 ? ("italic" as const)
...@@ -142,9 +150,7 @@ function SourceHighlightStatusView(props: { readonly status: SourceHighlightStat...@@ -142,9 +150,7 @@ function SourceHighlightStatusView(props: { readonly status: SourceHighlightStat
142 if (props.status === "error") {150 if (props.status === "error") {
143 return (151 return (
144 <View className="border-b border-border bg-card px-4 py-2">152 <View className="border-b border-border bg-card px-4 py-2">
145 <Text className="text-[11px] font-t3-medium uppercase text-foreground-muted">153 <Text className="text-2xs font-t3-medium uppercase text-foreground-muted">Plain text</Text>
146 Plain text
147 </Text>
148 </View>154 </View>
149 );155 );
150 }156 }
apps/mobile/src/features/files/ThreadFilesRouteScreen.tsx+8-7
...@@ -24,6 +24,7 @@ import { EmptyState } from "../../components/EmptyState";...@@ -24,6 +24,7 @@ import { EmptyState } from "../../components/EmptyState";
24import { LoadingScreen } from "../../components/LoadingScreen";24import { LoadingScreen } from "../../components/LoadingScreen";
25import { cn } from "../../lib/cn";25import { cn } from "../../lib/cn";
26import { buildThreadFilesNavigation } from "../../lib/routes";26import { buildThreadFilesNavigation } from "../../lib/routes";
27import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
27import { useThemeColor } from "../../lib/useThemeColor";28import { useThemeColor } from "../../lib/useThemeColor";
28import { useThreadSelection } from "../../state/use-thread-selection";29import { useThreadSelection } from "../../state/use-thread-selection";
29import { useSelectedThreadWorktree } from "../../state/use-selected-thread-worktree";30import { useSelectedThreadWorktree } from "../../state/use-selected-thread-worktree";
...@@ -100,7 +101,7 @@ function ModeButton(props: {...@@ -100,7 +101,7 @@ function ModeButton(props: {
100 <SymbolView name={props.icon} size={13} tintColor={iconColor} type="monochrome" />101 <SymbolView name={props.icon} size={13} tintColor={iconColor} type="monochrome" />
101 <Text102 <Text
102 className={cn(103 className={cn(
103 "text-[12px] font-t3-bold",104 "text-xs font-t3-bold",
104 props.active ? "text-primary-foreground" : "text-foreground-muted",105 props.active ? "text-primary-foreground" : "text-foreground-muted",
105 )}106 )}
106 >107 >
...@@ -187,7 +188,7 @@ function FileBreadcrumbs(props: { readonly projectName: string; readonly relativ...@@ -187,7 +188,7 @@ function FileBreadcrumbs(props: { readonly projectName: string; readonly relativ
187 ) : null}188 ) : null}
188 <Text189 <Text
189 className={cn(190 className={cn(
190 "max-w-[180px] px-1 text-[12px]",191 "max-w-[180px] px-1 text-xs",
191 crumb.kind === "file"192 crumb.kind === "file"
192 ? "font-t3-bold text-foreground"193 ? "font-t3-bold text-foreground"
193 : "font-t3-medium text-foreground-muted",194 : "font-t3-medium text-foreground-muted",
...@@ -308,7 +309,7 @@ function FileContent(props: {...@@ -308,7 +309,7 @@ function FileContent(props: {
308 return (309 return (
309 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">310 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">
310 <ActivityIndicator />311 <ActivityIndicator />
311 <Text className="text-center text-[13px] text-foreground-muted">Loading file...</Text>312 <Text className="text-center text-sm text-foreground-muted">Loading file...</Text>
312 </View>313 </View>
313 );314 );
314 }315 }
...@@ -317,10 +318,10 @@ function FileContent(props: {...@@ -317,10 +318,10 @@ function FileContent(props: {
317 <View className="flex-1 bg-card">318 <View className="flex-1 bg-card">
318 {props.truncated ? (319 {props.truncated ? (
319 <View className="border-b border-amber-200 bg-amber-50 px-4 py-2 dark:border-amber-900/60 dark:bg-amber-950/40">320 <View className="border-b border-amber-200 bg-amber-50 px-4 py-2 dark:border-amber-900/60 dark:bg-amber-950/40">
320 <Text className="text-[11px] font-t3-bold uppercase text-amber-700 dark:text-amber-300">321 <Text className="text-2xs font-t3-bold uppercase text-amber-700 dark:text-amber-300">
321 Partial file322 Partial file
322 </Text>323 </Text>
323 <Text className="text-[12px] leading-[17px] text-amber-800 dark:text-amber-200">324 <Text className="text-xs leading-[17px] text-amber-800 dark:text-amber-200">
324 Preview limited to the first 1 MB of a truncated file.325 Preview limited to the first 1 MB of a truncated file.
325 </Text>326 </Text>
326 </View>327 </View>
...@@ -389,7 +390,7 @@ function FilesHeaderTitle(props: { readonly projectName: string }) {...@@ -389,7 +390,7 @@ function FilesHeaderTitle(props: { readonly projectName: string }) {
389 style={{390 style={{
390 color: foregroundColor,391 color: foregroundColor,
391 fontFamily: "DMSans_700Bold",392 fontFamily: "DMSans_700Bold",
392 fontSize: 18,393 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
393 fontWeight: "900",394 fontWeight: "900",
394 letterSpacing: -0.4,395 letterSpacing: -0.4,
395 }}396 }}
...@@ -401,7 +402,7 @@ function FilesHeaderTitle(props: { readonly projectName: string }) {...@@ -401,7 +402,7 @@ function FilesHeaderTitle(props: { readonly projectName: string }) {
401 style={{402 style={{
402 color: secondaryForegroundColor,403 color: secondaryForegroundColor,
403 fontFamily: "DMSans_500Medium",404 fontFamily: "DMSans_500Medium",
404 fontSize: 12,405 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
405 fontWeight: "500",406 fontWeight: "500",
406 letterSpacing: 0.2,407 letterSpacing: 0.2,
407 }}408 }}
apps/mobile/src/features/files/WorkspaceFileImagePreview.tsx+2-2
...@@ -81,7 +81,7 @@ function CachedWorkspaceFileImagePreview(props: {...@@ -81,7 +81,7 @@ function CachedWorkspaceFileImagePreview(props: {
81 return (81 return (
82 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">82 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">
83 <ActivityIndicator />83 <ActivityIndicator />
84 <Text className="text-center text-[13px] text-foreground-muted">Loading image...</Text>84 <Text className="text-center text-sm text-foreground-muted">Loading image...</Text>
85 </View>85 </View>
86 );86 );
87 }87 }
...@@ -102,7 +102,7 @@ export function WorkspaceFileImagePreview(props: {...@@ -102,7 +102,7 @@ export function WorkspaceFileImagePreview(props: {
102 return (102 return (
103 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">103 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">
104 <ActivityIndicator />104 <ActivityIndicator />
105 <Text className="text-center text-[13px] text-foreground-muted">105 <Text className="text-center text-sm text-foreground-muted">
106 Preparing image preview...106 Preparing image preview...
107 </Text>107 </Text>
108 </View>108 </View>
apps/mobile/src/features/files/WorkspaceFileWebPreview.tsx+3-5
...@@ -13,7 +13,7 @@ export function WorkspaceFileWebPreview(props: { readonly uri: string | null })...@@ -13,7 +13,7 @@ export function WorkspaceFileWebPreview(props: { readonly uri: string | null })
13 return (13 return (
14 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">14 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">
15 <ActivityIndicator />15 <ActivityIndicator />
16 <Text className="text-center text-[13px] text-foreground-muted">Preparing preview...</Text>16 <Text className="text-center text-sm text-foreground-muted">Preparing preview...</Text>
17 </View>17 </View>
18 );18 );
19 }19 }
...@@ -23,10 +23,8 @@ export function WorkspaceFileWebPreview(props: { readonly uri: string | null })...@@ -23,10 +23,8 @@ export function WorkspaceFileWebPreview(props: { readonly uri: string | null })
23 {loadProgress > 0 && loadProgress < 1 ? <LoadingStrip progress={loadProgress} /> : null}23 {loadProgress > 0 && loadProgress < 1 ? <LoadingStrip progress={loadProgress} /> : null}
24 {loadError ? (24 {loadError ? (
25 <View className="border-b border-border bg-card px-4 py-2">25 <View className="border-b border-border bg-card px-4 py-2">
26 <Text className="text-[12px] font-t3-bold text-foreground">Preview failed</Text>26 <Text className="text-xs font-t3-bold text-foreground">Preview failed</Text>
27 <Text className="mt-0.5 text-[12px] leading-[17px] text-foreground-muted">27 <Text className="mt-0.5 text-xs leading-[17px] text-foreground-muted">{loadError}</Text>
28 {loadError}
29 </Text>
30 </View>28 </View>
31 ) : null}29 ) : null}
32 <WebView30 <WebView
apps/mobile/src/features/files/nativeSourceFileAdapter.test.ts+20
...@@ -3,10 +3,30 @@ import { describe, expect, it } from "vite-plus/test";...@@ -3,10 +3,30 @@ import { describe, expect, it } from "vite-plus/test";
3import {3import {
4 buildNativeSourceRows,4 buildNativeSourceRows,
5 buildNativeSourceTokens,5 buildNativeSourceTokens,
6 NATIVE_SOURCE_ROW_HEIGHT,
7 NATIVE_SOURCE_STYLE,
6 nativeSourceRowId,8 nativeSourceRowId,
7} from "./nativeSourceFileAdapter";9} from "./nativeSourceFileAdapter";
10import {
11 NATIVE_REVIEW_DIFF_ROW_HEIGHT,
12 NATIVE_REVIEW_DIFF_STYLE,
13} from "../review/nativeReviewDiffAdapter";
814
9describe("nativeSourceFileAdapter", () => {15describe("nativeSourceFileAdapter", () => {
16 it("uses the same compact code typography as the diff viewer", () => {
17 expect(NATIVE_SOURCE_ROW_HEIGHT).toBe(NATIVE_REVIEW_DIFF_ROW_HEIGHT);
18 expect(NATIVE_SOURCE_STYLE).toMatchObject({
19 rowHeight: NATIVE_REVIEW_DIFF_STYLE.rowHeight,
20 gutterWidth: NATIVE_REVIEW_DIFF_STYLE.gutterWidth,
21 codePadding: NATIVE_REVIEW_DIFF_STYLE.codePadding,
22 textVerticalInset: NATIVE_REVIEW_DIFF_STYLE.textVerticalInset,
23 codeFontSize: NATIVE_REVIEW_DIFF_STYLE.codeFontSize,
24 codeFontWeight: NATIVE_REVIEW_DIFF_STYLE.codeFontWeight,
25 lineNumberFontSize: NATIVE_REVIEW_DIFF_STYLE.lineNumberFontSize,
26 lineNumberFontWeight: NATIVE_REVIEW_DIFF_STYLE.lineNumberFontWeight,
27 });
28 });
29
10 it("maps plain source lines onto context rows with stable line numbers", () => {30 it("maps plain source lines onto context rows with stable line numbers", () => {
11 expect(buildNativeSourceRows(["const value = 1;", "\treturn value;"])).toEqual([31 expect(buildNativeSourceRows(["const value = 1;", "\treturn value;"])).toEqual([
12 {32 {
apps/mobile/src/features/files/nativeSourceFileAdapter.ts+10-8
...@@ -3,22 +3,24 @@ import type {...@@ -3,22 +3,24 @@ import type {
3 NativeReviewDiffStyle,3 NativeReviewDiffStyle,
4 NativeReviewDiffToken,4 NativeReviewDiffToken,
5} from "../diffs/nativeReviewDiffSurface";5} from "../diffs/nativeReviewDiffSurface";
6import { MOBILE_CODE_SURFACE, MOBILE_TYPOGRAPHY } from "../../lib/typography";
6import type { SourceHighlightTokens } from "./sourceHighlightingState";7import type { SourceHighlightTokens } from "./sourceHighlightingState";
78
8export const NATIVE_SOURCE_ROW_HEIGHT = 24;9export const NATIVE_SOURCE_ROW_HEIGHT = MOBILE_CODE_SURFACE.rowHeight;
9export const NATIVE_SOURCE_CONTENT_WIDTH = 32_000;10export const NATIVE_SOURCE_CONTENT_WIDTH = 32_000;
1011
11export const NATIVE_SOURCE_STYLE: NativeReviewDiffStyle = {12export const NATIVE_SOURCE_STYLE: NativeReviewDiffStyle = {
12 rowHeight: NATIVE_SOURCE_ROW_HEIGHT,13 rowHeight: NATIVE_SOURCE_ROW_HEIGHT,
13 contentWidth: NATIVE_SOURCE_CONTENT_WIDTH,14 contentWidth: NATIVE_SOURCE_CONTENT_WIDTH,
14 changeBarWidth: 0,15 changeBarWidth: 0,
15 gutterWidth: 58,16 gutterWidth: MOBILE_CODE_SURFACE.gutterWidth,
16 codePadding: 8,17 codePadding: MOBILE_CODE_SURFACE.codePadding,
17 codeFontSize: 13,18 textVerticalInset: MOBILE_CODE_SURFACE.textVerticalInset,
18 codeFontWeight: "medium",19 codeFontSize: MOBILE_CODE_SURFACE.fontSize,
19 lineNumberFontSize: 11,20 codeFontWeight: "regular",
20 lineNumberFontWeight: "medium",21 lineNumberFontSize: MOBILE_CODE_SURFACE.lineNumberFontSize,
21 emptyStateFontSize: 12,22 lineNumberFontWeight: "regular",
23 emptyStateFontSize: MOBILE_TYPOGRAPHY.label.fontSize,
22 emptyStateFontWeight: "medium",24 emptyStateFontWeight: "medium",
23};25};
2426
apps/mobile/src/features/home/HomeHeader.tsx+3-2
...@@ -12,6 +12,7 @@ import { Stack } from "expo-router";...@@ -12,6 +12,7 @@ import { Stack } from "expo-router";
12import { Text as RNText, View } from "react-native";12import { Text as RNText, View } from "react-native";
1313
14import { useThemeColor } from "../../lib/useThemeColor";14import { useThemeColor } from "../../lib/useThemeColor";
15import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
15import type { HomeProjectSortOrder } from "./homeThreadList";16import type { HomeProjectSortOrder } from "./homeThreadList";
1617
17export interface HomeHeaderEnvironment {18export interface HomeHeaderEnvironment {
...@@ -118,7 +119,7 @@ export function HomeHeader(props: {...@@ -118,7 +119,7 @@ export function HomeHeader(props: {
118 <RNText119 <RNText
119 style={{120 style={{
120 fontFamily: "DMSans_700Bold",121 fontFamily: "DMSans_700Bold",
121 fontSize: 17,122 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
122 color: iconColor,123 color: iconColor,
123 letterSpacing: -0.4,124 letterSpacing: -0.4,
124 }}125 }}
...@@ -136,7 +137,7 @@ export function HomeHeader(props: {...@@ -136,7 +137,7 @@ export function HomeHeader(props: {
136 <RNText137 <RNText
137 style={{138 style={{
138 fontFamily: "DMSans_700Bold",139 fontFamily: "DMSans_700Bold",
139 fontSize: 10,140 fontSize: MOBILE_TYPOGRAPHY.micro.fontSize,
140 color: mutedColor,141 color: mutedColor,
141 letterSpacing: 1.1,142 letterSpacing: 1.1,
142 textTransform: "uppercase",143 textTransform: "uppercase",
apps/mobile/src/features/home/HomeScreen.tsx+7-7
...@@ -186,7 +186,7 @@ function ProjectGroupLabel(props: {...@@ -186,7 +186,7 @@ function ProjectGroupLabel(props: {
186 workspaceRoot={props.project.workspaceRoot}186 workspaceRoot={props.project.workspaceRoot}
187 />187 />
188 <Text188 <Text
189 className="flex-1 text-[12px] font-t3-medium uppercase text-foreground-muted"189 className="flex-1 text-xs font-t3-medium uppercase text-foreground-muted"
190 style={{ letterSpacing: 0.5 }}190 style={{ letterSpacing: 0.5 }}
191 numberOfLines={1}191 numberOfLines={1}
192 >192 >
...@@ -196,7 +196,7 @@ function ProjectGroupLabel(props: {...@@ -196,7 +196,7 @@ function ProjectGroupLabel(props: {
196 {hiddenCount > 0 ? (196 {hiddenCount > 0 ? (
197 <Pressable onPress={props.onToggleExpand} hitSlop={8}>197 <Pressable onPress={props.onToggleExpand} hitSlop={8}>
198 <Text198 <Text
199 className="text-[12px] font-t3-medium text-foreground-muted"199 className="text-xs font-t3-medium text-foreground-muted"
200 style={{ letterSpacing: 0.4 }}200 style={{ letterSpacing: 0.4 }}
201 >201 >
202 {props.isExpanded ? "Show less" : `${hiddenCount} more`}202 {props.isExpanded ? "Show less" : `${hiddenCount} more`}
...@@ -335,7 +335,7 @@ function ThreadRow(props: {...@@ -335,7 +335,7 @@ function ThreadRow(props: {
335 <View style={{ flex: 1, gap: 3 }}>335 <View style={{ flex: 1, gap: 3 }}>
336 <View className="flex-row items-center justify-between gap-2">336 <View className="flex-row items-center justify-between gap-2">
337 <Text337 <Text
338 className="flex-1 text-[15px] font-t3-bold leading-[20px] text-foreground"338 className="flex-1 text-base font-t3-bold leading-[20px] text-foreground"
339 numberOfLines={1}339 numberOfLines={1}
340 >340 >
341 {props.thread.title}341 {props.thread.title}
...@@ -345,12 +345,12 @@ function ThreadRow(props: {...@@ -345,12 +345,12 @@ function ThreadRow(props: {
345 className={tone.pillClassName}345 className={tone.pillClassName}
346 style={{ borderRadius: 99, paddingHorizontal: 6, paddingVertical: 2 }}346 style={{ borderRadius: 99, paddingHorizontal: 6, paddingVertical: 2 }}
347 >347 >
348 <Text className={`text-[10px] font-t3-bold ${tone.textClassName}`}>348 <Text className={`text-3xs font-t3-bold ${tone.textClassName}`}>
349 {tone.label}349 {tone.label}
350 </Text>350 </Text>
351 </View>351 </View>
352 <Text352 <Text
353 className="text-[12px] text-foreground-tertiary"353 className="text-xs text-foreground-tertiary"
354 style={{ fontVariant: ["tabular-nums"] }}354 style={{ fontVariant: ["tabular-nums"] }}
355 >355 >
356 {timestamp}356 {timestamp}
...@@ -367,7 +367,7 @@ function ThreadRow(props: {...@@ -367,7 +367,7 @@ function ThreadRow(props: {
367 type="monochrome"367 type="monochrome"
368 />368 />
369 <Text369 <Text
370 className="text-[11px] text-foreground-tertiary"370 className="text-2xs text-foreground-tertiary"
371 numberOfLines={1}371 numberOfLines={1}
372 style={{ fontFamily: "monospace" }}372 style={{ fontFamily: "monospace" }}
373 >373 >
...@@ -429,7 +429,7 @@ function StaleCatalogStatusPill(props: {...@@ -429,7 +429,7 @@ function StaleCatalogStatusPill(props: {
429 weight="semibold"429 weight="semibold"
430 />430 />
431 )}431 )}
432 <Text className="max-w-[260px] text-[13px] font-t3-bold text-foreground" numberOfLines={1}>432 <Text className="max-w-[260px] text-sm font-t3-bold text-foreground" numberOfLines={1}>
433 {label}433 {label}
434 </Text>434 </Text>
435 </Pressable>435 </Pressable>
apps/mobile/src/features/home/thread-swipe-actions.tsx+1-1
...@@ -167,7 +167,7 @@ function SwipeActionButton(props: {...@@ -167,7 +167,7 @@ function SwipeActionButton(props: {
167 </Animated.View>167 </Animated.View>
168 </View>168 </View>
169 <Animated.View style={[{ paddingTop: 2 }, labelStyle]}>169 <Animated.View style={[{ paddingTop: 2 }, labelStyle]}>
170 <Text className="text-[10px] font-t3-medium text-foreground-muted">{props.label}</Text>170 <Text className="text-3xs font-t3-medium text-foreground-muted">{props.label}</Text>
171 </Animated.View>171 </Animated.View>
172 </Pressable>172 </Pressable>
173 </Animated.View>173 </Animated.View>
apps/mobile/src/features/projects/AddProjectScreen.tsx+11-11
...@@ -100,7 +100,7 @@ function sourceFromParam(value: string | string[] | undefined): AddProjectRemote...@@ -100,7 +100,7 @@ function sourceFromParam(value: string | string[] | undefined): AddProjectRemote
100function SectionTitle(props: { readonly children: string }) {100function SectionTitle(props: { readonly children: string }) {
101 return (101 return (
102 <Text102 <Text
103 className="px-1 text-[11px] font-t3-bold uppercase text-foreground-muted"103 className="px-1 text-2xs font-t3-bold uppercase text-foreground-muted"
104 style={{ letterSpacing: 0.7 }}104 style={{ letterSpacing: 0.7 }}
105 >105 >
106 {props.children}106 {props.children}
...@@ -168,9 +168,9 @@ function ListRow(props: {...@@ -168,9 +168,9 @@ function ListRow(props: {
168 {props.icon}168 {props.icon}
169 </View>169 </View>
170 <View className="flex-1 gap-0.5">170 <View className="flex-1 gap-0.5">
171 <Text className="text-[16px] leading-[21px] font-t3-bold">{props.title}</Text>171 <Text className="text-base leading-[21px] font-t3-bold">{props.title}</Text>
172 {props.subtitle ? (172 {props.subtitle ? (
173 <Text className="text-[13px] leading-[17px] text-foreground-muted" numberOfLines={2}>173 <Text className="text-sm leading-[17px] text-foreground-muted" numberOfLines={2}>
174 {props.subtitle}174 {props.subtitle}
175 </Text>175 </Text>
176 ) : null}176 ) : null}
...@@ -202,7 +202,7 @@ function PrimaryActionButton(props: {...@@ -202,7 +202,7 @@ function PrimaryActionButton(props: {
202 {props.loading ? (202 {props.loading ? (
203 <ActivityIndicator color={String(primaryForeground)} />203 <ActivityIndicator color={String(primaryForeground)} />
204 ) : (204 ) : (
205 <Text className="text-[14px] font-t3-bold text-primary-foreground">{props.label}</Text>205 <Text className="text-base font-t3-bold text-primary-foreground">{props.label}</Text>
206 )}206 )}
207 </Pressable>207 </Pressable>
208 );208 );
...@@ -215,7 +215,7 @@ function ProjectPathInput(props: {...@@ -215,7 +215,7 @@ function ProjectPathInput(props: {
215}) {215}) {
216 return (216 return (
217 <TextInput217 <TextInput
218 className="h-12 min-h-12 rounded-[24px] px-4 py-0 text-[15px] leading-[20px]"218 className="h-12 min-h-12 rounded-[24px] px-4 py-0 text-base leading-[20px]"
219 value={props.value}219 value={props.value}
220 onChangeText={props.onChangeText}220 onChangeText={props.onChangeText}
221 autoCapitalize="none"221 autoCapitalize="none"
...@@ -273,15 +273,15 @@ function EmptyEnvironmentState() {...@@ -273,15 +273,15 @@ function EmptyEnvironmentState() {
273273
274 return (274 return (
275 <View className="items-center gap-3 rounded-2xl bg-card px-5 py-8">275 <View className="items-center gap-3 rounded-2xl bg-card px-5 py-8">
276 <Text className="text-center text-[17px] font-t3-bold">No environments connected</Text>276 <Text className="text-center text-lg font-t3-bold">No environments connected</Text>
277 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">277 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
278 Add an environment before adding a project.278 Add an environment before adding a project.
279 </Text>279 </Text>
280 <Pressable280 <Pressable
281 onPress={() => router.replace("/connections/new")}281 onPress={() => router.replace("/connections/new")}
282 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"282 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
283 >283 >
284 <Text className="text-[13px] font-t3-bold text-primary-foreground">Add environment</Text>284 <Text className="text-sm font-t3-bold text-primary-foreground">Add environment</Text>
285 </Pressable>285 </Pressable>
286 </View>286 </View>
287 );287 );
...@@ -565,7 +565,7 @@ export function AddProjectRepositoryScreen() {...@@ -565,7 +565,7 @@ export function AddProjectRepositoryScreen() {
565 <AddProjectShell>565 <AddProjectShell>
566 {error ? <ErrorBanner message={error} /> : null}566 {error ? <ErrorBanner message={error} /> : null}
567 <TextInput567 <TextInput
568 className="h-12 min-h-12 rounded-[24px] px-4 py-0 text-[15px] leading-[20px]"568 className="h-12 min-h-12 rounded-[24px] px-4 py-0 text-base leading-[20px]"
569 value={repositoryInput}569 value={repositoryInput}
570 onChangeText={setRepositoryInput}570 onChangeText={setRepositoryInput}
571 autoCapitalize="none"571 autoCapitalize="none"
...@@ -806,8 +806,8 @@ export function AddProjectDestinationScreen() {...@@ -806,8 +806,8 @@ export function AddProjectDestinationScreen() {
806 {error ? <ErrorBanner message={error} /> : null}806 {error ? <ErrorBanner message={error} /> : null}
807 {repositoryTitle ? (807 {repositoryTitle ? (
808 <View className="rounded-[24px] bg-card px-4 py-3">808 <View className="rounded-[24px] bg-card px-4 py-3">
809 <Text className="text-[14px] font-t3-bold">{repositoryTitle}</Text>809 <Text className="text-base font-t3-bold">{repositoryTitle}</Text>
810 <Text className="mt-0.5 text-[12px] text-foreground-muted" numberOfLines={2}>810 <Text className="mt-0.5 text-xs text-foreground-muted" numberOfLines={2}>
811 {remoteUrl}811 {remoteUrl}
812 </Text>812 </Text>
813 </View>813 </View>
apps/mobile/src/features/review/ReviewCommentComposerSheet.tsx+8-8
...@@ -159,26 +159,26 @@ export function ReviewCommentComposerSheet() {...@@ -159,26 +159,26 @@ export function ReviewCommentComposerSheet() {
159 <SymbolView name="xmark" size={18} tintColor={iconTint} type="monochrome" />159 <SymbolView name="xmark" size={18} tintColor={iconTint} type="monochrome" />
160 </Pressable>160 </Pressable>
161161
162 <Text className="text-[18px] font-t3-bold text-foreground">Add Comment</Text>162 <Text className="text-lg font-t3-bold text-foreground">Add Comment</Text>
163163
164 <View className="h-12 w-12" />164 <View className="h-12 w-12" />
165 </View>165 </View>
166166
167 {!target ? (167 {!target ? (
168 <View className="rounded-[22px] border border-border bg-card px-4 py-5">168 <View className="rounded-[22px] border border-border bg-card px-4 py-5">
169 <Text className="text-[15px] font-t3-bold text-foreground">No selection</Text>169 <Text className="text-base font-t3-bold text-foreground">No selection</Text>
170 <Text className="mt-1 text-[13px] leading-[19px] text-foreground-muted">170 <Text className="mt-1 text-sm leading-[19px] text-foreground-muted">
171 Select a diff line or range first.171 Select a diff line or range first.
172 </Text>172 </Text>
173 </View>173 </View>
174 ) : (174 ) : (
175 <View className="min-h-0 flex-1 gap-4">175 <View className="min-h-0 flex-1 gap-4">
176 <View className="gap-1 px-1">176 <View className="gap-1 px-1">
177 <Text className="text-[11px] font-t3-bold uppercase text-foreground-muted">177 <Text className="text-2xs font-t3-bold uppercase text-foreground-muted">
178 {selectionLabel}178 {selectionLabel}
179 </Text>179 </Text>
180 <Text180 <Text
181 className="font-mono text-[12px] leading-[17px] text-foreground-muted"181 className="font-mono text-xs leading-[17px] text-foreground-muted"
182 ellipsizeMode="middle"182 ellipsizeMode="middle"
183 numberOfLines={2}183 numberOfLines={2}
184 >184 >
...@@ -215,7 +215,7 @@ export function ReviewCommentComposerSheet() {...@@ -215,7 +215,7 @@ export function ReviewCommentComposerSheet() {
215 >215 >
216 <ReviewChangeBar change={line.change} />216 <ReviewChangeBar change={line.change} />
217 <Text217 <Text
218 className="w-9 py-1 pr-1 text-right text-[11px] font-t3-medium text-foreground-muted"218 className="w-9 py-1 pr-1 text-right text-2xs font-t3-medium text-foreground-muted"
219 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY }}219 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY }}
220 >220 >
221 {lineNumber ?? ""}221 {lineNumber ?? ""}
...@@ -236,7 +236,7 @@ export function ReviewCommentComposerSheet() {...@@ -236,7 +236,7 @@ export function ReviewCommentComposerSheet() {
236 </View>236 </View>
237237
238 <View className="min-h-0 flex-1 gap-2">238 <View className="min-h-0 flex-1 gap-2">
239 <Text className="text-[13px] font-t3-bold text-foreground">Comment</Text>239 <Text className="text-sm font-t3-bold text-foreground">Comment</Text>
240 <View className="min-h-[132px] flex-1 overflow-hidden rounded-[20px] border border-border bg-card">240 <View className="min-h-[132px] flex-1 overflow-hidden rounded-[20px] border border-border bg-card">
241 <View className="min-h-0 flex-1 px-4 pt-3.5">241 <View className="min-h-0 flex-1 px-4 pt-3.5">
242 <TextInputWrapper onPaste={handleNativePaste} style={{ flex: 1, minHeight: 0 }}>242 <TextInputWrapper onPaste={handleNativePaste} style={{ flex: 1, minHeight: 0 }}>
...@@ -248,7 +248,7 @@ export function ReviewCommentComposerSheet() {...@@ -248,7 +248,7 @@ export function ReviewCommentComposerSheet() {
248 textAlignVertical="top"248 textAlignVertical="top"
249 value={commentText}249 value={commentText}
250 onChangeText={setCommentText}250 onChangeText={setCommentText}
251 className="h-full flex-1 border-0 bg-transparent px-0 py-0 font-sans text-[15px]"251 className="h-full flex-1 border-0 bg-transparent px-0 py-0 font-sans text-base"
252 style={{ flex: 1, minHeight: 0 }}252 style={{ flex: 1, minHeight: 0 }}
253 />253 />
254 </TextInputWrapper>254 </TextInputWrapper>
apps/mobile/src/features/review/ReviewSheet.tsx+19-18
...@@ -20,6 +20,7 @@ import { environmentCatalog } from "../../connection/catalog";...@@ -20,6 +20,7 @@ import { environmentCatalog } from "../../connection/catalog";
20import { useEnvironmentPresentation } from "../../state/presentation";20import { useEnvironmentPresentation } from "../../state/presentation";
21import { useAtomCommand } from "../../state/use-atom-command";21import { useAtomCommand } from "../../state/use-atom-command";
22import { useThemeColor } from "../../lib/useThemeColor";22import { useThemeColor } from "../../lib/useThemeColor";
23import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
23import { useThreadDraftForThread } from "../../state/use-thread-composer-state";24import { useThreadDraftForThread } from "../../state/use-thread-composer-state";
24import { EnvironmentConnectionNotice } from "../connection/EnvironmentConnectionNotice";25import { EnvironmentConnectionNotice } from "../connection/EnvironmentConnectionNotice";
25import { useReviewCacheForThread } from "./reviewState";26import { useReviewCacheForThread } from "./reviewState";
...@@ -41,10 +42,10 @@ const REVIEW_HEADER_SPACING = 0;...@@ -41,10 +42,10 @@ const REVIEW_HEADER_SPACING = 0;
41const ReviewNotice = memo(function ReviewNotice(props: { readonly notice: string }) {42const ReviewNotice = memo(function ReviewNotice(props: { readonly notice: string }) {
42 return (43 return (
43 <View className="border-b border-amber-200 bg-amber-50 px-4 py-3 dark:border-amber-900/60 dark:bg-amber-950/40">44 <View className="border-b border-amber-200 bg-amber-50 px-4 py-3 dark:border-amber-900/60 dark:bg-amber-950/40">
44 <Text className="text-[12px] font-t3-bold uppercase text-amber-700 dark:text-amber-300">45 <Text className="text-xs font-t3-bold uppercase text-amber-700 dark:text-amber-300">
45 Partial diff46 Partial diff
46 </Text>47 </Text>
47 <Text className="text-[12px] leading-[18px] text-amber-800 dark:text-amber-200">48 <Text className="text-xs leading-[18px] text-amber-800 dark:text-amber-200">
48 {props.notice}49 {props.notice}
49 </Text>50 </Text>
50 </View>51 </View>
...@@ -69,7 +70,7 @@ function ReviewSelectionActionBar(props: {...@@ -69,7 +70,7 @@ function ReviewSelectionActionBar(props: {
69 tintColor="#ffffff"70 tintColor="#ffffff"
70 type="monochrome"71 type="monochrome"
71 />72 />
72 <Text className="text-[15px] font-t3-bold text-white">{props.title}</Text>73 <Text className="text-base font-t3-bold text-white">{props.title}</Text>
73 </>74 </>
74 );75 );
7576
...@@ -218,8 +219,8 @@ export function ReviewSheet() {...@@ -218,8 +219,8 @@ export function ReviewSheet() {
218 if (error) {219 if (error) {
219 children.push(220 children.push(
220 <View key="review-error" className="border-b border-border bg-card px-4 py-3">221 <View key="review-error" className="border-b border-border bg-card px-4 py-3">
221 <Text className="text-[13px] font-t3-bold text-foreground">Review unavailable</Text>222 <Text className="text-sm font-t3-bold text-foreground">Review unavailable</Text>
222 <Text className="text-[12px] leading-[18px] text-foreground-muted">{error}</Text>223 <Text className="text-xs leading-[18px] text-foreground-muted">{error}</Text>
223 </View>,224 </View>,
224 );225 );
225 }226 }
...@@ -251,7 +252,7 @@ export function ReviewSheet() {...@@ -251,7 +252,7 @@ export function ReviewSheet() {
251 numberOfLines={1}252 numberOfLines={1}
252 style={{253 style={{
253 fontFamily: "DMSans_700Bold",254 fontFamily: "DMSans_700Bold",
254 fontSize: 18,255 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
255 fontWeight: "900",256 fontWeight: "900",
256 color: headerForeground,257 color: headerForeground,
257 letterSpacing: -0.4,258 letterSpacing: -0.4,
...@@ -273,7 +274,7 @@ export function ReviewSheet() {...@@ -273,7 +274,7 @@ export function ReviewSheet() {
273 <NativeText274 <NativeText
274 style={{275 style={{
275 fontFamily: "DMSans_700Bold",276 fontFamily: "DMSans_700Bold",
276 fontSize: 12,277 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
277 fontWeight: "700",278 fontWeight: "700",
278 color: "#16a34a",279 color: "#16a34a",
279 }}280 }}
...@@ -283,7 +284,7 @@ export function ReviewSheet() {...@@ -283,7 +284,7 @@ export function ReviewSheet() {
283 <NativeText284 <NativeText
284 style={{285 style={{
285 fontFamily: "DMSans_700Bold",286 fontFamily: "DMSans_700Bold",
286 fontSize: 12,287 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
287 fontWeight: "700",288 fontWeight: "700",
288 color: "#e11d48",289 color: "#e11d48",
289 }}290 }}
...@@ -294,7 +295,7 @@ export function ReviewSheet() {...@@ -294,7 +295,7 @@ export function ReviewSheet() {
294 <NativeText295 <NativeText
295 style={{296 style={{
296 fontFamily: "DMSans_700Bold",297 fontFamily: "DMSans_700Bold",
297 fontSize: 12,298 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
298 fontWeight: "700",299 fontWeight: "700",
299 color: "#b45309",300 color: "#b45309",
300 }}301 }}
...@@ -309,7 +310,7 @@ export function ReviewSheet() {...@@ -309,7 +310,7 @@ export function ReviewSheet() {
309 numberOfLines={1}310 numberOfLines={1}
310 style={{311 style={{
311 fontFamily: "DMSans_700Bold",312 fontFamily: "DMSans_700Bold",
312 fontSize: 12,313 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
313 fontWeight: "700",314 fontWeight: "700",
314 color: headerMuted,315 color: headerMuted,
315 }}316 }}
...@@ -320,7 +321,7 @@ export function ReviewSheet() {...@@ -320,7 +321,7 @@ export function ReviewSheet() {
320 <NativeText321 <NativeText
321 style={{322 style={{
322 fontFamily: "DMSans_700Bold",323 fontFamily: "DMSans_700Bold",
323 fontSize: 12,324 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
324 fontWeight: "700",325 fontWeight: "700",
325 color: "#b45309",326 color: "#b45309",
326 }}327 }}
...@@ -430,30 +431,30 @@ export function ReviewSheet() {...@@ -430,30 +431,30 @@ export function ReviewSheet() {
430 {listHeader}431 {listHeader}
431 {!selectedSection ? (432 {!selectedSection ? (
432 <View className="border-b border-border bg-card px-4 py-5">433 <View className="border-b border-border bg-card px-4 py-5">
433 <Text className="text-[14px] font-t3-bold text-foreground">No review diffs</Text>434 <Text className="text-sm font-t3-bold text-foreground">No review diffs</Text>
434 <Text className="text-[12px] leading-[18px] text-foreground-muted">435 <Text className="text-xs leading-[18px] text-foreground-muted">
435 This thread has no ready turn diffs and the worktree diff is empty.436 This thread has no ready turn diffs and the worktree diff is empty.
436 </Text>437 </Text>
437 </View>438 </View>
438 ) : selectedSection.isLoading && selectedSection.diff === null ? (439 ) : selectedSection.isLoading && selectedSection.diff === null ? (
439 <View className="items-center gap-3 border-b border-border bg-card px-4 py-6">440 <View className="items-center gap-3 border-b border-border bg-card px-4 py-6">
440 <ActivityIndicator size="small" />441 <ActivityIndicator size="small" />
441 <Text className="text-[12px] text-foreground-muted">Loading diff…</Text>442 <Text className="text-xs text-foreground-muted">Loading diff…</Text>
442 </View>443 </View>
443 ) : parsedDiff.kind === "empty" ? (444 ) : parsedDiff.kind === "empty" ? (
444 <View className="border-b border-border bg-card px-4 py-5">445 <View className="border-b border-border bg-card px-4 py-5">
445 <Text className="text-[14px] font-t3-bold text-foreground">No changes</Text>446 <Text className="text-sm font-t3-bold text-foreground">No changes</Text>
446 <Text className="text-[12px] leading-[18px] text-foreground-muted">447 <Text className="text-xs leading-[18px] text-foreground-muted">
447 {selectedSection.subtitle ?? "This diff is empty."}448 {selectedSection.subtitle ?? "This diff is empty."}
448 </Text>449 </Text>
449 </View>450 </View>
450 ) : parsedDiff.kind === "raw" ? (451 ) : parsedDiff.kind === "raw" ? (
451 <View className="gap-3 border-b border-border bg-card px-4 py-4">452 <View className="gap-3 border-b border-border bg-card px-4 py-4">
452 <Text className="text-[12px] leading-[18px] text-foreground-muted">453 <Text className="text-xs leading-[18px] text-foreground-muted">
453 {parsedDiff.reason}454 {parsedDiff.reason}
454 </Text>455 </Text>
455 <ScrollView horizontal showsHorizontalScrollIndicator={false} bounces={false}>456 <ScrollView horizontal showsHorizontalScrollIndicator={false} bounces={false}>
456 <Text selectable className="font-mono text-[12px] leading-[19px] text-foreground">457 <Text selectable className="font-mono text-xs leading-[19px] text-foreground">
457 {parsedDiff.text}458 {parsedDiff.text}
458 </Text>459 </Text>
459 </ScrollView>460 </ScrollView>
apps/mobile/src/features/review/nativeReviewDiffAdapter.ts+7-6
...@@ -5,6 +5,7 @@ import type {...@@ -5,6 +5,7 @@ import type {
5} from "../diffs/nativeReviewDiffTypes";5} from "../diffs/nativeReviewDiffTypes";
6import * as Arr from "effect/Array";6import * as Arr from "effect/Array";
7import { pipe } from "effect/Function";7import { pipe } from "effect/Function";
8import { MOBILE_CODE_SURFACE } from "../../lib/typography";
8import { getPierreTerminalTheme, type TerminalAppearanceScheme } from "../terminal/terminalTheme";9import { getPierreTerminalTheme, type TerminalAppearanceScheme } from "../terminal/terminalTheme";
9import { computeWordAltDiffRanges } from "./reviewWordDiffs";10import { computeWordAltDiffRanges } from "./reviewWordDiffs";
10import {11import {
...@@ -18,16 +19,16 @@ import type { ReviewInlineComment } from "./reviewCommentSelection";...@@ -18,16 +19,16 @@ import type { ReviewInlineComment } from "./reviewCommentSelection";
18const NATIVE_REVIEW_MAX_WORD_DIFF_RANGE_COUNT = 4;19const NATIVE_REVIEW_MAX_WORD_DIFF_RANGE_COUNT = 4;
19const NATIVE_REVIEW_MAX_WORD_DIFF_COVERAGE = 0.45;20const NATIVE_REVIEW_MAX_WORD_DIFF_COVERAGE = 0.45;
2021
21export const NATIVE_REVIEW_DIFF_ROW_HEIGHT = 20;22export const NATIVE_REVIEW_DIFF_ROW_HEIGHT = MOBILE_CODE_SURFACE.rowHeight;
22export const NATIVE_REVIEW_DIFF_CONTENT_WIDTH = 2_800;23export const NATIVE_REVIEW_DIFF_CONTENT_WIDTH = 2_800;
2324
24export const NATIVE_REVIEW_DIFF_STYLE = {25export const NATIVE_REVIEW_DIFF_STYLE = {
25 rowHeight: NATIVE_REVIEW_DIFF_ROW_HEIGHT,26 rowHeight: NATIVE_REVIEW_DIFF_ROW_HEIGHT,
26 contentWidth: NATIVE_REVIEW_DIFF_CONTENT_WIDTH,27 contentWidth: NATIVE_REVIEW_DIFF_CONTENT_WIDTH,
27 changeBarWidth: 4,28 changeBarWidth: 4,
28 gutterWidth: 46,29 gutterWidth: MOBILE_CODE_SURFACE.gutterWidth,
29 codePadding: 7,30 codePadding: MOBILE_CODE_SURFACE.codePadding,
30 textVerticalInset: 2,31 textVerticalInset: MOBILE_CODE_SURFACE.textVerticalInset,
31 fileHeaderHeight: 56,32 fileHeaderHeight: 56,
32 fileHeaderHorizontalMargin: 8,33 fileHeaderHorizontalMargin: 8,
33 fileHeaderVerticalMargin: 6,34 fileHeaderVerticalMargin: 6,
...@@ -36,9 +37,9 @@ export const NATIVE_REVIEW_DIFF_STYLE = {...@@ -36,9 +37,9 @@ export const NATIVE_REVIEW_DIFF_STYLE = {
36 fileHeaderPathRightPadding: 118,37 fileHeaderPathRightPadding: 118,
37 fileHeaderCountColumnWidth: 38,38 fileHeaderCountColumnWidth: 38,
38 fileHeaderCountGap: 5,39 fileHeaderCountGap: 5,
39 codeFontSize: 11,40 codeFontSize: MOBILE_CODE_SURFACE.fontSize,
40 codeFontWeight: "regular",41 codeFontWeight: "regular",
41 lineNumberFontSize: 10,42 lineNumberFontSize: MOBILE_CODE_SURFACE.lineNumberFontSize,
42 lineNumberFontWeight: "regular",43 lineNumberFontWeight: "regular",
43 hunkFontSize: 11,44 hunkFontSize: 11,
44 hunkFontWeight: "medium",45 hunkFontWeight: "medium",
apps/mobile/src/features/review/reviewDiffRendering.tsx+14-5
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1import { Platform, Text as NativeText, View } from "react-native";1import { Platform, Text as NativeText, View } from "react-native";
22
3import { cn } from "../../lib/cn";3import { cn } from "../../lib/cn";
4import { MOBILE_CODE_SURFACE } from "../../lib/typography";
45
5import type { ReviewRenderableLineRow } from "./reviewModel";6import type { ReviewRenderableLineRow } from "./reviewModel";
6import type { ReviewHighlightedToken } from "./shikiReviewHighlighter";7import type { ReviewHighlightedToken } from "./shikiReviewHighlighter";
...@@ -11,7 +12,7 @@ export const REVIEW_MONO_FONT_FAMILY = Platform.select({...@@ -11,7 +12,7 @@ export const REVIEW_MONO_FONT_FAMILY = Platform.select({
11 default: "monospace",12 default: "monospace",
12});13});
1314
14export const REVIEW_DIFF_LINE_HEIGHT = 26;15export const REVIEW_DIFF_LINE_HEIGHT = MOBILE_CODE_SURFACE.rowHeight;
15const REVIEW_DELETE_STRIPE_COUNT = REVIEW_DIFF_LINE_HEIGHT / 2;16const REVIEW_DELETE_STRIPE_COUNT = REVIEW_DIFF_LINE_HEIGHT / 2;
1617
17export function renderVisibleWhitespace(value: string): string {18export function renderVisibleWhitespace(value: string): string {
...@@ -71,8 +72,12 @@ export function DiffTokenText(props: {...@@ -71,8 +72,12 @@ export function DiffTokenText(props: {
71 <NativeText72 <NativeText
72 numberOfLines={1}73 numberOfLines={1}
73 selectable74 selectable
74 className={cn("text-[13px] leading-[17px] font-medium text-foreground", props.className)}75 className={cn("font-normal text-foreground", props.className)}
75 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY }}76 style={{
77 fontFamily: REVIEW_MONO_FONT_FAMILY,
78 fontSize: MOBILE_CODE_SURFACE.fontSize,
79 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
80 }}
76 >81 >
77 {renderVisibleWhitespace(props.fallback || " ")}82 {renderVisibleWhitespace(props.fallback || " ")}
78 </NativeText>83 </NativeText>
...@@ -83,8 +88,12 @@ export function DiffTokenText(props: {...@@ -83,8 +88,12 @@ export function DiffTokenText(props: {
83 <NativeText88 <NativeText
84 numberOfLines={1}89 numberOfLines={1}
85 selectable90 selectable
86 className={cn("text-[13px] leading-[17px] font-medium text-foreground", props.className)}91 className={cn("font-normal text-foreground", props.className)}
87 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY }}92 style={{
93 fontFamily: REVIEW_MONO_FONT_FAMILY,
94 fontSize: MOBILE_CODE_SURFACE.fontSize,
95 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
96 }}
88 >97 >
89 {(() => {98 {(() => {
90 let offset = 0;99 let offset = 0;
apps/mobile/src/features/terminal/NativeTerminalSurface.tsx+6-5
...@@ -11,6 +11,7 @@ import {...@@ -11,6 +11,7 @@ import {
11} from "react-native";11} from "react-native";
1212
13import { AppText as Text } from "../../components/AppText";13import { AppText as Text } from "../../components/AppText";
14import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
14import { resolveNativeTerminalSurfaceView } from "./nativeTerminalModule";15import { resolveNativeTerminalSurfaceView } from "./nativeTerminalModule";
15import {16import {
16 buildGhosttyThemeConfig,17 buildGhosttyThemeConfig,
...@@ -53,7 +54,7 @@ function estimateGridSize(input: {...@@ -53,7 +54,7 @@ function estimateGridSize(input: {
53}54}
5455
55const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: TerminalSurfaceProps) {56const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: TerminalSurfaceProps) {
56 const fontSize = props.fontSize ?? 12;57 const fontSize = props.fontSize ?? MOBILE_TYPOGRAPHY.label.fontSize;
57 const inputRef = useRef<TextInput>(null);58 const inputRef = useRef<TextInput>(null);
58 const appearanceScheme = useColorScheme() === "light" ? "light" : "dark";59 const appearanceScheme = useColorScheme() === "light" ? "light" : "dark";
59 const theme = props.theme ?? getPierreTerminalTheme(appearanceScheme);60 const theme = props.theme ?? getPierreTerminalTheme(appearanceScheme);
...@@ -93,7 +94,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter...@@ -93,7 +94,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
93 <Text94 <Text
94 style={{95 style={{
95 color: theme.mutedForeground,96 color: theme.mutedForeground,
96 fontSize: 11,97 fontSize: MOBILE_TYPOGRAPHY.caption.fontSize,
97 paddingBottom: 8,98 paddingBottom: 8,
98 }}99 }}
99 >100 >
...@@ -140,7 +141,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter...@@ -140,7 +141,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
140 color: theme.foreground,141 color: theme.foreground,
141 flex: 1,142 flex: 1,
142 fontFamily: "Menlo",143 fontFamily: "Menlo",
143 fontSize: 13,144 fontSize: MOBILE_TYPOGRAPHY.footnote.fontSize,
144 padding: 0,145 padding: 0,
145 }}146 }}
146 onSubmitEditing={(event) => {147 onSubmitEditing={(event) => {
...@@ -165,7 +166,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter...@@ -165,7 +166,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
165 style={{166 style={{
166 color: theme.foreground,167 color: theme.foreground,
167 fontFamily: "DMSans_700Bold",168 fontFamily: "DMSans_700Bold",
168 fontSize: 11,169 fontSize: MOBILE_TYPOGRAPHY.caption.fontSize,
169 }}170 }}
170 >171 >
171 Ctrl-C172 Ctrl-C
...@@ -177,7 +178,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter...@@ -177,7 +178,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
177});178});
178179
179export const TerminalSurface = memo(function TerminalSurface(props: TerminalSurfaceProps) {180export const TerminalSurface = memo(function TerminalSurface(props: TerminalSurfaceProps) {
180 const fontSize = props.fontSize ?? 12;181 const fontSize = props.fontSize ?? MOBILE_TYPOGRAPHY.label.fontSize;
181 const keyboardInputRef = useRef<TextInput>(null);182 const keyboardInputRef = useRef<TextInput>(null);
182 const appearanceScheme = useColorScheme() === "light" ? "light" : "dark";183 const appearanceScheme = useColorScheme() === "light" ? "light" : "dark";
183 const theme = props.theme ?? getPierreTerminalTheme(appearanceScheme);184 const theme = props.theme ?? getPierreTerminalTheme(appearanceScheme);
apps/mobile/src/features/terminal/ThreadTerminalPanel.tsx+3-3
...@@ -127,16 +127,16 @@ export const ThreadTerminalPanel = memo(function ThreadTerminalPanel(...@@ -127,16 +127,16 @@ export const ThreadTerminalPanel = memo(function ThreadTerminalPanel(
127 <View className="absolute inset-x-3 bottom-28 top-28 overflow-hidden rounded-[8px] border border-white/10 bg-neutral-950 shadow-2xl">127 <View className="absolute inset-x-3 bottom-28 top-28 overflow-hidden rounded-[8px] border border-white/10 bg-neutral-950 shadow-2xl">
128 <View className="flex-row items-center justify-between border-b border-white/10 px-3 py-2">128 <View className="flex-row items-center justify-between border-b border-white/10 px-3 py-2">
129 <View className="min-w-0 flex-1">129 <View className="min-w-0 flex-1">
130 <Text className="font-t3-bold text-[13px] text-neutral-100" numberOfLines={1}>130 <Text className="font-t3-bold text-sm text-neutral-100" numberOfLines={1}>
131 Terminal131 Terminal
132 </Text>132 </Text>
133 <Text className="text-[11px] text-neutral-500" numberOfLines={1}>133 <Text className="text-2xs text-neutral-500" numberOfLines={1}>
134 {nativeTerminalAvailable ? "Native Ghostty surface" : "Text fallback active"}134 {nativeTerminalAvailable ? "Native Ghostty surface" : "Text fallback active"}
135 </Text>135 </Text>
136 </View>136 </View>
137 <View className="flex-row items-center gap-2">137 <View className="flex-row items-center gap-2">
138 {terminal.error ? (138 {terminal.error ? (
139 <Text className="max-w-44 text-right text-[11px] text-red-300" numberOfLines={1}>139 <Text className="max-w-44 text-right text-2xs text-red-300" numberOfLines={1}>
140 {terminal.error}140 {terminal.error}
141 </Text>141 </Text>
142 ) : null}142 ) : null}
apps/mobile/src/features/terminal/ThreadTerminalRouteScreen.tsx+3-2
...@@ -25,6 +25,7 @@ import { terminalEnvironment } from "../../state/terminal";...@@ -25,6 +25,7 @@ import { terminalEnvironment } from "../../state/terminal";
25import { useAtomCommand } from "../../state/use-atom-command";25import { useAtomCommand } from "../../state/use-atom-command";
26import { useWorkspaceState } from "../../state/workspace";26import { useWorkspaceState } from "../../state/workspace";
27import { buildThreadTerminalNavigation } from "../../lib/routes";27import { buildThreadTerminalNavigation } from "../../lib/routes";
28import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
28import {29import {
29 useAttachedTerminalSession,30 useAttachedTerminalSession,
30 useKnownTerminalSessions,31 useKnownTerminalSessions,
...@@ -920,7 +921,7 @@ export function ThreadTerminalRouteScreen() {...@@ -920,7 +921,7 @@ export function ThreadTerminalRouteScreen() {
920 style={{921 style={{
921 color: terminalTheme.foreground,922 color: terminalTheme.foreground,
922 fontFamily: "DMSans_700Bold",923 fontFamily: "DMSans_700Bold",
923 fontSize: 13,924 fontSize: MOBILE_TYPOGRAPHY.footnote.fontSize,
924 lineHeight: 16,925 lineHeight: 16,
925 }}926 }}
926 >927 >
...@@ -932,7 +933,7 @@ export function ThreadTerminalRouteScreen() {...@@ -932,7 +933,7 @@ export function ThreadTerminalRouteScreen() {
932 style={{933 style={{
933 color: terminalTheme.mutedForeground,934 color: terminalTheme.mutedForeground,
934 fontFamily: "Menlo",935 fontFamily: "Menlo",
935 fontSize: 11,936 fontSize: MOBILE_TYPOGRAPHY.caption.fontSize,
936 lineHeight: 14,937 lineHeight: 14,
937 }}938 }}
938 >939 >
apps/mobile/src/features/threads/ComposerCommandPopover.tsx+13-4
...@@ -7,6 +7,7 @@ import { Pressable, ScrollView, useColorScheme, View, type ViewStyle } from "rea...@@ -7,6 +7,7 @@ import { Pressable, ScrollView, useColorScheme, View, type ViewStyle } from "rea
77
8import { AppText as Text } from "../../components/AppText";8import { AppText as Text } from "../../components/AppText";
9import { PierreEntryIcon } from "../../components/PierreEntryIcon";9import { PierreEntryIcon } from "../../components/PierreEntryIcon";
10import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
1011
11export type ComposerCommandItem =12export type ComposerCommandItem =
12 | {13 | {
...@@ -156,14 +157,22 @@ const CommandRow = memo(function CommandRow(props: {...@@ -156,14 +157,22 @@ const CommandRow = memo(function CommandRow(props: {
156 <SymbolView name={iconName} size={14} tintColor={iconColor} type="monochrome" />157 <SymbolView name={iconName} size={14} tintColor={iconColor} type="monochrome" />
157 ) : null}158 ) : null}
158 <Text159 <Text
159 className="text-[14px] font-t3-medium text-foreground"160 className="text-base font-t3-medium text-foreground"
160 numberOfLines={1}161 numberOfLines={1}
161 style={{ flexShrink: 0 }}162 style={{ flexShrink: 0 }}
162 >163 >
163 {props.item.label}164 {props.item.label}
164 </Text>165 </Text>
165 {props.item.description ? (166 {props.item.description ? (
166 <Text numberOfLines={1} style={{ flex: 1, minWidth: 0, fontSize: 12, color: "#a1a1aa" }}>167 <Text
168 numberOfLines={1}
169 style={{
170 flex: 1,
171 minWidth: 0,
172 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
173 color: "#a1a1aa",
174 }}
175 >
167 {props.item.description}176 {props.item.description}
168 </Text>177 </Text>
169 ) : null}178 ) : null}
...@@ -182,7 +191,7 @@ export const ComposerCommandPopover = memo(function ComposerCommandPopover(...@@ -182,7 +191,7 @@ export const ComposerCommandPopover = memo(function ComposerCommandPopover(
182 {label ? (191 {label ? (
183 <View style={{ paddingHorizontal: 14, paddingTop: 10, paddingBottom: 4 }}>192 <View style={{ paddingHorizontal: 14, paddingTop: 10, paddingBottom: 4 }}>
184 <Text193 <Text
185 className="text-[10px] font-t3-bold text-foreground-muted"194 className="text-3xs font-t3-bold text-foreground-muted"
186 style={{ letterSpacing: 0.8, textTransform: "uppercase" }}195 style={{ letterSpacing: 0.8, textTransform: "uppercase" }}
187 >196 >
188 {label}197 {label}
...@@ -206,7 +215,7 @@ export const ComposerCommandPopover = memo(function ComposerCommandPopover(...@@ -206,7 +215,7 @@ export const ComposerCommandPopover = memo(function ComposerCommandPopover(
206 </ScrollView>215 </ScrollView>
207 ) : (216 ) : (
208 <View style={{ paddingHorizontal: 14, paddingVertical: 10 }}>217 <View style={{ paddingHorizontal: 14, paddingVertical: 10 }}>
209 <Text className="text-[12px] text-foreground-tertiary">218 <Text className="text-xs text-foreground-tertiary">
210 {emptyText(props.triggerKind, props.isLoading)}219 {emptyText(props.triggerKind, props.isLoading)}
211 </Text>220 </Text>
212 </View>221 </View>
apps/mobile/src/features/threads/GitActionProgressOverlay.tsx+2-2
...@@ -73,12 +73,12 @@ function OverlayContent(props: { readonly progress: GitActionProgress }) {...@@ -73,12 +73,12 @@ function OverlayContent(props: { readonly progress: GitActionProgress }) {
7373
74 <View className="flex-1 gap-0.5">74 <View className="flex-1 gap-0.5">
75 {progress.label ? (75 {progress.label ? (
76 <Text className="text-[13px] font-t3-bold text-foreground" numberOfLines={1}>76 <Text className="text-sm font-t3-bold text-foreground" numberOfLines={1}>
77 {progress.label}77 {progress.label}
78 </Text>78 </Text>
79 ) : null}79 ) : null}
80 {progress.description ? (80 {progress.description ? (
81 <Text className="text-[11px] text-foreground-muted" numberOfLines={1}>81 <Text className="text-2xs text-foreground-muted" numberOfLines={1}>
82 {progress.description}82 {progress.description}
83 </Text>83 </Text>
84 ) : null}84 ) : null}
apps/mobile/src/features/threads/NewTaskDraftScreen.tsx+2-1
...@@ -30,6 +30,7 @@ import {...@@ -30,6 +30,7 @@ import {
30 resolveProviderOptionDescriptors,30 resolveProviderOptionDescriptors,
31} from "../../lib/providerOptions";31} from "../../lib/providerOptions";
32import { buildThreadRoutePath } from "../../lib/routes";32import { buildThreadRoutePath } from "../../lib/routes";
33import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
33import { useProjects } from "../../state/entities";34import { useProjects } from "../../state/entities";
34import { branchBadgeLabel, useNewTaskFlow } from "./new-task-flow-provider";35import { branchBadgeLabel, useNewTaskFlow } from "./new-task-flow-provider";
35import { useCreateProjectThread } from "./use-project-actions";36import { useCreateProjectThread } from "./use-project-actions";
...@@ -430,7 +431,7 @@ export function NewTaskDraftScreen(props: {...@@ -430,7 +431,7 @@ export function NewTaskDraftScreen(props: {
430 onPasteImages={(uris) => void handleNativePasteImages(uris)}431 onPasteImages={(uris) => void handleNativePasteImages(uris)}
431 placeholder={`Describe a coding task in ${selectedProject.title}`}432 placeholder={`Describe a coding task in ${selectedProject.title}`}
432 style={{ flex: 1, minHeight: 0 }}433 style={{ flex: 1, minHeight: 0 }}
433 textStyle={{ fontSize: 18, lineHeight: 28 }}434 textStyle={MOBILE_TYPOGRAPHY.composer}
434 />435 />
435 </View>436 </View>
436437
apps/mobile/src/features/threads/PendingApprovalCard.tsx+1-1
...@@ -16,7 +16,7 @@ export interface PendingApprovalCardProps {...@@ -16,7 +16,7 @@ export interface PendingApprovalCardProps {
16export function PendingApprovalCard(props: PendingApprovalCardProps) {16export function PendingApprovalCard(props: PendingApprovalCardProps) {
17 return (17 return (
18 <View className="gap-2.5 rounded-[20px] border border-neutral-200 bg-neutral-100/80 p-4 dark:border-white/6 dark:bg-neutral-900/80">18 <View className="gap-2.5 rounded-[20px] border border-neutral-200 bg-neutral-100/80 p-4 dark:border-white/6 dark:bg-neutral-900/80">
19 <Text className="font-t3-bold text-[11px] uppercase tracking-[1.1px] text-sky-700 dark:text-sky-300">19 <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-sky-700 dark:text-sky-300">
20 Approval needed20 Approval needed
21 </Text>21 </Text>
22 <Text className="font-t3-bold text-lg text-neutral-950 dark:text-neutral-50">22 <Text className="font-t3-bold text-lg text-neutral-950 dark:text-neutral-50">
apps/mobile/src/features/threads/PendingUserInputCard.tsx+4-4
...@@ -26,7 +26,7 @@ export interface PendingUserInputCardProps {...@@ -26,7 +26,7 @@ export interface PendingUserInputCardProps {
26export function PendingUserInputCard(props: PendingUserInputCardProps) {26export function PendingUserInputCard(props: PendingUserInputCardProps) {
27 return (27 return (
28 <View className="gap-2.5 rounded-[20px] border border-neutral-200 bg-neutral-100/80 p-4 dark:border-white/6 dark:bg-neutral-900/80">28 <View className="gap-2.5 rounded-[20px] border border-neutral-200 bg-neutral-100/80 p-4 dark:border-white/6 dark:bg-neutral-900/80">
29 <Text className="font-t3-bold text-[11px] uppercase tracking-[1.1px] text-sky-700 dark:text-sky-300">29 <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-sky-700 dark:text-sky-300">
30 User input needed30 User input needed
31 </Text>31 </Text>
32 <Text className="font-t3-bold text-lg text-neutral-950 dark:text-neutral-50">32 <Text className="font-t3-bold text-lg text-neutral-950 dark:text-neutral-50">
...@@ -39,7 +39,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {...@@ -39,7 +39,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
39 <Text className="font-t3-bold text-xs uppercase tracking-[1px] text-neutral-500 dark:text-neutral-500">39 <Text className="font-t3-bold text-xs uppercase tracking-[1px] text-neutral-500 dark:text-neutral-500">
40 {question.header}40 {question.header}
41 </Text>41 </Text>
42 <Text className="font-sans text-[15px] leading-[21px] text-neutral-950 dark:text-neutral-50">42 <Text className="font-sans text-base leading-[21px] text-neutral-950 dark:text-neutral-50">
43 {question.question}43 {question.question}
44 </Text>44 </Text>
45 <View className="flex-row flex-wrap gap-2.5">45 <View className="flex-row flex-wrap gap-2.5">
...@@ -65,7 +65,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {...@@ -65,7 +65,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
65 >65 >
66 <Text66 <Text
67 className={cn(67 className={cn(
68 "font-t3-bold text-[13px]",68 "font-t3-bold text-sm",
69 selected69 selected
70 ? "text-sky-700 dark:text-sky-300"70 ? "text-sky-700 dark:text-sky-300"
71 : "text-neutral-600 dark:text-neutral-300",71 : "text-neutral-600 dark:text-neutral-300",
...@@ -83,7 +83,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {...@@ -83,7 +83,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
83 props.onChangeCustomAnswer(props.pendingUserInput.requestId, question.id, value)83 props.onChangeCustomAnswer(props.pendingUserInput.requestId, question.id, value)
84 }84 }
85 placeholder="Or type a custom answer"85 placeholder="Or type a custom answer"
86 className="min-h-[54px] rounded-2xl border border-neutral-200 bg-white px-3.5 py-3 font-sans text-[15px] text-neutral-950 dark:border-white/8 dark:bg-neutral-950/70 dark:text-neutral-50"86 className="min-h-[54px] rounded-2xl border border-neutral-200 bg-white px-3.5 py-3 font-sans text-base text-neutral-950 dark:border-white/8 dark:bg-neutral-950/70 dark:text-neutral-50"
87 />87 />
88 </View>88 </View>
89 );89 );
apps/mobile/src/features/threads/ThreadComposer.tsx+5-6
...@@ -43,6 +43,7 @@ import { ControlPill, ControlPillMenu } from "../../components/ControlPill";...@@ -43,6 +43,7 @@ import { ControlPill, ControlPillMenu } from "../../components/ControlPill";
43import { ProviderIcon } from "../../components/ProviderIcon";43import { ProviderIcon } from "../../components/ProviderIcon";
44import type { DraftComposerImageAttachment } from "../../lib/composerImages";44import type { DraftComposerImageAttachment } from "../../lib/composerImages";
45import { buildModelOptions, groupByProvider } from "../../lib/modelOptions";45import { buildModelOptions, groupByProvider } from "../../lib/modelOptions";
46import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
46import type { RemoteClientConnectionState } from "../../lib/connection";47import type { RemoteClientConnectionState } from "../../lib/connection";
47import {48import {
48 insertRankedSearchResult,49 insertRankedSearchResult,
...@@ -189,7 +190,7 @@ const ComposerConnectionStatusPill = memo(function ComposerConnectionStatusPill(...@@ -189,7 +190,7 @@ const ComposerConnectionStatusPill = memo(function ComposerConnectionStatusPill(
189 <View className="h-2 w-2 rounded-full bg-red-500" />190 <View className="h-2 w-2 rounded-full bg-red-500" />
190 )}191 )}
191 <Text192 <Text
192 className="max-w-[260px] text-[13px] font-t3-bold leading-[17px] text-foreground"193 className="max-w-[260px] text-sm font-t3-bold leading-[17px] text-foreground"
193 numberOfLines={1}194 numberOfLines={1}
194 >195 >
195 {props.status.label}196 {props.status.label}
...@@ -717,8 +718,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer...@@ -717,8 +718,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
717 }718 }
718 }719 }
719 textStyle={{720 textStyle={{
720 fontSize: 15,721 ...MOBILE_TYPOGRAPHY.composer,
721 lineHeight: isExpanded ? 22 : 20,
722 color: foregroundColor,722 color: foregroundColor,
723 fontFamily: "DMSans_400Regular",723 fontFamily: "DMSans_400Regular",
724 }}724 }}
...@@ -751,7 +751,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer...@@ -751,7 +751,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
751 justifyContent: "center",751 justifyContent: "center",
752 }}752 }}
753 >753 >
754 <Text className="text-foreground-muted text-[11px] font-t3-bold">754 <Text className="text-foreground-muted text-2xs font-t3-bold">
755 +{props.draftAttachments.length - 3}755 +{props.draftAttachments.length - 3}
756 </Text>756 </Text>
757 </View>757 </View>
...@@ -831,8 +831,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer...@@ -831,8 +831,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
831 <Text831 <Text
832 className="text-foreground-muted"832 className="text-foreground-muted"
833 style={{833 style={{
834 fontSize: 12,834 ...MOBILE_TYPOGRAPHY.label,
835 lineHeight: 18,
836 paddingTop: 8,835 paddingTop: 8,
837 }}836 }}
838 >837 >
apps/mobile/src/features/threads/ThreadFeed.tsx+12-14
...@@ -56,6 +56,7 @@ import { buildReviewParsedDiff } from "../review/reviewModel";...@@ -56,6 +56,7 @@ import { buildReviewParsedDiff } from "../review/reviewModel";
56import { cn } from "../../lib/cn";56import { cn } from "../../lib/cn";
57import type { LayoutVariant } from "../../lib/layout";57import type { LayoutVariant } from "../../lib/layout";
58import { buildThreadFilesNavigation } from "../../lib/routes";58import { buildThreadFilesNavigation } from "../../lib/routes";
59import { MOBILE_CODE_SURFACE, MOBILE_TYPOGRAPHY } from "../../lib/typography";
59import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons";60import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons";
60import { resolveMarkdownLinkPresentation } from "@t3tools/mobile-markdown-text/links";61import { resolveMarkdownLinkPresentation } from "@t3tools/mobile-markdown-text/links";
61import {62import {
...@@ -444,8 +445,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe...@@ -444,8 +445,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
444 marginRight: 5,445 marginRight: 5,
445 color: inlineTextColor,446 color: inlineTextColor,
446 fontFamily: "DMSans_400Regular",447 fontFamily: "DMSans_400Regular",
447 fontSize: 15,448 ...MOBILE_TYPOGRAPHY.body,
448 lineHeight: 22,
449 textAlign: ordered ? "right" : "center",449 textAlign: ordered ? "right" : "center",
450 }}450 }}
451 >451 >
...@@ -466,7 +466,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe...@@ -466,7 +466,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
466 style={{466 style={{
467 color: inlineCodeTextColor,467 color: inlineCodeTextColor,
468 fontFamily: "ui-monospace",468 fontFamily: "ui-monospace",
469 fontSize: 12,469 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
470 lineHeight: 22,470 lineHeight: 22,
471 }}471 }}
472 >472 >
...@@ -503,7 +503,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe...@@ -503,7 +503,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
503 style={{503 style={{
504 color: markdownBodyColor,504 color: markdownBodyColor,
505 fontFamily: "ui-monospace",505 fontFamily: "ui-monospace",
506 fontSize: 12,506 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
507 opacity: 0.7,507 opacity: 0.7,
508 textTransform: "uppercase",508 textTransform: "uppercase",
509 }}509 }}
...@@ -523,7 +523,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe...@@ -523,7 +523,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
523 style={{523 style={{
524 color: blockTextColor,524 color: blockTextColor,
525 fontFamily: "ui-monospace",525 fontFamily: "ui-monospace",
526 fontSize: 12,526 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
527 lineHeight: 18,527 lineHeight: 18,
528 }}528 }}
529 >529 >
...@@ -603,8 +603,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe...@@ -603,8 +603,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
603 skillTextColor: "#f0abfc",603 skillTextColor: "#f0abfc",
604 quoteMarkerColor: markdownUserBodyColor,604 quoteMarkerColor: markdownUserBodyColor,
605 dividerColor: markdownUserBodyColor,605 dividerColor: markdownUserBodyColor,
606 fontSize: 15,606 ...MOBILE_TYPOGRAPHY.body,
607 lineHeight: 22,
608 fontFamily: "DMSans_400Regular",607 fontFamily: "DMSans_400Regular",
609 headingFontFamily: "DMSans_700Bold",608 headingFontFamily: "DMSans_700Bold",
610 boldFontFamily: "DMSans_700Bold",609 boldFontFamily: "DMSans_700Bold",
...@@ -633,8 +632,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe...@@ -633,8 +632,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
633 skillTextColor: inlineSkillForeground,632 skillTextColor: inlineSkillForeground,
634 quoteMarkerColor: markdownBlockquoteBorder,633 quoteMarkerColor: markdownBlockquoteBorder,
635 dividerColor: markdownHrColor,634 dividerColor: markdownHrColor,
636 fontSize: 15,635 ...MOBILE_TYPOGRAPHY.body,
637 lineHeight: 22,
638 fontFamily: "DMSans_400Regular",636 fontFamily: "DMSans_400Regular",
639 headingFontFamily: "DMSans_700Bold",637 headingFontFamily: "DMSans_700Bold",
640 boldFontFamily: "DMSans_700Bold",638 boldFontFamily: "DMSans_700Bold",
...@@ -821,7 +819,7 @@ function renderFeedEntry(...@@ -821,7 +819,7 @@ function renderFeedEntry(
821 className="max-w-[85%] gap-2 rounded-[22px] rounded-br-[6px] px-3.5 py-2.5 opacity-60"819 className="max-w-[85%] gap-2 rounded-[22px] rounded-br-[6px] px-3.5 py-2.5 opacity-60"
822 style={{ backgroundColor: userBubbleColor }}820 style={{ backgroundColor: userBubbleColor }}
823 >821 >
824 <Text className="font-sans text-[15px] leading-[22px] text-white">822 <Text className="font-sans text-base leading-[22px] text-white">
825 {entry.queuedMessage.text}823 {entry.queuedMessage.text}
826 </Text>824 </Text>
827 {entry.queuedMessage.attachments.length > 0 ? (825 {entry.queuedMessage.attachments.length > 0 ? (
...@@ -995,7 +993,7 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {...@@ -995,7 +993,7 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {
995 </View>993 </View>
996 <View className="min-w-0 flex-1">994 <View className="min-w-0 flex-1">
997 <Text995 <Text
998 className="font-mono text-[12px] leading-[16px]"996 className="font-mono text-xs leading-[16px]"
999 numberOfLines={1}997 numberOfLines={1}
1000 style={{ color: props.colors.text }}998 style={{ color: props.colors.text }}
1001 >999 >
...@@ -1040,8 +1038,8 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {...@@ -1040,8 +1038,8 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {
1040 style={{1038 style={{
1041 color: props.colors.text,1039 color: props.colors.text,
1042 fontFamily: "ui-monospace",1040 fontFamily: "ui-monospace",
1043 fontSize: 12,1041 fontSize: MOBILE_CODE_SURFACE.fontSize,
1044 lineHeight: 18,1042 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
1045 }}1043 }}
1046 >1044 >
1047 {props.comment.diff.trim()}1045 {props.comment.diff.trim()}
...@@ -1052,7 +1050,7 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {...@@ -1052,7 +1050,7 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {
1052 <View className="border-t px-3 py-3" style={{ borderColor: props.colors.border }}>1050 <View className="border-t px-3 py-3" style={{ borderColor: props.colors.border }}>
1053 <Text1051 <Text
1054 selectable1052 selectable
1055 className="text-[15px] leading-[21px]"1053 className="text-base leading-[21px]"
1056 style={{ color: props.colors.text }}1054 style={{ color: props.colors.text }}
1057 >1055 >
1058 {props.comment.text}1056 {props.comment.text}
apps/mobile/src/features/threads/ThreadNavigationDrawer.tsx+5-7
...@@ -152,7 +152,7 @@ export function ThreadNavigationDrawer(props: {...@@ -152,7 +152,7 @@ export function ThreadNavigationDrawer(props: {
152 ]}152 ]}
153 >153 >
154 <View className="flex-row items-center justify-between px-4 pb-5">154 <View className="flex-row items-center justify-between px-4 pb-5">
155 <Text className="text-[26px] font-t3-bold">Threads</Text>155 <Text className="text-2xl font-t3-bold">Threads</Text>
156 <Pressable156 <Pressable
157 onPress={() => {157 onPress={() => {
158 props.onClose();158 props.onClose();
...@@ -224,7 +224,7 @@ function ThreadNavigationDrawerContent(props: {...@@ -224,7 +224,7 @@ function ThreadNavigationDrawerContent(props: {
224 {groupedThreads.map((group) => (224 {groupedThreads.map((group) => (
225 <View key={group.key} className="gap-3">225 <View key={group.key} className="gap-3">
226 <Text226 <Text
227 className="px-1 text-[15px] font-t3-bold text-foreground-muted"227 className="px-1 text-base font-t3-bold text-foreground-muted"
228 style={{ letterSpacing: -0.2 }}228 style={{ letterSpacing: -0.2 }}
229 >229 >
230 {group.title}230 {group.title}
...@@ -233,9 +233,7 @@ function ThreadNavigationDrawerContent(props: {...@@ -233,9 +233,7 @@ function ThreadNavigationDrawerContent(props: {
233 <View className="overflow-hidden rounded-[22px] bg-card">233 <View className="overflow-hidden rounded-[22px] bg-card">
234 {group.threads.length === 0 ? (234 {group.threads.length === 0 ? (
235 <View className="px-4 py-4">235 <View className="px-4 py-4">
236 <Text className="text-[14px] font-medium text-foreground-tertiary">236 <Text className="text-sm font-medium text-foreground-tertiary">No threads yet</Text>
237 No threads yet
238 </Text>
239 </View>237 </View>
240 ) : (238 ) : (
241 group.threads.map((thread, index) => {239 group.threads.map((thread, index) => {
...@@ -260,11 +258,11 @@ function ThreadNavigationDrawerContent(props: {...@@ -260,11 +258,11 @@ function ThreadNavigationDrawerContent(props: {
260 >258 >
261 <View className="flex-row items-start justify-between gap-3">259 <View className="flex-row items-start justify-between gap-3">
262 <View className="flex-1 gap-1">260 <View className="flex-1 gap-1">
263 <Text className="text-[16px] font-t3-bold" numberOfLines={1}>261 <Text className="text-base font-t3-bold" numberOfLines={1}>
264 {thread.title}262 {thread.title}
265 </Text>263 </Text>
266 <Text264 <Text
267 className="text-[13px] font-medium text-foreground-muted"265 className="text-sm font-medium text-foreground-muted"
268 numberOfLines={1}266 numberOfLines={1}
269 >267 >
270 {relativeTime(thread.updatedAt ?? thread.createdAt)}268 {relativeTime(thread.updatedAt ?? thread.createdAt)}
apps/mobile/src/features/threads/ThreadRouteScreen.tsx+3-2
...@@ -20,6 +20,7 @@ import { EmptyState } from "../../components/EmptyState";...@@ -20,6 +20,7 @@ import { EmptyState } from "../../components/EmptyState";
20import { LoadingScreen } from "../../components/LoadingScreen";20import { LoadingScreen } from "../../components/LoadingScreen";
21import { buildThreadRoutePath, buildThreadTerminalNavigation } from "../../lib/routes";21import { buildThreadRoutePath, buildThreadTerminalNavigation } from "../../lib/routes";
22import { scopedThreadKey } from "../../lib/scopedEntities";22import { scopedThreadKey } from "../../lib/scopedEntities";
23import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
23import { connectionTone } from "../connection/connectionTone";24import { connectionTone } from "../connection/connectionTone";
2425
25import {26import {
...@@ -390,7 +391,7 @@ export function ThreadRouteScreen() {...@@ -390,7 +391,7 @@ export function ThreadRouteScreen() {
390 numberOfLines={1}391 numberOfLines={1}
391 style={{392 style={{
392 fontFamily: "DMSans_700Bold",393 fontFamily: "DMSans_700Bold",
393 fontSize: 18,394 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
394 fontWeight: "900",395 fontWeight: "900",
395 color: foregroundColor,396 color: foregroundColor,
396 letterSpacing: -0.4,397 letterSpacing: -0.4,
...@@ -402,7 +403,7 @@ export function ThreadRouteScreen() {...@@ -402,7 +403,7 @@ export function ThreadRouteScreen() {
402 numberOfLines={1}403 numberOfLines={1}
403 style={{404 style={{
404 fontFamily: "DMSans_700Bold",405 fontFamily: "DMSans_700Bold",
405 fontSize: 12,406 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
406 fontWeight: "700",407 fontWeight: "700",
407 color: secondaryFg,408 color: secondaryFg,
408 letterSpacing: 0.3,409 letterSpacing: 0.3,
apps/mobile/src/features/threads/git/GitBranchesSheet.tsx+10-12
...@@ -69,7 +69,7 @@ export function GitBranchesSheet() {...@@ -69,7 +69,7 @@ export function GitBranchesSheet() {
69 >69 >
70 <View className="gap-2 rounded-[18px] border border-border bg-card px-4 py-4">70 <View className="gap-2 rounded-[18px] border border-border bg-card px-4 py-4">
71 <Text71 <Text
72 className="text-foreground-secondary text-[11px] font-t3-bold uppercase"72 className="text-foreground-secondary text-2xs font-t3-bold uppercase"
73 style={{ letterSpacing: 1 }}73 style={{ letterSpacing: 1 }}
74 >74 >
75 New branch75 New branch
...@@ -78,7 +78,7 @@ export function GitBranchesSheet() {...@@ -78,7 +78,7 @@ export function GitBranchesSheet() {
78 value={newBranchName}78 value={newBranchName}
79 onChangeText={setNewBranchName}79 onChangeText={setNewBranchName}
80 placeholder="feature/mobile-polish"80 placeholder="feature/mobile-polish"
81 className="rounded-[18px] px-3.5 py-3 font-sans text-[15px]"81 className="rounded-[18px] px-3.5 py-3 font-sans text-base"
82 style={{82 style={{
83 borderWidth: 1,83 borderWidth: 1,
84 borderColor: inputBorderColor,84 borderColor: inputBorderColor,
...@@ -104,7 +104,7 @@ export function GitBranchesSheet() {...@@ -104,7 +104,7 @@ export function GitBranchesSheet() {
104104
105 <View className="gap-2 rounded-[18px] border border-border bg-card px-4 py-4">105 <View className="gap-2 rounded-[18px] border border-border bg-card px-4 py-4">
106 <Text106 <Text
107 className="text-foreground-secondary text-[11px] font-t3-bold uppercase"107 className="text-foreground-secondary text-2xs font-t3-bold uppercase"
108 style={{ letterSpacing: 1 }}108 style={{ letterSpacing: 1 }}
109 >109 >
110 New worktree110 New worktree
...@@ -113,7 +113,7 @@ export function GitBranchesSheet() {...@@ -113,7 +113,7 @@ export function GitBranchesSheet() {
113 value={worktreeBaseBranch}113 value={worktreeBaseBranch}
114 onChangeText={setWorktreeBaseBranch}114 onChangeText={setWorktreeBaseBranch}
115 placeholder="main"115 placeholder="main"
116 className="rounded-[18px] px-3.5 py-3 font-sans text-[15px]"116 className="rounded-[18px] px-3.5 py-3 font-sans text-base"
117 style={{117 style={{
118 borderWidth: 1,118 borderWidth: 1,
119 borderColor: inputBorderColor,119 borderColor: inputBorderColor,
...@@ -125,7 +125,7 @@ export function GitBranchesSheet() {...@@ -125,7 +125,7 @@ export function GitBranchesSheet() {
125 value={worktreeBranchName}125 value={worktreeBranchName}
126 onChangeText={setWorktreeBranchName}126 onChangeText={setWorktreeBranchName}
127 placeholder="feature/mobile-thread"127 placeholder="feature/mobile-thread"
128 className="rounded-[18px] px-3.5 py-3 font-sans text-[15px]"128 className="rounded-[18px] px-3.5 py-3 font-sans text-base"
129 style={{129 style={{
130 borderWidth: 1,130 borderWidth: 1,
131 borderColor: inputBorderColor,131 borderColor: inputBorderColor,
...@@ -154,18 +154,16 @@ export function GitBranchesSheet() {...@@ -154,18 +154,16 @@ export function GitBranchesSheet() {
154154
155 <View className="gap-2">155 <View className="gap-2">
156 <Text156 <Text
157 className="text-foreground-secondary text-[11px] font-t3-bold uppercase"157 className="text-foreground-secondary text-2xs font-t3-bold uppercase"
158 style={{ letterSpacing: 1 }}158 style={{ letterSpacing: 1 }}
159 >159 >
160 Existing branches160 Existing branches
161 </Text>161 </Text>
162 {branchesLoading ? (162 {branchesLoading ? (
163 <Text className="text-foreground-secondary text-[13px] font-medium">163 <Text className="text-foreground-secondary text-sm font-medium">Loading branches...</Text>
164 Loading branches...
165 </Text>
166 ) : null}164 ) : null}
167 {!branchesLoading && availableBranches.length === 0 ? (165 {!branchesLoading && availableBranches.length === 0 ? (
168 <Text className="text-foreground-secondary text-[13px] font-medium">166 <Text className="text-foreground-secondary text-sm font-medium">
169 No local branches found.167 No local branches found.
170 </Text>168 </Text>
171 ) : null}169 ) : null}
...@@ -195,8 +193,8 @@ export function GitBranchesSheet() {...@@ -195,8 +193,8 @@ export function GitBranchesSheet() {
195 }}193 }}
196 >194 >
197 <View className="absolute inset-0 rounded-[18px] bg-card" />195 <View className="absolute inset-0 rounded-[18px] bg-card" />
198 <Text className="text-foreground text-[15px] font-t3-bold">{branch.name}</Text>196 <Text className="text-foreground text-base font-t3-bold">{branch.name}</Text>
199 <Text className="text-foreground-secondary text-[12px] font-medium">{subtitle}</Text>197 <Text className="text-foreground-secondary text-xs font-medium">{subtitle}</Text>
200 </Pressable>198 </Pressable>
201 );199 );
202 })}200 })}
apps/mobile/src/features/threads/git/GitCommitSheet.tsx+18-18
...@@ -79,14 +79,14 @@ export function GitCommitSheet() {...@@ -79,14 +79,14 @@ export function GitCommitSheet() {
79 >79 >
80 <View className="gap-3 rounded-[22px] border border-border bg-card px-4 py-4">80 <View className="gap-3 rounded-[22px] border border-border bg-card px-4 py-4">
81 <View className="flex-row items-center justify-between gap-3">81 <View className="flex-row items-center justify-between gap-3">
82 <Text className="text-foreground-muted text-[13px] font-medium">Branch</Text>82 <Text className="text-foreground-muted text-sm font-medium">Branch</Text>
83 <Text className="text-foreground text-[15px] font-t3-bold">83 <Text className="text-foreground text-base font-t3-bold">
84 {gitStatus.data?.refName ?? "(detached HEAD)"}84 {gitStatus.data?.refName ?? "(detached HEAD)"}
85 </Text>85 </Text>
86 </View>86 </View>
87 {isDefaultRef ? (87 {isDefaultRef ? (
88 <Text88 <Text
89 className="text-[12px] leading-[18px]"89 className="text-xs leading-[18px]"
90 style={{ color: isDarkMode ? "#fbbf24" : "#b45309" }}90 style={{ color: isDarkMode ? "#fbbf24" : "#b45309" }}
91 >91 >
92 Warning: this is the default branch.92 Warning: this is the default branch.
...@@ -97,8 +97,8 @@ export function GitCommitSheet() {...@@ -97,8 +97,8 @@ export function GitCommitSheet() {
97 <View className="gap-3 rounded-[22px] border border-border bg-card px-4 py-4">97 <View className="gap-3 rounded-[22px] border border-border bg-card px-4 py-4">
98 <View className="flex-row items-center justify-between gap-3">98 <View className="flex-row items-center justify-between gap-3">
99 <View className="gap-1">99 <View className="gap-1">
100 <Text className="text-foreground text-[16px] font-t3-bold">Files</Text>100 <Text className="text-foreground text-base font-t3-bold">Files</Text>
101 <Text className="text-foreground-muted text-[12px] leading-[18px]">101 <Text className="text-foreground-muted text-xs leading-[18px]">
102 {selectedFiles.length} selected · +{selectedInsertions} / -{selectedDeletions}102 {selectedFiles.length} selected · +{selectedInsertions} / -{selectedDeletions}
103 </Text>103 </Text>
104 </View>104 </View>
...@@ -108,14 +108,14 @@ export function GitCommitSheet() {...@@ -108,14 +108,14 @@ export function GitCommitSheet() {
108 className="bg-subtle rounded-full px-3 py-2"108 className="bg-subtle rounded-full px-3 py-2"
109 onPress={() => setExcludedFiles(new Set())}109 onPress={() => setExcludedFiles(new Set())}
110 >110 >
111 <Text className="text-foreground text-[11px] font-t3-bold uppercase">Reset</Text>111 <Text className="text-foreground text-2xs font-t3-bold uppercase">Reset</Text>
112 </Pressable>112 </Pressable>
113 ) : null}113 ) : null}
114 <Pressable114 <Pressable
115 className="bg-subtle rounded-full px-3 py-2"115 className="bg-subtle rounded-full px-3 py-2"
116 onPress={() => setIsEditingFiles((current) => !current)}116 onPress={() => setIsEditingFiles((current) => !current)}
117 >117 >
118 <Text className="text-foreground text-[11px] font-t3-bold uppercase">118 <Text className="text-foreground text-2xs font-t3-bold uppercase">
119 {isEditingFiles ? "Done" : "Edit"}119 {isEditingFiles ? "Done" : "Edit"}
120 </Text>120 </Text>
121 </Pressable>121 </Pressable>
...@@ -123,26 +123,26 @@ export function GitCommitSheet() {...@@ -123,26 +123,26 @@ export function GitCommitSheet() {
123 </View>123 </View>
124124
125 {allFiles.length === 0 ? (125 {allFiles.length === 0 ? (
126 <Text className="text-foreground-secondary text-[13px] leading-[19px]">126 <Text className="text-foreground-secondary text-sm leading-[19px]">
127 No changed files are available to commit.127 No changed files are available to commit.
128 </Text>128 </Text>
129 ) : !isEditingFiles ? (129 ) : !isEditingFiles ? (
130 <View className="gap-2">130 <View className="gap-2">
131 {selectedFilePreview.map((file) => (131 {selectedFilePreview.map((file) => (
132 <View key={file.path} className="flex-row items-center justify-between gap-3">132 <View key={file.path} className="flex-row items-center justify-between gap-3">
133 <Text className="text-foreground flex-1 text-[13px] font-medium" numberOfLines={1}>133 <Text className="text-foreground flex-1 text-sm font-medium" numberOfLines={1}>
134 {file.path}134 {file.path}
135 </Text>135 </Text>
136 <Text className="text-[12px] font-t3-bold" style={{ color: "#10b981" }}>136 <Text className="text-xs font-t3-bold" style={{ color: "#10b981" }}>
137 +{file.insertions}137 +{file.insertions}
138 </Text>138 </Text>
139 <Text className="text-[12px] font-t3-bold" style={{ color: "#f43f5e" }}>139 <Text className="text-xs font-t3-bold" style={{ color: "#f43f5e" }}>
140 -{file.deletions}140 -{file.deletions}
141 </Text>141 </Text>
142 </View>142 </View>
143 ))}143 ))}
144 {selectedFiles.length > selectedFilePreview.length ? (144 {selectedFiles.length > selectedFilePreview.length ? (
145 <Text className="text-foreground-muted text-[12px] leading-[17px]">145 <Text className="text-foreground-muted text-xs leading-[17px]">
146 +{selectedFiles.length - selectedFilePreview.length} more files146 +{selectedFiles.length - selectedFilePreview.length} more files
147 </Text>147 </Text>
148 ) : null}148 ) : null}
...@@ -177,21 +177,21 @@ export function GitCommitSheet() {...@@ -177,21 +177,21 @@ export function GitCommitSheet() {
177 <View className="flex-1 gap-1">177 <View className="flex-1 gap-1">
178 <Text178 <Text
179 selectable179 selectable
180 className={`text-[13px] font-t3-bold ${included ? "text-foreground" : "text-foreground-muted"}`}180 className={`text-sm font-t3-bold ${included ? "text-foreground" : "text-foreground-muted"}`}
181 >181 >
182 {file.path}182 {file.path}
183 </Text>183 </Text>
184 {!included ? (184 {!included ? (
185 <Text className="text-foreground-muted text-[11px] leading-[16px]">185 <Text className="text-foreground-muted text-2xs leading-[16px]">
186 Excluded from this commit186 Excluded from this commit
187 </Text>187 </Text>
188 ) : null}188 ) : null}
189 </View>189 </View>
190 <View className="items-end gap-1">190 <View className="items-end gap-1">
191 <Text className="text-[12px] font-t3-bold" style={{ color: "#10b981" }}>191 <Text className="text-xs font-t3-bold" style={{ color: "#10b981" }}>
192 +{file.insertions}192 +{file.insertions}
193 </Text>193 </Text>
194 <Text className="text-[12px] font-t3-bold" style={{ color: "#f43f5e" }}>194 <Text className="text-xs font-t3-bold" style={{ color: "#f43f5e" }}>
195 -{file.deletions}195 -{file.deletions}
196 </Text>196 </Text>
197 </View>197 </View>
...@@ -204,14 +204,14 @@ export function GitCommitSheet() {...@@ -204,14 +204,14 @@ export function GitCommitSheet() {
204 </View>204 </View>
205205
206 <View className="gap-2">206 <View className="gap-2">
207 <Text className="text-foreground text-[13px] font-t3-bold">Commit message</Text>207 <Text className="text-foreground text-sm font-t3-bold">Commit message</Text>
208 <TextInput208 <TextInput
209 multiline209 multiline
210 value={dialogCommitMessage}210 value={dialogCommitMessage}
211 onChangeText={setDialogCommitMessage}211 onChangeText={setDialogCommitMessage}
212 placeholder="Leave empty to auto-generate"212 placeholder="Leave empty to auto-generate"
213 textAlignVertical="top"213 textAlignVertical="top"
214 className="min-h-[128px] rounded-[20px] px-4 py-3.5 font-sans text-[15px]"214 className="min-h-[128px] rounded-[20px] px-4 py-3.5 font-sans text-base"
215 style={{215 style={{
216 minHeight: 128,216 minHeight: 128,
217 borderWidth: 1,217 borderWidth: 1,
apps/mobile/src/features/threads/git/GitConfirmSheet.tsx+3-3
...@@ -90,15 +90,15 @@ export function GitConfirmSheet() {...@@ -90,15 +90,15 @@ export function GitConfirmSheet() {
9090
91 <View className="items-center gap-1 px-5 pb-3 pt-4">91 <View className="items-center gap-1 px-5 pb-3 pt-4">
92 <Text92 <Text
93 className="text-[12px] font-t3-bold uppercase text-foreground-muted"93 className="text-xs font-t3-bold uppercase text-foreground-muted"
94 style={{ letterSpacing: 1 }}94 style={{ letterSpacing: 1 }}
95 >95 >
96 Confirm96 Confirm
97 </Text>97 </Text>
98 <Text className="text-center text-[28px] font-t3-bold">98 <Text className="text-center text-3xl font-t3-bold">
99 {copy?.title ?? "Run action on default branch?"}99 {copy?.title ?? "Run action on default branch?"}
100 </Text>100 </Text>
101 <Text className="text-center text-foreground-secondary text-[13px] font-medium leading-[19px]">101 <Text className="text-center text-foreground-secondary text-sm font-medium leading-[19px]">
102 {copy?.description ?? "Choose how to continue."}102 {copy?.description ?? "Choose how to continue."}
103 </Text>103 </Text>
104 </View>104 </View>
apps/mobile/src/features/threads/git/GitOverviewSheet.tsx+3-3
...@@ -175,13 +175,13 @@ export function GitOverviewSheet() {...@@ -175,13 +175,13 @@ export function GitOverviewSheet() {
175 />175 />
176 </Pressable>176 </Pressable>
177 <Text177 <Text
178 className="text-[12px] font-t3-bold uppercase text-foreground-muted"178 className="text-xs font-t3-bold uppercase text-foreground-muted"
179 style={{ letterSpacing: 1 }}179 style={{ letterSpacing: 1 }}
180 >180 >
181 Branch181 Branch
182 </Text>182 </Text>
183 <Text className="text-[28px] font-t3-bold">{currentBranchLabel}</Text>183 <Text className="text-3xl font-t3-bold">{currentBranchLabel}</Text>
184 <Text className="text-foreground-secondary text-[13px] font-medium leading-[19px]">184 <Text className="text-foreground-secondary text-sm font-medium leading-[19px]">
185 {statusSummary(gitStatus.data)}185 {statusSummary(gitStatus.data)}
186 </Text>186 </Text>
187 </View>187 </View>
apps/mobile/src/features/threads/git/gitSheetComponents.tsx+5-5
...@@ -56,7 +56,7 @@ export function SheetActionButton(props: {...@@ -56,7 +56,7 @@ export function SheetActionButton(props: {
56 >56 >
57 <SymbolView name={props.icon} size={16} tintColor={colors.textColor} type="monochrome" />57 <SymbolView name={props.icon} size={16} tintColor={colors.textColor} type="monochrome" />
58 <Text58 <Text
59 className="text-[12px] font-t3-bold uppercase"59 className="text-xs font-t3-bold uppercase"
60 style={{ color: colors.textColor, letterSpacing: 0.9 }}60 style={{ color: colors.textColor, letterSpacing: 0.9 }}
61 >61 >
62 {props.label}62 {props.label}
...@@ -69,12 +69,12 @@ export function MetaCard(props: { readonly label: string; readonly value: string...@@ -69,12 +69,12 @@ export function MetaCard(props: { readonly label: string; readonly value: string
69 return (69 return (
70 <View className="rounded-[18px] border border-border bg-card px-4 py-3">70 <View className="rounded-[18px] border border-border bg-card px-4 py-3">
71 <Text71 <Text
72 className="text-foreground-muted text-[11px] font-t3-bold uppercase"72 className="text-foreground-muted text-2xs font-t3-bold uppercase"
73 style={{ letterSpacing: 0.9 }}73 style={{ letterSpacing: 0.9 }}
74 >74 >
75 {props.label}75 {props.label}
76 </Text>76 </Text>
77 <Text selectable className="text-foreground text-[13px] font-medium" numberOfLines={1}>77 <Text selectable className="text-foreground text-sm font-medium" numberOfLines={1}>
78 {props.value}78 {props.value}
79 </Text>79 </Text>
80 </View>80 </View>
...@@ -102,9 +102,9 @@ export function SheetListRow(props: {...@@ -102,9 +102,9 @@ export function SheetListRow(props: {
102 <SymbolView name={props.icon} size={16} tintColor={iconColor} type="monochrome" />102 <SymbolView name={props.icon} size={16} tintColor={iconColor} type="monochrome" />
103 </View>103 </View>
104 <View className="flex-1 gap-0.5">104 <View className="flex-1 gap-0.5">
105 <Text className="text-foreground text-[16px] font-t3-bold">{props.title}</Text>105 <Text className="text-foreground text-base font-t3-bold">{props.title}</Text>
106 {props.subtitle ? (106 {props.subtitle ? (
107 <Text className="text-foreground-muted text-[12px] leading-[17px]">{props.subtitle}</Text>107 <Text className="text-foreground-muted text-xs leading-[17px]">{props.subtitle}</Text>
108 ) : null}108 ) : null}
109 </View>109 </View>
110 <SymbolView name="chevron.right" size={13} tintColor={iconSubtleColor} type="monochrome" />110 <SymbolView name="chevron.right" size={13} tintColor={iconSubtleColor} type="monochrome" />
apps/mobile/src/features/threads/thread-work-log.tsx+3-3
...@@ -98,7 +98,7 @@ export function ThreadWorkLog(props: {...@@ -98,7 +98,7 @@ export function ThreadWorkLog(props: {
98 return (98 return (
99 <View className="-mx-1 mb-3 px-1 py-0.5">99 <View className="-mx-1 mb-3 px-1 py-0.5">
100 {!onlyToolRows ? (100 {!onlyToolRows ? (
101 <Text className="px-0.5 pb-0.5 font-t3-medium text-[11px] text-foreground-muted opacity-60">101 <Text className="px-0.5 pb-0.5 font-t3-medium text-2xs text-foreground-muted opacity-60">
102 work log102 work log
103 </Text>103 </Text>
104 ) : null}104 ) : null}
...@@ -164,7 +164,7 @@ export function ThreadWorkLog(props: {...@@ -164,7 +164,7 @@ export function ThreadWorkLog(props: {
164164
165 <View className="shrink-0 flex-row items-center gap-px">165 <View className="shrink-0 flex-row items-center gap-px">
166 {props.copiedRowId === row.id ? (166 {props.copiedRowId === row.id ? (
167 <Text className="pr-1 font-t3-medium text-[10px] text-emerald-600 dark:text-emerald-400">167 <Text className="pr-1 font-t3-medium text-3xs text-emerald-600 dark:text-emerald-400">
168 Copied168 Copied
169 </Text>169 </Text>
170 ) : null}170 ) : null}
...@@ -209,7 +209,7 @@ export function ThreadWorkLog(props: {...@@ -209,7 +209,7 @@ export function ThreadWorkLog(props: {
209 >209 >
210 <Text210 <Text
211 selectable211 selectable
212 className="text-[11px] leading-[17px] text-foreground-muted"212 className="text-2xs leading-[17px] text-foreground-muted"
213 style={{ fontFamily: "ui-monospace" }}213 style={{ fontFamily: "ui-monospace" }}
214 >214 >
215 {row.fullDetail}215 {row.fullDetail}
apps/mobile/src/lib/typography.test.ts created+23
...@@ -0,0 +1,23 @@
1import { describe, expect, it } from "vite-plus/test";
2
3import { MOBILE_CODE_SURFACE, MOBILE_TYPOGRAPHY } from "./typography";
4
5describe("mobile typography", () => {
6 it("uses the intentional compact mobile font scale", () => {
7 expect(Object.values(MOBILE_TYPOGRAPHY).map(({ fontSize }) => fontSize)).toEqual([
8 10, 11, 12, 13, 14, 15, 17, 20, 24, 28,
9 ]);
10 });
11
12 it("uses a compact shared style for editable composer text", () => {
13 expect(MOBILE_TYPOGRAPHY.composer).toEqual({ fontSize: 14, lineHeight: 20 });
14 });
15
16 it("uses caption-sized code with a compact readable row height", () => {
17 expect(MOBILE_CODE_SURFACE).toMatchObject({
18 fontSize: MOBILE_TYPOGRAPHY.caption.fontSize,
19 lineNumberFontSize: MOBILE_TYPOGRAPHY.micro.fontSize,
20 rowHeight: 20,
21 });
22 });
23});
apps/mobile/src/lib/typography.ts created+22
...@@ -0,0 +1,22 @@
1export const MOBILE_TYPOGRAPHY = {
2 micro: { fontSize: 10, lineHeight: 13 },
3 caption: { fontSize: 11, lineHeight: 15 },
4 label: { fontSize: 12, lineHeight: 16 },
5 footnote: { fontSize: 13, lineHeight: 18 },
6 composer: { fontSize: 14, lineHeight: 20 },
7 body: { fontSize: 15, lineHeight: 22 },
8 headline: { fontSize: 17, lineHeight: 22 },
9 title: { fontSize: 20, lineHeight: 26 },
10 largeTitle: { fontSize: 24, lineHeight: 30 },
11 display: { fontSize: 28, lineHeight: 34 },
12} as const;
13
14/** Shared geometry for dense, horizontally scrolling code surfaces. */
15export const MOBILE_CODE_SURFACE = {
16 rowHeight: 20,
17 gutterWidth: 46,
18 codePadding: 7,
19 textVerticalInset: 2,
20 fontSize: MOBILE_TYPOGRAPHY.caption.fontSize,
21 lineNumberFontSize: MOBILE_TYPOGRAPHY.micro.fontSize,
22} as const;
apps/mobile/src/native/T3ComposerEditor.ios.tsx+9-2
...@@ -6,6 +6,7 @@ import { Image, StyleSheet } from "react-native";...@@ -6,6 +6,7 @@ import { Image, StyleSheet } from "react-native";
66
7import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons";7import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons";
8import { resolveMarkdownFileIcon } from "@t3tools/mobile-markdown-text/links";8import { resolveMarkdownFileIcon } from "@t3tools/mobile-markdown-text/links";
9import { MOBILE_TYPOGRAPHY } from "../lib/typography";
9import { useThemeColor } from "../lib/useThemeColor";10import { useThemeColor } from "../lib/useThemeColor";
10import type { ComposerEditorProps, ComposerEditorSelection } from "./T3ComposerEditor.types";11import type { ComposerEditorProps, ComposerEditorSelection } from "./T3ComposerEditor.types";
1112
...@@ -150,9 +151,15 @@ export function ComposerEditor({...@@ -150,9 +151,15 @@ export function ComposerEditor({
150 ? resolvedTextStyle.fontFamily151 ? resolvedTextStyle.fontFamily
151 : "DMSans_400Regular"152 : "DMSans_400Regular"
152 }153 }
153 fontSize={typeof resolvedTextStyle.fontSize === "number" ? resolvedTextStyle.fontSize : 15}154 fontSize={
155 typeof resolvedTextStyle.fontSize === "number"
156 ? resolvedTextStyle.fontSize
157 : MOBILE_TYPOGRAPHY.composer.fontSize
158 }
154 lineHeight={159 lineHeight={
155 typeof resolvedTextStyle.lineHeight === "number" ? resolvedTextStyle.lineHeight : 22160 typeof resolvedTextStyle.lineHeight === "number"
161 ? resolvedTextStyle.lineHeight
162 : MOBILE_TYPOGRAPHY.composer.lineHeight
156 }163 }
157 contentInsetVertical={contentInsetVertical}164 contentInsetVertical={contentInsetVertical}
158 editable={props.editable ?? true}165 editable={props.editable ?? true}
apps/mobile/src/native/T3ComposerEditor.tsx+2-2
...@@ -2,6 +2,7 @@ import { TextInputWrapper } from "expo-paste-input";...@@ -2,6 +2,7 @@ import { TextInputWrapper } from "expo-paste-input";
2import { useImperativeHandle, useRef } from "react";2import { useImperativeHandle, useRef } from "react";
3import { TextInput, type TextInput as RNTextInput } from "react-native";3import { TextInput, type TextInput as RNTextInput } from "react-native";
44
5import { MOBILE_TYPOGRAPHY } from "../lib/typography";
5import { useThemeColor } from "../lib/useThemeColor";6import { useThemeColor } from "../lib/useThemeColor";
6import { useNativePaste } from "../lib/useNativePaste";7import { useNativePaste } from "../lib/useNativePaste";
7import type { ComposerEditorProps } from "./T3ComposerEditor.types";8import type { ComposerEditorProps } from "./T3ComposerEditor.types";
...@@ -47,8 +48,7 @@ export function ComposerEditor({...@@ -47,8 +48,7 @@ export function ComposerEditor({
47 minHeight: 0,48 minHeight: 0,
48 color: foregroundColor,49 color: foregroundColor,
49 fontFamily: "DMSans_400Regular",50 fontFamily: "DMSans_400Regular",
50 fontSize: 15,51 ...MOBILE_TYPOGRAPHY.composer,
51 lineHeight: 22,
52 paddingVertical: contentInsetVertical,52 paddingVertical: contentInsetVertical,
53 },53 },
54 textStyle,54 textStyle,