feat: 添加产品经理和全栈开发角色资源文件

初始化产品经理和全栈开发角色的相关资源文件,包括角色定义、知识库、思维模式和执行流程文档
This commit is contained in:
2025-07-21 22:47:16 +08:00
parent 581bd40184
commit ff20f6f23a
104 changed files with 74 additions and 9967 deletions

View File

@ -0,0 +1,91 @@
"use client"
import { useState } from "react"
import Image from "next/image"
import { Card } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Calendar, MapPin } from "lucide-react"
interface Photo {
id: number
src: string
title: string
description: string
category: string
tags: string[]
date: string
exif: {
camera: string
lens: string
settings: string
location: string
}
}
interface PhotoGalleryProps {
photos: Photo[]
onPhotoClick: (photo: Photo) => void
}
export function PhotoGallery({ photos, onPhotoClick }: PhotoGalleryProps) {
const [loadedImages, setLoadedImages] = useState<Set<number>>(new Set())
const handleImageLoad = (photoId: number) => {
setLoadedImages((prev) => new Set(prev).add(photoId))
}
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{photos.map((photo) => (
<Card
key={photo.id}
className="group cursor-pointer overflow-hidden border-0 shadow-sm hover:shadow-xl transition-all duration-300 hover:scale-[1.02]"
onClick={() => onPhotoClick(photo)}
>
<div className="relative aspect-[4/3] overflow-hidden">
{!loadedImages.has(photo.id) && <div className="absolute inset-0 bg-gray-100 animate-pulse" />}
<Image
src={photo.src || "/placeholder.svg"}
alt={photo.title}
fill
className={`object-cover transition-all duration-500 group-hover:scale-110 ${
loadedImages.has(photo.id) ? "opacity-100" : "opacity-0"
}`}
onLoad={() => handleImageLoad(photo.id)}
/>
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/20 transition-all duration-300" />
{/* Hover overlay */}
<div className="absolute inset-0 p-4 flex flex-col justify-end opacity-0 group-hover:opacity-100 transition-all duration-300">
<div className="text-white">
<h3 className="font-medium text-lg mb-1">{photo.title}</h3>
<p className="text-sm text-white/80 mb-2">{photo.description}</p>
<div className="flex items-center gap-2 text-xs text-white/70">
<Calendar className="h-3 w-3" />
<span>{photo.date}</span>
<MapPin className="h-3 w-3 ml-2" />
<span>{photo.exif.location}</span>
</div>
</div>
</div>
</div>
{/* Card content */}
<div className="p-4">
<h3 className="font-medium text-gray-900 mb-2">{photo.title}</h3>
<div className="flex flex-wrap gap-1 mb-3">
{photo.tags.slice(0, 2).map((tag) => (
<Badge key={tag} variant="secondary" className="text-xs">
{tag}
</Badge>
))}
</div>
<div className="text-xs text-gray-500">
{photo.exif.camera} {photo.exif.settings}
</div>
</div>
</Card>
))}
</div>
)
}