diff --git a/client/src/components/social-share.tsx b/client/src/components/social-share.tsx
new file mode 100644
index 0000000..7331942
--- /dev/null
+++ b/client/src/components/social-share.tsx
@@ -0,0 +1,154 @@
+import { useState } from "react";
+import { Copy, Check, Share2 } from "lucide-react";
+import {
+ SiX,
+ SiFacebook,
+ SiLinkedin,
+ SiWhatsapp,
+ SiTelegram,
+ SiReddit
+} from "react-icons/si";
+import { Button } from "@/components/ui/button";
+import { type Video } from "@shared/schema";
+
+interface SocialShareProps {
+ video: Video;
+ className?: string;
+}
+
+export function SocialShare({ video, className = "" }: SocialShareProps) {
+ const [copied, setCopied] = useState(false);
+ const [shareOpen, setShareOpen] = useState(false);
+
+ // Generate shareable URL (in production, this would be your actual domain)
+ const shareUrl = `${window.location.origin}/?video=${video.id}`;
+ const shareText = `Check out this video: ${video.title}`;
+ const shareTextEncoded = encodeURIComponent(shareText);
+ const shareUrlEncoded = encodeURIComponent(shareUrl);
+
+ const handleCopyLink = async () => {
+ try {
+ await navigator.clipboard.writeText(shareUrl);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ } catch (err) {
+ console.error('Failed to copy link:', err);
+ }
+ };
+
+ const socialPlatforms = [
+ {
+ name: "X",
+ icon: SiX,
+ url: `https://twitter.com/intent/tweet?text=${shareTextEncoded}&url=${shareUrlEncoded}`,
+ color: "hover:bg-gray-900 hover:text-white",
+ },
+ {
+ name: "Facebook",
+ icon: SiFacebook,
+ url: `https://www.facebook.com/sharer/sharer.php?u=${shareUrlEncoded}`,
+ color: "hover:bg-blue-600 hover:text-white",
+ },
+ {
+ name: "LinkedIn",
+ icon: SiLinkedin,
+ url: `https://www.linkedin.com/sharing/share-offsite/?url=${shareUrlEncoded}`,
+ color: "hover:bg-blue-700 hover:text-white",
+ },
+ {
+ name: "WhatsApp",
+ icon: SiWhatsapp,
+ url: `https://wa.me/?text=${shareTextEncoded}%20${shareUrlEncoded}`,
+ color: "hover:bg-green-500 hover:text-white",
+ },
+ {
+ name: "Telegram",
+ icon: SiTelegram,
+ url: `https://t.me/share/url?url=${shareUrlEncoded}&text=${shareTextEncoded}`,
+ color: "hover:bg-blue-400 hover:text-white",
+ },
+ {
+ name: "Reddit",
+ icon: SiReddit,
+ url: `https://reddit.com/submit?url=${shareUrlEncoded}&title=${shareTextEncoded}`,
+ color: "hover:bg-orange-500 hover:text-white",
+ },
+ ];
+
+ const handlePlatformShare = (platform: typeof socialPlatforms[0]) => {
+ window.open(platform.url, '_blank', 'width=600,height=400');
+ };
+
+ return (
+
+
+
+ {shareOpen && (
+ <>
+ {/* Backdrop */}
+
setShareOpen(false)}
+ />
+
+ {/* Share Menu */}
+
+
Share this video
+
+ {/* Copy Link */}
+
+
+
+
+ {/* Social Platforms */}
+
+ {socialPlatforms.map((platform) => {
+ const IconComponent = platform.icon;
+ return (
+
+ );
+ })}
+
+
+ >
+ )}
+
+ );
+}
\ No newline at end of file
diff --git a/client/src/components/video-card.tsx b/client/src/components/video-card.tsx
index 73d9866..c15c3a9 100644
--- a/client/src/components/video-card.tsx
+++ b/client/src/components/video-card.tsx
@@ -1,5 +1,6 @@
-import { Play } from "lucide-react";
+import { Play, Share2 } from "lucide-react";
import { type Video } from "@shared/schema";
+import { Button } from "@/components/ui/button";
interface VideoCardProps {
video: Video;
@@ -40,6 +41,30 @@ function formatDate(date: Date | string): string {
}
export default function VideoCard({ video, onClick }: VideoCardProps) {
+ const handleShare = async (e: React.MouseEvent) => {
+ e.stopPropagation(); // Prevent video modal from opening
+
+ const shareUrl = `${window.location.origin}/?video=${video.id}`;
+ const shareData = {
+ title: video.title,
+ text: `Check out this video: ${video.title}`,
+ url: shareUrl,
+ };
+
+ try {
+ if (navigator.share) {
+ // Use native share API if available (mobile devices)
+ await navigator.share(shareData);
+ } else {
+ // Fallback: copy to clipboard
+ await navigator.clipboard.writeText(shareUrl);
+ alert('Video link copied to clipboard!');
+ }
+ } catch (err) {
+ console.error('Error sharing:', err);
+ }
+ };
+
return (
+
+ {/* Share button */}
+
+
+
diff --git a/client/src/components/video-modal.tsx b/client/src/components/video-modal.tsx
index e27a24f..6922ba3 100644
--- a/client/src/components/video-modal.tsx
+++ b/client/src/components/video-modal.tsx
@@ -1,9 +1,10 @@
import { useEffect, useRef } from "react";
-import { X } from "lucide-react";
+import { X, Share2, Copy, Check } from "lucide-react";
import { type Video } from "@shared/schema";
import { Button } from "@/components/ui/button";
import { apiRequest } from "@/lib/queryClient";
import Hls from "hls.js";
+import { SocialShare } from "@/components/social-share";
interface VideoModalProps {
video: Video | null;
@@ -212,16 +213,19 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
>
{video.title}
-
-
- {formatViews(video.views)}
-
-
- {formatDate(video.createdAt)}
-
-
- {formatDuration(video.duration)}
-
+
+
+
+ {formatViews(video.views)}
+
+
+ {formatDate(video.createdAt)}
+
+
+ {formatDuration(video.duration)}
+
+
+
{video.description && (
diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx
index af9c65e..60d58e5 100644
--- a/client/src/pages/home.tsx
+++ b/client/src/pages/home.tsx
@@ -3,6 +3,7 @@ import { useQuery } from "@tanstack/react-query";
import { type Video } from "@shared/schema";
import SearchHeader from "@/components/search-header";
import VideoGrid from "@/components/video-grid";
+import VideoModal from "@/components/video-modal";
interface VideosResponse {
videos: Video[];
@@ -15,6 +16,23 @@ export default function Home() {
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
const [offset, setOffset] = useState(0);
const [allVideos, setAllVideos] = useState