Files
paseo/packages/voice-mobile/components/artifact-drawer.tsx
T
0f1450381a feat: implement realtime audio with VAD for Android
- Install react-native-vad and expo-audio-studio for voice detection
- Create use-realtime-audio hook for continuous recording + VAD segmentation
- Add Android FOREGROUND_SERVICE permissions for background mic access
- Update UI components with Lucide icons and markdown rendering
- Add npm overrides to resolve peer dependency conflicts with Expo SDK 54
- Integrate realtime mode toggle with pulse animation for speech detection

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2025-10-21 21:33:14 +02:00

128 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { View, Text, ScrollView, Pressable, Modal } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useEffect } from 'react';
export interface Artifact {
id: string;
type: 'markdown' | 'diff' | 'image' | 'code';
title: string;
content: string;
isBase64: boolean;
}
interface ArtifactDrawerProps {
artifact: Artifact | null;
onClose: () => void;
}
export function ArtifactDrawer({ artifact, onClose }: ArtifactDrawerProps) {
useEffect(() => {
if (!artifact) return;
console.log('[ArtifactDrawer] Showing artifact:', artifact.id, artifact.type, artifact.title);
}, [artifact]);
if (!artifact) {
return null;
}
// Decode content if base64
const content = artifact.isBase64 ? atob(artifact.content) : artifact.content;
// Type badge colors
const typeColors = {
markdown: 'bg-blue-600',
diff: 'bg-purple-600',
image: 'bg-green-600',
code: 'bg-orange-600',
};
return (
<Modal
visible={!!artifact}
animationType="slide"
presentationStyle="pageSheet"
onRequestClose={onClose}
>
<SafeAreaView edges={['top', 'bottom']} className="flex-1 bg-black">
{/* Header */}
<View className="pb-4 px-4 border-b border-zinc-800">
<View className="flex-row items-center justify-between">
<View className="flex-1 mr-4">
<Text className="text-white text-xl font-bold" numberOfLines={2}>
{artifact.title}
</Text>
</View>
<View className="flex-row items-center gap-2">
<View className={`${typeColors[artifact.type]} px-3 py-1 rounded-full`}>
<Text className="text-white text-xs font-semibold uppercase">
{artifact.type}
</Text>
</View>
<Pressable
onPress={onClose}
className="bg-zinc-800 w-10 h-10 rounded-full items-center justify-center"
>
<Text className="text-white text-xl font-bold">×</Text>
</Pressable>
</View>
</View>
</View>
{/* Content */}
<ScrollView className="flex-1" contentContainerClassName="p-4">
{artifact.type === 'image' ? (
<View className="items-center justify-center">
<Text className="text-zinc-400 text-sm">
Image viewing not yet implemented
</Text>
<Text className="text-zinc-600 text-xs mt-2">
Base64 image data received
</Text>
</View>
) : (
<View className="bg-zinc-900 rounded-lg p-4 border border-zinc-800">
<ScrollView horizontal showsHorizontalScrollIndicator={true}>
<Text
className="text-zinc-300 text-sm font-mono"
style={{ fontFamily: 'monospace' }}
>
{content}
</Text>
</ScrollView>
</View>
)}
{/* Metadata */}
<View className="mt-4 bg-zinc-900 rounded-lg p-3 border border-zinc-800">
<Text className="text-zinc-500 text-xs font-semibold mb-2">METADATA</Text>
<View className="space-y-1">
<View className="flex-row">
<Text className="text-zinc-500 text-xs w-20">ID:</Text>
<Text className="text-zinc-400 text-xs flex-1 font-mono">
{artifact.id}
</Text>
</View>
<View className="flex-row">
<Text className="text-zinc-500 text-xs w-20">Type:</Text>
<Text className="text-zinc-400 text-xs">{artifact.type}</Text>
</View>
<View className="flex-row">
<Text className="text-zinc-500 text-xs w-20">Encoding:</Text>
<Text className="text-zinc-400 text-xs">
{artifact.isBase64 ? 'Base64' : 'Plain text'}
</Text>
</View>
<View className="flex-row">
<Text className="text-zinc-500 text-xs w-20">Size:</Text>
<Text className="text-zinc-400 text-xs">
{content.length.toLocaleString()} characters
</Text>
</View>
</View>
</View>
</ScrollView>
</SafeAreaView>
</Modal>
);
}