Spaces:
Sleeping
Sleeping
| 'use client' | |
| import { useState, useEffect } from 'react' | |
| import { ArrowRight, Loader2 } from 'lucide-react' | |
| import { Button } from '@/components/ui/button' | |
| import { api } from '@/lib/api' | |
| const staticProjects = [ | |
| { | |
| title: 'AgriTech Nepal', | |
| description: 'Smart agricultural solutions connecting farmers with modern technology to improve crop yield and reduce costs', | |
| image: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', | |
| tags: ['Agriculture', 'IoT', 'Data Analytics'], | |
| contributors: 12, | |
| }, | |
| { | |
| title: 'WDUBot', | |
| description: 'An intelligent bot platform for Nepali universities providing academic support and administrative assistance', | |
| image: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)', | |
| tags: ['AI', 'Education', 'Chatbot'], | |
| contributors: 8, | |
| }, | |
| { | |
| title: 'HealthLink', | |
| description: 'Connecting patients with healthcare providers in remote areas of Nepal through telemedicine platform', | |
| image: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)', | |
| tags: ['Healthcare', 'Telemedicine', 'Web'], | |
| contributors: 15, | |
| }, | |
| ] | |
| export function FeaturedProjects() { | |
| const [projects, setProjects] = useState<any[]>([]) | |
| const [loading, setLoading] = useState(true) | |
| useEffect(() => { | |
| const loadProjects = async () => { | |
| try { | |
| const data = await api.projects.list() | |
| if (data && data.length > 0) { | |
| setProjects(data) | |
| } else { | |
| setProjects(staticProjects) | |
| } | |
| } catch (error) { | |
| console.error('Failed to fetch projects:', error) | |
| setProjects(staticProjects) | |
| } finally { | |
| setLoading(false) | |
| } | |
| } | |
| loadProjects() | |
| }, []) | |
| return ( | |
| <section id="featured-projects" className="py-12 sm:py-16 md:py-20 px-4 md:px-6 bg-muted/30 scroll-mt-20" aria-labelledby="projects-heading"> | |
| <div className="container mx-auto"> | |
| <div className="text-center mb-10 sm:mb-12 md:mb-16"> | |
| <h2 id="projects-heading" className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-foreground mb-3 sm:mb-4"> | |
| Featured Projects | |
| </h2> | |
| <p className="text-sm sm:text-base md:text-lg text-muted-foreground max-w-2xl mx-auto px-2"> | |
| Showcasing innovative solutions built by our community members | |
| </p> | |
| </div> | |
| {loading ? ( | |
| <div className="flex justify-center py-20"> | |
| <Loader2 className="w-8 h-8 animate-spin text-primary" /> | |
| </div> | |
| ) : ( | |
| <div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6 md:gap-8 max-w-6xl mx-auto"> | |
| {projects.map((project, index) => ( | |
| <article | |
| key={index} | |
| className="bg-card rounded-xl sm:rounded-2xl overflow-hidden border border-border hover:border-primary transition-all duration-300 hover:shadow-xl group" | |
| > | |
| {/* Project Image */} | |
| <div | |
| className="h-36 sm:h-40 md:h-48 bg-cover bg-center group-hover:scale-110 transition-transform duration-300" | |
| style={{ | |
| background: project.image?.startsWith('linear-gradient') || !project.image | |
| ? (project.image || 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)') | |
| : undefined, | |
| backgroundImage: project.image && !project.image.startsWith('linear-gradient') | |
| ? `url(${project.image})` | |
| : undefined | |
| }} | |
| role="img" | |
| aria-label={`${project.title} project visual`} | |
| /> | |
| {/* Project Content */} | |
| <div className="p-4 sm:p-5 md:p-6"> | |
| <h3 className="text-lg sm:text-xl md:text-2xl font-bold text-foreground mb-1.5 sm:mb-2"> | |
| {project.title} | |
| </h3> | |
| <p className="text-sm sm:text-base text-muted-foreground mb-3 sm:mb-4 leading-relaxed line-clamp-3"> | |
| {project.description} | |
| </p> | |
| {/* Tags */} | |
| <div className="flex flex-wrap gap-1.5 sm:gap-2 mb-3 sm:mb-4"> | |
| {(project.tags || []).map((tag: string) => ( | |
| <span | |
| key={tag} | |
| className="text-[10px] sm:text-xs font-medium bg-primary/10 text-primary px-2 sm:px-3 py-0.5 sm:py-1 rounded-full" | |
| > | |
| {tag} | |
| </span> | |
| ))} | |
| </div> | |
| {/* Contributors and View Button */} | |
| <div className="flex items-center justify-between"> | |
| <div className="text-xs sm:text-sm text-muted-foreground"> | |
| <span className="font-semibold text-foreground">{project.contributors || 0}</span> contributors | |
| </div> | |
| {project.link ? ( | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| className="text-primary hover:text-primary/80 text-xs sm:text-sm px-2 sm:px-3" | |
| asChild | |
| > | |
| <a href={project.link} target="_blank" rel="noopener noreferrer"> | |
| View <ArrowRight className="w-3 h-3 sm:w-4 sm:h-4 ml-1 sm:ml-2" aria-hidden="true" /> | |
| </a> | |
| </Button> | |
| ) : ( | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| className="text-primary hover:text-primary/80 text-xs sm:text-sm px-2 sm:px-3" | |
| disabled | |
| > | |
| View <ArrowRight className="w-3 h-3 sm:w-4 sm:h-4 ml-1 sm:ml-2" aria-hidden="true" /> | |
| </Button> | |
| )} | |
| </div> | |
| </div> | |
| </article> | |
| ))} | |
| </div> | |
| )} | |
| {/* See All Projects Button */} | |
| <div className="text-center mt-8 sm:mt-10 md:mt-12"> | |
| <Button | |
| size="lg" | |
| className="bg-gradient-to-r from-primary to-secondary hover:opacity-90 text-sm sm:text-base px-6 sm:px-8" | |
| > | |
| See All Projects | |
| </Button> | |
| </div> | |
| </div> | |
| </section> | |
| ) | |
| } | |