This commit is contained in:
Tomas Dvorak
2025-11-11 10:29:30 +01:00
parent d5b4faea61
commit 8762bde4bf
139 changed files with 7240 additions and 2870 deletions
+78 -27
View File
@@ -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);