Restored to 'e087324c769fdb5e778619a362ad06f5e61119bf'

Replit-Restored-To: e087324c76
This commit is contained in:
sebastjanartic
2025-08-04 20:11:57 +00:00
parent 6593691ab3
commit 018f559617
11 changed files with 15 additions and 620 deletions
-171
View File
@@ -1,171 +0,0 @@
import { useState } from "react";
import { X, Copy, Facebook, Twitter, Link, Share2 } from "lucide-react";
import { type Video } from "@shared/schema";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useToast } from "@/hooks/use-toast";
interface ShareModalProps {
video: Video | null;
isOpen: boolean;
onClose: () => void;
}
export default function ShareModal({ video, isOpen, onClose }: ShareModalProps) {
const [copied, setCopied] = useState(false);
const { toast } = useToast();
if (!isOpen || !video) return null;
// Generate shareable URL
const shareUrl = `${window.location.origin}/video/${video.id}`;
const encodedUrl = encodeURIComponent(shareUrl);
const encodedTitle = encodeURIComponent(video.title);
const encodedDescription = encodeURIComponent(video.description || `Oglej si ta video: ${video.title}`);
// Social media URLs
const facebookUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}&quote=${encodedTitle}`;
const twitterUrl = `https://twitter.com/intent/tweet?url=${encodedUrl}&text=${encodedTitle}`;
const whatsappUrl = `https://wa.me/?text=${encodedTitle}%20${encodedUrl}`;
const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText(shareUrl);
setCopied(true);
toast({
title: "Povezava kopirana!",
description: "Povezava do videa je bila kopirana v odložišče.",
});
setTimeout(() => setCopied(false), 2000);
} catch (error) {
toast({
title: "Napaka",
description: "Povezave ni bilo mogoče kopirati.",
variant: "destructive",
});
}
};
const handleBackdropClick = (e: React.MouseEvent) => {
if (e.target === e.currentTarget) {
onClose();
}
};
return (
<div
className="fixed inset-0 bg-black/90 backdrop-blur-sm z-50 flex items-center justify-center p-4"
onClick={handleBackdropClick}
data-testid="modal-share"
>
<div className="relative w-full max-w-md bg-bunny-gray rounded-lg p-6">
<Button
variant="ghost"
size="icon"
onClick={onClose}
className="absolute top-4 right-4 text-bunny-muted hover:text-bunny-light"
data-testid="button-close-share"
>
<X className="w-5 h-5" />
</Button>
<div className="mb-6">
<div className="flex items-center space-x-3 mb-4">
<Share2 className="w-6 h-6 text-bunny-blue" />
<h2 className="text-xl font-bold text-bunny-light">Deli video</h2>
</div>
<div className="flex items-start space-x-3 mb-4">
<img
src={video.thumbnailUrl}
alt={video.title}
className="w-16 h-16 rounded-lg object-cover"
/>
<div className="flex-1 min-w-0">
<h3 className="text-sm font-medium text-bunny-light truncate">
{video.title}
</h3>
<p className="text-xs text-bunny-muted mt-1">
{Math.floor(video.duration / 60)}:{(video.duration % 60).toString().padStart(2, '0')} min
</p>
</div>
</div>
</div>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-bunny-light mb-2">
Povezava do videa
</label>
<div className="flex space-x-2">
<Input
value={shareUrl}
readOnly
className="bg-bunny-dark border-gray-600 text-bunny-light"
data-testid="input-share-url"
/>
<Button
onClick={copyToClipboard}
className={`px-4 ${copied ? 'bg-green-600 hover:bg-green-700' : 'bg-bunny-blue hover:bg-blue-600'} text-white`}
data-testid="button-copy-url"
>
{copied ? (
<>
<span className="text-sm">Kopirano!</span>
</>
) : (
<>
<Copy className="w-4 h-4 mr-2" />
<span className="text-sm">Kopiraj</span>
</>
)}
</Button>
</div>
</div>
<div>
<label className="block text-sm font-medium text-bunny-light mb-3">
Deli na socialnih omrežjih
</label>
<div className="grid grid-cols-3 gap-3">
<Button
asChild
className="bg-blue-600 hover:bg-blue-700 text-white flex flex-col items-center py-4 h-auto"
data-testid="button-share-facebook"
>
<a href={facebookUrl} target="_blank" rel="noopener noreferrer">
<Facebook className="w-6 h-6 mb-1" />
<span className="text-xs">Facebook</span>
</a>
</Button>
<Button
asChild
className="bg-sky-500 hover:bg-sky-600 text-white flex flex-col items-center py-4 h-auto"
data-testid="button-share-twitter"
>
<a href={twitterUrl} target="_blank" rel="noopener noreferrer">
<Twitter className="w-6 h-6 mb-1" />
<span className="text-xs">Twitter</span>
</a>
</Button>
<Button
asChild
className="bg-green-600 hover:bg-green-700 text-white flex flex-col items-center py-4 h-auto"
data-testid="button-share-whatsapp"
>
<a href={whatsappUrl} target="_blank" rel="noopener noreferrer">
<svg className="w-6 h-6 mb-1" viewBox="0 0 24 24" fill="currentColor">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893A11.821 11.821 0 0020.885 3.488"/>
</svg>
<span className="text-xs">WhatsApp</span>
</a>
</Button>
</div>
</div>
</div>
</div>
</div>
);
}
+9 -45
View File
@@ -1,11 +1,9 @@
import { Play, Share2 } from "lucide-react";
import { Play } from "lucide-react";
import { type Video } from "@shared/schema";
import { Button } from "@/components/ui/button";
interface VideoCardProps {
video: Video;
onClick: (video: Video) => void;
onShare?: (video: Video) => void;
}
function formatDuration(seconds: number): string {
@@ -41,14 +39,7 @@ function formatDate(date: Date | string): string {
return `${Math.floor(diffDays / 30)} month${Math.floor(diffDays / 30) > 1 ? 's' : ''} ago`;
}
export default function VideoCard({ video, onClick, onShare }: VideoCardProps) {
const handleShareClick = (e: React.MouseEvent) => {
e.stopPropagation();
if (onShare) {
onShare(video);
}
};
export default function VideoCard({ video, onClick }: VideoCardProps) {
return (
<div
className="group cursor-pointer"
@@ -74,20 +65,6 @@ export default function VideoCard({ video, onClick, onShare }: VideoCardProps) {
{formatDuration(video.duration)}
</span>
</div>
{onShare && (
<div className="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-opacity">
<Button
variant="ghost"
size="sm"
onClick={handleShareClick}
className="bg-black/60 hover:bg-black/80 text-white p-2 h-auto"
data-testid={`button-share-${video.id}`}
>
<Share2 className="w-4 h-4" />
</Button>
</div>
)}
</div>
<div className="space-y-2">
@@ -97,26 +74,13 @@ export default function VideoCard({ video, onClick, onShare }: VideoCardProps) {
>
{video.title}
</h3>
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3 text-sm text-bunny-muted">
<span data-testid={`text-views-${video.id}`}>
{formatViews(video.views)}
</span>
<span data-testid={`text-date-${video.id}`}>
{formatDate(video.createdAt)}
</span>
</div>
{onShare && (
<Button
variant="ghost"
size="sm"
onClick={handleShareClick}
className="opacity-0 group-hover:opacity-100 transition-opacity text-bunny-muted hover:text-bunny-blue p-1 h-auto"
data-testid={`button-share-bottom-${video.id}`}
>
<Share2 className="w-4 h-4" />
</Button>
)}
<div className="flex items-center space-x-3 text-sm text-bunny-muted">
<span data-testid={`text-views-${video.id}`}>
{formatViews(video.views)}
</span>
<span data-testid={`text-date-${video.id}`}>
{formatDate(video.createdAt)}
</span>
</div>
</div>
</div>
-20
View File
@@ -2,7 +2,6 @@ import { useState } from "react";
import { type Video } from "@shared/schema";
import VideoCard from "./video-card";
import VideoModal from "./video-modal";
import ShareModal from "./share-modal";
import { Button } from "@/components/ui/button";
import { ChevronDown } from "lucide-react";
@@ -17,8 +16,6 @@ interface VideoGridProps {
export default function VideoGrid({ videos, isLoading, hasMore, onLoadMore, viewMode }: VideoGridProps) {
const [selectedVideo, setSelectedVideo] = useState<Video | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [shareVideo, setShareVideo] = useState<Video | null>(null);
const [isShareModalOpen, setIsShareModalOpen] = useState(false);
const handleVideoClick = (video: Video) => {
setSelectedVideo(video);
@@ -30,16 +27,6 @@ export default function VideoGrid({ videos, isLoading, hasMore, onLoadMore, view
setSelectedVideo(null);
};
const handleShareVideo = (video: Video) => {
setShareVideo(video);
setIsShareModalOpen(true);
};
const handleCloseShareModal = () => {
setIsShareModalOpen(false);
setShareVideo(null);
};
if (isLoading && videos.length === 0) {
return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6" data-testid="grid-loading">
@@ -81,7 +68,6 @@ export default function VideoGrid({ videos, isLoading, hasMore, onLoadMore, view
key={video.id}
video={video}
onClick={handleVideoClick}
onShare={handleShareVideo}
/>
))}
</div>
@@ -114,12 +100,6 @@ export default function VideoGrid({ videos, isLoading, hasMore, onLoadMore, view
isOpen={isModalOpen}
onClose={handleCloseModal}
/>
<ShareModal
video={shareVideo}
isOpen={isShareModalOpen}
onClose={handleCloseShareModal}
/>
</>
);
}
+2 -3
View File
@@ -184,9 +184,8 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
<iframe
src={video.videoUrl}
className="w-full h-auto max-h-[80vh] aspect-video"
allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture; fullscreen;"
allowFullScreen={true}
frameBorder="0"
allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;"
allowFullScreen
onLoad={handleVideoPlay}
data-testid="video-iframe"
/>