Skip to content

Commit 3e2881f

Browse files
committed
Add VideoFeedDemo and update web support with mobile wrapper
1 parent cb680b7 commit 3e2881f

File tree

14 files changed

+1813
-149
lines changed

14 files changed

+1813
-149
lines changed

example/ActiveLayerLayoutDemo.tsx

Lines changed: 115 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import React, { useState } from 'react';
2-
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, StatusBar, Dimensions } from 'react-native';
1+
import React, { useState, useRef, useEffect } from 'react';
2+
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, StatusBar, Dimensions, Platform } from 'react-native';
33
import { CLDVideoLayer } from '../src/widgets/video/layer/CLDVideoLayer';
44
import { ButtonPosition, ButtonLayoutDirection } from '../src/widgets/video/layer/types';
55
import { Cloudinary } from '@cloudinary/url-gen';
6+
import { Ionicons } from '@expo/vector-icons';
67

78
interface ActiveLayerLayoutDemoProps {
89
onNavigateToYouTube?: () => void;
@@ -11,6 +12,56 @@ interface ActiveLayerLayoutDemoProps {
1112

1213
export const ActiveLayerLayoutDemo: React.FC<ActiveLayerLayoutDemoProps> = ({ onNavigateToYouTube, onBack }) => {
1314
const [currentExample, setCurrentExample] = useState('horizontal');
15+
const scrollViewRef = useRef<ScrollView>(null);
16+
17+
// Add mouse drag scrolling for web
18+
useEffect(() => {
19+
if (Platform.OS === 'web' && scrollViewRef.current) {
20+
const scrollElement = (scrollViewRef.current as any).getScrollableNode?.();
21+
if (scrollElement) {
22+
let isDown = false;
23+
let startX = 0;
24+
let scrollLeft = 0;
25+
26+
const handleMouseDown = (e: MouseEvent) => {
27+
isDown = true;
28+
scrollElement.style.cursor = 'grabbing';
29+
startX = e.pageX - scrollElement.offsetLeft;
30+
scrollLeft = scrollElement.scrollLeft;
31+
};
32+
33+
const handleMouseLeave = () => {
34+
isDown = false;
35+
scrollElement.style.cursor = 'grab';
36+
};
37+
38+
const handleMouseUp = () => {
39+
isDown = false;
40+
scrollElement.style.cursor = 'grab';
41+
};
42+
43+
const handleMouseMove = (e: MouseEvent) => {
44+
if (!isDown) return;
45+
e.preventDefault();
46+
const x = e.pageX - scrollElement.offsetLeft;
47+
const walk = (x - startX) * 2;
48+
scrollElement.scrollLeft = scrollLeft - walk;
49+
};
50+
51+
scrollElement.addEventListener('mousedown', handleMouseDown);
52+
scrollElement.addEventListener('mouseleave', handleMouseLeave);
53+
scrollElement.addEventListener('mouseup', handleMouseUp);
54+
scrollElement.addEventListener('mousemove', handleMouseMove);
55+
56+
return () => {
57+
scrollElement.removeEventListener('mousedown', handleMouseDown);
58+
scrollElement.removeEventListener('mouseleave', handleMouseLeave);
59+
scrollElement.removeEventListener('mouseup', handleMouseUp);
60+
scrollElement.removeEventListener('mousemove', handleMouseMove);
61+
};
62+
}
63+
}
64+
}, []);
1465

1566
// Create a sample video
1667
const cld = new Cloudinary({
@@ -246,25 +297,32 @@ export const ActiveLayerLayoutDemo: React.FC<ActiveLayerLayoutDemoProps> = ({ on
246297
{/* Professional Header */}
247298
<View style={styles.header}>
248299
<View style={styles.headerContent}>
249-
<View style={styles.brandSection}>
250-
<Text style={styles.brandTitle}>Cloudinary Video SDK</Text>
251-
<Text style={styles.brandSubtitle}>Interactive Button Layout Showcase</Text>
252-
</View>
253-
254300
{onBack && (
255301
<TouchableOpacity style={styles.backButton} onPress={onBack}>
256-
<Text style={styles.backButtonText}>← Back</Text>
302+
<Ionicons name="arrow-back" size={24} color="white" />
257303
</TouchableOpacity>
258304
)}
305+
306+
<View style={styles.brandSection}>
307+
<Text style={styles.brandTitle}>Cloudinary Video SDK</Text>
308+
<Text style={styles.brandSubtitle}>Interactive Button Layout Showcase</Text>
309+
</View>
259310
</View>
260311

261312
{/* Professional Example Selector */}
262-
<ScrollView
263-
horizontal
264-
showsHorizontalScrollIndicator={false}
265-
style={styles.examplesContainer}
266-
contentContainerStyle={styles.examplesContent}
267-
>
313+
<View style={styles.scrollViewWrapper}>
314+
<ScrollView
315+
ref={scrollViewRef}
316+
horizontal
317+
showsHorizontalScrollIndicator={false}
318+
style={styles.examplesContainer}
319+
contentContainerStyle={styles.examplesContent}
320+
scrollEnabled={true}
321+
nestedScrollEnabled={true}
322+
{...(Platform.OS === 'web' && {
323+
dataSet: { scrollable: 'true' }
324+
})}
325+
>
268326
{examples.map((example, index) => (
269327
<TouchableOpacity
270328
key={example.id}
@@ -298,7 +356,8 @@ export const ActiveLayerLayoutDemo: React.FC<ActiveLayerLayoutDemoProps> = ({ on
298356
</View>
299357
</TouchableOpacity>
300358
))}
301-
</ScrollView>
359+
</ScrollView>
360+
</View>
302361
</View>
303362

304363
{/* Enhanced Video Player */}
@@ -351,9 +410,9 @@ const styles = StyleSheet.create({
351410
},
352411
headerContent: {
353412
flexDirection: 'row',
354-
justifyContent: 'space-between',
355413
alignItems: 'flex-start',
356414
marginBottom: 24,
415+
gap: 16,
357416
},
358417
brandSection: {
359418
flex: 1,
@@ -374,34 +433,63 @@ const styles = StyleSheet.create({
374433
opacity: 0.9,
375434
},
376435
backButton: {
377-
backgroundColor: 'rgba(255, 255, 255, 0.1)',
378-
paddingHorizontal: 20,
379-
paddingVertical: 12,
380-
borderRadius: 25,
381-
borderWidth: 1,
382-
borderColor: 'rgba(255, 255, 255, 0.2)',
436+
width: 40,
437+
height: 40,
438+
borderRadius: 20,
439+
backgroundColor: 'rgba(255, 255, 255, 0.15)',
440+
justifyContent: 'center',
441+
alignItems: 'center',
442+
shadowColor: '#000',
443+
shadowOffset: { width: 0, height: 2 },
444+
shadowOpacity: 0.3,
445+
shadowRadius: 4,
446+
elevation: 5,
383447
},
384-
backButtonText: {
385-
color: '#ffffff',
386-
fontSize: 16,
387-
fontWeight: '600',
448+
scrollViewWrapper: {
449+
width: '100%',
450+
...(Platform.OS === 'web' && {
451+
overflow: 'visible' as any,
452+
}),
388453
},
389454
examplesContainer: {
390455
flexGrow: 0,
456+
height: 160,
457+
...(Platform.OS === 'web' ? {
458+
overflowX: 'auto' as any,
459+
overflowY: 'hidden' as any,
460+
WebkitOverflowScrolling: 'touch' as any,
461+
scrollbarWidth: 'thin' as any,
462+
scrollbarColor: 'rgba(255, 255, 255, 0.3) transparent' as any,
463+
cursor: 'grab' as any,
464+
userSelect: 'none' as any,
465+
touchAction: 'pan-x' as any,
466+
} : {
467+
flex: 1,
468+
}),
391469
},
392470
examplesContent: {
393471
paddingLeft: 4,
472+
paddingRight: 20,
473+
flexDirection: 'row',
474+
alignItems: 'center',
475+
...(Platform.OS === 'web' && {
476+
display: 'flex' as any,
477+
width: 'auto' as any,
478+
minWidth: '100%' as any,
479+
}),
394480
},
395481
exampleCard: {
396482
backgroundColor: 'rgba(255, 255, 255, 0.05)',
397483
borderRadius: 16,
398484
padding: 16,
399485
marginRight: 16,
400-
width: SCREEN_WIDTH * 0.7,
486+
width: Platform.OS === 'web' ? 320 : SCREEN_WIDTH * 0.7,
487+
minWidth: Platform.OS === 'web' ? 320 : undefined,
401488
borderWidth: 1,
402489
borderColor: 'rgba(255, 255, 255, 0.1)',
403490
flexDirection: 'row',
404491
alignItems: 'center',
492+
flexShrink: 0,
405493
},
406494
activeExampleCard: {
407495
backgroundColor: 'rgba(99, 102, 241, 0.2)',

0 commit comments

Comments
 (0)