From e57072e917c60b0c74c53f226b9d93506a458385 Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Thu, 28 Aug 2025 11:39:38 +0000 Subject: [PATCH] Add dedicated video pages and related content recommendations Introduce a new route for individual video pages, enabling direct navigation to videos. The video cards now link to this new page. Additionally, a new `VideoPage` component is added to display video details, track plays, and show recommended videos similar to YouTube's interface. Replit-Commit-Author: Agent Replit-Commit-Session-Id: d7424866-83d1-4486-a212-ac12b4c7becf Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/d7424866-83d1-4486-a212-ac12b4c7becf/gfjV9kW --- client/src/App.tsx | 2 + client/src/components/video-card.tsx | 4 +- client/src/pages/VideoPage.tsx | 280 +++++++++++++++++++++++++++ 3 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 client/src/pages/VideoPage.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index 77d7084..db59e06 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -4,6 +4,7 @@ import { QueryClientProvider } from "@tanstack/react-query"; import { Toaster } from "@/components/ui/toaster"; import { TooltipProvider } from "@/components/ui/tooltip"; import Home from "@/pages/home"; +import VideoPage from "@/pages/VideoPage"; import Admin from "@/pages/admin"; import BunnyAdminPage from "@/pages/BunnyAdminPage"; import NotFound from "@/pages/not-found"; @@ -12,6 +13,7 @@ function Router() { return ( + diff --git a/client/src/components/video-card.tsx b/client/src/components/video-card.tsx index ce86daf..f8c59c8 100644 --- a/client/src/components/video-card.tsx +++ b/client/src/components/video-card.tsx @@ -49,7 +49,7 @@ export default function VideoCard({ video, onClick }: VideoCardProps) { {/* Simple thumbnail with fallback - no HLS loading until needed */}
onClick(video)} + onClick={() => window.location.href = `/video/${video.id}`} >

onClick(video)} + onClick={() => window.location.href = `/video/${video.id}`} data-testid={`text-title-${video.id}`} > {video.title} diff --git a/client/src/pages/VideoPage.tsx b/client/src/pages/VideoPage.tsx new file mode 100644 index 0000000..e6f86b0 --- /dev/null +++ b/client/src/pages/VideoPage.tsx @@ -0,0 +1,280 @@ +import { useState, useEffect } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { useRoute } from "wouter"; +import { type Video } from "@shared/schema"; +// Helper functions +const formatViews = (views: number): string => { + if (views >= 1000000) return `${(views / 1000000).toFixed(1)}M`; + if (views >= 1000) return `${(views / 1000).toFixed(1)}K`; + return views.toString(); +}; + +const formatDuration = (seconds: number): string => { + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const secs = seconds % 60; + + if (hours > 0) { + return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; + } + return `${minutes}:${secs.toString().padStart(2, '0')}`; +}; + +const formatDate = (date: Date | string): string => { + const d = typeof date === 'string' ? new Date(date) : date; + return d.toLocaleDateString('sl-SI', { + year: 'numeric', + month: 'long', + day: 'numeric' + }); +}; +import { Button } from "@/components/ui/button"; +import { Share2, X, Edit3 } from "lucide-react"; +import { apiRequest } from "@/lib/queryClient"; +import { + FacebookShareButton, + TwitterShareButton, + WhatsappShareButton, + FacebookIcon, + TwitterIcon, + WhatsappIcon, +} from "react-share"; + +interface VideosResponse { + videos: Video[]; + total: number; + hasMore: boolean; +} + +export default function VideoPage() { + const [, params] = useRoute("/video/:id"); + const videoId = params?.id; + const [showShareMenu, setShowShareMenu] = useState(false); + + // Fetch current video + const { data: currentVideo, isLoading: videoLoading } = useQuery