Spaces:
Running
Running
| import React, { useState, useEffect } from 'react'; | |
| import { Search, User, Calendar, Tag, Heart, MessageCircle, Share2, Filter, Plus, Globe, Users, TrendingUp } from 'lucide-react'; | |
| const App = () => { | |
| const [posts, setPosts] = useState([]); | |
| const [filteredPosts, setFilteredPosts] = useState([]); | |
| const [searchTerm, setSearchTerm] = useState(''); | |
| const [selectedCategory, setSelectedCategory] = useState('all'); | |
| const [showCreateModal, setShowCreateModal] = useState(false); | |
| // Mock data for guest posts | |
| const mockPosts = [ | |
| { | |
| id: 1, | |
| title: "The Future of Sustainable Web Development", | |
| author: "Sarah Chen", | |
| authorAvatar: "https://placehold.co/40x40/6366f1/white?text=SC", | |
| category: "Technology", | |
| tags: ["Web Dev", "Sustainability", "Green Tech"], | |
| excerpt: "Exploring how developers can build more environmentally conscious websites and applications in 2024.", | |
| likes: 24, | |
| comments: 8, | |
| date: "2024-01-15", | |
| readTime: "5 min read", | |
| featured: true | |
| }, | |
| { | |
| id: 2, | |
| title: "Mindfulness Practices for Remote Teams", | |
| author: "Marcus Johnson", | |
| authorAvatar: "https://placehold.co/40x40/10b981/white?text=MJ", | |
| category: "Lifestyle", | |
| tags: ["Remote Work", "Wellness", "Team Building"], | |
| excerpt: "Simple mindfulness techniques that can transform your remote work experience and boost team productivity.", | |
| likes: 18, | |
| comments: 12, | |
| date: "2024-01-12", | |
| readTime: "4 min read", | |
| featured: false | |
| }, | |
| { | |
| id: 3, | |
| title: "The Art of Storytelling in Digital Marketing", | |
| author: "Elena Rodriguez", | |
| authorAvatar: "https://placehold.co/40x40/f59e0b/white?text=ER", | |
| category: "Marketing", | |
| tags: ["Storytelling", "Content Marketing", "Brand Building"], | |
| excerpt: "How to craft compelling narratives that resonate with your audience and drive engagement.", | |
| likes: 31, | |
| comments: 15, | |
| date: "2024-01-10", | |
| readTime: "6 min read", | |
| featured: true | |
| }, | |
| { | |
| id: 4, | |
| title: "Building Resilient Microservices Architecture", | |
| author: "David Kim", | |
| authorAvatar: "https://placehold.co/40x40/ef4444/white?text=DK", | |
| category: "Technology", | |
| tags: ["Microservices", "Architecture", "DevOps"], | |
| excerpt: "Key principles and best practices for designing scalable and fault-tolerant microservices systems.", | |
| likes: 27, | |
| comments: 9, | |
| date: "2024-01-08", | |
| readTime: "8 min read", | |
| featured: false | |
| }, | |
| { | |
| id: 5, | |
| title: "The Psychology of Color in Brand Design", | |
| author: "Amira Hassan", | |
| authorAvatar: "https://placehold.co/40x40/8b5cf6/white?text=AH", | |
| category: "Design", | |
| tags: ["Color Theory", "Branding", "Psychology"], | |
| excerpt: "Understanding how color choices impact consumer behavior and brand perception in digital spaces.", | |
| likes: 22, | |
| comments: 7, | |
| date: "2024-01-05", | |
| readTime: "5 min read", | |
| featured: false | |
| }, | |
| { | |
| id: 6, | |
| title: "Financial Literacy for Young Entrepreneurs", | |
| author: "James Wilson", | |
| authorAvatar: "https://placehold.co/40x40/06b6d4/white?text=JW", | |
| category: "Business", | |
| tags: ["Finance", "Entrepreneurship", "Investing"], | |
| excerpt: "Essential financial concepts every young business owner should master to build sustainable ventures.", | |
| likes: 19, | |
| comments: 11, | |
| date: "2024-01-03", | |
| readTime: "7 min read", | |
| featured: false | |
| } | |
| ]; | |
| const categories = [ | |
| { id: 'all', name: 'All Categories', icon: Globe }, | |
| { id: 'technology', name: 'Technology', icon: TrendingUp }, | |
| { id: 'design', name: 'Design', icon: TrendingUp }, | |
| { id: 'marketing', name: 'Marketing', icon: TrendingUp }, | |
| { id: 'business', name: 'Business', icon: TrendingUp }, | |
| { id: 'lifestyle', name: 'Lifestyle', icon: TrendingUp } | |
| ]; | |
| useEffect(() => { | |
| setPosts(mockPosts); | |
| setFilteredPosts(mockPosts); | |
| }, []); | |
| useEffect(() => { | |
| let filtered = posts; | |
| if (searchTerm) { | |
| filtered = filtered.filter(post => | |
| post.title.toLowerCase().includes(searchTerm.toLowerCase()) || | |
| post.excerpt.toLowerCase().includes(searchTerm.toLowerCase()) || | |
| post.tags.some(tag => tag.toLowerCase().includes(searchTerm.toLowerCase())) | |
| ); | |
| } | |
| if (selectedCategory !== 'all') { | |
| filtered = filtered.filter(post => | |
| post.category.toLowerCase() === selectedCategory.toLowerCase() | |
| ); | |
| } | |
| setFilteredPosts(filtered); | |
| }, [searchTerm, selectedCategory, posts]); | |
| const handleLike = (postId) => { | |
| setPosts(posts.map(post => | |
| post.id === postId | |
| ? { ...post, likes: post.likes + 1 } | |
| : post | |
| )); | |
| }; | |
| const CreatePostModal = () => ( | |
| <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"> | |
| <div className="bg-white rounded-2xl max-w-2xl w-full max-h-screen overflow-y-auto"> | |
| <div className="p-6"> | |
| <div className="flex justify-between items-center mb-6"> | |
| <h2 className="text-2xl font-bold text-gray-900">Create Guest Post</h2> | |
| <button | |
| onClick={() => setShowCreateModal(false)} | |
| className="text-gray-400 hover:text-gray-600 text-2xl" | |
| > | |
| × | |
| </button> | |
| </div> | |
| <form className="space-y-6"> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-700 mb-2">Post Title</label> | |
| <input | |
| type="text" | |
| className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent" | |
| placeholder="Enter your post title" | |
| /> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-700 mb-2">Category</label> | |
| <select className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"> | |
| <option>Select a category</option> | |
| <option>Technology</option> | |
| <option>Design</option> | |
| <option>Marketing</option> | |
| <option>Business</option> | |
| <option>Lifestyle</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-700 mb-2">Tags</label> | |
| <input | |
| type="text" | |
| className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent" | |
| placeholder="Enter tags separated by commas" | |
| /> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-700 mb-2">Excerpt</label> | |
| <textarea | |
| rows="3" | |
| className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent" | |
| placeholder="Brief summary of your post" | |
| ></textarea> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-700 mb-2">Full Content</label> | |
| <textarea | |
| rows="8" | |
| className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent" | |
| placeholder="Write your full guest post content here..." | |
| ></textarea> | |
| </div> | |
| <div className="flex gap-4 pt-4"> | |
| <button | |
| type="button" | |
| onClick={() => setShowCreateModal(false)} | |
| className="flex-1 px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors" | |
| > | |
| Cancel | |
| </button> | |
| <button | |
| type="submit" | |
| className="flex-1 px-6 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors" | |
| > | |
| Submit for Review | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| return ( | |
| <div className="min-h-screen bg-gray-50"> | |
| {/* Header */} | |
| <header className="bg-white shadow-sm border-b"> | |
| <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div className="flex justify-between items-center h-16"> | |
| <div className="flex items-center"> | |
| <div className="flex-shrink-0"> | |
| <h1 className="text-2xl font-bold text-indigo-600">GuestPostHub</h1> | |
| </div> | |
| </div> | |
| <nav className="hidden md:flex space-x-8"> | |
| <a href="#" className="text-gray-900 hover:text-indigo-600 font-medium">Browse</a> | |
| <a href="#" className="text-gray-500 hover:text-indigo-600 font-medium">My Posts</a> | |
| <a href="#" className="text-gray-500 hover:text-indigo-600 font-medium">Community</a> | |
| </nav> | |
| <div className="flex items-center space-x-4"> | |
| <button className="p-2 text-gray-400 hover:text-gray-600"> | |
| <User className="h-6 w-6" /> | |
| </button> | |
| <button | |
| onClick={() => setShowCreateModal(true)} | |
| className="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition-colors flex items-center space-x-2" | |
| > | |
| <Plus className="h-4 w-4" /> | |
| <span>Create Post</span> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| {/* Hero Section */} | |
| <section className="bg-gradient-to-r from-indigo-600 to-purple-600 text-white py-16"> | |
| <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center"> | |
| <h1 className="text-4xl md:text-6xl font-bold mb-6">Share Your Voice, Expand Your Reach</h1> | |
| <p className="text-xl md:text-2xl mb-8 text-indigo-100">Connect with publishers and writers for quality guest post exchanges</p> | |
| <div className="flex flex-col sm:flex-row gap-4 justify-center"> | |
| <button className="bg-white text-indigo-600 px-8 py-3 rounded-lg font-semibold hover:bg-gray-100 transition-colors"> | |
| Find Guest Posts | |
| </button> | |
| <button | |
| onClick={() => setShowCreateModal(true)} | |
| className="border-2 border-white text-white px-8 py-3 rounded-lg font-semibold hover:bg-white hover:text-indigo-600 transition-colors" | |
| > | |
| Submit Your Post | |
| </button> | |
| </div> | |
| </div> | |
| </section> | |
| {/* Stats Section */} | |
| <section className="py-12 bg-white"> | |
| <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div className="grid grid-cols-1 md:grid-cols-3 gap-8 text-center"> | |
| <div className="p-6"> | |
| <div className="flex justify-center mb-4"> | |
| <Globe className="h-12 w-12 text-indigo-600" /> | |
| </div> | |
| <h3 className="text-3xl font-bold text-gray-900 mb-2">10K+</h3> | |
| <p className="text-gray-600">Active Publishers</p> | |
| </div> | |
| <div className="p-6"> | |
| <div className="flex justify-center mb-4"> | |
| <Users className="h-12 w-12 text-indigo-600" /> | |
| </div> | |
| <h3 className="text-3xl font-bold text-gray-900 mb-2">50K+</h3> | |
| <p className="text-gray-600">Writers Community</p> | |
| </div> | |
| <div className="p-6"> | |
| <div className="flex justify-center mb-4"> | |
| <TrendingUp className="h-12 w-12 text-indigo-600" /> | |
| </div> | |
| <h3 className="text-3xl font-bold text-gray-900 mb-2">100K+</h3> | |
| <p className="text-gray-600">Posts Published</p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| {/* Main Content */} | |
| <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> | |
| {/* Search and Filter Bar */} | |
| <div className="mb-8"> | |
| <div className="flex flex-col lg:flex-row gap-4 items-center justify-between"> | |
| <div className="relative flex-1 max-w-2xl"> | |
| <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" /> | |
| <input | |
| type="text" | |
| placeholder="Search guest posts, topics, or authors..." | |
| className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent" | |
| value={searchTerm} | |
| onChange={(e) => setSearchTerm(e.target.value)} | |
| /> | |
| </div> | |
| <div className="flex items-center space-x-4"> | |
| <Filter className="h-5 w-5 text-gray-400" /> | |
| <select | |
| className="px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent" | |
| value={selectedCategory} | |
| onChange={(e) => setSelectedCategory(e.target.value)} | |
| > | |
| {categories.map(category => ( | |
| <option key={category.id} value={category.id}>{category.name}</option> | |
| ))} | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Categories */} | |
| <div className="mb-8"> | |
| <div className="flex flex-wrap gap-3"> | |
| {categories.map(category => { | |
| const IconComponent = category.icon; | |
| return ( | |
| <button | |
| key={category.id} | |
| onClick={() => setSelectedCategory(category.id)} | |
| className={`flex items-center space-x-2 px-4 py-2 rounded-full transition-colors ${ | |
| selectedCategory === category.id | |
| ? 'bg-indigo-600 text-white' | |
| : 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300' | |
| }`} | |
| > | |
| <IconComponent className="h-4 w-4" /> | |
| <span>{category.name}</span> | |
| </button> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| {/* Featured Posts */} | |
| <section className="mb-12"> | |
| <h2 className="text-2xl font-bold text-gray-900 mb-6">Featured Guest Posts</h2> | |
| <div className="grid grid-cols-1 lg:grid-cols-2 gap-8"> | |
| {filteredPosts.filter(post => post.featured).map(post => ( | |
| <div key={post.id} className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden hover:shadow-md transition-shadow"> | |
| <div className="p-6"> | |
| <div className="flex items-center justify-between mb-4"> | |
| <span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-indigo-100 text-indigo-800"> | |
| {post.category} | |
| </span> | |
| <span className="text-sm text-gray-500">{post.readTime}</span> | |
| </div> | |
| <h3 className="text-xl font-bold text-gray-900 mb-3">{post.title}</h3> | |
| <p className="text-gray-600 mb-4">{post.excerpt}</p> | |
| <div className="flex flex-wrap gap-2 mb-4"> | |
| {post.tags.map(tag => ( | |
| <span key={tag} className="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-gray-100 text-gray-800"> | |
| <Tag className="h-3 w-3 mr-1" /> | |
| {tag} | |
| </span> | |
| ))} | |
| </div> | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center space-x-3"> | |
| <img | |
| src={post.authorAvatar} | |
| alt={post.author} | |
| className="h-10 w-10 rounded-full" | |
| /> | |
| <div> | |
| <p className="text-sm font-medium text-gray-900">{post.author}</p> | |
| <p className="text-sm text-gray-500">{new Date(post.date).toLocaleDateString()}</p> | |
| </div> | |
| </div> | |
| <div className="flex items-center space-x-4"> | |
| <button | |
| onClick={() => handleLike(post.id)} | |
| className="flex items-center space-x-1 text-gray-500 hover:text-red-500 transition-colors" | |
| > | |
| <Heart className="h-5 w-5" /> | |
| <span className="text-sm">{post.likes}</span> | |
| </button> | |
| <button className="flex items-center space-x-1 text-gray-500 hover:text-indigo-600 transition-colors"> | |
| <MessageCircle className="h-5 w-5" /> | |
| <span className="text-sm">{post.comments}</span> | |
| </button> | |
| <button className="text-gray-500 hover:text-indigo-600 transition-colors"> | |
| <Share2 className="h-5 w-5" /> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ))} | |
| </div> | |
| </section> | |
| {/* All Posts */} | |
| <section> | |
| <h2 className="text-2xl font-bold text-gray-900 mb-6">All Guest Posts</h2> | |
| <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> | |
| {filteredPosts.map(post => ( | |
| <div key={post.id} className="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden hover:shadow-md transition-shadow"> | |
| <div className="p-5"> | |
| <div className="flex items-center justify-between mb-3"> | |
| <span className="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-gray-100 text-gray-800"> | |
| {post.category} | |
| </span> | |
| <span className="text-xs text-gray-500">{post.readTime}</span> | |
| </div> | |
| <h3 className="text-lg font-semibold text-gray-900 mb-2 line-clamp-2">{post.title}</h3> | |
| <p className="text-gray-600 text-sm mb-3 line-clamp-2">{post.excerpt}</p> | |
| <div className="flex flex-wrap gap-1 mb-4"> | |
| {post.tags.slice(0, 2).map(tag => ( | |
| <span key={tag} className="inline-flex items-center px-2 py-1 rounded text-xs bg-gray-50 text-gray-600"> | |
| {tag} | |
| </span> | |
| ))} | |
| {post.tags.length > 2 && ( | |
| <span className="text-xs text-gray-500">+{post.tags.length - 2}</span> | |
| )} | |
| </div> | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center space-x-2"> | |
| <img | |
| src={post.authorAvatar} | |
| alt={post.author} | |
| className="h-8 w-8 rounded-full" | |
| /> | |
| <div> | |
| <p className="text-sm font-medium text-gray-900">{post.author}</p> | |
| <p className="text-xs text-gray-500">{new Date(post.date).toLocaleDateString()}</p> | |
| </div> | |
| </div> | |
| <div className="flex items-center space-x-2"> | |
| <button | |
| onClick={() => handleLike(post.id)} | |
| className="flex items-center space-x-1 text-gray-500 hover:text-red-500 transition-colors" | |
| > | |
| <Heart className="h-4 w-4" /> | |
| <span className="text-xs">{post.likes}</span> | |
| </button> | |
| <button className="flex items-center space-x-1 text-gray-500 hover:text-indigo-600 transition-colors"> | |
| <MessageCircle className="h-4 w-4" /> | |
| <span className="text-xs">{post.comments}</span> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ))} | |
| </div> | |
| </section> | |
| {filteredPosts.length === 0 && ( | |
| <div className="text-center py-12"> | |
| <p className="text-gray-500 text-lg">No guest posts found matching your criteria.</p> | |
| </div> | |
| )} | |
| </main> | |
| {/* Footer */} | |
| <footer className="bg-gray-900 text-white py-12"> | |
| <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div className="grid grid-cols-1 md:grid-cols-4 gap-8"> | |
| <div> | |
| <h3 className="text-xl font-bold mb-4">GuestPostHub</h3> | |
| <p className="text-gray-400">Connecting writers and publishers for quality guest post exchanges.</p> | |
| </div> | |
| <div> | |
| <h4 className="font-semibold mb-4">For Writers</h4> | |
| <ul className="space-y-2 text-gray-400"> | |
| <li><a href="#" className="hover:text-white transition-colors">Submit Posts</a></li> | |
| <li><a href="#" className="hover:text-white transition-colors">Find Publishers</a></li> | |
| <li><a href="#" className="hover:text-white transition-colors">Writing Tips</a></li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h4 className="font-semibold mb-4">For Publishers</h4> | |
| <ul className="space-y-2 text-gray-400"> | |
| <li><a href="#" className="hover:text-white transition-colors">Post Opportunities</a></li> | |
| <li><a href="#" className="hover:text-white transition-colors">Find Writers</a></li> | |
| <li><a href="#" className="hover:text-white transition-colors">Publishing Guide</a></li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h4 className="font-semibold mb-4">Support</h4> | |
| <ul className="space-y-2 text-gray-400"> | |
| <li><a href="#" className="hover:text-white transition-colors">Help Center</a></li> | |
| <li><a href="#" className="hover:text-white transition-colors">Community</a></li> | |
| <li><a href="#" className="hover:text-white transition-colors">Contact Us</a></li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div className="border-t border-gray-800 mt-8 pt-8 text-center text-gray-400"> | |
| <p>© 2024 GuestPostHub. All rights reserved.</p> | |
| </div> | |
| </div> | |
| </footer> | |
| {/* Create Post Modal */} | |
| {showCreateModal && <CreatePostModal />} | |
| </div> | |
| ); | |
| }; | |
| export default App; |