unified-video-framework
Version:
Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more
302 lines (264 loc) • 7.63 kB
JSX
import React, { useRef } from 'react';
import { PortraitPlayerView } from '../PortraitPlayerView';
/**
* URL Routing Example for Portrait Player
*
* This demonstrates YouTube Shorts-style URL routing where:
* - Scrolling updates the URL without page reload
* - Browser back/forward buttons work seamlessly
* - Direct URL access loads the specific video
* - No page refreshes occur during navigation
*/
// Example video data
const sampleVideos = [
{
id: 'gP6Lqo9WUNk',
url: 'https://example.com/video1.mp4',
posterUrl: 'https://example.com/poster1.jpg',
title: 'Amazing Nature Scene',
description: 'Beautiful footage of nature #nature #wildlife',
hashtags: ['nature', 'wildlife', 'beautiful'],
creator: {
name: 'Nature Channel',
avatar: 'https://example.com/avatar1.jpg',
verified: true,
followers: 125000,
},
likes: 12500,
comments: 342,
shares: 89,
views: 250000,
},
{
id: 'xYz123AbCd',
url: 'https://example.com/video2.mp4',
posterUrl: 'https://example.com/poster2.jpg',
title: 'Cooking Tutorial',
description: 'Quick and easy recipe #cooking #food',
hashtags: ['cooking', 'food', 'recipe'],
creator: {
name: 'Chef Master',
avatar: 'https://example.com/avatar2.jpg',
verified: true,
followers: 89000,
},
likes: 8900,
comments: 234,
shares: 56,
views: 180000,
},
{
id: 'qWe456RtY',
url: 'https://example.com/video3.mp4',
posterUrl: 'https://example.com/poster3.jpg',
title: 'Dance Performance',
description: 'Epic dance moves #dance #performance',
hashtags: ['dance', 'performance', 'talent'],
creator: {
name: 'Dance Studio',
avatar: 'https://example.com/avatar3.jpg',
verified: false,
followers: 45000,
},
likes: 15000,
comments: 567,
shares: 123,
views: 320000,
},
];
/**
* Example 1: Path-based routing (like YouTube Shorts)
* URL: /shorts/gP6Lqo9WUNk
*/
export const PathBasedRoutingExample = () => {
const playerRef = useRef(null);
return (
<PortraitPlayerView
videos={sampleVideos}
playerRef={playerRef}
// Enable URL routing
enableUrlRouting={true}
urlPattern="path"
baseUrl="/shorts"
// Optional: Custom URL generator
getVideoUrl={(video) => `/shorts/${video.id}`}
// Optional: Start with specific video from URL
initialVideoId={undefined} // Auto-detects from URL
onVideoChange={(index, video) => {
console.log('Video changed:', video.id);
// URL is automatically updated!
}}
onLike={(video) => console.log('Liked:', video.id)}
onComment={(video) => console.log('Comment on:', video.id)}
onShare={(video) => {
const url = `${window.location.origin}/shorts/${video.id}`;
navigator.clipboard.writeText(url);
alert(`Link copied: ${url}`);
}}
/>
);
};
/**
* Example 2: Hash-based routing (for single-page apps)
* URL: #/video/gP6Lqo9WUNk
*/
export const HashBasedRoutingExample = () => {
const playerRef = useRef(null);
return (
<PortraitPlayerView
videos={sampleVideos}
playerRef={playerRef}
// Enable hash-based routing
enableUrlRouting={true}
urlPattern="hash"
baseUrl="/video"
onVideoChange={(index, video) => {
console.log('Current video:', video.id);
console.log('Current URL:', window.location.hash);
}}
/>
);
};
/**
* Example 3: Custom URL format
* URL: /watch/gP6Lqo9WUNk?mode=portrait
*/
export const CustomUrlFormatExample = () => {
const playerRef = useRef(null);
return (
<PortraitPlayerView
videos={sampleVideos}
playerRef={playerRef}
enableUrlRouting={true}
urlPattern="path"
baseUrl="/watch"
// Custom URL generator with query params
getVideoUrl={(video) => `/watch/${video.id}?mode=portrait`}
onVideoChange={(index, video) => {
// Update page title for better SEO
document.title = `${video.title || 'Video'} - Portrait Player`;
}}
/>
);
};
/**
* Example 4: Without URL routing (default behavior)
*/
export const NoRoutingExample = () => {
return (
<PortraitPlayerView
videos={sampleVideos}
// enableUrlRouting is false by default
onVideoChange={(index, video) => {
console.log('Video changed (no URL update):', video.id);
}}
/>
);
};
/**
* Example 5: Server-side rendering with hydration
*/
export const SSRExample = ({ videoId }) => {
const playerRef = useRef(null);
return (
<PortraitPlayerView
videos={sampleVideos}
playerRef={playerRef}
enableUrlRouting={true}
urlPattern="path"
baseUrl="/shorts"
// Start with specific video for SSR
initialVideoId={videoId}
onVideoChange={(index, video) => {
console.log('Hydrated and changed:', video.id);
}}
/>
);
};
/**
* Example 6: Programmatic navigation with URL sync
*/
export const ProgrammaticNavigationExample = () => {
const playerRef = useRef(null);
const navigateToVideo = (videoId) => {
const index = sampleVideos.findIndex(v => v.id === videoId);
if (index !== -1) {
playerRef.current?.goTo(index);
// URL will automatically update!
}
};
return (
<div>
<div style={{ padding: 20, background: '#f0f0f0' }}>
<h3>Quick Navigation</h3>
{sampleVideos.map((video) => (
<button
key={video.id}
onClick={() => navigateToVideo(video.id)}
style={{ margin: 5, padding: '8px 16px' }}
>
Go to {video.title}
</button>
))}
</div>
<PortraitPlayerView
videos={sampleVideos}
playerRef={playerRef}
enableUrlRouting={true}
urlPattern="path"
baseUrl="/shorts"
/>
</div>
);
};
/**
* Example 7: React Router Integration
*/
export const ReactRouterExample = () => {
const playerRef = useRef(null);
return (
<PortraitPlayerView
videos={sampleVideos}
playerRef={playerRef}
// Use hash-based routing when using React Router
enableUrlRouting={true}
urlPattern="hash"
baseUrl="/player"
onVideoChange={(index, video) => {
// Analytics tracking
if (window.gtag) {
window.gtag('event', 'video_view', {
video_id: video.id,
video_title: video.title,
});
}
}}
/>
);
};
/**
* Example 8: Next.js App Router Integration
*/
export const NextJsExample = () => {
const playerRef = useRef(null);
return (
<PortraitPlayerView
videos={sampleVideos}
playerRef={playerRef}
enableUrlRouting={true}
urlPattern="path"
baseUrl="/shorts"
onVideoChange={(index, video) => {
// Update page metadata
if (typeof window !== 'undefined') {
document.title = `${video.title} - My App`;
// Update meta tags for social sharing
const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) {
metaDescription.setAttribute('content', video.description || '');
}
}
}}
/>
);
};