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: #f59e0b; | |
| --primary-dark: #d97706; | |
| --secondary: #fbbf24; | |
| --accent: #f472b6; | |
| --text: #1f2937; | |
| --text-light: #6b7280; | |
| --bg: #fef7ed; | |
| --bg-card: #ffffff; | |
| --border: #e5e7eb; | |
| --success: #10b981; | |
| --warning: #f59e0b; | |
| --error: #ef4444; | |
| --radius: 12px; | |
| --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | |
| --transition: all 0.3s ease; | |
| } | |
| .dark-mode { | |
| --primary: #f59e0b; | |
| --primary-dark: #d97706; | |
| --secondary: #fbbf24; | |
| --accent: #f472b6; | |
| --text: #f9fafb; | |
| --text-light: #d1d5db; | |
| --bg: #1f2937; | |
| --bg-card: #374151; | |
| --border: #4b5563; | |
| --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background-color: var(--bg); | |
| color: var(--text); | |
| transition: var(--transition); | |
| line-height: 1.6; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 0 1rem; | |
| } | |
| header { | |
| background-color: var(--bg-card); | |
| box-shadow: var(--shadow); | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| } | |
| .header-content { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 1rem 0; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| font-weight: 700; | |
| font-size: 1.5rem; | |
| color: var(--primary); | |
| } | |
| .logo i { | |
| font-size: 1.75rem; | |
| } | |
| .nav-links { | |
| display: flex; | |
| gap: 2rem; | |
| } | |
| .nav-links a { | |
| text-decoration: none; | |
| color: var(--text); | |
| font-weight: 500; | |
| transition: var(--transition); | |
| position: relative; | |
| } | |
| .nav-links a:hover { | |
| color: var(--primary); | |
| } | |
| .nav-links a.active { | |
| color: var(--primary); | |
| } | |
| .nav-links a.active::after { | |
| content: ''; | |
| position: absolute; | |
| bottom: -0.5rem; | |
| left: 0; | |
| width: 100%; | |
| height: 2px; | |
| background-color: var(--primary); | |
| } | |
| .header-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); | |
| } | |
| .theme-toggle:hover { | |
| color: var(--primary); | |
| } | |
| .add-review-btn { | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 0.5rem 1rem; | |
| border-radius: var(--radius); | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .add-review-btn:hover { | |
| background-color: var(--primary-dark); | |
| } | |
| .mobile-menu-btn { | |
| display: none; | |
| background: none; | |
| border: none; | |
| color: var(--text); | |
| font-size: 1.5rem; | |
| cursor: pointer; | |
| } | |
| .hero { | |
| padding: 3rem 0; | |
| text-align: center; | |
| background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%); | |
| color: white; | |
| border-radius: 0 0 var(--radius) var(--radius); | |
| margin-bottom: 2rem; | |
| } | |
| .hero h1 { | |
| font-size: 2.5rem; | |
| margin-bottom: 1rem; | |
| } | |
| .hero p { | |
| font-size: 1.25rem; | |
| max-width: 600px; | |
| margin: 0 auto 1.5rem; | |
| } | |
| .hero-actions { | |
| display: flex; | |
| gap: 1rem; | |
| justify-content: center; | |
| } | |
| .btn { | |
| padding: 0.75rem 1.5rem; | |
| border-radius: var(--radius); | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| border: none; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .btn-primary { | |
| background-color: white; | |
| color: var(--primary); | |
| } | |
| .btn-primary:hover { | |
| background-color: rgba(255, 255, 255, 0.9); | |
| } | |
| .btn-secondary { | |
| background-color: transparent; | |
| color: white; | |
| border: 2px solid white; | |
| } | |
| .btn-secondary:hover { | |
| background-color: white; | |
| color: var(--primary); | |
| } | |
| .section-title { | |
| font-size: 1.75rem; | |
| margin-bottom: 1.5rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .section-title i { | |
| color: var(--primary); | |
| } | |
| .reviews-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 1.5rem; | |
| margin-bottom: 3rem; | |
| } | |
| .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(-5px); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | |
| } | |
| .review-image { | |
| width: 100%; | |
| height: 200px; | |
| object-fit: cover; | |
| } | |
| .review-content { | |
| padding: 1.25rem; | |
| } | |
| .review-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: flex-start; | |
| margin-bottom: 0.75rem; | |
| } | |
| .review-title { | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| margin-bottom: 0.25rem; | |
| } | |
| .review-badge { | |
| background-color: var(--primary); | |
| color: white; | |
| padding: 0.25rem 0.5rem; | |
| border-radius: 20px; | |
| font-size: 0.75rem; | |
| font-weight: 500; | |
| } | |
| .review-badge.exception { | |
| background-color: var(--accent); | |
| } | |
| .review-meta { | |
| color: var(--text-light); | |
| font-size: 0.875rem; | |
| margin-bottom: 0.75rem; | |
| } | |
| .rating { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| margin-bottom: 0.75rem; | |
| } | |
| .rating-stars { | |
| color: var(--primary); | |
| display: flex; | |
| } | |
| .rating-value { | |
| font-weight: 600; | |
| } | |
| .review-tags { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.5rem; | |
| margin-bottom: 1rem; | |
| } | |
| .tag { | |
| background-color: var(--bg); | |
| color: var(--text); | |
| padding: 0.25rem 0.5rem; | |
| border-radius: 20px; | |
| font-size: 0.75rem; | |
| } | |
| .review-preview { | |
| color: var(--text-light); | |
| font-size: 0.875rem; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 3; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| } | |
| .filters { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 1rem; | |
| margin-bottom: 2rem; | |
| background-color: var(--bg-card); | |
| padding: 1.25rem; | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow); | |
| } | |
| .filter-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| } | |
| .filter-label { | |
| font-size: 0.875rem; | |
| font-weight: 500; | |
| } | |
| .filter-select, .filter-input { | |
| padding: 0.5rem; | |
| border-radius: var(--radius); | |
| border: 1px solid var(--border); | |
| background-color: var(--bg); | |
| color: var(--text); | |
| } | |
| .search-bar { | |
| display: flex; | |
| gap: 0.5rem; | |
| margin-bottom: 2rem; | |
| } | |
| .search-input { | |
| flex: 1; | |
| padding: 0.75rem 1rem; | |
| border-radius: var(--radius); | |
| border: 1px solid var(--border); | |
| background-color: var(--bg); | |
| color: var(--text); | |
| } | |
| .search-btn { | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 0 1.25rem; | |
| border-radius: var(--radius); | |
| cursor: pointer; | |
| } | |
| .form-container { | |
| max-width: 800px; | |
| margin: 0 auto; | |
| background-color: var(--bg-card); | |
| padding: 2rem; | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow); | |
| } | |
| .form-group { | |
| margin-bottom: 1.5rem; | |
| } | |
| .form-label { | |
| display: block; | |
| margin-bottom: 0.5rem; | |
| font-weight: 500; | |
| } | |
| .form-input, .form-textarea, .form-select { | |
| width: 100%; | |
| padding: 0.75rem; | |
| border-radius: var(--radius); | |
| border: 1px solid var(--border); | |
| background-color: var(--bg); | |
| color: var(--text); | |
| transition: var(--transition); | |
| } | |
| .form-input:focus, .form-textarea:focus, .form-select:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2); | |
| } | |
| .form-textarea { | |
| min-height: 150px; | |
| resize: vertical; | |
| } | |
| .form-row { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 1rem; | |
| } | |
| .rating-slider { | |
| width: 100%; | |
| margin: 0.5rem 0; | |
| } | |
| .rating-display { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-top: 0.5rem; | |
| font-size: 0.875rem; | |
| color: var(--text-light); | |
| } | |
| .sub-ratings { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | |
| gap: 1rem; | |
| margin-top: 1rem; | |
| } | |
| .checkbox-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .checkbox { | |
| width: 1.25rem; | |
| height: 1.25rem; | |
| accent-color: var(--primary); | |
| } | |
| .photo-upload { | |
| border: 2px dashed var(--border); | |
| border-radius: var(--radius); | |
| padding: 2rem; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| .photo-upload:hover { | |
| border-color: var(--primary); | |
| } | |
| .photo-preview { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 1rem; | |
| margin-top: 1rem; | |
| } | |
| .preview-image { | |
| width: 100px; | |
| height: 100px; | |
| object-fit: cover; | |
| border-radius: var(--radius); | |
| } | |
| .submit-btn { | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 0.75rem 2rem; | |
| border-radius: var(--radius); | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| width: 100%; | |
| font-size: 1rem; | |
| } | |
| .submit-btn:hover { | |
| background-color: var(--primary-dark); | |
| } | |
| .toast { | |
| position: fixed; | |
| bottom: 1rem; | |
| right: 1rem; | |
| 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.3s ease; | |
| } | |
| .toast.show { | |
| transform: translateX(0); | |
| } | |
| .toast.success { | |
| border-left: 4px solid var(--success); | |
| } | |
| .toast.error { | |
| border-left: 4px solid var(--error); | |
| } | |
| .toast-icon { | |
| font-size: 1.25rem; | |
| } | |
| .toast.success .toast-icon { | |
| color: var(--success); | |
| } | |
| .toast.error .toast-icon { | |
| color: var(--error); | |
| } | |
| .top-lists { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 1.5rem; | |
| margin-bottom: 3rem; | |
| } | |
| .top-list { | |
| background-color: var(--bg-card); | |
| border-radius: var(--radius); | |
| padding: 1.5rem; | |
| box-shadow: var(--shadow); | |
| } | |
| .top-list-item { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 0.75rem 0; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .top-list-item:last-child { | |
| border-bottom: none; | |
| } | |
| .premium-badge { | |
| background: linear-gradient(135deg, #f59e0b, #f472b6); | |
| color: white; | |
| padding: 0.25rem 0.5rem; | |
| border-radius: 20px; | |
| font-size: 0.75rem; | |
| font-weight: 500; | |
| margin-left: 0.5rem; | |
| } | |
| footer { | |
| background-color: var(--bg-card); | |
| padding: 2rem 0; | |
| margin-top: 3rem; | |
| border-top: 1px solid var(--border); | |
| } | |
| .footer-content { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .footer-links { | |
| display: flex; | |
| gap: 1.5rem; | |
| } | |
| .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; | |
| } | |
| .built-with a:hover { | |
| text-decoration: underline; | |
| } | |
| .detail-container { | |
| max-width: 900px; | |
| margin: 0 auto; | |
| background-color: var(--bg-card); | |
| border-radius: var(--radius); | |
| overflow: hidden; | |
| box-shadow: var(--shadow); | |
| } | |
| .detail-gallery { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | |
| gap: 1rem; | |
| padding: 1.5rem; | |
| } | |
| .detail-image { | |
| width: 100%; | |
| height: 150px; | |
| object-fit: cover; | |
| border-radius: var(--radius); | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| .detail-image:hover { | |
| transform: scale(1.05); | |
| } | |
| .detail-content { | |
| padding: 1.5rem; | |
| } | |
| .detail-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: flex-start; | |
| margin-bottom: 1rem; | |
| } | |
| .detail-meta { | |
| color: var(--text-light); | |
| margin-bottom: 1.5rem; | |
| } | |
| .detail-ratings { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | |
| gap: 1rem; | |
| margin-bottom: 1.5rem; | |
| } | |
| .rating-bar { | |
| height: 8px; | |
| background-color: var(--border); | |
| border-radius: 4px; | |
| overflow: hidden; | |
| margin-top: 0.25rem; | |
| } | |
| .rating-fill { | |
| height: 100%; | |
| background-color: var(--primary); | |
| border-radius: 4px; | |
| } | |
| .detail-text { | |
| line-height: 1.7; | |
| margin-bottom: 1.5rem; | |
| } | |
| .modal { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: rgba(0, 0, 0, 0.7); | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| z-index: 1000; | |
| opacity: 0; | |
| visibility: hidden; | |
| transition: var(--transition); | |
| } | |
| .modal.show { | |
| opacity: 1; | |
| visibility: visible; | |
| } | |
| .modal-content { | |
| max-width: 90%; | |
| max-height: 90%; | |
| position: relative; | |
| } | |
| .modal-image { | |
| max-width: 100%; | |
| max-height: 90vh; | |
| border-radius: var(--radius); | |
| } | |
| .modal-close { | |
| position: absolute; | |
| top: 1rem; | |
| right: 1rem; | |
| background-color: rgba(0, 0, 0, 0.5); | |
| color: white; | |
| border: none; | |
| width: 2.5rem; | |
| height: 2.5rem; | |
| border-radius: 50%; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| .modal-close:hover { | |
| background-color: rgba(0, 0, 0, 0.7); | |
| } | |
| .skeleton { | |
| background: linear-gradient(90deg, var(--border) 25%, var(--bg) 50%, var(--border) 75%); | |
| background-size: 200% 100%; | |
| animation: loading 1.5s infinite; | |
| border-radius: var(--radius); | |
| } | |
| @keyframes loading { | |
| 0% { | |
| background-position: 200% 0; | |
| } | |
| 100% { | |
| background-position: -200% 0; | |
| } | |
| } | |
| .skeleton-image { | |
| height: 200px; | |
| width: 100%; | |
| } | |
| .skeleton-text { | |
| height: 1rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| .skeleton-text.short { | |
| width: 60%; | |
| } | |
| .mobile-nav { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: var(--bg); | |
| z-index: 200; | |
| display: flex; | |
| flex-direction: column; | |
| padding: 2rem; | |
| transform: translateX(-100%); | |
| transition: var(--transition); | |
| } | |
| .mobile-nav.show { | |
| transform: translateX(0); | |
| } | |
| .mobile-nav-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 2rem; | |
| } | |
| .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: 1.5rem; | |
| } | |
| .mobile-nav-links a { | |
| text-decoration: none; | |
| color: var(--text); | |
| font-size: 1.25rem; | |
| font-weight: 500; | |
| } | |
| .mobile-nav-links a.active { | |
| color: var(--primary); | |
| } | |
| @media (max-width: 768px) { | |
| .nav-links, .header-actions .add-review-btn { | |
| display: none; | |
| } | |
| .mobile-menu-btn { | |
| display: block; | |
| } | |
| .hero h1 { | |
| font-size: 2rem; | |
| } | |
| .hero p { | |
| font-size: 1rem; | |
| } | |
| .hero-actions { | |
| flex-direction: column; | |
| align-items: center; | |
| } | |
| .form-row { | |
| grid-template-columns: 1fr; | |
| } | |
| .footer-content { | |
| flex-direction: column; | |
| gap: 1.5rem; | |
| text-align: center; | |
| } | |
| .reviews-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="container"> | |
| <div class="header-content"> | |
| <div class="logo"> | |
| <i class="fas fa-cheese"></i> | |
| <span>The Cheesecake Club</span> | |
| </div> | |
| <nav class="nav-links"> | |
| <a href="#" class="active">Home</a> | |
| <a href="#">Explore</a> | |
| <a href="#">Top Lists</a> | |
| <a href="#">Premium</a> | |
| </nav> | |
| <div class="header-actions"> | |
| <button class="theme-toggle" id="themeToggle"> | |
| <i class="fas fa-moon"></i> | |
| </button> | |
| <button class="add-review-btn"> | |
| <i class="fas fa-plus"></i> | |
| Add Review | |
| </button> | |
| <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"> | |
| <div class="logo"> | |
| <i class="fas fa-cheese"></i> | |
| <span>The Cheesecake Club</span> | |
| </div> | |
| <button class="mobile-nav-close" id="mobileNavClose"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| <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> | |
| <a href="#">Premium</a> | |
| </div> | |
| </div> | |
| <div 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 and other sweet treats 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> | |
| </div> | |
| <main class="container"> | |
| <div class="search-bar"> | |
| <input type="text" class="search-input" placeholder="Search by dessert, restaurant, city, or review text..."> | |
| <button class="search-btn"> | |
| <i class="fas fa-search"></i> | |
| </button> | |
| </div> | |
| <div class="filters"> | |
| <div class="filter-group"> | |
| <label class="filter-label">Dessert Type</label> | |
| <select class="filter-select"> | |
| <option>All Desserts</option> | |
| <option>Cheesecake Only</option> | |
| <option>Exceptions Only</option> | |
| </select> | |
| </div> | |
| <div class="filter-group"> | |
| <label class="filter-label">City</label> | |
| <select class="filter-select"> | |
| <option>All Cities</option> | |
| <option>New York</option> | |
| <option>Lisbon</option> | |
| <option>Paris</option> | |
| <option>Tokyo</option> | |
| </select> | |
| </div> | |
| <div class="filter-group"> | |
| <label class="filter-label">Min Rating</label> | |
| <select class="filter-select"> | |
| <option>Any Rating</option> | |
| <option>9+</option> | |
| <option>8+</option> | |
| <option>7+</option> | |
| <option>6+</option> | |
| </select> | |
| </div> | |
| <div class="filter-group"> | |
| <label class="filter-label">Sort By</label> | |
| <select class="filter-select"> | |
| <option>Newest First</option> | |
| <option>Highest Rated</option> | |
| <option>Oldest First</option> | |
| </select> | |
| </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 Rated 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 class="top-list-item"> | |
| <span>Strawberry Swirl Cheesecake</span> | |
| <span class="rating-value">9.0</span> | |
| </div> | |
| </div> | |
| <div class="top-list"> | |
| <h3>Top Rated Exceptions</h3> | |
| <div class="top-list-item"> | |
| <span>Tiramisu</span> | |
| <span class="rating-value">9.7</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Chocolate Lava Cake</span> | |
| <span class="rating-value">9.4</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Crème Brûlée</span> | |
| <span class="rating-value">9.2</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Apple Pie</span> | |
| <span class="rating-value">9.0</span> | |
| </div> | |
| <div class="top-list-item"> | |
| <span>Panna Cotta</span> | |
| <span class="rating-value">8.8</span> | |
| </div> | |
| </div> | |
| <div class="top-list"> | |
| <h3>By City</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 class="top-list-item"> | |
| <span>London</span> | |
| <span class="rating-value">8.5</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> | |
| <div class="modal" id="imageModal"> | |
| <div class="modal-content"> | |
| <img class="modal-image" id="modalImage" src="" alt=""> | |
| <button class="modal-close" id="modalClose"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </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. Definitivamente voltaria só por esta sobremesa.', | |
| 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. Perfeito para terminar uma refeição.', | |
| 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 between cream cheese and cookie flavors. The chocolate ganache topping is rich but not overwhelming.', | |
| 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 | |
| }, | |
| { | |
| id: 5, | |
| dessertType: 'cheesecake', | |
| dessertName: 'Basque Burnt Cheesecake', | |
| restaurantName: 'La Fromagerie', | |
| city: 'Paris', | |
| country: 'France', | |
| dateEaten: '2023-09-12', | |
| overallRating: 9.2, | |
| subRatings: { | |
| base: 8.5, | |
| texture: 9.5, | |
| sweetness: 9.0, | |
| topping: 8.0 | |
| }, | |
| wouldReturn: true, | |
| tags: ['Burnt', 'Creamy', 'Rustic'], | |
| textReview: 'A textura é incrível - cremosa por dentro com aquela crosta caramelizada por fora. Menos doce que um cheesecake tradicional, o que permite que o sabor do queijo realmente brilhe. A apresentação rústica é encantadora.', | |
| imageUrl: 'https://images.unsplash.com/photo-1569670751316-4d5c5d5b5b5b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80', | |
| price: 7.00 | |
| } | |
| ]; | |
| // 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 imageModal = document.getElementById('imageModal'); | |
| const modalImage = document.getElementById('modalImage'); | |
| const modalClose = document.getElementById('modalClose'); | |
| // 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'); | |
| // In a real app, this would navigate to the add review page | |
| }); | |
| exploreBtn.addEventListener('click', () => { | |
| showToast('Loading explore page...', 'success'); | |
| // In a real app, this would navigate to the explore page | |
| }); | |
| // Show toast notification | |
| function showToast(message, type) { | |
| toast.className = `toast ${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', (e) => { | |
| if (!e.target.classList.contains('review-image')) { | |
| const reviewId = card.getAttribute('data-id'); | |
| showReviewDetail(reviewId); | |
| } | |
| }); | |
| }); | |
| // Add click event to review images | |
| document.querySelectorAll('.review-image').forEach(img => { | |
| img.addEventListener('click', (e) => { | |
| e.stopPropagation(); | |
| const reviewId = img.closest('.review-card').getAttribute('data-id'); | |
| openImageModal(reviewId); | |
| }); | |
| }); | |
| } | |
| // Show review detail | |
| function showReviewDetail(reviewId) { | |
| const review = reviews.find(r => r.id == reviewId); | |
| if (!review) return; | |
| // In a real app, this would navigate to the review detail page | |
| showToast(`Loading review: ${review.dessertName}`, 'success'); | |
| } | |
| // Open image modal | |
| function openImageModal(reviewId) { | |
| const review = reviews.find(r => r.id == reviewId); | |
| if (!review) return; | |
| modalImage.src = review.imageUrl; | |
| modalImage.alt = review.dessertName; | |
| imageModal.classList.add('show'); | |
| } | |
| // Close image modal | |
| modalClose.addEventListener('click', () => { | |
| imageModal.classList.remove('show'); | |
| }); | |
| // Close modal when clicking outside the image | |
| imageModal.addEventListener('click', (e) => { | |
| if (e.target === imageModal) { | |
| imageModal.classList.remove('show'); | |
| } | |
| }); | |
| // Initialize the app | |
| document.addEventListener('DOMContentLoaded', () => { | |
| renderReviews(); | |
| // Show welcome toast | |
| setTimeout(() => { | |
| showToast('Welcome to The Cheesecake Club!', 'success'); | |
| }, 1000); | |
| }); | |
| </script> | |
| </body> | |
| </html> |