mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-05 03:02:56 +00:00
dev day #89
This commit is contained in:
@@ -5,7 +5,8 @@ import HorizontalScroller from '../ui/HorizontalScroller';
|
||||
import { useClubTheme } from '../../contexts/ClubThemeContext';
|
||||
import { usePublicSettings } from '../../hooks/usePublicSettings';
|
||||
import { getCachedYouTube, YouTubeVideo } from '../../services/youtube';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import CommentsSection from '../comments/CommentsSection';
|
||||
|
||||
type Props = {
|
||||
videos?: string[];
|
||||
@@ -46,6 +47,7 @@ const VideosSection: React.FC<Props> = ({ videos, variant }) => {
|
||||
const [yt, setYt] = useState<YouTubeVideo[]>([]);
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [selectedVideo, setSelectedVideo] = useState<RenderItem | null>(null);
|
||||
const titleOverrides: Record<string, string> = (settings as any)?.videos_title_overrides || {};
|
||||
// If admin explicitly disabled, respect it. Otherwise default to ON when there are manual videos configured
|
||||
// or when a YouTube URL is present for auto mode.
|
||||
const hasManualConfigured = Boolean((settings as any)?.videos_items?.length || (settings as any)?.videos?.length);
|
||||
@@ -64,13 +66,14 @@ const VideosSection: React.FC<Props> = ({ videos, variant }) => {
|
||||
// Default to 6 items on homepage unless overridden by settings (max 12)
|
||||
const limit = Math.max(1, Math.min(12, settings?.videos_limit ?? 6));
|
||||
const youtubeUrl = (settings as any)?.youtube_url || (settings as any)?.social_youtube || null;
|
||||
const titleOverrides: Record<string, string> = (settings as any)?.videos_title_overrides || {};
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (isOpen) onClose();
|
||||
setSelectedVideo(null);
|
||||
} catch {}
|
||||
}, [style, isOpen, onClose]);
|
||||
}, [style]);
|
||||
|
||||
useEffect(() => {
|
||||
let canceled = false;
|
||||
@@ -97,7 +100,7 @@ const VideosSection: React.FC<Props> = ({ videos, variant }) => {
|
||||
if (source === 'auto') {
|
||||
return (yt || []).slice(0, limit).map(v => ({
|
||||
key: v.video_id,
|
||||
title: v.title,
|
||||
title: (titleOverrides?.[v.video_id]?.trim()) || v.title,
|
||||
embedUrl: toEmbed(v.video_id),
|
||||
thumbnail: v.thumbnail_url,
|
||||
date: v.published_date,
|
||||
@@ -126,7 +129,7 @@ const VideosSection: React.FC<Props> = ({ videos, variant }) => {
|
||||
};
|
||||
});
|
||||
return (manual.length ? manual : legacy).slice(0, limit);
|
||||
}, [source, yt, settings?.videos_items, settings?.videos, videos, limit]);
|
||||
}, [source, yt, settings?.videos_items, settings?.videos, videos, limit, titleOverrides]);
|
||||
|
||||
if (!enabled || items.length === 0) return null;
|
||||
|
||||
@@ -290,17 +293,41 @@ const VideosSection: React.FC<Props> = ({ videos, variant }) => {
|
||||
<ModalCloseButton color="white" size="lg" bg="blackAlpha.600" _hover={{ bg: 'blackAlpha.700' }} borderRadius="full" zIndex={2} />
|
||||
<ModalBody p={0}>
|
||||
{selectedVideo && (
|
||||
<AspectRatio ratio={16 / 9} maxH="90vh">
|
||||
<iframe
|
||||
src={`${selectedVideo.embedUrl}?autoplay=1&vq=hd1080&rel=0&modestbranding=1&playsinline=1`}
|
||||
title={selectedVideo.title}
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowFullScreen
|
||||
loading="lazy"
|
||||
referrerPolicy="strict-origin-when-cross-origin"
|
||||
style={{ borderRadius: '8px' }}
|
||||
/>
|
||||
</AspectRatio>
|
||||
<Box>
|
||||
<AspectRatio ratio={16 / 9} maxH="90vh">
|
||||
<iframe
|
||||
src={`${selectedVideo.embedUrl}?autoplay=1&vq=hd1080&rel=0&modestbranding=1&playsinline=1`}
|
||||
title={selectedVideo.title}
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowFullScreen
|
||||
loading="lazy"
|
||||
referrerPolicy="strict-origin-when-cross-origin"
|
||||
style={{ borderRadius: '8px' }}
|
||||
/>
|
||||
</AspectRatio>
|
||||
<Box bg={useColorModeValue('white', 'gray.800')} p={4} borderRadius="md" mt={2}>
|
||||
<HStack justify="space-between" align="start">
|
||||
<VStack align="start" flex={1}>
|
||||
<Text fontWeight="bold" fontSize="lg">{selectedVideo.title}</Text>
|
||||
{selectedVideo.date && (
|
||||
<Text color={useColorModeValue('gray.600', 'gray.300')} fontSize="sm">
|
||||
{new Date(selectedVideo.date).toLocaleDateString('cs-CZ', { year: 'numeric', month: 'long', day: 'numeric' })}
|
||||
</Text>
|
||||
)}
|
||||
</VStack>
|
||||
{selectedVideo.videoId && (
|
||||
<Link href={`https://www.youtube.com/watch?v=${selectedVideo.videoId}`} isExternal>
|
||||
<Button size="sm" colorScheme="red" leftIcon={<Icon as={FaYoutube} />}>Otevřít na YouTube</Button>
|
||||
</Link>
|
||||
)}
|
||||
</HStack>
|
||||
{selectedVideo.videoId && (
|
||||
<Box mt={4}>
|
||||
<CommentsSection targetType="youtube_video" targetId={selectedVideo.videoId} />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
@@ -331,17 +358,41 @@ const VideosSection: React.FC<Props> = ({ videos, variant }) => {
|
||||
<ModalCloseButton color="white" size="lg" bg="blackAlpha.600" _hover={{ bg: 'blackAlpha.700' }} borderRadius="full" zIndex={2} />
|
||||
<ModalBody p={0}>
|
||||
{selectedVideo && (
|
||||
<AspectRatio ratio={16 / 9} maxH="90vh">
|
||||
<iframe
|
||||
src={`${selectedVideo.embedUrl}?autoplay=1&vq=hd1080&rel=0&modestbranding=1&playsinline=1`}
|
||||
title={selectedVideo.title}
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowFullScreen
|
||||
loading="lazy"
|
||||
referrerPolicy="strict-origin-when-cross-origin"
|
||||
style={{ borderRadius: '8px' }}
|
||||
/>
|
||||
</AspectRatio>
|
||||
<Box>
|
||||
<AspectRatio ratio={16 / 9} maxH="90vh">
|
||||
<iframe
|
||||
src={`${selectedVideo.embedUrl}?autoplay=1&vq=hd1080&rel=0&modestbranding=1&playsinline=1`}
|
||||
title={selectedVideo.title}
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowFullScreen
|
||||
loading="lazy"
|
||||
referrerPolicy="strict-origin-when-cross-origin"
|
||||
style={{ borderRadius: '8px' }}
|
||||
/>
|
||||
</AspectRatio>
|
||||
<Box bg={useColorModeValue('white', 'gray.800')} p={4} borderRadius="md" mt={2}>
|
||||
<HStack justify="space-between" align="start">
|
||||
<VStack align="start" flex={1}>
|
||||
<Text fontWeight="bold" fontSize="lg">{selectedVideo.title}</Text>
|
||||
{selectedVideo.date && (
|
||||
<Text color={useColorModeValue('gray.600', 'gray.300')} fontSize="sm">
|
||||
{new Date(selectedVideo.date).toLocaleDateString('cs-CZ', { year: 'numeric', month: 'long', day: 'numeric' })}
|
||||
</Text>
|
||||
)}
|
||||
</VStack>
|
||||
{selectedVideo.videoId && (
|
||||
<Link href={`https://www.youtube.com/watch?v=${selectedVideo.videoId}`} isExternal>
|
||||
<Button size="sm" colorScheme="red" leftIcon={<Icon as={FaYoutube} />}>Otevřít na YouTube</Button>
|
||||
</Link>
|
||||
)}
|
||||
</HStack>
|
||||
{selectedVideo.videoId && (
|
||||
<Box mt={4}>
|
||||
<CommentsSection targetType="youtube_video" targetId={selectedVideo.videoId} />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
@@ -350,4 +401,4 @@ const VideosSection: React.FC<Props> = ({ videos, variant }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default VideosSection;
|
||||
export default React.memo(VideosSection);
|
||||
|
||||
Reference in New Issue
Block a user