From 2f5d866e9850e54c1079cd74dab025b671427ce6 Mon Sep 17 00:00:00 2001 From: edgar Date: Wed, 3 Dec 2025 22:35:01 -0500 Subject: [PATCH] adding chat history to debugger-ios --- apps/debugger-ios/package.json | 3 +- apps/debugger-ios/src/App.tsx | 76 ++- apps/debugger-ios/src/index.js | 1 + .../src/screens/ChatHistoryTest.tsx | 574 ++++++++++++++++++ apps/debugger-ios/src/unistyles.config.ts | 22 + bun.lock | 15 +- packages/streamdown-rn/src/StreamdownRN.tsx | 1 - 7 files changed, 660 insertions(+), 32 deletions(-) create mode 100644 apps/debugger-ios/src/screens/ChatHistoryTest.tsx create mode 100644 apps/debugger-ios/src/unistyles.config.ts diff --git a/apps/debugger-ios/package.json b/apps/debugger-ios/package.json index 5b9818e..4187f3c 100644 --- a/apps/debugger-ios/package.json +++ b/apps/debugger-ios/package.json @@ -6,13 +6,14 @@ "start": "bunx expo start --port 8082 --host lan", "ios": "RCT_METRO_PORT=8082 bunx expo run:ios", "web": "bunx expo start --web --port 8082", - "dev": "RCT_METRO_PORT=8082 bunx concurrently --kill-others \"bun run start\" \"sleep 5 && echo '🔧 Metro port: 8082 (RCT_METRO_PORT)' && bun run ios\"", + "dev": "RCT_METRO_PORT=8082 bunx concurrently \"bun run start\" \"sleep 5 && echo '🔧 Metro port: 8082 (RCT_METRO_PORT)' && bun run ios\"", "lint": "eslint .", "setup": "node setup.js" }, "dependencies": { "@babel/runtime": "^7.28.4", "@darkresearch/debug-components": "workspace:*", + "@legendapp/list": "^2.0.16", "streamdown-rn": "workspace:*", "@expo-google-fonts/geist": "^0.4.1", "@expo/metro-runtime": "~6.1.2", diff --git a/apps/debugger-ios/src/App.tsx b/apps/debugger-ios/src/App.tsx index 6236290..45b1250 100644 --- a/apps/debugger-ios/src/App.tsx +++ b/apps/debugger-ios/src/App.tsx @@ -1,35 +1,25 @@ import { useState, useEffect } from 'react'; -import { View, Text, ScrollView } from 'react-native'; +import { View, Text, ScrollView, Pressable } from 'react-native'; import { StyleSheet, UnistylesRuntime } from 'react-native-unistyles'; import { StreamdownRN } from 'streamdown-rn'; import { debugComponentRegistry } from '@darkresearch/debug-components'; +import { ChatHistoryTest } from './screens/ChatHistoryTest'; const WS_URL = 'ws://localhost:3001'; -// Configure Unistyles -StyleSheet.configure({ - themes: { - dark: { - colors: { - bg: '#1a1a1a', - statusBg: '#141414', - border: '#333', - text: '#888', - placeholder: '#666', - connected: '#4ade80', - }, - }, - }, - settings: { - initialTheme: 'dark', - }, -}); +type AppMode = 'debugger' | 'chat-history'; + +// Note: Unistyles is configured in unistyles.config.ts (imported by index.js) export default function App() { + const [mode, setMode] = useState('debugger'); const [content, setContent] = useState(''); const [connected, setConnected] = useState(false); useEffect(() => { + // Only connect to WebSocket in debugger mode + if (mode !== 'debugger') return; + let ws: WebSocket | null = null; let reconnectTimeout: NodeJS.Timeout | null = null; let hasConnectedOnce = false; @@ -83,8 +73,14 @@ export default function App() { if (reconnectTimeout) clearTimeout(reconnectTimeout); ws?.close(); }; - }, []); + }, [mode]); + // Chat History Test Mode + if (mode === 'chat-history') { + return setMode('debugger')} />; + } + + // Default: Debugger Mode return ( @@ -92,6 +88,12 @@ export default function App() { {connected ? 'Connected to debugger' : 'Waiting for debugger...'} + setMode('chat-history')} + style={styles.modeButton} + > + 💬 Chat Test + ) : ( - - Waiting for content from web debugger... - + + + Waiting for content from web debugger... + + + Or tap "💬 Chat Test" above to test chat history rendering + + )} @@ -135,19 +142,40 @@ const styles = StyleSheet.create((theme) => ({ color: theme.colors.connected, }, statusText: { + flex: 1, color: theme.colors.text, fontSize: 14, }, + modeButton: { + backgroundColor: '#2a2a2a', + paddingHorizontal: 12, + paddingVertical: 6, + borderRadius: 16, + }, + modeButtonText: { + color: '#fff', + fontSize: 12, + fontWeight: '500', + }, content: { flex: 1, }, contentContainer: { padding: 16, }, + placeholderContainer: { + alignItems: 'center', + marginTop: 40, + gap: 12, + }, placeholder: { color: theme.colors.placeholder, fontSize: 16, textAlign: 'center', - marginTop: 40, + }, + hint: { + color: theme.colors.text, + fontSize: 14, + textAlign: 'center', }, })); diff --git a/apps/debugger-ios/src/index.js b/apps/debugger-ios/src/index.js index eefb082..678d5a8 100644 --- a/apps/debugger-ios/src/index.js +++ b/apps/debugger-ios/src/index.js @@ -1,3 +1,4 @@ +import './unistyles.config'; // Must be first - configures Unistyles before any StyleSheet.create() import { registerRootComponent } from 'expo'; import App from './App'; diff --git a/apps/debugger-ios/src/screens/ChatHistoryTest.tsx b/apps/debugger-ios/src/screens/ChatHistoryTest.tsx new file mode 100644 index 0000000..7687037 --- /dev/null +++ b/apps/debugger-ios/src/screens/ChatHistoryTest.tsx @@ -0,0 +1,574 @@ +import { useState, useCallback } from 'react'; +import { View, Text, Pressable, TextInput } from 'react-native'; +import { StyleSheet, UnistylesRuntime } from 'react-native-unistyles'; +import { LegendList } from '@legendapp/list'; +import { StreamdownRN } from 'streamdown-rn'; +import { debugComponentRegistry } from '@darkresearch/debug-components'; + +type Message = { + id: string; + role: 'user' | 'assistant'; + content: string; + isStreaming?: boolean; +}; + +// Pre-populated chat history (simulating loading from database) +const INITIAL_MESSAGES: Message[] = [ + { + id: '1', + role: 'user', + content: 'What is React Native?', + }, + { + id: '2', + role: 'assistant', + content: `### React Native + +React Native is a **framework** for building native mobile apps using JavaScript and React. + +**Key Features:** +- Cross-platform development +- Native performance +- Large ecosystem +- Hot reloading + +It was created by Facebook and is now used by companies like: +- Instagram +- Airbnb +- Discord +- Shopify`, + }, + { + id: '3', + role: 'user', + content: 'How does it compare to Flutter?', + }, + { + id: '4', + role: 'assistant', + content: `### React Native vs Flutter + +**When to choose React Native:** +- You have JavaScript/React experience +- You need to share code with web +- You want native look and feel + +**When to choose Flutter:** +- You want pixel-perfect UI control +- Performance is critical +- You're starting fresh +`, + }, + { + id: '5', + role: 'user', + content: 'Can you show me a code example?', + }, + { + id: '6', + role: 'assistant', + content: `### Simple React Native Component + +Here's a basic example: + +\`\`\`typescript +import { View, Text, StyleSheet } from 'react-native'; + +export function Greeting({ name }: { name: string }) { + return ( + + + Hello, {name}! + + + ); +} + +const styles = StyleSheet.create({ + container: { + padding: 16, + backgroundColor: '#f0f0f0', + borderRadius: 8, + }, + text: { + fontSize: 18, + fontWeight: 'bold', + }, +}); +\`\`\` + +This creates a simple greeting component with styling!`, + }, + { + id: '7', + role: 'user', + content: 'What about state management?', + }, + { + id: '8', + role: 'assistant', + content: `### State Management in React Native + +There are several popular options: + +**Built-in:** +- \`useState\` - Simple local state +- \`useReducer\` - Complex local state +- \`Context API\` - Prop drilling solution + +**Third-party libraries:** + +1. **Redux** - The classic choice + - Predictable state + - Great devtools + - Large ecosystem + +2. **Zustand** - Modern and simple + - Minimal boilerplate + - TypeScript friendly + - Small bundle size + +3. **Legend State** - High performance + - Fine-grained reactivity + - Persistence built-in + - Great for large apps + +4. **Jotai** - Atomic approach + - Bottom-up state + - Minimal API + - Good for React devs`, + }, + { + id: '9', + role: 'user', + content: 'Tell me about navigation', + }, + { + id: '10', + role: 'assistant', + content: `### Navigation in React Native + +The most popular solution is **React Navigation**. + +**Installation:** +\`\`\`bash +npm install @react-navigation/native +npm install @react-navigation/stack +\`\`\` + +**Navigator Types:** + +- **Stack Navigator** - Screen stacking +- **Tab Navigator** - Bottom/top tabs +- **Drawer Navigator** - Side menu +- **Native Stack** - Native animations + +**Example Setup:** + +\`\`\`typescript +import { NavigationContainer } from '@react-navigation/native'; +import { createStackNavigator } from '@react-navigation/stack'; + +const Stack = createStackNavigator(); + +function App() { + return ( + + + + + + + ); +} +\`\`\``, + }, + // Add more messages to test scrolling with many items + { + id: '11', + role: 'user', + content: 'What about animations?', + }, + { + id: '12', + role: 'assistant', + content: `### Animations in React Native + +**Options:** + +1. **Animated API** (Built-in) + - Good for simple animations + - JS-driven + +2. **Reanimated** (Recommended) + - Runs on UI thread + - 60fps performance + - Gesture handling + +**Example with Reanimated:** + +\`\`\`typescript +import Animated, { + useSharedValue, + withSpring +} from 'react-native-reanimated'; + +function AnimatedBox() { + const offset = useSharedValue(0); + + return ( + + ); +} +\`\`\``, + }, + { + id: '13', + role: 'user', + content: 'How do I handle forms?', + }, + { + id: '14', + role: 'assistant', + content: `### Form Handling in React Native + +**Libraries:** +- \`react-hook-form\` - Best performance +- \`formik\` - Popular, feature-rich +- \`react-native-form-validator\` - Simple validation + +**react-hook-form Example:** + +\`\`\`typescript +import { useForm, Controller } from 'react-hook-form'; +import { TextInput, Button } from 'react-native'; + +function LoginForm() { + const { control, handleSubmit } = useForm(); + + const onSubmit = (data) => { + console.log(data); + }; + + return ( + <> + ( + + )} + /> +