From 8b9bf3bc8887ce0a17721c08b6a322ea4b5b9b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 3 Jun 2026 15:28:22 -0700 Subject: [PATCH 1/2] feat: add Callstack tab --- app/(tabs)/_layout.tsx | 7 +++ app/(tabs)/callstack.tsx | 107 ++++++++++++++++++++++++++++++++++ components/ui/icon-symbol.tsx | 8 ++- hooks/use-color-scheme.ts | 8 ++- hooks/use-color-scheme.web.ts | 6 +- 5 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 app/(tabs)/callstack.tsx diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 54e11d0..e84e088 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -30,6 +30,13 @@ export default function TabLayout() { tabBarIcon: ({ color }) => , }} /> + , + }} + /> ); } diff --git a/app/(tabs)/callstack.tsx b/app/(tabs)/callstack.tsx new file mode 100644 index 0000000..ad9c8ad --- /dev/null +++ b/app/(tabs)/callstack.tsx @@ -0,0 +1,107 @@ +import { StyleSheet } from 'react-native'; + +import { ExternalLink } from '@/components/external-link'; +import ParallaxScrollView from '@/components/parallax-scroll-view'; +import { ThemedText } from '@/components/themed-text'; +import { ThemedView } from '@/components/themed-view'; +import { IconSymbol } from '@/components/ui/icon-symbol'; +import { Fonts } from '@/constants/theme'; + +const services = [ + { + title: 'Engineering', + body: 'Feature development, end-to-end product delivery, AI-assisted migrations, and architecture or performance work for React Native products.', + }, + { + title: 'Infrastructure', + body: 'AI-driven QA and testing, custom agents, and self-hosted CI/CD infrastructure that helps teams turn agent output into releases.', + }, + { + title: 'Adoption & governance', + body: 'AI tooling setup, adoption measurement, team training, private model strategy, compliance support, and AI security audits.', + }, +]; + +const highlights = [ + 'React Foundation members and React Native core contributors', + 'Open-source contributors across the React Native ecosystem since 2016', + '100+ enterprise clients and 10+ years helping teams ship cross-platform products', +]; + +export default function CallstackScreen() { + return ( + + }> + + + Callstack + + + + + Callstack helps companies ship production-grade React Native and AI-native products. Their + work spans product engineering, delivery infrastructure, AI adoption, and enterprise + governance. + + + + What they offer + {services.map((service) => ( + + {service.title} + {service.body} + + ))} + + + + Why teams choose them + {highlights.map((highlight) => ( + + - + {highlight} + + ))} + + + + Visit callstack.com + + + ); +} + +const styles = StyleSheet.create({ + headerImage: { + bottom: -48, + opacity: 0.42, + position: 'absolute', + right: -24, + }, + highlight: { + alignItems: 'flex-start', + flexDirection: 'row', + gap: 8, + }, + highlightText: { + flex: 1, + }, + section: { + gap: 12, + }, + service: { + gap: 4, + }, + titleContainer: { + flexDirection: 'row', + gap: 8, + }, +}); diff --git a/components/ui/icon-symbol.tsx b/components/ui/icon-symbol.tsx index b7ece6b..ac7e279 100644 --- a/components/ui/icon-symbol.tsx +++ b/components/ui/icon-symbol.tsx @@ -2,10 +2,11 @@ import MaterialIcons from '@expo/vector-icons/MaterialIcons'; import { SymbolWeight, SymbolViewProps } from 'expo-symbols'; -import { ComponentProps } from 'react'; +import { type ComponentProps } from 'react'; import { OpaqueColorValue, type StyleProp, type TextStyle } from 'react-native'; -type IconMapping = Record['name']>; +type SymbolName = Extract; +type MaterialIconName = ComponentProps['name']; type IconSymbolName = keyof typeof MAPPING; /** @@ -16,9 +17,10 @@ type IconSymbolName = keyof typeof MAPPING; const MAPPING = { 'house.fill': 'home', 'paperplane.fill': 'send', + 'briefcase.fill': 'business', 'chevron.left.forwardslash.chevron.right': 'code', 'chevron.right': 'chevron-right', -} as IconMapping; +} satisfies Partial>; /** * An icon component that uses native SF Symbols on iOS, and Material Icons on Android and web. diff --git a/hooks/use-color-scheme.ts b/hooks/use-color-scheme.ts index 17e3c63..83f4ef3 100644 --- a/hooks/use-color-scheme.ts +++ b/hooks/use-color-scheme.ts @@ -1 +1,7 @@ -export { useColorScheme } from 'react-native'; +import { useColorScheme as useRNColorScheme } from 'react-native'; + +export type AppColorScheme = 'light' | 'dark'; + +export function useColorScheme(): AppColorScheme { + return useRNColorScheme() === 'dark' ? 'dark' : 'light'; +} diff --git a/hooks/use-color-scheme.web.ts b/hooks/use-color-scheme.web.ts index 7eb1c1b..b7ce6e5 100644 --- a/hooks/use-color-scheme.web.ts +++ b/hooks/use-color-scheme.web.ts @@ -1,10 +1,12 @@ import { useEffect, useState } from 'react'; import { useColorScheme as useRNColorScheme } from 'react-native'; +import type { AppColorScheme } from '@/hooks/use-color-scheme'; + /** * To support static rendering, this value needs to be re-calculated on the client side for web */ -export function useColorScheme() { +export function useColorScheme(): AppColorScheme { const [hasHydrated, setHasHydrated] = useState(false); useEffect(() => { @@ -14,7 +16,7 @@ export function useColorScheme() { const colorScheme = useRNColorScheme(); if (hasHydrated) { - return colorScheme; + return colorScheme === 'dark' ? 'dark' : 'light'; } return 'light'; From 9e11033e8d040f11a8767d937703bb22100d1d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 3 Jun 2026 16:01:39 -0700 Subject: [PATCH 2/2] chore: trigger CI rebuild