Spaces:
Running
Running
File size: 6,473 Bytes
8139e18 c63c36c 8139e18 c63c36c 8139e18 c63c36c 8139e18 c63c36c 8139e18 c63c36c f1588df c63c36c 8139e18 c63c36c 8139e18 c63c36c 8139e18 c63c36c f1588df 8139e18 c63c36c 8139e18 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | '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>
)
}
|