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 @@
11included:
22 - ios/T3Code
3 - modules/t3-composer-editor/ios
34 - modules/t3-terminal/ios
45 - modules/t3-review-diff/ios
56
apps/mobile/global.css+21-1
......@@ -192,11 +192,31 @@
192192 }
193193}
194194
195/* ─── Font family ───────────────────────────────────────────────────── */
195/* ─── Typography ────────────────────────────────────────────────────── */
196196@theme {
197197 --font-sans: "DMSans_400Regular";
198198 --font-medium: "DMSans_500Medium";
199199 --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;
200220}
201221
202222/* ─── Custom utilities ──────────────────────────────────────────────── */
apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift+27-4
......@@ -275,8 +275,8 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
275275 fileTint: "#737373"
276276 )
277277 private var fontFamily = "DMSans_400Regular"
278 private var fontSize: CGFloat = 15
279 private var lineHeight: CGFloat = 22
278 private var fontSize: CGFloat = 14
279 private var lineHeight: CGFloat = 20
280280 private var contentInsetVertical: CGFloat = 0
281281 private var shouldAutoFocus = false
282282 private var didAutoFocus = false
......@@ -460,9 +460,19 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
460460 guard !isApplyingControlledValue else {
461461 return
462462 }
463 restoreBaseTypingAttributes()
463464 emitSelection()
464465 }
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
466476 public func textViewDidBeginEditing(_ textView: UITextView) {
467477 onComposerFocus()
468478 }
......@@ -484,6 +494,7 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
484494 let targetSelection = requestedSelection ?? previousSelection
485495 requestedSelection = nil
486496 textView.selectedRange = displayRange(for: targetSelection)
497 restoreBaseTypingAttributes()
487498 isApplyingControlledValue = false
488499 updatePlaceholderVisibility()
489500 emitContentSizeIfNeeded()
......@@ -556,7 +567,12 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
556567 size: image.size,
557568 baselineOffset: baselineOffset
558569 )
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
560576 }
561577
562578 private func renderChip(
......@@ -660,11 +676,18 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
660676 let font = UIFont(name: fontFamily, size: fontSize)
661677 ?? UIFont.systemFont(ofSize: fontSize)
662678 textView.font = font
663 textView.typingAttributes = baseAttributes()
679 restoreBaseTypingAttributes()
664680 placeholderLabel.font = font
665681 setNeedsLayout()
666682 }
667683
684 private func restoreBaseTypingAttributes() {
685 guard textView.markedTextRange == nil else {
686 return
687 }
688 textView.typingAttributes = baseAttributes()
689 }
690
668691 private func applyTheme() {
669692 textView.textColor = UIColor(composerHex: theme.text) ?? .label
670693 placeholderLabel.textColor = UIColor(composerHex: theme.placeholder) ?? .placeholderText
apps/mobile/src/app/+not-found.tsx+2-2
......@@ -21,7 +21,7 @@ export default function NotFoundRoute() {
2121 }}
2222 style={[{ flex: 1 }, screenBgStyle]}
2323 >
24 <Text className="text-[28px] font-t3-bold text-foreground" selectable>
24 <Text className="text-3xl font-t3-bold text-foreground" selectable>
2525 Route not found
2626 </Text>
2727 <Link href="/" asChild>
......@@ -35,7 +35,7 @@ export default function NotFoundRoute() {
3535 primaryBgStyle,
3636 ]}
3737 >
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>
3939 </Pressable>
4040 </Link>
4141 </ScrollView>
apps/mobile/src/app/connections/index.tsx+1-1
......@@ -85,7 +85,7 @@ export default function ConnectionsRouteScreen() {
8585 type="monochrome"
8686 />
8787 </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">
8989 No environments connected yet.{"\n"}Tap{" "}
9090 <Text className="font-t3-bold text-foreground">+</Text> to add one.
9191 </Text>
apps/mobile/src/app/connections/new.tsx+5-5
......@@ -171,7 +171,7 @@ export default function ConnectionsNewRouteScreen() {
171171 className="items-center gap-3 rounded-[24px] bg-card px-5 py-8"
172172 style={{ borderCurve: "continuous" }}
173173 >
174 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">
174 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
175175 Camera permission is required to scan a QR code.
176176 </Text>
177177 <ConnectionSheetButton
......@@ -189,7 +189,7 @@ export default function ConnectionsNewRouteScreen() {
189189 <View collapsable={false} className="gap-4 rounded-[24px] bg-card p-4">
190190 <View collapsable={false} className="gap-1.5">
191191 <Text
192 className="text-[11px] font-t3-bold uppercase text-foreground-muted"
192 className="text-2xs font-t3-bold uppercase text-foreground-muted"
193193 style={{ letterSpacing: 0.8 }}
194194 >
195195 Host
......@@ -202,13 +202,13 @@ export default function ConnectionsNewRouteScreen() {
202202 placeholderTextColor={placeholderColor}
203203 value={hostInput}
204204 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"
206206 />
207207 </View>
208208
209209 <View collapsable={false} className="gap-1.5">
210210 <Text
211 className="text-[11px] font-t3-bold uppercase text-foreground-muted"
211 className="text-2xs font-t3-bold uppercase text-foreground-muted"
212212 style={{ letterSpacing: 0.8 }}
213213 >
214214 Pairing code
......@@ -220,7 +220,7 @@ export default function ConnectionsNewRouteScreen() {
220220 placeholderTextColor={placeholderColor}
221221 value={codeInput}
222222 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"
224224 />
225225 </View>
226226
apps/mobile/src/app/new/index.tsx+5-7
......@@ -129,10 +129,10 @@ export default function NewTaskRoute() {
129129 {items.length === 0 ? (
130130 <View collapsable={false} className="items-center gap-3 rounded-[24px] bg-card px-6 py-8">
131131 {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">
133133 {projectEmptyState.title}
134134 </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">
136136 {projectEmptyState.detail}
137137 </Text>
138138 {!catalogState.hasReadyEnvironment ? (
......@@ -140,7 +140,7 @@ export default function NewTaskRoute() {
140140 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
141141 onPress={() => router.push("/connections/new")}
142142 >
143 <Text className="text-[13px] font-t3-bold text-primary-foreground">
143 <Text className="text-sm font-t3-bold text-primary-foreground">
144144 Add environment
145145 </Text>
146146 </Pressable>
......@@ -149,7 +149,7 @@ export default function NewTaskRoute() {
149149 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
150150 onPress={() => router.push("/new/add-project")}
151151 >
152 <Text className="text-[13px] font-t3-bold text-primary-foreground">
152 <Text className="text-sm font-t3-bold text-primary-foreground">
153153 Add new project
154154 </Text>
155155 </Pressable>
......@@ -197,9 +197,7 @@ export default function NewTaskRoute() {
197197 />
198198 </View>
199199 <View className="flex-1">
200 <Text className="text-[16px] leading-[21px] font-t3-bold">
201 {item.title}
202 </Text>
200 <Text className="text-base leading-[21px] font-t3-bold">{item.title}</Text>
203201 </View>
204202 <SymbolView
205203 name="chevron.right"
apps/mobile/src/app/settings/environments.tsx+11-11
......@@ -111,7 +111,7 @@ export default function SettingsEnvironmentsRouteScreen() {
111111 type="monochrome"
112112 />
113113 </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">
115115 No environments connected yet.{"\n"}Tap{" "}
116116 <Text className="font-t3-bold text-foreground">+</Text> to add one.
117117 </Text>
......@@ -160,7 +160,7 @@ function ConfiguredCloudEnvironmentRows(props: {
160160 return (
161161 <View collapsable={false} className="mt-5 gap-3">
162162 <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>
164164 <Pressable
165165 accessibilityRole="button"
166166 disabled={controller.relayDiscovery.isRefreshing}
......@@ -204,16 +204,16 @@ function ConfiguredCloudEnvironmentRows(props: {
204204 ) : controller.relayDiscovery.isRefreshing ? (
205205 <View collapsable={false} className="items-center gap-3 rounded-[24px] bg-card p-6">
206206 <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">
208208 Loading linked cloud environments.
209209 </Text>
210210 </View>
211211 ) : controller.relayDiscovery.error ? (
212212 <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">
214214 Could not load T3 Cloud environments
215215 </Text>
216 <Text className="text-[13px] leading-[18px] text-foreground-muted">
216 <Text className="text-sm leading-[18px] text-foreground-muted">
217217 {controller.relayDiscovery.error}
218218 </Text>
219219 {controller.relayDiscovery.errorTraceId ? (
......@@ -222,7 +222,7 @@ function ConfiguredCloudEnvironmentRows(props: {
222222 </View>
223223 ) : (
224224 <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">
226226 No additional linked cloud environments.
227227 </Text>
228228 </View>
......@@ -361,7 +361,7 @@ function CloudEnvironmentRowShell(props: {
361361 <View className="min-w-0 flex-row items-center gap-2">
362362 <ConnectionStatusDot state={props.connectionState} pulse={shouldPulse} size={7} />
363363 <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"
365365 numberOfLines={1}
366366 >
367367 {props.label}
......@@ -370,7 +370,7 @@ function CloudEnvironmentRowShell(props: {
370370 {props.connectionError ? (
371371 <Text
372372 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)}
374374 onTextLayout={onMeasuredErrorTextLayout}
375375 style={{ opacity: 0, zIndex: -1 }}
376376 >
......@@ -384,7 +384,7 @@ function CloudEnvironmentRowShell(props: {
384384 className="min-w-0 flex-row items-start gap-1"
385385 >
386386 <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)}
388388 numberOfLines={isErrorExpanded ? undefined : 1}
389389 >
390390 {statusText}
......@@ -394,7 +394,7 @@ function CloudEnvironmentRowShell(props: {
394394 <Text
395395 accessibilityHint="Copies the trace ID"
396396 accessibilityRole="button"
397 className={cn("text-[12px] leading-[16px] underline", statusClassName)}
397 className={cn("text-xs leading-[16px] underline", statusClassName)}
398398 onLongPress={(event) => {
399399 event.stopPropagation();
400400 copyTextWithHaptic(errorTraceId);
......@@ -446,7 +446,7 @@ function CopyTraceIdButton(props: { readonly traceId: string }) {
446446 className="self-start flex-row items-center gap-1.5 rounded-full bg-subtle px-3 py-2 active:opacity-70"
447447 >
448448 <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>
450450 </Pressable>
451451 );
452452}
apps/mobile/src/app/settings/index.tsx+7-7
......@@ -346,7 +346,7 @@ function ConfiguredSettingsRouteScreen() {
346346 onPress={openAccount}
347347 />
348348 </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">
350350 T3 Code works locally without signing in. Cloud features are optional.
351351 </Text>
352352 </View>
......@@ -389,7 +389,7 @@ type SymbolName = ComponentProps<typeof SymbolView>["name"];
389389function SettingsSection(props: { readonly title: string; readonly children: ReactNode }) {
390390 return (
391391 <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>
393393 <View
394394 className="overflow-hidden rounded-[28px] bg-card"
395395 style={{ borderCurve: "continuous" }}
......@@ -413,8 +413,8 @@ function AppSettingsSection() {
413413 type="monochrome"
414414 weight="regular"
415415 />
416 <Text className="flex-1 text-[17px] text-foreground">Version</Text>
417 <Text className="text-[17px] text-foreground-muted">Alpha</Text>
416 <Text className="flex-1 text-lg text-foreground">Version</Text>
417 <Text className="text-lg text-foreground-muted">Alpha</Text>
418418 </View>
419419 </SettingsSection>
420420 );
......@@ -444,13 +444,13 @@ function SettingsRow(props: {
444444 style={{ opacity: props.disabled ? 0.45 : 1 }}
445445 >
446446 <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}>
448448 {props.label}
449449 </Text>
450450 <View className="min-w-0 flex-1 items-end">
451451 {props.value ? (
452452 <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"
454454 ellipsizeMode="middle"
455455 numberOfLines={1}
456456 >
......@@ -502,7 +502,7 @@ function SettingsSwitchRow(props: {
502502 style={{ opacity: props.disabled ? 0.45 : 1 }}
503503 >
504504 <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>
506506 <Switch
507507 disabled={props.disabled}
508508 ios_backgroundColor={track}
apps/mobile/src/components/AppText.tsx+1-1
......@@ -40,7 +40,7 @@ export function AppTextInput({
4040 <RNTextInput
4141 ref={ref}
4242 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",
4444 className,
4545 )}
4646 placeholderTextColor={placeholderTextColor ?? placeholderColor}
apps/mobile/src/components/BrandMark.tsx+3-6
......@@ -22,15 +22,12 @@ export function BrandMark(props: { readonly compact?: boolean; readonly stageLab
2222 />
2323 <View className="gap-1">
2424 <View className="flex-row items-center gap-2">
25 <Text
26 className="text-[17px] font-t3-bold text-foreground"
27 style={{ letterSpacing: -0.4 }}
28 >
25 <Text className="text-lg font-t3-bold text-foreground" style={{ letterSpacing: -0.4 }}>
2926 T3 Code
3027 </Text>
3128 <View className="rounded-full bg-subtle px-2 py-1">
3229 <Text
33 className="text-[10px] font-t3-bold uppercase text-foreground-muted"
30 className="text-3xs font-t3-bold uppercase text-foreground-muted"
3431 style={{ letterSpacing: 1.1 }}
3532 >
3633 {stageLabel}
......@@ -38,7 +35,7 @@ export function BrandMark(props: { readonly compact?: boolean; readonly stageLab
3835 </View>
3936 </View>
4037 {!compact ? (
41 <Text className="text-[12px] font-medium text-foreground-muted">
38 <Text className="text-xs font-medium text-foreground-muted">
4239 Mobile control surface for your live coding environments
4340 </Text>
4441 ) : null}
apps/mobile/src/components/ComposerToolbarTrigger.tsx+1-1
......@@ -223,7 +223,7 @@ export function ComposerToolbarButton(props: {
223223 {props.label ? (
224224 <Text
225225 className={cn(
226 "shrink text-center text-[13px] font-t3-bold",
226 "shrink text-center text-sm font-t3-bold",
227227 variant === "primary"
228228 ? props.disabled
229229 ? "text-foreground-muted"
apps/mobile/src/components/ControlPill.tsx+1-1
......@@ -48,7 +48,7 @@ export function ControlPill(props: {
4848 : "bg-subtle",
4949 );
5050 const labelClassName = cn(
51 "text-center text-[12px] font-t3-bold",
51 "text-center text-xs font-t3-bold",
5252 variant === "primary"
5353 ? props.disabled
5454 ? "text-foreground-muted"
apps/mobile/src/components/EmptyState.tsx+1-3
......@@ -19,9 +19,7 @@ export function EmptyState(props: {
1919 className="mt-4 self-start rounded-full bg-primary px-4 py-2.5 active:opacity-70"
2020 onPress={props.onAction}
2121 >
22 <Text className="text-[13px] font-t3-bold text-primary-foreground">
23 {props.actionLabel}
24 </Text>
22 <Text className="text-sm font-t3-bold text-primary-foreground">{props.actionLabel}</Text>
2523 </Pressable>
2624 ) : null}
2725 </View>
apps/mobile/src/components/ErrorBanner.tsx+1-1
......@@ -4,7 +4,7 @@ import { AppText as Text } from "./AppText";
44export function ErrorBanner(props: { readonly message: string }) {
55 return (
66 <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">
88 {props.message}
99 </Text>
1010 </View>
apps/mobile/src/components/StatusPill.tsx+1-1
......@@ -26,7 +26,7 @@ export function StatusPill(
2626 <Text
2727 className={cn(
2828 "font-t3-bold",
29 size === "compact" ? "text-[11px]" : "text-xs",
29 size === "compact" ? "text-2xs" : "text-xs",
3030 props.textClassName,
3131 )}
3232 >
apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx+11-9
......@@ -147,14 +147,14 @@ function ProjectGroupLabel(props: {
147147 workspaceRoot={props.project.workspaceRoot}
148148 />
149149 <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"
151151 numberOfLines={1}
152152 style={{ letterSpacing: 0.5 }}
153153 >
154154 {props.project.title}
155155 </Text>
156156 {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}>
158158 {props.environmentLabel}
159159 </Text>
160160 ) : null}
......@@ -265,13 +265,13 @@ function ArchivedThreadRow(props: {
265265 <View className="min-w-0 flex-1 gap-1">
266266 <View className="flex-row items-center gap-2">
267267 <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"
269269 numberOfLines={1}
270270 >
271271 {props.thread.title}
272272 </Text>
273273 <Text
274 className="text-[12px] text-foreground-tertiary"
274 className="text-xs text-foreground-tertiary"
275275 style={{ fontVariant: ["tabular-nums"] }}
276276 >
277277 {timestamp}
......@@ -286,7 +286,7 @@ function ArchivedThreadRow(props: {
286286 type="monochrome"
287287 />
288288 <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"
290290 numberOfLines={1}
291291 style={{ fontFamily: "monospace" }}
292292 >
......@@ -314,10 +314,12 @@ function ArchivedThreadRow(props: {
314314function ArchiveError(props: { readonly message: string; readonly onRetry: () => void }) {
315315 return (
316316 <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>
318 <Text className="mt-1 text-[13px] leading-[18px] text-foreground-muted">{props.message}</Text>
317 <Text className="text-base font-t3-bold text-danger-foreground">
318 Could not load every archive
319 </Text>
320 <Text className="mt-1 text-sm leading-[18px] text-foreground-muted">{props.message}</Text>
319321 <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>
321323 </Pressable>
322324 </View>
323325 );
......@@ -386,7 +388,7 @@ export function ArchivedThreadsScreen(props: {
386388 {isInitialLoad ? (
387389 <View className="items-center py-16">
388390 <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>
390392 </View>
391393 ) : props.groups.length === 0 ? (
392394 <EmptyState
apps/mobile/src/features/cloud/CloudWaitlistEnrollment.tsx+8-12
......@@ -2,6 +2,7 @@ import { useWaitlist } from "@clerk/expo";
22import { ActivityIndicator, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
33import { useState } from "react";
44
5import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
56import { useThemeColor } from "../../lib/useThemeColor";
67
78export function CloudWaitlistEnrollment(props: { readonly onSignIn: () => void }) {
......@@ -141,12 +142,11 @@ function useCloudWaitlistColors() {
141142const styles = StyleSheet.create({
142143 body: {
143144 fontFamily: "DMSans_400Regular",
144 fontSize: 15,
145 lineHeight: 21,
145 ...MOBILE_TYPOGRAPHY.body,
146146 },
147147 buttonText: {
148148 fontFamily: "DMSans_700Bold",
149 fontSize: 16,
149 fontSize: MOBILE_TYPOGRAPHY.body.fontSize,
150150 },
151151 content: {
152152 gap: 18,
......@@ -156,8 +156,7 @@ const styles = StyleSheet.create({
156156 },
157157 error: {
158158 fontFamily: "DMSans_400Regular",
159 fontSize: 13,
160 lineHeight: 18,
159 ...MOBILE_TYPOGRAPHY.footnote,
161160 },
162161 field: {
163162 gap: 8,
......@@ -167,15 +166,14 @@ const styles = StyleSheet.create({
167166 borderRadius: 16,
168167 borderWidth: 1,
169168 fontFamily: "DMSans_400Regular",
170 fontSize: 17,
169 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
171170 minHeight: 54,
172171 paddingHorizontal: 16,
173172 paddingVertical: 14,
174173 },
175174 label: {
176175 fontFamily: "DMSans_700Bold",
177 fontSize: 13,
178 lineHeight: 18,
176 ...MOBILE_TYPOGRAPHY.footnote,
179177 },
180178 primaryButton: {
181179 alignItems: "center",
......@@ -196,13 +194,11 @@ const styles = StyleSheet.create({
196194 },
197195 signInText: {
198196 fontFamily: "DMSans_700Bold",
199 fontSize: 15,
200 lineHeight: 21,
197 ...MOBILE_TYPOGRAPHY.body,
201198 },
202199 title: {
203200 fontFamily: "DMSans_700Bold",
204 fontSize: 20,
205 lineHeight: 26,
201 ...MOBILE_TYPOGRAPHY.title,
206202 textAlign: "center",
207203 },
208204});
apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx+9-12
......@@ -76,19 +76,16 @@ export function ConnectionEnvironmentRow(props: {
7676 />
7777
7878 <View className="flex-1 gap-0.5">
79 <Text
80 className="text-[16px] font-t3-bold leading-[21px] text-foreground"
81 numberOfLines={1}
82 >
79 <Text className="text-base font-t3-bold leading-[21px] text-foreground" numberOfLines={1}>
8380 {props.environment.environmentLabel}
8481 </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}>
8683 {props.environment.displayUrl}
8784 </Text>
8885 {statusLabel ? (
8986 <Text
9087 className={cn(
91 "text-[12px] leading-[16px]",
88 "text-xs leading-[16px]",
9289 hasConnectionFailure ? "text-rose-500 dark:text-rose-400" : "text-foreground-muted",
9390 )}
9491 numberOfLines={props.expanded ? undefined : 1}
......@@ -137,14 +134,14 @@ export function ConnectionEnvironmentRow(props: {
137134 className="gap-3 px-4 pb-4"
138135 >
139136 {props.environment.isRelayManaged ? (
140 <Text className="text-[13px] leading-[18px] text-foreground-muted">
137 <Text className="text-sm leading-[18px] text-foreground-muted">
141138 Managed by T3 Cloud. Tunnel details update automatically.
142139 </Text>
143140 ) : (
144141 <>
145142 <View className="gap-1.5">
146143 <Text
147 className="text-[11px] font-t3-bold uppercase text-foreground-muted"
144 className="text-2xs font-t3-bold uppercase text-foreground-muted"
148145 style={{ letterSpacing: 0.8 }}
149146 >
150147 Label
......@@ -156,13 +153,13 @@ export function ConnectionEnvironmentRow(props: {
156153 placeholderTextColor={placeholderColor}
157154 value={label}
158155 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"
160157 />
161158 </View>
162159
163160 <View className="gap-1.5">
164161 <Text
165 className="text-[11px] font-t3-bold uppercase text-foreground-muted"
162 className="text-2xs font-t3-bold uppercase text-foreground-muted"
166163 style={{ letterSpacing: 0.8 }}
167164 >
168165 URL
......@@ -175,7 +172,7 @@ export function ConnectionEnvironmentRow(props: {
175172 placeholderTextColor={placeholderColor}
176173 value={url}
177174 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"
179176 />
180177 </View>
181178 </>
......@@ -189,7 +186,7 @@ export function ConnectionEnvironmentRow(props: {
189186 >
190187 <SymbolView name="checkmark" size={13} tintColor={primaryFg} type="monochrome" />
191188 <Text
192 className="text-[12px] font-t3-bold uppercase text-primary-foreground"
189 className="text-xs font-t3-bold uppercase text-primary-foreground"
193190 style={{ letterSpacing: 0.8 }}
194191 >
195192 Save
apps/mobile/src/features/connection/ConnectionSheetButton.tsx+1-1
......@@ -104,7 +104,7 @@ export function ConnectionSheetButton(props: {
104104 type="monochrome"
105105 />
106106 <Text
107 className="text-[12px] font-t3-bold uppercase"
107 className="text-xs font-t3-bold uppercase"
108108 style={{ color: colors.textColor, letterSpacing: 0.8 }}
109109 >
110110 {props.label}
apps/mobile/src/features/connection/EnvironmentConnectionNotice.tsx+3-3
......@@ -73,10 +73,10 @@ export function EnvironmentConnectionNotice(props: {
7373 />
7474 )}
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">
7777 {noticeTitle(props.connection.phase, props.environmentLabel)}
7878 </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">
8080 {noticeDetail(props.connection.phase, props.resourceName, props.connection.error)}
8181 {props.connection.traceId ? (
8282 <>
......@@ -99,7 +99,7 @@ export function EnvironmentConnectionNotice(props: {
9999 className="mt-1 rounded-full bg-subtle px-4 py-2.5 active:opacity-70"
100100 onPress={props.onRetry}
101101 >
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>
103103 </Pressable>
104104 ) : null}
105105 </View>
apps/mobile/src/features/files/FileMarkdownPreview.tsx+3-4
......@@ -7,6 +7,7 @@ import {
77} from "react-native-nitro-markdown";
88import { Linking, ScrollView, Text as NativeText, View } from "react-native";
99
10import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
1011import { useThemeColor } from "../../lib/useThemeColor";
1112import {
1213 hasNativeSelectableMarkdownText,
......@@ -72,8 +73,7 @@ function useMarkdownPreviewStyles(): MarkdownPreviewStyles {
7273 text: {
7374 color: body,
7475 fontFamily: "DMSans_400Regular",
75 fontSize: 15,
76 lineHeight: 22,
76 ...MOBILE_TYPOGRAPHY.body,
7777 },
7878 heading: {
7979 color: strong,
......@@ -123,8 +123,7 @@ function useMarkdownPreviewStyles(): MarkdownPreviewStyles {
123123 skillTextColor: codeText,
124124 quoteMarkerColor: blockquoteBorder,
125125 dividerColor: horizontalRule,
126 fontSize: 15,
127 lineHeight: 22,
126 ...MOBILE_TYPOGRAPHY.body,
128127 fontFamily: "DMSans_400Regular",
129128 headingFontFamily: "DMSans_700Bold",
130129 boldFontFamily: "DMSans_700Bold",
apps/mobile/src/features/files/FileTreeBrowser.tsx+6-8
......@@ -64,7 +64,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {
6464 <PierreEntryIcon path={node.path} kind={node.kind} size={17} />
6565 <Text
6666 className={cn(
67 "min-w-0 flex-1 text-[14px] leading-[19px]",
67 "min-w-0 flex-1 text-sm leading-[19px]",
6868 selected ? "font-t3-bold text-foreground" : "font-t3-medium text-foreground-secondary",
6969 )}
7070 numberOfLines={1}
......@@ -72,7 +72,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {
7272 {node.name}
7373 </Text>
7474 {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">
7676 {node.children.length}
7777 </Text>
7878 ) : null}
......@@ -142,10 +142,8 @@ export function FileTreeBrowser(props: {
142142 <View className="flex-1 bg-sheet">
143143 {props.error && props.entries.length === 0 ? (
144144 <View className="px-4 py-5">
145 <Text className="text-[13px] font-t3-bold text-foreground">Files unavailable</Text>
146 <Text className="mt-1 text-[12px] leading-[18px] text-foreground-muted">
147 {props.error}
148 </Text>
145 <Text className="text-sm font-t3-bold text-foreground">Files unavailable</Text>
146 <Text className="mt-1 text-xs leading-[18px] text-foreground-muted">{props.error}</Text>
149147 </View>
150148 ) : (
151149 <FlatList
......@@ -174,8 +172,8 @@ export function FileTreeBrowser(props: {
174172 <ActivityIndicator size="small" />
175173 ) : (
176174 <>
177 <Text className="text-[13px] font-t3-bold text-foreground">No files found</Text>
178 <Text className="mt-1 text-[12px] leading-[18px] text-foreground-muted">
175 <Text className="text-sm font-t3-bold text-foreground">No files found</Text>
176 <Text className="mt-1 text-xs leading-[18px] text-foreground-muted">
179177 {props.searchQuery.trim().length > 0
180178 ? "Try a different search."
181179 : "The workspace file index is empty."}
apps/mobile/src/features/files/SourceFileSurface.tsx+15-9
......@@ -18,6 +18,7 @@ import {
1818} from "../review/reviewDiffRendering";
1919import type { ReviewHighlightedToken } from "../review/shikiReviewHighlighter";
2020import { cn } from "../../lib/cn";
21import { MOBILE_CODE_SURFACE } from "../../lib/typography";
2122import {
2223 buildNativeSourceRows,
2324 buildNativeSourceTokens,
......@@ -28,8 +29,8 @@ import {
2829} from "./nativeSourceFileAdapter";
2930import { sourceHighlightAtom } from "./sourceHighlightingState";
3031
31const SOURCE_LINE_HEIGHT = 24;
32const SOURCE_LINE_NUMBER_WIDTH = 58;
32const SOURCE_LINE_HEIGHT = MOBILE_CODE_SURFACE.rowHeight;
33const SOURCE_LINE_NUMBER_WIDTH = MOBILE_CODE_SURFACE.gutterWidth;
3334const NATIVE_SOURCE_STYLE_JSON = JSON.stringify(NATIVE_SOURCE_STYLE);
3435
3536interface SourceFileSurfaceProps {
......@@ -56,10 +57,12 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {
5657 style={{ minHeight: SOURCE_LINE_HEIGHT }}
5758 >
5859 <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"
6061 style={{
6162 width: SOURCE_LINE_NUMBER_WIDTH,
6263 fontFamily: REVIEW_MONO_FONT_FAMILY,
64 fontSize: MOBILE_CODE_SURFACE.lineNumberFontSize,
65 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
6366 }}
6467 >
6568 {props.index + 1}
......@@ -67,8 +70,13 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {
6770 <NativeText
6871 selectable
6972 numberOfLines={1}
70 className="text-[13px] font-medium leading-[24px] text-foreground"
71 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY, minWidth: 320 }}
73 className="font-normal text-foreground"
74 style={{
75 fontFamily: REVIEW_MONO_FONT_FAMILY,
76 fontSize: MOBILE_CODE_SURFACE.fontSize,
77 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
78 minWidth: 320,
79 }}
7280 >
7381 {props.tokens && props.tokens.length > 0
7482 ? (() => {
......@@ -80,7 +88,7 @@ const HighlightedSourceLine = memo(function HighlightedSourceLine(props: {
8088 const fontWeight =
8189 token.fontStyle !== null && (token.fontStyle & 2) === 2
8290 ? ("700" as const)
83 : ("500" as const);
91 : ("400" as const);
8492 const fontStyle =
8593 token.fontStyle !== null && (token.fontStyle & 1) === 1
8694 ? ("italic" as const)
......@@ -142,9 +150,7 @@ function SourceHighlightStatusView(props: { readonly status: SourceHighlightStat
142150 if (props.status === "error") {
143151 return (
144152 <View className="border-b border-border bg-card px-4 py-2">
145 <Text className="text-[11px] font-t3-medium uppercase text-foreground-muted">
146 Plain text
147 </Text>
153 <Text className="text-2xs font-t3-medium uppercase text-foreground-muted">Plain text</Text>
148154 </View>
149155 );
150156 }
apps/mobile/src/features/files/ThreadFilesRouteScreen.tsx+8-7
......@@ -24,6 +24,7 @@ import { EmptyState } from "../../components/EmptyState";
2424import { LoadingScreen } from "../../components/LoadingScreen";
2525import { cn } from "../../lib/cn";
2626import { buildThreadFilesNavigation } from "../../lib/routes";
27import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
2728import { useThemeColor } from "../../lib/useThemeColor";
2829import { useThreadSelection } from "../../state/use-thread-selection";
2930import { useSelectedThreadWorktree } from "../../state/use-selected-thread-worktree";
......@@ -100,7 +101,7 @@ function ModeButton(props: {
100101 <SymbolView name={props.icon} size={13} tintColor={iconColor} type="monochrome" />
101102 <Text
102103 className={cn(
103 "text-[12px] font-t3-bold",
104 "text-xs font-t3-bold",
104105 props.active ? "text-primary-foreground" : "text-foreground-muted",
105106 )}
106107 >
......@@ -187,7 +188,7 @@ function FileBreadcrumbs(props: { readonly projectName: string; readonly relativ
187188 ) : null}
188189 <Text
189190 className={cn(
190 "max-w-[180px] px-1 text-[12px]",
191 "max-w-[180px] px-1 text-xs",
191192 crumb.kind === "file"
192193 ? "font-t3-bold text-foreground"
193194 : "font-t3-medium text-foreground-muted",
......@@ -308,7 +309,7 @@ function FileContent(props: {
308309 return (
309310 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">
310311 <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>
312313 </View>
313314 );
314315 }
......@@ -317,10 +318,10 @@ function FileContent(props: {
317318 <View className="flex-1 bg-card">
318319 {props.truncated ? (
319320 <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">
321322 Partial file
322323 </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">
324325 Preview limited to the first 1 MB of a truncated file.
325326 </Text>
326327 </View>
......@@ -389,7 +390,7 @@ function FilesHeaderTitle(props: { readonly projectName: string }) {
389390 style={{
390391 color: foregroundColor,
391392 fontFamily: "DMSans_700Bold",
392 fontSize: 18,
393 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
393394 fontWeight: "900",
394395 letterSpacing: -0.4,
395396 }}
......@@ -401,7 +402,7 @@ function FilesHeaderTitle(props: { readonly projectName: string }) {
401402 style={{
402403 color: secondaryForegroundColor,
403404 fontFamily: "DMSans_500Medium",
404 fontSize: 12,
405 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
405406 fontWeight: "500",
406407 letterSpacing: 0.2,
407408 }}
apps/mobile/src/features/files/WorkspaceFileImagePreview.tsx+2-2
......@@ -81,7 +81,7 @@ function CachedWorkspaceFileImagePreview(props: {
8181 return (
8282 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">
8383 <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>
8585 </View>
8686 );
8787 }
......@@ -102,7 +102,7 @@ export function WorkspaceFileImagePreview(props: {
102102 return (
103103 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">
104104 <ActivityIndicator />
105 <Text className="text-center text-[13px] text-foreground-muted">
105 <Text className="text-center text-sm text-foreground-muted">
106106 Preparing image preview...
107107 </Text>
108108 </View>
apps/mobile/src/features/files/WorkspaceFileWebPreview.tsx+3-5
......@@ -13,7 +13,7 @@ export function WorkspaceFileWebPreview(props: { readonly uri: string | null })
1313 return (
1414 <View className="flex-1 items-center justify-center gap-3 bg-card px-6">
1515 <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>
1717 </View>
1818 );
1919 }
......@@ -23,10 +23,8 @@ export function WorkspaceFileWebPreview(props: { readonly uri: string | null })
2323 {loadProgress > 0 && loadProgress < 1 ? <LoadingStrip progress={loadProgress} /> : null}
2424 {loadError ? (
2525 <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>
27 <Text className="mt-0.5 text-[12px] leading-[17px] text-foreground-muted">
28 {loadError}
29 </Text>
26 <Text className="text-xs font-t3-bold text-foreground">Preview failed</Text>
27 <Text className="mt-0.5 text-xs leading-[17px] text-foreground-muted">{loadError}</Text>
3028 </View>
3129 ) : null}
3230 <WebView
apps/mobile/src/features/files/nativeSourceFileAdapter.test.ts+20
......@@ -3,10 +3,30 @@ import { describe, expect, it } from "vite-plus/test";
33import {
44 buildNativeSourceRows,
55 buildNativeSourceTokens,
6 NATIVE_SOURCE_ROW_HEIGHT,
7 NATIVE_SOURCE_STYLE,
68 nativeSourceRowId,
79} from "./nativeSourceFileAdapter";
10import {
11 NATIVE_REVIEW_DIFF_ROW_HEIGHT,
12 NATIVE_REVIEW_DIFF_STYLE,
13} from "../review/nativeReviewDiffAdapter";
814
915describe("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
1030 it("maps plain source lines onto context rows with stable line numbers", () => {
1131 expect(buildNativeSourceRows(["const value = 1;", "\treturn value;"])).toEqual([
1232 {
apps/mobile/src/features/files/nativeSourceFileAdapter.ts+10-8
......@@ -3,22 +3,24 @@ import type {
33 NativeReviewDiffStyle,
44 NativeReviewDiffToken,
55} from "../diffs/nativeReviewDiffSurface";
6import { MOBILE_CODE_SURFACE, MOBILE_TYPOGRAPHY } from "../../lib/typography";
67import type { SourceHighlightTokens } from "./sourceHighlightingState";
78
8export const NATIVE_SOURCE_ROW_HEIGHT = 24;
9export const NATIVE_SOURCE_ROW_HEIGHT = MOBILE_CODE_SURFACE.rowHeight;
910export const NATIVE_SOURCE_CONTENT_WIDTH = 32_000;
1011
1112export const NATIVE_SOURCE_STYLE: NativeReviewDiffStyle = {
1213 rowHeight: NATIVE_SOURCE_ROW_HEIGHT,
1314 contentWidth: NATIVE_SOURCE_CONTENT_WIDTH,
1415 changeBarWidth: 0,
15 gutterWidth: 58,
16 codePadding: 8,
17 codeFontSize: 13,
18 codeFontWeight: "medium",
19 lineNumberFontSize: 11,
20 lineNumberFontWeight: "medium",
21 emptyStateFontSize: 12,
16 gutterWidth: MOBILE_CODE_SURFACE.gutterWidth,
17 codePadding: MOBILE_CODE_SURFACE.codePadding,
18 textVerticalInset: MOBILE_CODE_SURFACE.textVerticalInset,
19 codeFontSize: MOBILE_CODE_SURFACE.fontSize,
20 codeFontWeight: "regular",
21 lineNumberFontSize: MOBILE_CODE_SURFACE.lineNumberFontSize,
22 lineNumberFontWeight: "regular",
23 emptyStateFontSize: MOBILE_TYPOGRAPHY.label.fontSize,
2224 emptyStateFontWeight: "medium",
2325};
2426
apps/mobile/src/features/home/HomeHeader.tsx+3-2
......@@ -12,6 +12,7 @@ import { Stack } from "expo-router";
1212import { Text as RNText, View } from "react-native";
1313
1414import { useThemeColor } from "../../lib/useThemeColor";
15import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
1516import type { HomeProjectSortOrder } from "./homeThreadList";
1617
1718export interface HomeHeaderEnvironment {
......@@ -118,7 +119,7 @@ export function HomeHeader(props: {
118119 <RNText
119120 style={{
120121 fontFamily: "DMSans_700Bold",
121 fontSize: 17,
122 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
122123 color: iconColor,
123124 letterSpacing: -0.4,
124125 }}
......@@ -136,7 +137,7 @@ export function HomeHeader(props: {
136137 <RNText
137138 style={{
138139 fontFamily: "DMSans_700Bold",
139 fontSize: 10,
140 fontSize: MOBILE_TYPOGRAPHY.micro.fontSize,
140141 color: mutedColor,
141142 letterSpacing: 1.1,
142143 textTransform: "uppercase",
apps/mobile/src/features/home/HomeScreen.tsx+7-7
......@@ -186,7 +186,7 @@ function ProjectGroupLabel(props: {
186186 workspaceRoot={props.project.workspaceRoot}
187187 />
188188 <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"
190190 style={{ letterSpacing: 0.5 }}
191191 numberOfLines={1}
192192 >
......@@ -196,7 +196,7 @@ function ProjectGroupLabel(props: {
196196 {hiddenCount > 0 ? (
197197 <Pressable onPress={props.onToggleExpand} hitSlop={8}>
198198 <Text
199 className="text-[12px] font-t3-medium text-foreground-muted"
199 className="text-xs font-t3-medium text-foreground-muted"
200200 style={{ letterSpacing: 0.4 }}
201201 >
202202 {props.isExpanded ? "Show less" : `${hiddenCount} more`}
......@@ -335,7 +335,7 @@ function ThreadRow(props: {
335335 <View style={{ flex: 1, gap: 3 }}>
336336 <View className="flex-row items-center justify-between gap-2">
337337 <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"
339339 numberOfLines={1}
340340 >
341341 {props.thread.title}
......@@ -345,12 +345,12 @@ function ThreadRow(props: {
345345 className={tone.pillClassName}
346346 style={{ borderRadius: 99, paddingHorizontal: 6, paddingVertical: 2 }}
347347 >
348 <Text className={`text-[10px] font-t3-bold ${tone.textClassName}`}>
348 <Text className={`text-3xs font-t3-bold ${tone.textClassName}`}>
349349 {tone.label}
350350 </Text>
351351 </View>
352352 <Text
353 className="text-[12px] text-foreground-tertiary"
353 className="text-xs text-foreground-tertiary"
354354 style={{ fontVariant: ["tabular-nums"] }}
355355 >
356356 {timestamp}
......@@ -367,7 +367,7 @@ function ThreadRow(props: {
367367 type="monochrome"
368368 />
369369 <Text
370 className="text-[11px] text-foreground-tertiary"
370 className="text-2xs text-foreground-tertiary"
371371 numberOfLines={1}
372372 style={{ fontFamily: "monospace" }}
373373 >
......@@ -429,7 +429,7 @@ function StaleCatalogStatusPill(props: {
429429 weight="semibold"
430430 />
431431 )}
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}>
433433 {label}
434434 </Text>
435435 </Pressable>
apps/mobile/src/features/home/thread-swipe-actions.tsx+1-1
......@@ -167,7 +167,7 @@ function SwipeActionButton(props: {
167167 </Animated.View>
168168 </View>
169169 <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>
171171 </Animated.View>
172172 </Pressable>
173173 </Animated.View>
apps/mobile/src/features/projects/AddProjectScreen.tsx+11-11
......@@ -100,7 +100,7 @@ function sourceFromParam(value: string | string[] | undefined): AddProjectRemote
100100function SectionTitle(props: { readonly children: string }) {
101101 return (
102102 <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"
104104 style={{ letterSpacing: 0.7 }}
105105 >
106106 {props.children}
......@@ -168,9 +168,9 @@ function ListRow(props: {
168168 {props.icon}
169169 </View>
170170 <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>
172172 {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}>
174174 {props.subtitle}
175175 </Text>
176176 ) : null}
......@@ -202,7 +202,7 @@ function PrimaryActionButton(props: {
202202 {props.loading ? (
203203 <ActivityIndicator color={String(primaryForeground)} />
204204 ) : (
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>
206206 )}
207207 </Pressable>
208208 );
......@@ -215,7 +215,7 @@ function ProjectPathInput(props: {
215215}) {
216216 return (
217217 <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]"
219219 value={props.value}
220220 onChangeText={props.onChangeText}
221221 autoCapitalize="none"
......@@ -273,15 +273,15 @@ function EmptyEnvironmentState() {
273273
274274 return (
275275 <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>
277 <Text className="text-center text-[14px] leading-[20px] text-foreground-muted">
276 <Text className="text-center text-lg font-t3-bold">No environments connected</Text>
277 <Text className="text-center text-sm leading-[20px] text-foreground-muted">
278278 Add an environment before adding a project.
279279 </Text>
280280 <Pressable
281281 onPress={() => router.replace("/connections/new")}
282282 className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
283283 >
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>
285285 </Pressable>
286286 </View>
287287 );
......@@ -565,7 +565,7 @@ export function AddProjectRepositoryScreen() {
565565 <AddProjectShell>
566566 {error ? <ErrorBanner message={error} /> : null}
567567 <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]"
569569 value={repositoryInput}
570570 onChangeText={setRepositoryInput}
571571 autoCapitalize="none"
......@@ -806,8 +806,8 @@ export function AddProjectDestinationScreen() {
806806 {error ? <ErrorBanner message={error} /> : null}
807807 {repositoryTitle ? (
808808 <View className="rounded-[24px] bg-card px-4 py-3">
809 <Text className="text-[14px] font-t3-bold">{repositoryTitle}</Text>
810 <Text className="mt-0.5 text-[12px] text-foreground-muted" numberOfLines={2}>
809 <Text className="text-base font-t3-bold">{repositoryTitle}</Text>
810 <Text className="mt-0.5 text-xs text-foreground-muted" numberOfLines={2}>
811811 {remoteUrl}
812812 </Text>
813813 </View>
apps/mobile/src/features/review/ReviewCommentComposerSheet.tsx+8-8
......@@ -159,26 +159,26 @@ export function ReviewCommentComposerSheet() {
159159 <SymbolView name="xmark" size={18} tintColor={iconTint} type="monochrome" />
160160 </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
164164 <View className="h-12 w-12" />
165165 </View>
166166
167167 {!target ? (
168168 <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>
170 <Text className="mt-1 text-[13px] leading-[19px] text-foreground-muted">
169 <Text className="text-base font-t3-bold text-foreground">No selection</Text>
170 <Text className="mt-1 text-sm leading-[19px] text-foreground-muted">
171171 Select a diff line or range first.
172172 </Text>
173173 </View>
174174 ) : (
175175 <View className="min-h-0 flex-1 gap-4">
176176 <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">
178178 {selectionLabel}
179179 </Text>
180180 <Text
181 className="font-mono text-[12px] leading-[17px] text-foreground-muted"
181 className="font-mono text-xs leading-[17px] text-foreground-muted"
182182 ellipsizeMode="middle"
183183 numberOfLines={2}
184184 >
......@@ -215,7 +215,7 @@ export function ReviewCommentComposerSheet() {
215215 >
216216 <ReviewChangeBar change={line.change} />
217217 <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"
219219 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY }}
220220 >
221221 {lineNumber ?? ""}
......@@ -236,7 +236,7 @@ export function ReviewCommentComposerSheet() {
236236 </View>
237237
238238 <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>
240240 <View className="min-h-[132px] flex-1 overflow-hidden rounded-[20px] border border-border bg-card">
241241 <View className="min-h-0 flex-1 px-4 pt-3.5">
242242 <TextInputWrapper onPaste={handleNativePaste} style={{ flex: 1, minHeight: 0 }}>
......@@ -248,7 +248,7 @@ export function ReviewCommentComposerSheet() {
248248 textAlignVertical="top"
249249 value={commentText}
250250 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"
252252 style={{ flex: 1, minHeight: 0 }}
253253 />
254254 </TextInputWrapper>
apps/mobile/src/features/review/ReviewSheet.tsx+19-18
......@@ -20,6 +20,7 @@ import { environmentCatalog } from "../../connection/catalog";
2020import { useEnvironmentPresentation } from "../../state/presentation";
2121import { useAtomCommand } from "../../state/use-atom-command";
2222import { useThemeColor } from "../../lib/useThemeColor";
23import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
2324import { useThreadDraftForThread } from "../../state/use-thread-composer-state";
2425import { EnvironmentConnectionNotice } from "../connection/EnvironmentConnectionNotice";
2526import { useReviewCacheForThread } from "./reviewState";
......@@ -41,10 +42,10 @@ const REVIEW_HEADER_SPACING = 0;
4142const ReviewNotice = memo(function ReviewNotice(props: { readonly notice: string }) {
4243 return (
4344 <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">
4546 Partial diff
4647 </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">
4849 {props.notice}
4950 </Text>
5051 </View>
......@@ -69,7 +70,7 @@ function ReviewSelectionActionBar(props: {
6970 tintColor="#ffffff"
7071 type="monochrome"
7172 />
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>
7374 </>
7475 );
7576
......@@ -218,8 +219,8 @@ export function ReviewSheet() {
218219 if (error) {
219220 children.push(
220221 <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-[12px] leading-[18px] text-foreground-muted">{error}</Text>
222 <Text className="text-sm font-t3-bold text-foreground">Review unavailable</Text>
223 <Text className="text-xs leading-[18px] text-foreground-muted">{error}</Text>
223224 </View>,
224225 );
225226 }
......@@ -251,7 +252,7 @@ export function ReviewSheet() {
251252 numberOfLines={1}
252253 style={{
253254 fontFamily: "DMSans_700Bold",
254 fontSize: 18,
255 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
255256 fontWeight: "900",
256257 color: headerForeground,
257258 letterSpacing: -0.4,
......@@ -273,7 +274,7 @@ export function ReviewSheet() {
273274 <NativeText
274275 style={{
275276 fontFamily: "DMSans_700Bold",
276 fontSize: 12,
277 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
277278 fontWeight: "700",
278279 color: "#16a34a",
279280 }}
......@@ -283,7 +284,7 @@ export function ReviewSheet() {
283284 <NativeText
284285 style={{
285286 fontFamily: "DMSans_700Bold",
286 fontSize: 12,
287 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
287288 fontWeight: "700",
288289 color: "#e11d48",
289290 }}
......@@ -294,7 +295,7 @@ export function ReviewSheet() {
294295 <NativeText
295296 style={{
296297 fontFamily: "DMSans_700Bold",
297 fontSize: 12,
298 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
298299 fontWeight: "700",
299300 color: "#b45309",
300301 }}
......@@ -309,7 +310,7 @@ export function ReviewSheet() {
309310 numberOfLines={1}
310311 style={{
311312 fontFamily: "DMSans_700Bold",
312 fontSize: 12,
313 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
313314 fontWeight: "700",
314315 color: headerMuted,
315316 }}
......@@ -320,7 +321,7 @@ export function ReviewSheet() {
320321 <NativeText
321322 style={{
322323 fontFamily: "DMSans_700Bold",
323 fontSize: 12,
324 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
324325 fontWeight: "700",
325326 color: "#b45309",
326327 }}
......@@ -430,30 +431,30 @@ export function ReviewSheet() {
430431 {listHeader}
431432 {!selectedSection ? (
432433 <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-[12px] leading-[18px] text-foreground-muted">
434 <Text className="text-sm font-t3-bold text-foreground">No review diffs</Text>
435 <Text className="text-xs leading-[18px] text-foreground-muted">
435436 This thread has no ready turn diffs and the worktree diff is empty.
436437 </Text>
437438 </View>
438439 ) : selectedSection.isLoading && selectedSection.diff === null ? (
439440 <View className="items-center gap-3 border-b border-border bg-card px-4 py-6">
440441 <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>
442443 </View>
443444 ) : parsedDiff.kind === "empty" ? (
444445 <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-[12px] leading-[18px] text-foreground-muted">
446 <Text className="text-sm font-t3-bold text-foreground">No changes</Text>
447 <Text className="text-xs leading-[18px] text-foreground-muted">
447448 {selectedSection.subtitle ?? "This diff is empty."}
448449 </Text>
449450 </View>
450451 ) : parsedDiff.kind === "raw" ? (
451452 <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">
453454 {parsedDiff.reason}
454455 </Text>
455456 <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">
457458 {parsedDiff.text}
458459 </Text>
459460 </ScrollView>
apps/mobile/src/features/review/nativeReviewDiffAdapter.ts+7-6
......@@ -5,6 +5,7 @@ import type {
55} from "../diffs/nativeReviewDiffTypes";
66import * as Arr from "effect/Array";
77import { pipe } from "effect/Function";
8import { MOBILE_CODE_SURFACE } from "../../lib/typography";
89import { getPierreTerminalTheme, type TerminalAppearanceScheme } from "../terminal/terminalTheme";
910import { computeWordAltDiffRanges } from "./reviewWordDiffs";
1011import {
......@@ -18,16 +19,16 @@ import type { ReviewInlineComment } from "./reviewCommentSelection";
1819const NATIVE_REVIEW_MAX_WORD_DIFF_RANGE_COUNT = 4;
1920const 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;
2223export const NATIVE_REVIEW_DIFF_CONTENT_WIDTH = 2_800;
2324
2425export const NATIVE_REVIEW_DIFF_STYLE = {
2526 rowHeight: NATIVE_REVIEW_DIFF_ROW_HEIGHT,
2627 contentWidth: NATIVE_REVIEW_DIFF_CONTENT_WIDTH,
2728 changeBarWidth: 4,
28 gutterWidth: 46,
29 codePadding: 7,
30 textVerticalInset: 2,
29 gutterWidth: MOBILE_CODE_SURFACE.gutterWidth,
30 codePadding: MOBILE_CODE_SURFACE.codePadding,
31 textVerticalInset: MOBILE_CODE_SURFACE.textVerticalInset,
3132 fileHeaderHeight: 56,
3233 fileHeaderHorizontalMargin: 8,
3334 fileHeaderVerticalMargin: 6,
......@@ -36,9 +37,9 @@ export const NATIVE_REVIEW_DIFF_STYLE = {
3637 fileHeaderPathRightPadding: 118,
3738 fileHeaderCountColumnWidth: 38,
3839 fileHeaderCountGap: 5,
39 codeFontSize: 11,
40 codeFontSize: MOBILE_CODE_SURFACE.fontSize,
4041 codeFontWeight: "regular",
41 lineNumberFontSize: 10,
42 lineNumberFontSize: MOBILE_CODE_SURFACE.lineNumberFontSize,
4243 lineNumberFontWeight: "regular",
4344 hunkFontSize: 11,
4445 hunkFontWeight: "medium",
apps/mobile/src/features/review/reviewDiffRendering.tsx+14-5
......@@ -1,6 +1,7 @@
11import { Platform, Text as NativeText, View } from "react-native";
22
33import { cn } from "../../lib/cn";
4import { MOBILE_CODE_SURFACE } from "../../lib/typography";
45
56import type { ReviewRenderableLineRow } from "./reviewModel";
67import type { ReviewHighlightedToken } from "./shikiReviewHighlighter";
......@@ -11,7 +12,7 @@ export const REVIEW_MONO_FONT_FAMILY = Platform.select({
1112 default: "monospace",
1213});
1314
14export const REVIEW_DIFF_LINE_HEIGHT = 26;
15export const REVIEW_DIFF_LINE_HEIGHT = MOBILE_CODE_SURFACE.rowHeight;
1516const REVIEW_DELETE_STRIPE_COUNT = REVIEW_DIFF_LINE_HEIGHT / 2;
1617
1718export function renderVisibleWhitespace(value: string): string {
......@@ -71,8 +72,12 @@ export function DiffTokenText(props: {
7172 <NativeText
7273 numberOfLines={1}
7374 selectable
74 className={cn("text-[13px] leading-[17px] font-medium text-foreground", props.className)}
75 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY }}
75 className={cn("font-normal text-foreground", props.className)}
76 style={{
77 fontFamily: REVIEW_MONO_FONT_FAMILY,
78 fontSize: MOBILE_CODE_SURFACE.fontSize,
79 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
80 }}
7681 >
7782 {renderVisibleWhitespace(props.fallback || " ")}
7883 </NativeText>
......@@ -83,8 +88,12 @@ export function DiffTokenText(props: {
8388 <NativeText
8489 numberOfLines={1}
8590 selectable
86 className={cn("text-[13px] leading-[17px] font-medium text-foreground", props.className)}
87 style={{ fontFamily: REVIEW_MONO_FONT_FAMILY }}
91 className={cn("font-normal text-foreground", props.className)}
92 style={{
93 fontFamily: REVIEW_MONO_FONT_FAMILY,
94 fontSize: MOBILE_CODE_SURFACE.fontSize,
95 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
96 }}
8897 >
8998 {(() => {
9099 let offset = 0;
apps/mobile/src/features/terminal/NativeTerminalSurface.tsx+6-5
......@@ -11,6 +11,7 @@ import {
1111} from "react-native";
1212
1313import { AppText as Text } from "../../components/AppText";
14import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
1415import { resolveNativeTerminalSurfaceView } from "./nativeTerminalModule";
1516import {
1617 buildGhosttyThemeConfig,
......@@ -53,7 +54,7 @@ function estimateGridSize(input: {
5354}
5455
5556const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: TerminalSurfaceProps) {
56 const fontSize = props.fontSize ?? 12;
57 const fontSize = props.fontSize ?? MOBILE_TYPOGRAPHY.label.fontSize;
5758 const inputRef = useRef<TextInput>(null);
5859 const appearanceScheme = useColorScheme() === "light" ? "light" : "dark";
5960 const theme = props.theme ?? getPierreTerminalTheme(appearanceScheme);
......@@ -93,7 +94,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
9394 <Text
9495 style={{
9596 color: theme.mutedForeground,
96 fontSize: 11,
97 fontSize: MOBILE_TYPOGRAPHY.caption.fontSize,
9798 paddingBottom: 8,
9899 }}
99100 >
......@@ -140,7 +141,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
140141 color: theme.foreground,
141142 flex: 1,
142143 fontFamily: "Menlo",
143 fontSize: 13,
144 fontSize: MOBILE_TYPOGRAPHY.footnote.fontSize,
144145 padding: 0,
145146 }}
146147 onSubmitEditing={(event) => {
......@@ -165,7 +166,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
165166 style={{
166167 color: theme.foreground,
167168 fontFamily: "DMSans_700Bold",
168 fontSize: 11,
169 fontSize: MOBILE_TYPOGRAPHY.caption.fontSize,
169170 }}
170171 >
171172 Ctrl-C
......@@ -177,7 +178,7 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
177178});
178179
179180export const TerminalSurface = memo(function TerminalSurface(props: TerminalSurfaceProps) {
180 const fontSize = props.fontSize ?? 12;
181 const fontSize = props.fontSize ?? MOBILE_TYPOGRAPHY.label.fontSize;
181182 const keyboardInputRef = useRef<TextInput>(null);
182183 const appearanceScheme = useColorScheme() === "light" ? "light" : "dark";
183184 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(
127127 <View className="absolute inset-x-3 bottom-28 top-28 overflow-hidden rounded-[8px] border border-white/10 bg-neutral-950 shadow-2xl">
128128 <View className="flex-row items-center justify-between border-b border-white/10 px-3 py-2">
129129 <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}>
131131 Terminal
132132 </Text>
133 <Text className="text-[11px] text-neutral-500" numberOfLines={1}>
133 <Text className="text-2xs text-neutral-500" numberOfLines={1}>
134134 {nativeTerminalAvailable ? "Native Ghostty surface" : "Text fallback active"}
135135 </Text>
136136 </View>
137137 <View className="flex-row items-center gap-2">
138138 {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}>
140140 {terminal.error}
141141 </Text>
142142 ) : null}
apps/mobile/src/features/terminal/ThreadTerminalRouteScreen.tsx+3-2
......@@ -25,6 +25,7 @@ import { terminalEnvironment } from "../../state/terminal";
2525import { useAtomCommand } from "../../state/use-atom-command";
2626import { useWorkspaceState } from "../../state/workspace";
2727import { buildThreadTerminalNavigation } from "../../lib/routes";
28import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
2829import {
2930 useAttachedTerminalSession,
3031 useKnownTerminalSessions,
......@@ -920,7 +921,7 @@ export function ThreadTerminalRouteScreen() {
920921 style={{
921922 color: terminalTheme.foreground,
922923 fontFamily: "DMSans_700Bold",
923 fontSize: 13,
924 fontSize: MOBILE_TYPOGRAPHY.footnote.fontSize,
924925 lineHeight: 16,
925926 }}
926927 >
......@@ -932,7 +933,7 @@ export function ThreadTerminalRouteScreen() {
932933 style={{
933934 color: terminalTheme.mutedForeground,
934935 fontFamily: "Menlo",
935 fontSize: 11,
936 fontSize: MOBILE_TYPOGRAPHY.caption.fontSize,
936937 lineHeight: 14,
937938 }}
938939 >
apps/mobile/src/features/threads/ComposerCommandPopover.tsx+13-4
......@@ -7,6 +7,7 @@ import { Pressable, ScrollView, useColorScheme, View, type ViewStyle } from "rea
77
88import { AppText as Text } from "../../components/AppText";
99import { PierreEntryIcon } from "../../components/PierreEntryIcon";
10import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
1011
1112export type ComposerCommandItem =
1213 | {
......@@ -156,14 +157,22 @@ const CommandRow = memo(function CommandRow(props: {
156157 <SymbolView name={iconName} size={14} tintColor={iconColor} type="monochrome" />
157158 ) : null}
158159 <Text
159 className="text-[14px] font-t3-medium text-foreground"
160 className="text-base font-t3-medium text-foreground"
160161 numberOfLines={1}
161162 style={{ flexShrink: 0 }}
162163 >
163164 {props.item.label}
164165 </Text>
165166 {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 >
167176 {props.item.description}
168177 </Text>
169178 ) : null}
......@@ -182,7 +191,7 @@ export const ComposerCommandPopover = memo(function ComposerCommandPopover(
182191 {label ? (
183192 <View style={{ paddingHorizontal: 14, paddingTop: 10, paddingBottom: 4 }}>
184193 <Text
185 className="text-[10px] font-t3-bold text-foreground-muted"
194 className="text-3xs font-t3-bold text-foreground-muted"
186195 style={{ letterSpacing: 0.8, textTransform: "uppercase" }}
187196 >
188197 {label}
......@@ -206,7 +215,7 @@ export const ComposerCommandPopover = memo(function ComposerCommandPopover(
206215 </ScrollView>
207216 ) : (
208217 <View style={{ paddingHorizontal: 14, paddingVertical: 10 }}>
209 <Text className="text-[12px] text-foreground-tertiary">
218 <Text className="text-xs text-foreground-tertiary">
210219 {emptyText(props.triggerKind, props.isLoading)}
211220 </Text>
212221 </View>
apps/mobile/src/features/threads/GitActionProgressOverlay.tsx+2-2
......@@ -73,12 +73,12 @@ function OverlayContent(props: { readonly progress: GitActionProgress }) {
7373
7474 <View className="flex-1 gap-0.5">
7575 {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}>
7777 {progress.label}
7878 </Text>
7979 ) : null}
8080 {progress.description ? (
81 <Text className="text-[11px] text-foreground-muted" numberOfLines={1}>
81 <Text className="text-2xs text-foreground-muted" numberOfLines={1}>
8282 {progress.description}
8383 </Text>
8484 ) : null}
apps/mobile/src/features/threads/NewTaskDraftScreen.tsx+2-1
......@@ -30,6 +30,7 @@ import {
3030 resolveProviderOptionDescriptors,
3131} from "../../lib/providerOptions";
3232import { buildThreadRoutePath } from "../../lib/routes";
33import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
3334import { useProjects } from "../../state/entities";
3435import { branchBadgeLabel, useNewTaskFlow } from "./new-task-flow-provider";
3536import { useCreateProjectThread } from "./use-project-actions";
......@@ -430,7 +431,7 @@ export function NewTaskDraftScreen(props: {
430431 onPasteImages={(uris) => void handleNativePasteImages(uris)}
431432 placeholder={`Describe a coding task in ${selectedProject.title}`}
432433 style={{ flex: 1, minHeight: 0 }}
433 textStyle={{ fontSize: 18, lineHeight: 28 }}
434 textStyle={MOBILE_TYPOGRAPHY.composer}
434435 />
435436 </View>
436437
apps/mobile/src/features/threads/PendingApprovalCard.tsx+1-1
......@@ -16,7 +16,7 @@ export interface PendingApprovalCardProps {
1616export function PendingApprovalCard(props: PendingApprovalCardProps) {
1717 return (
1818 <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">
2020 Approval needed
2121 </Text>
2222 <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 {
2626export function PendingUserInputCard(props: PendingUserInputCardProps) {
2727 return (
2828 <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">
3030 User input needed
3131 </Text>
3232 <Text className="font-t3-bold text-lg text-neutral-950 dark:text-neutral-50">
......@@ -39,7 +39,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
3939 <Text className="font-t3-bold text-xs uppercase tracking-[1px] text-neutral-500 dark:text-neutral-500">
4040 {question.header}
4141 </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">
4343 {question.question}
4444 </Text>
4545 <View className="flex-row flex-wrap gap-2.5">
......@@ -65,7 +65,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
6565 >
6666 <Text
6767 className={cn(
68 "font-t3-bold text-[13px]",
68 "font-t3-bold text-sm",
6969 selected
7070 ? "text-sky-700 dark:text-sky-300"
7171 : "text-neutral-600 dark:text-neutral-300",
......@@ -83,7 +83,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
8383 props.onChangeCustomAnswer(props.pendingUserInput.requestId, question.id, value)
8484 }
8585 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"
8787 />
8888 </View>
8989 );
apps/mobile/src/features/threads/ThreadComposer.tsx+5-6
......@@ -43,6 +43,7 @@ import { ControlPill, ControlPillMenu } from "../../components/ControlPill";
4343import { ProviderIcon } from "../../components/ProviderIcon";
4444import type { DraftComposerImageAttachment } from "../../lib/composerImages";
4545import { buildModelOptions, groupByProvider } from "../../lib/modelOptions";
46import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
4647import type { RemoteClientConnectionState } from "../../lib/connection";
4748import {
4849 insertRankedSearchResult,
......@@ -189,7 +190,7 @@ const ComposerConnectionStatusPill = memo(function ComposerConnectionStatusPill(
189190 <View className="h-2 w-2 rounded-full bg-red-500" />
190191 )}
191192 <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"
193194 numberOfLines={1}
194195 >
195196 {props.status.label}
......@@ -717,8 +718,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
717718 }
718719 }
719720 textStyle={{
720 fontSize: 15,
721 lineHeight: isExpanded ? 22 : 20,
721 ...MOBILE_TYPOGRAPHY.composer,
722722 color: foregroundColor,
723723 fontFamily: "DMSans_400Regular",
724724 }}
......@@ -751,7 +751,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
751751 justifyContent: "center",
752752 }}
753753 >
754 <Text className="text-foreground-muted text-[11px] font-t3-bold">
754 <Text className="text-foreground-muted text-2xs font-t3-bold">
755755 +{props.draftAttachments.length - 3}
756756 </Text>
757757 </View>
......@@ -831,8 +831,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
831831 <Text
832832 className="text-foreground-muted"
833833 style={{
834 fontSize: 12,
835 lineHeight: 18,
834 ...MOBILE_TYPOGRAPHY.label,
836835 paddingTop: 8,
837836 }}
838837 >
apps/mobile/src/features/threads/ThreadFeed.tsx+12-14
......@@ -56,6 +56,7 @@ import { buildReviewParsedDiff } from "../review/reviewModel";
5656import { cn } from "../../lib/cn";
5757import type { LayoutVariant } from "../../lib/layout";
5858import { buildThreadFilesNavigation } from "../../lib/routes";
59import { MOBILE_CODE_SURFACE, MOBILE_TYPOGRAPHY } from "../../lib/typography";
5960import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons";
6061import { resolveMarkdownLinkPresentation } from "@t3tools/mobile-markdown-text/links";
6162import {
......@@ -444,8 +445,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
444445 marginRight: 5,
445446 color: inlineTextColor,
446447 fontFamily: "DMSans_400Regular",
447 fontSize: 15,
448 lineHeight: 22,
448 ...MOBILE_TYPOGRAPHY.body,
449449 textAlign: ordered ? "right" : "center",
450450 }}
451451 >
......@@ -466,7 +466,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
466466 style={{
467467 color: inlineCodeTextColor,
468468 fontFamily: "ui-monospace",
469 fontSize: 12,
469 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
470470 lineHeight: 22,
471471 }}
472472 >
......@@ -503,7 +503,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
503503 style={{
504504 color: markdownBodyColor,
505505 fontFamily: "ui-monospace",
506 fontSize: 12,
506 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
507507 opacity: 0.7,
508508 textTransform: "uppercase",
509509 }}
......@@ -523,7 +523,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
523523 style={{
524524 color: blockTextColor,
525525 fontFamily: "ui-monospace",
526 fontSize: 12,
526 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
527527 lineHeight: 18,
528528 }}
529529 >
......@@ -603,8 +603,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
603603 skillTextColor: "#f0abfc",
604604 quoteMarkerColor: markdownUserBodyColor,
605605 dividerColor: markdownUserBodyColor,
606 fontSize: 15,
607 lineHeight: 22,
606 ...MOBILE_TYPOGRAPHY.body,
608607 fontFamily: "DMSans_400Regular",
609608 headingFontFamily: "DMSans_700Bold",
610609 boldFontFamily: "DMSans_700Bold",
......@@ -633,8 +632,7 @@ function useMarkdownStyles(onLinkPress: (href: string) => void): MarkdownStyleSe
633632 skillTextColor: inlineSkillForeground,
634633 quoteMarkerColor: markdownBlockquoteBorder,
635634 dividerColor: markdownHrColor,
636 fontSize: 15,
637 lineHeight: 22,
635 ...MOBILE_TYPOGRAPHY.body,
638636 fontFamily: "DMSans_400Regular",
639637 headingFontFamily: "DMSans_700Bold",
640638 boldFontFamily: "DMSans_700Bold",
......@@ -821,7 +819,7 @@ function renderFeedEntry(
821819 className="max-w-[85%] gap-2 rounded-[22px] rounded-br-[6px] px-3.5 py-2.5 opacity-60"
822820 style={{ backgroundColor: userBubbleColor }}
823821 >
824 <Text className="font-sans text-[15px] leading-[22px] text-white">
822 <Text className="font-sans text-base leading-[22px] text-white">
825823 {entry.queuedMessage.text}
826824 </Text>
827825 {entry.queuedMessage.attachments.length > 0 ? (
......@@ -995,7 +993,7 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {
995993 </View>
996994 <View className="min-w-0 flex-1">
997995 <Text
998 className="font-mono text-[12px] leading-[16px]"
996 className="font-mono text-xs leading-[16px]"
999997 numberOfLines={1}
1000998 style={{ color: props.colors.text }}
1001999 >
......@@ -1040,8 +1038,8 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {
10401038 style={{
10411039 color: props.colors.text,
10421040 fontFamily: "ui-monospace",
1043 fontSize: 12,
1044 lineHeight: 18,
1041 fontSize: MOBILE_CODE_SURFACE.fontSize,
1042 lineHeight: MOBILE_CODE_SURFACE.rowHeight,
10451043 }}
10461044 >
10471045 {props.comment.diff.trim()}
......@@ -1052,7 +1050,7 @@ const ReviewCommentCard = memo(function ReviewCommentCard(props: {
10521050 <View className="border-t px-3 py-3" style={{ borderColor: props.colors.border }}>
10531051 <Text
10541052 selectable
1055 className="text-[15px] leading-[21px]"
1053 className="text-base leading-[21px]"
10561054 style={{ color: props.colors.text }}
10571055 >
10581056 {props.comment.text}
apps/mobile/src/features/threads/ThreadNavigationDrawer.tsx+5-7
......@@ -152,7 +152,7 @@ export function ThreadNavigationDrawer(props: {
152152 ]}
153153 >
154154 <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>
156156 <Pressable
157157 onPress={() => {
158158 props.onClose();
......@@ -224,7 +224,7 @@ function ThreadNavigationDrawerContent(props: {
224224 {groupedThreads.map((group) => (
225225 <View key={group.key} className="gap-3">
226226 <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"
228228 style={{ letterSpacing: -0.2 }}
229229 >
230230 {group.title}
......@@ -233,9 +233,7 @@ function ThreadNavigationDrawerContent(props: {
233233 <View className="overflow-hidden rounded-[22px] bg-card">
234234 {group.threads.length === 0 ? (
235235 <View className="px-4 py-4">
236 <Text className="text-[14px] font-medium text-foreground-tertiary">
237 No threads yet
238 </Text>
236 <Text className="text-sm font-medium text-foreground-tertiary">No threads yet</Text>
239237 </View>
240238 ) : (
241239 group.threads.map((thread, index) => {
......@@ -260,11 +258,11 @@ function ThreadNavigationDrawerContent(props: {
260258 >
261259 <View className="flex-row items-start justify-between gap-3">
262260 <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}>
264262 {thread.title}
265263 </Text>
266264 <Text
267 className="text-[13px] font-medium text-foreground-muted"
265 className="text-sm font-medium text-foreground-muted"
268266 numberOfLines={1}
269267 >
270268 {relativeTime(thread.updatedAt ?? thread.createdAt)}
apps/mobile/src/features/threads/ThreadRouteScreen.tsx+3-2
......@@ -20,6 +20,7 @@ import { EmptyState } from "../../components/EmptyState";
2020import { LoadingScreen } from "../../components/LoadingScreen";
2121import { buildThreadRoutePath, buildThreadTerminalNavigation } from "../../lib/routes";
2222import { scopedThreadKey } from "../../lib/scopedEntities";
23import { MOBILE_TYPOGRAPHY } from "../../lib/typography";
2324import { connectionTone } from "../connection/connectionTone";
2425
2526import {
......@@ -390,7 +391,7 @@ export function ThreadRouteScreen() {
390391 numberOfLines={1}
391392 style={{
392393 fontFamily: "DMSans_700Bold",
393 fontSize: 18,
394 fontSize: MOBILE_TYPOGRAPHY.headline.fontSize,
394395 fontWeight: "900",
395396 color: foregroundColor,
396397 letterSpacing: -0.4,
......@@ -402,7 +403,7 @@ export function ThreadRouteScreen() {
402403 numberOfLines={1}
403404 style={{
404405 fontFamily: "DMSans_700Bold",
405 fontSize: 12,
406 fontSize: MOBILE_TYPOGRAPHY.label.fontSize,
406407 fontWeight: "700",
407408 color: secondaryFg,
408409 letterSpacing: 0.3,
apps/mobile/src/features/threads/git/GitBranchesSheet.tsx+10-12
......@@ -69,7 +69,7 @@ export function GitBranchesSheet() {
6969 >
7070 <View className="gap-2 rounded-[18px] border border-border bg-card px-4 py-4">
7171 <Text
72 className="text-foreground-secondary text-[11px] font-t3-bold uppercase"
72 className="text-foreground-secondary text-2xs font-t3-bold uppercase"
7373 style={{ letterSpacing: 1 }}
7474 >
7575 New branch
......@@ -78,7 +78,7 @@ export function GitBranchesSheet() {
7878 value={newBranchName}
7979 onChangeText={setNewBranchName}
8080 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"
8282 style={{
8383 borderWidth: 1,
8484 borderColor: inputBorderColor,
......@@ -104,7 +104,7 @@ export function GitBranchesSheet() {
104104
105105 <View className="gap-2 rounded-[18px] border border-border bg-card px-4 py-4">
106106 <Text
107 className="text-foreground-secondary text-[11px] font-t3-bold uppercase"
107 className="text-foreground-secondary text-2xs font-t3-bold uppercase"
108108 style={{ letterSpacing: 1 }}
109109 >
110110 New worktree
......@@ -113,7 +113,7 @@ export function GitBranchesSheet() {
113113 value={worktreeBaseBranch}
114114 onChangeText={setWorktreeBaseBranch}
115115 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"
117117 style={{
118118 borderWidth: 1,
119119 borderColor: inputBorderColor,
......@@ -125,7 +125,7 @@ export function GitBranchesSheet() {
125125 value={worktreeBranchName}
126126 onChangeText={setWorktreeBranchName}
127127 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"
129129 style={{
130130 borderWidth: 1,
131131 borderColor: inputBorderColor,
......@@ -154,18 +154,16 @@ export function GitBranchesSheet() {
154154
155155 <View className="gap-2">
156156 <Text
157 className="text-foreground-secondary text-[11px] font-t3-bold uppercase"
157 className="text-foreground-secondary text-2xs font-t3-bold uppercase"
158158 style={{ letterSpacing: 1 }}
159159 >
160160 Existing branches
161161 </Text>
162162 {branchesLoading ? (
163 <Text className="text-foreground-secondary text-[13px] font-medium">
164 Loading branches...
165 </Text>
163 <Text className="text-foreground-secondary text-sm font-medium">Loading branches...</Text>
166164 ) : null}
167165 {!branchesLoading && availableBranches.length === 0 ? (
168 <Text className="text-foreground-secondary text-[13px] font-medium">
166 <Text className="text-foreground-secondary text-sm font-medium">
169167 No local branches found.
170168 </Text>
171169 ) : null}
......@@ -195,8 +193,8 @@ export function GitBranchesSheet() {
195193 }}
196194 >
197195 <View className="absolute inset-0 rounded-[18px] bg-card" />
198 <Text className="text-foreground text-[15px] font-t3-bold">{branch.name}</Text>
199 <Text className="text-foreground-secondary text-[12px] font-medium">{subtitle}</Text>
196 <Text className="text-foreground text-base font-t3-bold">{branch.name}</Text>
197 <Text className="text-foreground-secondary text-xs font-medium">{subtitle}</Text>
200198 </Pressable>
201199 );
202200 })}
apps/mobile/src/features/threads/git/GitCommitSheet.tsx+18-18
......@@ -79,14 +79,14 @@ export function GitCommitSheet() {
7979 >
8080 <View className="gap-3 rounded-[22px] border border-border bg-card px-4 py-4">
8181 <View className="flex-row items-center justify-between gap-3">
82 <Text className="text-foreground-muted text-[13px] font-medium">Branch</Text>
83 <Text className="text-foreground text-[15px] font-t3-bold">
82 <Text className="text-foreground-muted text-sm font-medium">Branch</Text>
83 <Text className="text-foreground text-base font-t3-bold">
8484 {gitStatus.data?.refName ?? "(detached HEAD)"}
8585 </Text>
8686 </View>
8787 {isDefaultRef ? (
8888 <Text
89 className="text-[12px] leading-[18px]"
89 className="text-xs leading-[18px]"
9090 style={{ color: isDarkMode ? "#fbbf24" : "#b45309" }}
9191 >
9292 Warning: this is the default branch.
......@@ -97,8 +97,8 @@ export function GitCommitSheet() {
9797 <View className="gap-3 rounded-[22px] border border-border bg-card px-4 py-4">
9898 <View className="flex-row items-center justify-between gap-3">
9999 <View className="gap-1">
100 <Text className="text-foreground text-[16px] font-t3-bold">Files</Text>
101 <Text className="text-foreground-muted text-[12px] leading-[18px]">
100 <Text className="text-foreground text-base font-t3-bold">Files</Text>
101 <Text className="text-foreground-muted text-xs leading-[18px]">
102102 {selectedFiles.length} selected · +{selectedInsertions} / -{selectedDeletions}
103103 </Text>
104104 </View>
......@@ -108,14 +108,14 @@ export function GitCommitSheet() {
108108 className="bg-subtle rounded-full px-3 py-2"
109109 onPress={() => setExcludedFiles(new Set())}
110110 >
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>
112112 </Pressable>
113113 ) : null}
114114 <Pressable
115115 className="bg-subtle rounded-full px-3 py-2"
116116 onPress={() => setIsEditingFiles((current) => !current)}
117117 >
118 <Text className="text-foreground text-[11px] font-t3-bold uppercase">
118 <Text className="text-foreground text-2xs font-t3-bold uppercase">
119119 {isEditingFiles ? "Done" : "Edit"}
120120 </Text>
121121 </Pressable>
......@@ -123,26 +123,26 @@ export function GitCommitSheet() {
123123 </View>
124124
125125 {allFiles.length === 0 ? (
126 <Text className="text-foreground-secondary text-[13px] leading-[19px]">
126 <Text className="text-foreground-secondary text-sm leading-[19px]">
127127 No changed files are available to commit.
128128 </Text>
129129 ) : !isEditingFiles ? (
130130 <View className="gap-2">
131131 {selectedFilePreview.map((file) => (
132132 <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}>
134134 {file.path}
135135 </Text>
136 <Text className="text-[12px] font-t3-bold" style={{ color: "#10b981" }}>
136 <Text className="text-xs font-t3-bold" style={{ color: "#10b981" }}>
137137 +{file.insertions}
138138 </Text>
139 <Text className="text-[12px] font-t3-bold" style={{ color: "#f43f5e" }}>
139 <Text className="text-xs font-t3-bold" style={{ color: "#f43f5e" }}>
140140 -{file.deletions}
141141 </Text>
142142 </View>
143143 ))}
144144 {selectedFiles.length > selectedFilePreview.length ? (
145 <Text className="text-foreground-muted text-[12px] leading-[17px]">
145 <Text className="text-foreground-muted text-xs leading-[17px]">
146146 +{selectedFiles.length - selectedFilePreview.length} more files
147147 </Text>
148148 ) : null}
......@@ -177,21 +177,21 @@ export function GitCommitSheet() {
177177 <View className="flex-1 gap-1">
178178 <Text
179179 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"}`}
181181 >
182182 {file.path}
183183 </Text>
184184 {!included ? (
185 <Text className="text-foreground-muted text-[11px] leading-[16px]">
185 <Text className="text-foreground-muted text-2xs leading-[16px]">
186186 Excluded from this commit
187187 </Text>
188188 ) : null}
189189 </View>
190190 <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" }}>
192192 +{file.insertions}
193193 </Text>
194 <Text className="text-[12px] font-t3-bold" style={{ color: "#f43f5e" }}>
194 <Text className="text-xs font-t3-bold" style={{ color: "#f43f5e" }}>
195195 -{file.deletions}
196196 </Text>
197197 </View>
......@@ -204,14 +204,14 @@ export function GitCommitSheet() {
204204 </View>
205205
206206 <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>
208208 <TextInput
209209 multiline
210210 value={dialogCommitMessage}
211211 onChangeText={setDialogCommitMessage}
212212 placeholder="Leave empty to auto-generate"
213213 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"
215215 style={{
216216 minHeight: 128,
217217 borderWidth: 1,
apps/mobile/src/features/threads/git/GitConfirmSheet.tsx+3-3
......@@ -90,15 +90,15 @@ export function GitConfirmSheet() {
9090
9191 <View className="items-center gap-1 px-5 pb-3 pt-4">
9292 <Text
93 className="text-[12px] font-t3-bold uppercase text-foreground-muted"
93 className="text-xs font-t3-bold uppercase text-foreground-muted"
9494 style={{ letterSpacing: 1 }}
9595 >
9696 Confirm
9797 </Text>
98 <Text className="text-center text-[28px] font-t3-bold">
98 <Text className="text-center text-3xl font-t3-bold">
9999 {copy?.title ?? "Run action on default branch?"}
100100 </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]">
102102 {copy?.description ?? "Choose how to continue."}
103103 </Text>
104104 </View>
apps/mobile/src/features/threads/git/GitOverviewSheet.tsx+3-3
......@@ -175,13 +175,13 @@ export function GitOverviewSheet() {
175175 />
176176 </Pressable>
177177 <Text
178 className="text-[12px] font-t3-bold uppercase text-foreground-muted"
178 className="text-xs font-t3-bold uppercase text-foreground-muted"
179179 style={{ letterSpacing: 1 }}
180180 >
181181 Branch
182182 </Text>
183 <Text className="text-[28px] font-t3-bold">{currentBranchLabel}</Text>
184 <Text className="text-foreground-secondary text-[13px] font-medium leading-[19px]">
183 <Text className="text-3xl font-t3-bold">{currentBranchLabel}</Text>
184 <Text className="text-foreground-secondary text-sm font-medium leading-[19px]">
185185 {statusSummary(gitStatus.data)}
186186 </Text>
187187 </View>
apps/mobile/src/features/threads/git/gitSheetComponents.tsx+5-5
......@@ -56,7 +56,7 @@ export function SheetActionButton(props: {
5656 >
5757 <SymbolView name={props.icon} size={16} tintColor={colors.textColor} type="monochrome" />
5858 <Text
59 className="text-[12px] font-t3-bold uppercase"
59 className="text-xs font-t3-bold uppercase"
6060 style={{ color: colors.textColor, letterSpacing: 0.9 }}
6161 >
6262 {props.label}
......@@ -69,12 +69,12 @@ export function MetaCard(props: { readonly label: string; readonly value: string
6969 return (
7070 <View className="rounded-[18px] border border-border bg-card px-4 py-3">
7171 <Text
72 className="text-foreground-muted text-[11px] font-t3-bold uppercase"
72 className="text-foreground-muted text-2xs font-t3-bold uppercase"
7373 style={{ letterSpacing: 0.9 }}
7474 >
7575 {props.label}
7676 </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}>
7878 {props.value}
7979 </Text>
8080 </View>
......@@ -102,9 +102,9 @@ export function SheetListRow(props: {
102102 <SymbolView name={props.icon} size={16} tintColor={iconColor} type="monochrome" />
103103 </View>
104104 <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>
106106 {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>
108108 ) : null}
109109 </View>
110110 <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: {
9898 return (
9999 <View className="-mx-1 mb-3 px-1 py-0.5">
100100 {!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">
102102 work log
103103 </Text>
104104 ) : null}
......@@ -164,7 +164,7 @@ export function ThreadWorkLog(props: {
164164
165165 <View className="shrink-0 flex-row items-center gap-px">
166166 {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">
168168 Copied
169169 </Text>
170170 ) : null}
......@@ -209,7 +209,7 @@ export function ThreadWorkLog(props: {
209209 >
210210 <Text
211211 selectable
212 className="text-[11px] leading-[17px] text-foreground-muted"
212 className="text-2xs leading-[17px] text-foreground-muted"
213213 style={{ fontFamily: "ui-monospace" }}
214214 >
215215 {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";
66
77import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons";
88import { resolveMarkdownFileIcon } from "@t3tools/mobile-markdown-text/links";
9import { MOBILE_TYPOGRAPHY } from "../lib/typography";
910import { useThemeColor } from "../lib/useThemeColor";
1011import type { ComposerEditorProps, ComposerEditorSelection } from "./T3ComposerEditor.types";
1112
......@@ -150,9 +151,15 @@ export function ComposerEditor({
150151 ? resolvedTextStyle.fontFamily
151152 : "DMSans_400Regular"
152153 }
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 }
154159 lineHeight={
155 typeof resolvedTextStyle.lineHeight === "number" ? resolvedTextStyle.lineHeight : 22
160 typeof resolvedTextStyle.lineHeight === "number"
161 ? resolvedTextStyle.lineHeight
162 : MOBILE_TYPOGRAPHY.composer.lineHeight
156163 }
157164 contentInsetVertical={contentInsetVertical}
158165 editable={props.editable ?? true}
apps/mobile/src/native/T3ComposerEditor.tsx+2-2
......@@ -2,6 +2,7 @@ import { TextInputWrapper } from "expo-paste-input";
22import { useImperativeHandle, useRef } from "react";
33import { TextInput, type TextInput as RNTextInput } from "react-native";
44
5import { MOBILE_TYPOGRAPHY } from "../lib/typography";
56import { useThemeColor } from "../lib/useThemeColor";
67import { useNativePaste } from "../lib/useNativePaste";
78import type { ComposerEditorProps } from "./T3ComposerEditor.types";
......@@ -47,8 +48,7 @@ export function ComposerEditor({
4748 minHeight: 0,
4849 color: foregroundColor,
4950 fontFamily: "DMSans_400Regular",
50 fontSize: 15,
51 lineHeight: 22,
51 ...MOBILE_TYPOGRAPHY.composer,
5252 paddingVertical: contentInsetVertical,
5353 },
5454 textStyle,