diff --git a/frontend/src/pages/CategoryList.tsx b/frontend/src/pages/CategoryList.tsx index a053110..1acd327 100644 --- a/frontend/src/pages/CategoryList.tsx +++ b/frontend/src/pages/CategoryList.tsx @@ -10,10 +10,13 @@ import { Rating as MuiRating, Paper, Chip, - Container + Container, + IconButton } from '@mui/material'; import { Link, useLocation } from 'react-router-dom'; import StarIcon from '@mui/icons-material/Star'; +import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import api from '../api'; import { useTitle } from '../hooks/useTitle'; @@ -32,6 +35,7 @@ interface Flavor { image_url: string | null; is_available: boolean; is_legacy: boolean; + ratings: any[]; } interface Review { @@ -52,6 +56,7 @@ const CategoryList: React.FC = () => { const [recentReviews, setRecentReviews] = useState([]); const [allFlavors, setAllFlavors] = useState([]); const [loading, setLoading] = useState(true); + const [activeIndex, setActiveIndex] = useState(0); const location = useLocation(); const query = new URLSearchParams(location.search).get('q') || ''; @@ -82,10 +87,23 @@ const CategoryList: React.FC = () => { fetchData(); }, [query]); + // Auto-rotate + useEffect(() => { + if (topFlavors.length > 0 && !query) { + const timer = setInterval(() => { + setActiveIndex(prev => (prev + 1) % topFlavors.length); + }, 6000); + return () => clearInterval(timer); + } + }, [topFlavors, query]); + useTitle(query ? `Search: ${query}` : 'Holy Flavors Archive'); if (loading) return ; + const handlePrev = () => setActiveIndex(prev => (prev - 1 + topFlavors.length) % topFlavors.length); + const handleNext = () => setActiveIndex(prev => (prev + 1) % topFlavors.length); + // --- SEARCH VIEW --- if (query) { const filteredFlavors = allFlavors.filter(f => @@ -160,9 +178,12 @@ const CategoryList: React.FC = () => { } // --- HOME VIEW --- + const currentTop = topFlavors[activeIndex]; + const featuredReview = currentTop?.ratings?.find(r => r.comment) || null; + return ( - {/* Hero Section - True Full Width, No Overflow */} + {/* Hero Section */} { textAlign: 'center', borderBottom: '1px solid rgba(255,255,255,0.1)', width: '100%', - maxWidth: '100%', boxSizing: 'border-box', overflow: 'hidden' }} > - + The Ultimate Holy Archive @@ -200,146 +210,165 @@ const CategoryList: React.FC = () => { - - {/* Main Content inside Container */} - {/* Top Rated Flavors */} - {topFlavors.length > 0 && ( - - - - Hall of Fame - - - - {topFlavors.map(flavor => ( - - - - {flavor.image_url && ( - - - - )} - - {flavor.name} - - - - {(flavor.average_rating || 0).toFixed(1)} - - - - - - - ))} - - - )} + + {/* Hall of Fame Carousel */} + {topFlavors.length > 0 && currentTop && ( + + + + + Hall of Fame + + + + + + - {/* Categories Grid */} - - Browse by Category - - {categories.map(category => ( - - - - {category.name} + + + + + + {currentTop.name} + + + + {(currentTop.average_rating || 0).toFixed(1)} / 10 + + + {featuredReview && ( + + + "{featuredReview.comment}" + + + {featuredReview.user.charAt(0)} + — {featuredReview.user} + + + )} + + - + + {/* Progress Indicators */} + + {topFlavors.map((_, i) => ( + setActiveIndex(i)} + sx={{ + width: activeIndex === i ? 24 : 8, + height: 8, + borderRadius: 4, + bgcolor: activeIndex === i ? 'primary.main' : 'divider', + cursor: 'pointer', + transition: 'all 0.3s ease' + }} + /> + ))} + - ))} - - + )} - {/* Recent Reviews */} - {recentReviews.length > 0 && ( - - Community Voice - - {recentReviews.map(review => ( - - - - {!review.user_avatar && review.user.charAt(0).toUpperCase()} - - - {review.user} - - on {review.flavor_name} - - - - - - {review.score}/10 - - - "{review.comment}" - - - ))} - - - )} + {/* Categories Grid */} + + Browse by Category + + {categories.map(category => ( + + + + + {category.name} + + + + + ))} + + + + {/* Recent Reviews */} + {recentReviews.length > 0 && ( + + Community Voice + + {recentReviews.map(review => ( + + + + {!review.user_avatar && review.user.charAt(0).toUpperCase()} + + + {review.user} + + on {review.flavor_name} + + + + + + {review.score}/10 + + "{review.comment}" + + ))} + + + )} );