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