Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>The Cheesecake Club</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #ff6b6b; | |
| --primary-dark: #ee5a52; | |
| --secondary: #4ecdc4; | |
| --accent: #ffd166; | |
| --text: #2d3748; | |
| --text-light: #718096; | |
| --bg: #f8f9fa; | |
| --bg-card: #ffffff; | |
| --border: #e2e8f0; | |
| --success: #48bb78; | |
| --warning: #ed8936; | |
| --error: #f56565; | |
| --radius: 16px; | |
| --shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); | |
| --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| } | |
| .dark-mode { | |
| --primary: #ff6b6b; | |
| --primary-dark: #ee5a52; | |
| --secondary: #4ecdc4; | |
| --accent: #ffd166; | |
| --text: #f7fafc; | |
| --text-light: #cbd5e0; | |
| --bg: #1a202c; | |
| --bg-card: #2d3748; | |
| --border: #4a5568; | |
| --shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.4); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; | |
| } | |
| body { | |
| background-color: var(--bg); | |
| color: var(--text); | |
| transition: var(--transition); | |
| line-height: 1.6; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 0 1.5rem; | |
| } | |
| /* Header */ | |
| header { | |
| background-color: var(--bg-card); | |
| backdrop-filter: blur(10px); | |
| position: sticky; | |
| top: 0; | |
| z-index: 1000; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .nav-container { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 1rem 0; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| font-weight: 700; | |
| font-size: 1.5rem; | |
| color: var(--primary); | |
| text-decoration: none; | |
| } | |
| .logo-icon { | |
| font-size: 1.75rem; | |
| } | |
| .nav-actions { | |
| display: flex; | |
| align-items: center; | |
| gap: 1rem; | |
| } | |
| .theme-toggle { | |
| background: none; | |
| border: none; | |
| color: var(--text); | |
| cursor: pointer; | |
| font-size: 1.25rem; | |
| transition: var(--transition); | |
| padding: 0.5rem; | |
| border-radius: var(--radius); | |
| } | |
| .theme-toggle:hover { | |
| background-color: var(--bg); | |
| color: var(--primary); | |
| } | |
| .primary-btn { | |
| background: linear-gradient(135deg, var(--primary), var(--primary-dark)); | |
| color: white; | |
| border: none; | |
| padding: 0.75rem 1.5rem; | |
| border-radius: var(--radius); | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| text-decoration: none; | |
| } | |
| .primary-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 25px -8px var(--primary); | |
| } | |
| .mobile-menu-btn { | |
| display: none; | |
| background: none; | |
| border: none; | |
| color: var(--text); | |
| font-size: 1.5rem; | |
| cursor: pointer; | |
| padding: 0.5rem; | |
| border-radius: var(--radius); | |
| } | |
| /* Hero Section */ | |
| .hero { | |
| padding: 4rem 0; | |
| text-align: center; | |
| background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%); | |
| color: white; | |
| margin-bottom: 3rem; | |
| } | |
| .hero h1 { | |
| font-size: 3rem; | |
| font-weight: 800; | |
| margin-bottom: 1.5rem; | |
| line-height: 1.2; | |
| } | |
| .hero p { | |
| font-size: 1.25rem; | |
| max-width: 600px; | |
| margin: 0 auto 2rem; | |
| opacity: 0.95; | |
| } | |
| .hero-actions { | |
| display: flex; | |
| gap: 1rem; | |
| justify-content: center; | |
| flex-wrap: wrap; | |
| } | |
| .btn { | |
| padding: 0.875rem 2rem; | |
| border-radius: var(--radius); | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| border: none; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| text-decoration: none; | |
| } | |
| .btn-primary { | |
| background-color: white; | |
| color: var(--primary); | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 25px -8px rgba(255, 255, 255, 0.3); | |
| } | |
| .btn-secondary { | |
| background-color: transparent; | |
| color: white; | |
| border: 2px solid white; | |
| } | |
| .btn-secondary:hover { | |
| background-color: white; | |
| color: var(--primary); | |
| } | |
| /* Main Content */ | |
| .main-content { | |
| padding-bottom: 3rem; | |
| } | |
| .section-title { | |
| font-size: 2rem; | |
| font-weight: 700; | |
| margin-bottom: 2rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| } | |
| .section-title i { | |
| color: var(--primary); | |
| } | |
| /* Search & Filters */ | |
| .search-container { | |
| margin-bottom: 2rem; | |
| } | |
| .search-bar { | |
| display: flex; | |
| background-color: var(--bg-card); | |
| border-radius: var(--radius); | |
| overflow: hidden; | |
| box-shadow: var(--shadow); | |
| } | |
| .search-input { | |
| flex: 1; | |
| padding: 1rem 1.5rem; | |
| border: none; | |
| background-color: var(--bg-card); | |
| color: var(--text); | |
| font-size: 1rem; | |
| } | |
| .search-input:focus { | |
| outline: none; | |
| } | |
| .search-btn { | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 0 1.5rem; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| .search-btn:hover { | |
| background-color: var(--primary-dark); | |
| } | |
| .filters-container { | |
| display: flex; | |
| gap: 1rem; | |
| flex-wrap: wrap; | |
| margin-bottom: 2rem; | |
| } | |
| .filter-chip { | |
| background-color: var(--bg-card); | |
| color: var(--text); | |
| padding: 0.75rem 1.5rem; | |
| border-radius: 50px; | |
| border: 1px solid var(--border); | |
| cursor: pointer; | |
| transition: var(--transition); | |
| font-weight: 500; | |
| } | |
| .filter-chip.active { | |
| background-color: var(--primary); | |
| color: white; | |
| border-color: var(--primary); | |
| } | |
| .filter-chip:hover { | |
| background-color: var(--bg); | |
| } | |
| /* Reviews Grid */ | |
| .reviews-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); | |
| gap: 2rem; | |
| margin-bottom: 4rem; | |
| } | |
| .review-card { | |
| background-color: var(--bg-card); | |
| border-radius: var(--radius); | |
| overflow: hidden; | |
| box-shadow: var(--shadow); | |
| transition: var(--transition); | |
| } | |
| .review-card:hover { | |
| transform: translateY(-8px); | |
| box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.25); | |
| } | |
| .review-image { | |
| width: 100%; | |
| height: 220px; | |
| object-fit: cover; | |
| } | |
| .review-content { | |
| padding: 1.5rem; | |
| } | |
| .review-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: flex-start; | |
| margin-bottom: 1rem; | |
| } | |
| .review-title { | |
| font-size: 1.375rem; | |
| font-weight: 700; | |
| margin-bottom: 0.5rem; | |
| } | |
| .review-meta { | |
| color: var(--text-light); | |
| font-size: 0.875rem; | |
| margin-bottom: 1rem; | |
| } | |
| .review-badge { | |
| background-color: var(--primary); | |
| color: white; | |
| padding: 0.375rem 0.75rem; | |
| border-radius: 20px; | |
| font-size: 0.75rem; | |
| font-weight: 600; | |
| } | |
| .review-badge.exception { | |
| background-color: var(--secondary); | |
| } | |
| .rating { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| margin-bottom: 1rem; | |
| } | |
| .rating-stars { | |
| color: var(--accent); | |
| display: flex; | |
| gap: 0.125rem; | |
| } | |
| .rating-value { | |
| font-weight: 700; | |
| font-size: 1.125rem; | |
| } | |
| .review-tags { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.5rem; | |
| margin-bottom: 1rem; | |
| } | |
| .tag { | |
| background-color: var(--bg); | |
| color: var(--text); | |
| padding: 0.375rem 0.75rem; | |
| border-radius: 20px; | |
| font-size: 0.75rem; | |
| font-weight: 500; | |
| } | |
| .review-preview { | |
| color: var(--text-light); | |
| font-size: 0.875rem; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 3; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| } | |
| /* Top Lists */ | |
| .top-lists { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 2rem; | |
| } | |
| .top-list { | |
| background-color: var(--bg-card); | |
| border-radius: var(--radius); | |
| padding: 2rem; | |
| box-shadow: var(--shadow); | |
| } | |
| .top-list h3 { | |
| font-size: 1.25rem; | |
| font-weight: 700; | |
| margin-bottom: 1.5rem; | |
| } | |
| .top-list-item { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 1rem 0; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .top-list-item:last-child { | |
| border-bottom: none; | |
| } | |
| /* Footer */ | |
| footer { | |
| background-color: var(--bg-card); | |
| padding: 3rem 0; | |
| border-top: 1px solid var(--border); | |
| } | |
| .footer-content { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .footer-links { | |
| display: flex; | |
| gap: 2rem; | |
| } | |
| .footer-links a { | |
| color: var(--text-light); | |
| text-decoration: none; | |
| transition: var(--transition); | |
| } | |
| .footer-links a:hover { | |
| color: var(--primary); | |
| } | |
| .built-with { | |
| color: var(--text-light); | |
| font-size: 0.875rem; | |
| } | |
| .built-with a { | |
| color: var(--primary); | |
| text-decoration: none; | |
| font-weight: 600; | |
| } | |
| .built-with a:hover { | |
| text-decoration: underline; | |
| } | |
| /* Toast */ | |
| .toast { | |
| position: fixed; | |
| bottom: 2rem; | |
| right: 2rem; | |
| background-color: var(--bg-card); | |
| color: var(--text); | |
| padding: 1rem 1.5rem; | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| z-index: 1000; | |
| transform: translateX(150%); | |
| transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55); | |
| border-left: 4px solid var(--success); | |
| } | |
| .toast.show { | |
| transform: translateX(0); | |
| } | |
| .toast-icon { | |
| font-size: 1.25rem; | |
| color: var(--success); | |
| } | |
| /* Mobile Navigation */ | |
| .mobile-nav { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: var(--bg); | |
| z-index: 2000; | |
| transform: translateX(-100%); | |
| transition: var(--transition); | |
| padding: 2rem; | |
| } | |
| .mobile-nav.show { | |
| transform: translateX(0); | |
| } | |
| .mobile-nav-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 3rem; | |
| } | |
| .mobile-nav-close { | |
| background: none; | |
| border: none; | |
| color: var(--text); | |
| font-size: 1.5rem; | |
| cursor: pointer; | |
| } | |
| .mobile-nav-links { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 2rem; | |
| } | |
| .mobile-nav-links a { | |
| text-decoration: none; | |
| color: var(--text); | |
| font-size: 1.5rem; | |
| font-weight: 600; | |
| } | |
| .mobile-nav-links a.active { | |
| color: var(--primary); | |
| } | |
| /* Responsive Design */ | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 0 1rem; | |
| } | |
| .hero h1 { | |
| font-size: 2.25rem; | |
| } | |
| .hero p { | |
| font-size: 1.125rem; | |
| } | |
| .nav-actions .primary-btn { | |
| display: none; | |
| } | |
| .mobile-menu-btn { | |
| display: block; | |
| } | |
| .hero-actions { | |
| flex-direction: column; | |
| align-items: center; | |
| } | |
| .btn { | |
| width: 100%; | |
| justify-content: center; | |
| } | |
| .filters-container { | |
| justify-content: center; | |
| } | |
| .reviews-grid { | |
| grid-template-columns: 1fr; | |
| gap: 1.5rem; | |
| } | |
| .footer-content { | |
| flex-direction: column; | |
| gap: 2rem; | |
| text-align: center; | |
| } | |
| .footer-links { | |
| flex-direction: column; | |
| gap: 1rem; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .hero { | |
| padding: 3rem 0; | |
| } | |
| .hero h1 { | |
| font-size: 2rem; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="container"> | |
| <div class="nav-container"> | |
| <a href="#" class="logo"> | |
| <i class="fas fa-cheese logo-icon"></i> | |
| <span>The Cheesecake Club</span> | |
| </a> | |
| <div class="nav-actions"> | |
| <button class="theme-toggle" id="themeToggle"> | |
| <i class="fas fa-moon"></i> | |
| </button> | |
| <a href="#" class="primary-btn"> | |
| <i class="fas fa-plus"></i> | |
| Add Review | |
| </a> | |
| <button class="mobile-menu-btn" id="mobileMenuBtn"> | |
| <i class="fas fa-bars"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="mobile-nav" id="mobileNav"> | |
| <div class="mobile-nav-header"> | |
| <a href="#" class="logo"> | |
| <i class="fas fa-cheese logo-icon"></i> | |
| <span>The Cheesecake Club</span> | |
| </a> | |
| <button class="mobile-nav-close" id="mobileNavClose"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="mobile-nav-links"> | |
| <a href="#" class="active">Home</a> | |
| <a href="#">Explore</a> | |
| <a href="#">Top Lists</a> | |
| <a href="#">Add Review</a> | |
| </div> | |
| </div> | |
| <section class="hero"> | |
| <div class="container"> | |
| <h1>Discover the World's Best Cheesecakes</h1> | |
| <p>A community of dessert lovers sharing honest reviews, ratings, and photos of cheesecakes from around the globe.</p> | |
| <div class="hero-actions"> | |
| <button class="btn btn-primary" id="addReviewBtn"> | |
| <i class="fas fa-plus"></i> | |
| Add Your Review | |
| </button> | |
| <button class="btn btn-secondary" id="exploreBtn"> | |
| <i class="fas fa-compass"></i> | |
| Explore Reviews | |
| </button> | |
| </div> | |
| </div> | |
| </section> | |
| <main class="container main-content"> | |
| <div class="search-container"> | |
| <div class="search-bar"> | |
| <input type="text" class="search-input" placeholder="Search by dessert, restaurant, or city..."> | |
| <button class="search-btn"> | |
| <i class="fas fa-search"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="filters-container"> | |
| <div class="filter-chip active">All Desserts</div> | |
| <div class="filter-chip">Cheesecake</div> | |
| <div class="filter-chip">Exceptions</div> | |
| <div class="filter-chip">Top Rated</div> | |
| </div> | |
| <h2 class="section-title"> | |
| <i class="fas fa-clock"></i> | |
| Latest Reviews | |
| </h2> | |
| <div class="reviews-grid" id="reviewsGrid"> | |
| <!-- Reviews will be populated by JavaScript --> | |
| </div> | |
| <h2 class="section-title"> | |
| <i class="fas fa-trophy"></i> | |
| Top Lists | |
| </h2> | |
| <div class="top-lists"> | |
| <div class="top-list"> | |
| <h3>Top Cheesecakes</h3> | |
| <div class="top-list-item"> | |
| <span>New York Cheesecake</span> | |
| <span class="rating-value">9.8</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Caramel American Cheesecake</span> | |
| <span class="rating-value">9.5</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Oreo Cheesecake</span> | |
| <span class="rating-value">9.3</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Basque Burnt Cheesecake</span> | |
| <span class="rating-value">9.2</span> | |
| </div> | |
| </div> | |
| <div class="top-list"> | |
| <h3>Top Cities</h3> | |
| <div class="top-list-item"> | |
| <span>New York</span> | |
| <span class="rating-value">9.4</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Lisbon</span> | |
| <span class="rating-value">9.1</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Paris</span> | |
| <span class="rating-value">8.9</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Tokyo</span> | |
| <span class="rating-value">8.7</span> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <footer> | |
| <div class="container"> | |
| <div class="footer-content"> | |
| <div class="footer-links"> | |
| <a href="#">About</a> | |
| <a href="#">Contact</a> | |
| <a href="#">Privacy</a> | |
| <a href="#">Terms</a> | |
| </div> | |
| <div class="built-with"> | |
| Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder">anycoder</a> | |
| </div> | |
| </div> | |
| </div> | |
| </footer> | |
| <div class="toast" id="toast"> | |
| <i class="fas fa-check-circle toast-icon"></i> | |
| <div class="toast-message">Review added successfully!</div> | |
| </div> | |
| <script> | |
| // Sample review data | |
| const reviews = [ | |
| { | |
| id: 1, | |
| dessertType: 'cheesecake', | |
| dessertName: 'New York Cheesecake', | |
| restaurantName: 'Junior\'s Restaurant', | |
| city: 'New York', | |
| country: 'USA', | |
| dateEaten: '2023-05-15', | |
| overallRating: 9.8, | |
| subRatings: { | |
| base: 9.5, | |
| texture: 10, | |
| sweetness: 9.5, | |
| topping: 9.0 | |
| }, | |
| wouldReturn: true, | |
| tags: ['NY Style', 'Classic', 'Dense'], | |
| textReview: 'This is the quintessential New York cheesecake. Perfectly dense, creamy, with just the right amount of sweetness. The graham cracker crust is perfectly crisp and buttery. Absolutely worth the hype!', | |
| imageUrl: 'https://images.unsplash.com/photo-1567306301408-9b74779a11f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80', | |
| price: 8.50 | |
| }, | |
| { | |
| id: 2, | |
| dessertType: 'cheesecake', | |
| dessertName: 'Caramel American Cheesecake', | |
| restaurantName: 'The Cheesecake Factory', | |
| city: 'Lisbon', | |
| country: 'Portugal', | |
| dateEaten: '2023-06-22', | |
| overallRating: 9.5, | |
| subRatings: { | |
| base: 9.0, | |
| texture: 9.5, | |
| sweetness: 9.0, | |
| topping: 10 | |
| }, | |
| wouldReturn: true, | |
| tags: ['Caramel', 'Creamy', 'Rich'], | |
| textReview: 'Incrível! A textura é perfeita, nem muito densa nem muito leve. O caramelo é divino - nem doce demais nem amargo. A combinação com a base de biscoito é perfeita.', | |
| imageUrl: 'https://images.unsplash.com/photo-1524351199678-941a58a3df50?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80', | |
| price: 7.80 | |
| }, | |
| { | |
| id: 3, | |
| dessertType: 'exception', | |
| dessertName: 'Tiramisu', | |
| restaurantName: 'Trattoria Italiana', | |
| city: 'Paris', | |
| country: 'France', | |
| dateEaten: '2023-07-10', | |
| overallRating: 9.7, | |
| subRatings: { | |
| base: 9.5, | |
| texture: 9.8, | |
| sweetness: 9.5, | |
| topping: 9.0 | |
| }, | |
| wouldReturn: true, | |
| tags: ['Coffee', 'Mascarpone', 'Italian'], | |
| textReview: 'Um dos melhores tiramisù que já provei. O equilíbrio entre o café e o mascarpone é perfeito. Não é excessivamente doce e tem uma textura incrivelmente leve.', | |
| imageUrl: 'https://images.unsplash.com/photo-1571877227200-a0d98ea1ae6?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80', | |
| price: 9.20 | |
| }, | |
| { | |
| id: 4, | |
| dessertType: 'cheesecake', | |
| dessertName: 'Oreo Cheesecake', | |
| restaurantName: 'Sweet Corner', | |
| city: 'Tokyo', | |
| country: 'Japan', | |
| dateEaten: '2023-08-05', | |
| overallRating: 9.3, | |
| subRatings: { | |
| base: 9.5, | |
| texture: 9.0, | |
| sweetness: 9.0, | |
| topping: 9.5 | |
| }, | |
| wouldReturn: true, | |
| tags: ['Oreo', 'Chocolate', 'Creamy'], | |
| textReview: 'This cheesecake is a chocolate lover\'s dream. The Oreo crust is thick and crunchy, and the filling is perfectly balanced.', | |
| imageUrl: 'https://images.unsplash.com/photo-1623334044303-2410217754f3?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80', | |
| price: 6.50 | |
| } | |
| ]; | |
| // DOM elements | |
| const themeToggle = document.getElementById('themeToggle'); | |
| const mobileMenuBtn = document.getElementById('mobileMenuBtn'); | |
| const mobileNav = document.getElementById('mobileNav'); | |
| const mobileNavClose = document.getElementById('mobileNavClose'); | |
| const addReviewBtn = document.getElementById('addReviewBtn'); | |
| const exploreBtn = document.getElementById('exploreBtn'); | |
| const reviewsGrid = document.getElementById('reviewsGrid'); | |
| const toast = document.getElementById('toast'); | |
| const filterChips = document.querySelectorAll('.filter-chip'); | |
| // Theme toggle functionality | |
| themeToggle.addEventListener('click', () => { | |
| document.body.classList.toggle('dark-mode'); | |
| const icon = themeToggle.querySelector('i'); | |
| if (document.body.classList.contains('dark-mode')) { | |
| icon.classList.remove('fa-moon'); | |
| icon.classList.add('fa-sun'); | |
| localStorage.setItem('theme', 'dark'); | |
| } else { | |
| icon.classList.remove('fa-sun'); | |
| icon.classList.add('fa-moon'); | |
| localStorage.setItem('theme', 'light'); | |
| } | |
| }); | |
| // Check for saved theme preference | |
| const savedTheme = localStorage.getItem('theme'); | |
| if (savedTheme === 'dark') { | |
| document.body.classList.add('dark-mode'); | |
| const icon = themeToggle.querySelector('i'); | |
| icon.classList.remove('fa-moon'); | |
| icon.classList.add('fa-sun'); | |
| } | |
| // Mobile menu functionality | |
| mobileMenuBtn.addEventListener('click', () => { | |
| mobileNav.classList.add('show'); | |
| }); | |
| mobileNavClose.addEventListener('click', () => { | |
| mobileNav.classList.remove('show'); | |
| }); | |
| // Add review button functionality | |
| addReviewBtn.addEventListener('click', () => { | |
| showToast('Redirecting to add review form...', 'success'); | |
| }); | |
| exploreBtn.addEventListener('click', () => { | |
| showToast('Loading explore page...', 'success'); | |
| }); | |
| // Filter chip functionality | |
| filterChips.forEach(chip => { | |
| chip.addEventListener('click', () => { | |
| filterChips.forEach(c => c.classList.remove('active')); | |
| chip.classList.add('active'); | |
| showToast(`Filtered by: ${chip.textContent}`, 'success'); | |
| }); | |
| }); | |
| // Show toast notification | |
| function showToast(message, type) { | |
| toast.querySelector('.toast-message').textContent = message; | |
| toast.classList.add('show'); | |
| setTimeout(() => { | |
| toast.classList.remove('show'); | |
| }, 3000); | |
| } | |
| // Render stars based on rating | |
| function renderStars(rating) { | |
| const fullStars = Math.floor(rating / 2); | |
| const hasHalfStar = rating % 2 >= 1; | |
| let starsHtml = ''; | |
| for (let i = 0; i < 5; i++) { | |
| if (i < fullStars) { | |
| starsHtml += '<i class="fas fa-star"></i>'; | |
| } else if (i === fullStars && hasHalfStar) { | |
| starsHtml += '<i class="fas fa-star-half-alt"></i>'; | |
| } else { | |
| starsHtml += '<i class="far fa-star"></i>'; | |
| } | |
| } | |
| return starsHtml; | |
| } | |
| // Render reviews | |
| function renderReviews() { | |
| let reviewsHtml = ''; | |
| reviews.forEach(review => { | |
| const badgeClass = review.dessertType === 'exception' ? 'exception' : ''; | |
| reviewsHtml += ` | |
| <div class="review-card" data-id="${review.id}"> | |
| <img src="${review.imageUrl}" alt="${review.dessertName}" class="review-image"> | |
| <div class="review-content"> | |
| <div class="review-header"> | |
| <div> | |
| <h3 class="review-title">${review.dessertName}</h3> | |
| <div class="review-meta">${review.restaurantName} • ${review.city}</div> | |
| </div> | |
| <span class="review-badge ${badgeClass}">${review.dessertType === 'cheesecake' ? 'Cheesecake' : 'Exception'}</span> | |
| </div> | |
| <div class="rating"> | |
| <div class="rating-stars"> | |
| ${renderStars(review.overallRating)} | |
| </div> | |
| <span class="rating-value">${review.overallRating}</span> | |
| </div> | |
| <div class="review-tags"> | |
| ${review.tags.map(tag => `<span class="tag">${tag}</span>`).join('')} | |
| </div> | |
| <p class="review-preview">${review.textReview}</p> | |
| </div> | |
| </div> | |
| `; | |
| }); | |
| reviewsGrid.innerHTML = reviewsHtml; | |
| // Add click event to review cards | |
| document.querySelectorAll('.review-card').forEach(card => { | |
| card.addEventListener('click', () => { | |
| const reviewId = card.getAttribute('data-id'); | |
| showReviewDetail(reviewId); | |
| }); | |
| }); | |
| } | |
| // Show review detail | |
| function showReviewDetail(reviewId) { | |
| const review = reviews.find(r => r.id == reviewId); | |
| if (!review) return; | |
| showToast(`Loading review: ${review.dessertName}`, 'success'); | |
| } | |
| // Initialize the app | |
| document.addEventListener('DOMContentLoaded', () => { | |
| renderReviews(); | |
| // Show welcome toast | |
| setTimeout(() => { | |
| showToast('Welcome to The Cheesecake Club!', 'success'); | |
| }, 1000); | |
| }); | |
| </script> | |
| </body> | |
| </html> |