Live video on the AT Protocol

Merge branch 'natb/reporting-interface' into eli/reporting

+123 -2
+10
js/app/components/mobile/desktop-ui.tsx
··· 32 32 useSharedValue, 33 33 withTiming, 34 34 } from "react-native-reanimated"; 35 + import ReportModal from "./report-modal"; 35 36 import { useResponsiveLayout } from "./useResponsiveLayout"; 36 37 37 38 const { borders, colors, gap, h, layout, position, w, px, py, r, p, bg, text } = ··· 189 190 const { doSetIngestCamera } = useCameraToggle(); 190 191 const avatars = useAvatars(profile?.did ? [profile?.did] : []); 191 192 const { safeAreaInsets, shouldShowFloatingMetrics } = useResponsiveLayout(); 193 + 194 + const [reporting, setReporting] = useState(false); 192 195 193 196 const fullscreen = usePlayerStore((state) => state.fullscreen); 194 197 const setFullscreen = usePlayerStore((state) => state.setFullscreen); ··· 454 457 onDone={() => { 455 458 setShowCountdown(false); 456 459 }} 460 + /> 461 + 462 + <ReportModal 463 + open={reporting} 464 + onOpenChange={setReporting} 465 + title={`Report ${profile?.handle}`} 466 + onSubmit={() => {}} 457 467 /> 458 468 459 469 <Toast
+111
js/app/components/mobile/report-modal.tsx
··· 1 + import { 2 + Button, 3 + Dialog, 4 + DialogFooter, 5 + ModalContent, 6 + Text, 7 + Textarea, 8 + zero, 9 + } from "@streamplace/components"; 10 + import { CheckCircle, Circle } from "@tamagui/lucide-icons"; 11 + import React, { useState } from "react"; 12 + import { TouchableOpacity, View } from "react-native"; 13 + 14 + const REPORT_REASONS = [ 15 + "Terrorism", 16 + "Nudity or Sexually Explicit", 17 + "Hateful Conduct", 18 + "Bullying or Harassment", 19 + "Violence or Gore", 20 + "Self-Harm", 21 + "Spam, Scams, Bots, or Tampering", 22 + "Miscategorized Content", 23 + "Missing or Incorrect Content Classification Label", 24 + "Search", 25 + ]; 26 + 27 + interface ReportModalProps { 28 + open: boolean; 29 + onOpenChange: (open: boolean) => void; 30 + onSubmit: (reason: string) => void; 31 + title?: string; 32 + description?: string; 33 + } 34 + 35 + export const ReportModal: React.FC<ReportModalProps> = ({ 36 + open, 37 + onOpenChange, 38 + onSubmit, 39 + title = "Report", 40 + description = "Why are you submitting this report?", 41 + }) => { 42 + const [selectedReason, setSelectedReason] = useState<string | null>(null); 43 + 44 + const handleCancel = () => { 45 + setSelectedReason(null); 46 + onOpenChange(false); 47 + }; 48 + 49 + const handleSubmit = () => { 50 + if (selectedReason) { 51 + onSubmit(selectedReason); 52 + setSelectedReason(null); 53 + onOpenChange(false); 54 + } 55 + }; 56 + 57 + return ( 58 + <Dialog 59 + open={open} 60 + onOpenChange={onOpenChange} 61 + title={title} 62 + description={description} 63 + showCloseButton 64 + variant="default" 65 + size="md" 66 + dismissible={false} 67 + position="center" 68 + > 69 + <ModalContent style={[zero.pb[2]]}> 70 + {REPORT_REASONS.map((reason) => ( 71 + <TouchableOpacity 72 + key={reason} 73 + onPress={() => setSelectedReason(reason)} 74 + style={[ 75 + zero.layout.flex.row, 76 + zero.gap.all[2], 77 + zero.py[1], 78 + zero.px[2], 79 + zero.borderRadius[8], 80 + zero.layout.flex.alignCenter, 81 + ]} 82 + > 83 + <View> 84 + {selectedReason === reason ? <CheckCircle /> : <Circle />} 85 + </View> 86 + <Text>{reason}</Text> 87 + </TouchableOpacity> 88 + ))} 89 + 90 + <View style={[zero.pb[4], zero.mt[4], zero.px[2]]}> 91 + <Text style={[zero.mb[2]]}>Additional Comments (optional)</Text> 92 + <Textarea maxLength={500} numberOfLines={2} /> 93 + </View> 94 + </ModalContent> 95 + <DialogFooter> 96 + <Button variant="secondary" onPress={handleCancel}> 97 + <Text>Cancel</Text> 98 + </Button> 99 + <Button 100 + variant="primary" 101 + onPress={handleSubmit} 102 + disabled={!selectedReason} 103 + > 104 + Submit 105 + </Button> 106 + </DialogFooter> 107 + </Dialog> 108 + ); 109 + }; 110 + 111 + export default ReportModal;
+1 -1
js/components/src/components/ui/dialog.tsx
··· 254 254 255 255 // Dialog Close Icon component (Lucide X) 256 256 const DialogCloseIcon = () => { 257 - return <ThemedX size="md" variant="muted" />; 257 + return <ThemedX size="md" variant="default" />; 258 258 }; 259 259 260 260 // Create theme-aware styles
+1
js/components/src/components/ui/index.ts
··· 14 14 export * from "./resizeable"; 15 15 export * from "./slider"; 16 16 export * from "./text"; 17 + export * from "./textarea"; 17 18 export * from "./toast"; 18 19 export * from "./view"; 19 20
-1
js/components/src/components/ui/primitives/modal.tsx
··· 334 334 padding: 16, 335 335 }, 336 336 content: { 337 - backgroundColor: "white", 338 337 borderRadius: 8, 339 338 overflow: "hidden", 340 339 },