import React, { useEffect, useState, useRef } from "react"; // MiniVideoPlatform.jsx // Single-file React component (Tailwind CSS assumed). // Features: // - Create posts with video or image and optional caption // - Feed of posts (videos autoplay muted on scroll into view) // - Comments per post // - Likes // - Local persistence via localStorage // - Simple responsive layout // How to use: // 1) Create a React app (Vite or CRA) with Tailwind CSS configured. // 2) Drop this file into src/components or src/ and import it into App.jsx. // 3) Run the dev server. Files are stored in-memory (object URLs) and metadata in localStorage. export default function MiniVideoPlatform() { const [posts, setPosts] = useState(() => { try { const raw = localStorage.getItem("mvp_posts_v1"); return raw ? JSON.parse(raw) : []; } catch (e) { return []; } }); const [file, setFile] = useState(null); const [caption, setCaption] = useState(""); const [uploading, setUploading] = useState(false); const [query, setQuery] = useState(""); useEffect(() => { localStorage.setItem("mvp_posts_v1", JSON.stringify(posts)); }, [posts]); // Helper to create an object URL and store minimal metadata function handleFileChange(e) { const f = e.target.files && e.target.files[0]; if (!f) return; // Basic validation const isVideo = f.type.startsWith("video/"); const isImage = f.type.startsWith("image/"); if (!isVideo && !isImage) { alert("Please select a video or image file."); return; } setFile({ file: f, preview: URL.createObjectURL(f), type: isVideo ? "video" : "image" }); } function createPost(e) { e.preventDefault(); if (!file) return alert("Choose an image or video first."); setUploading(true); // Simulate upload delay setTimeout(() => { const newPost = { id: Date.now().toString(), type: file.type, url: file.preview, caption: caption.trim(), likes: 0, comments: [], createdAt: new Date().toISOString(), }; setPosts(prev => [newPost, ...prev]); setFile(null); setCaption(""); setUploading(false); }, 600); } function addComment(postId, text) { if (!text || !text.trim()) return; setPosts(prev => prev.map(p => p.id === postId ? { ...p, comments: [...p.comments, { id: Date.now().toString(), text: text.trim(), createdAt: new Date().toISOString() }] } : p)); } function toggleLike(postId) { setPosts(prev => prev.map(p => p.id === postId ? { ...p, likes: p.likes + 1 } : p)); } function deletePost(postId) { // Revoke object URL to free memory const post = posts.find(p => p.id === postId); if (post && post.url && post.url.startsWith("blob:")) URL.revokeObjectURL(post.url); setPosts(prev => prev.filter(p => p.id !== postId)); } // Simple search/filter const visiblePosts = posts.filter(p => p.caption.toLowerCase().includes(query.toLowerCase())); return (
A simple client-side demo of a short-video feed: upload videos/images, comment, like.