fullstuckdev's picture
Upload 26 files
fff42e3 verified
'use client'
import { useState } from 'react';
import { cultures } from '@/data/cultures';
import { generateDescription, generateImage } from '@/services/ai';
import { motion, AnimatePresence } from 'framer-motion';
export default function Home() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [showPreview, setShowPreview] = useState(false);
const [culture, setCulture] = useState<{
name: string;
description: string;
imageUrl: string;
} | null>(null);
const generateRandomCulture = async () => {
setLoading(true);
setError(null);
try {
const randomCulture = cultures[Math.floor(Math.random() * cultures.length)];
const [description, imageData] = await Promise.all([
generateDescription(randomCulture),
generateImage(`Indonesian traditional culture ${randomCulture}, professional photography style, high quality, detailed, 4k resolution`)
]);
if (!imageData || !imageData.imageUrl) {
throw new Error('Failed to generate image');
}
setCulture({
name: randomCulture,
description: description || '',
imageUrl: imageData.imageUrl
});
} catch (error) {
console.error('Error:', error);
setError('Failed to generate content. Please try again.');
} finally {
setLoading(false);
}
};
return (
<main className="min-h-screen p-8 bg-gradient-to-br from-orange-100 to-red-100">
<div className="max-w-4xl mx-auto">
<div className="text-center mb-12">
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
className="text-5xl font-bold mb-3 text-red-800"
>
Warisan Nusantara
</motion.h1>
<motion.p
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="text-xl text-red-700/80"
>
Menjelajahi Ragam Warisan Budaya Indonesia
</motion.p>
</div>
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={generateRandomCulture}
disabled={loading}
className="w-full max-w-md mx-auto block px-6 py-3 bg-red-600 text-white rounded-lg shadow-lg hover:bg-red-700 transition-colors disabled:bg-gray-400"
>
{loading ? (
<div className="flex items-center justify-center">
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-white mr-2"></div>
Memuat...
</div>
) : (
'Jelajahi Budaya'
)}
</motion.button>
{error && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="mt-4 p-4 bg-red-100 text-red-700 rounded-lg"
>
{error}
</motion.div>
)}
<AnimatePresence>
{culture && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
className="mt-12 bg-white rounded-xl shadow-xl overflow-hidden"
>
<div className="relative h-[400px] w-full cursor-pointer" onClick={() => setShowPreview(true)}>
{culture.imageUrl && (
<img
src={culture.imageUrl}
alt={culture.name}
className="w-full h-full object-contain"
onError={(e) => {
console.error('Image failed to load');
e.currentTarget.src = '/placeholder-image.jpg';
}}
/>
)}
<div className="absolute inset-0 bg-black bg-opacity-0 hover:bg-opacity-10 transition-all duration-300 flex items-center justify-center">
<span className="text-white opacity-0 hover:opacity-100 transition-opacity duration-300">
Klik untuk memperbesar
</span>
</div>
</div>
<div className="p-6">
<h2 className="text-2xl font-bold mb-4 text-red-800">
{culture.name}
</h2>
<p className="text-gray-700 leading-relaxed whitespace-pre-wrap">
{culture.description}
</p>
</div>
</motion.div>
)}
</AnimatePresence>
<AnimatePresence>
{showPreview && culture && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black bg-opacity-90 z-50 flex items-center justify-center p-4"
onClick={() => setShowPreview(false)}
>
<motion.div
initial={{ scale: 0.9 }}
animate={{ scale: 1 }}
exit={{ scale: 0.9 }}
className="relative max-w-[90vw] max-h-[90vh]"
>
<img
src={culture.imageUrl}
alt={culture.name}
className="max-w-full max-h-[90vh] object-contain"
/>
<button
className="absolute top-4 right-4 text-white bg-black bg-opacity-50 rounded-full p-2 hover:bg-opacity-70"
onClick={() => setShowPreview(false)}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</div>
</main>
);
}