Commit ·
b10c786
1
Parent(s): c37ac4d
hero section 2.0
Browse files
frontend/src/app/globals.css
CHANGED
|
@@ -1,23 +1,28 @@
|
|
| 1 |
-
@import url(
|
| 2 |
|
| 3 |
@tailwind base;
|
| 4 |
@tailwind components;
|
| 5 |
@tailwind utilities;
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
body {
|
| 8 |
-
font-family:
|
| 9 |
-
background-color:
|
| 10 |
-
-ms-overflow-style: none;
|
| 11 |
-
scrollbar-width: none;
|
| 12 |
scroll-behavior: smooth;
|
| 13 |
}
|
| 14 |
|
| 15 |
-
.app-container{
|
| 16 |
-
-ms-overflow-style: none;
|
| 17 |
-
scrollbar-width: none;
|
| 18 |
scroll-behavior: smooth;
|
| 19 |
overflow: scroll;
|
| 20 |
-
|
| 21 |
padding-top: 80px;
|
| 22 |
}
|
| 23 |
|
|
|
|
| 1 |
+
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;900&family=Noto+Sans:wght@400;500;700;900&display=swap");
|
| 2 |
|
| 3 |
@tailwind base;
|
| 4 |
@tailwind components;
|
| 5 |
@tailwind utilities;
|
| 6 |
|
| 7 |
+
:root {
|
| 8 |
+
--bg-primary: #11121f;
|
| 9 |
+
--bg-secondary: #0c0c16;
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
body {
|
| 13 |
+
font-family: "Inter", "Noto Sans", sans-serif;
|
| 14 |
+
background-color: var(--bg-primary) !important;
|
| 15 |
+
-ms-overflow-style: none; /* IE and Edge */
|
| 16 |
+
scrollbar-width: none; /* Firefox */
|
| 17 |
scroll-behavior: smooth;
|
| 18 |
}
|
| 19 |
|
| 20 |
+
.app-container {
|
| 21 |
+
-ms-overflow-style: none; /* IE and Edge */
|
| 22 |
+
scrollbar-width: none; /* Firefox */
|
| 23 |
scroll-behavior: smooth;
|
| 24 |
overflow: scroll;
|
| 25 |
+
height: 100dvh;
|
| 26 |
padding-top: 80px;
|
| 27 |
}
|
| 28 |
|
frontend/src/app/index.css
CHANGED
|
@@ -11,7 +11,6 @@
|
|
| 11 |
.index-page-container {
|
| 12 |
display: flex;
|
| 13 |
flex-direction: column;
|
| 14 |
-
margin: 0 auto;
|
| 15 |
flex: 1;
|
| 16 |
}
|
| 17 |
|
|
|
|
| 11 |
.index-page-container {
|
| 12 |
display: flex;
|
| 13 |
flex-direction: column;
|
|
|
|
| 14 |
flex: 1;
|
| 15 |
}
|
| 16 |
|
frontend/src/components/HeroSection.css
CHANGED
|
@@ -12,32 +12,80 @@
|
|
| 12 |
.hero-container {
|
| 13 |
position: relative;
|
| 14 |
width: 100%;
|
| 15 |
-
overflow:
|
| 16 |
}
|
| 17 |
|
| 18 |
.hero-section {
|
| 19 |
display: flex;
|
| 20 |
flex-direction: column;
|
| 21 |
-
min-height:
|
|
|
|
| 22 |
position: relative;
|
| 23 |
border-radius: 12px;
|
| 24 |
-
|
| 25 |
-
padding-bottom: 2.5rem;
|
| 26 |
justify-content: center;
|
| 27 |
-
animation: fadeIn 1s ease-in-out; /* Add fade-in animation */
|
| 28 |
}
|
| 29 |
|
| 30 |
.hero-image {
|
| 31 |
position: absolute;
|
| 32 |
top: 0;
|
| 33 |
left: 0;
|
| 34 |
-
width:
|
| 35 |
-
height:
|
| 36 |
background-size: cover;
|
| 37 |
background-position: center;
|
| 38 |
background-repeat: no-repeat;
|
| 39 |
transition: opacity 1s ease-in-out; /* Smooth transition */
|
| 40 |
opacity: 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
}
|
| 42 |
|
| 43 |
.hero-image.active {
|
|
@@ -47,24 +95,27 @@
|
|
| 47 |
.hero-text {
|
| 48 |
display: flex;
|
| 49 |
flex-direction: column;
|
| 50 |
-
justify-content: center;
|
| 51 |
color: white;
|
| 52 |
gap: 0.5rem;
|
| 53 |
text-align: left;
|
| 54 |
z-index: 1;
|
| 55 |
height: 100%;
|
| 56 |
-
margin:
|
| 57 |
-
|
|
|
|
|
|
|
| 58 |
}
|
| 59 |
|
| 60 |
.hero-title {
|
| 61 |
color: white;
|
| 62 |
-
font-size:
|
| 63 |
font-family: "Anton", sans-serif;
|
| 64 |
font-weight: 400;
|
| 65 |
font-style: normal;
|
| 66 |
line-height: 1;
|
| 67 |
transition: font-size 0.3s ease-in-out;
|
|
|
|
|
|
|
| 68 |
}
|
| 69 |
|
| 70 |
.hero-section-play-button {
|
|
@@ -76,7 +127,7 @@
|
|
| 76 |
|
| 77 |
.hero-description {
|
| 78 |
color: white;
|
| 79 |
-
font-size:
|
| 80 |
font-weight: normal;
|
| 81 |
line-height: 1.4;
|
| 82 |
overflow: hidden; /* Hide text overflow */
|
|
@@ -85,13 +136,13 @@
|
|
| 85 |
-webkit-box-orient: vertical; /* Set box orientation to vertical */
|
| 86 |
text-overflow: ellipsis; /* Add ellipsis (...) */
|
| 87 |
transition: font-size 0.3s ease-in-out;
|
|
|
|
| 88 |
}
|
| 89 |
|
| 90 |
.hero-indicators {
|
| 91 |
position: absolute;
|
| 92 |
bottom: 1rem;
|
| 93 |
left: 50%;
|
| 94 |
-
transform: translateX(-50%);
|
| 95 |
display: flex;
|
| 96 |
gap: 0.5rem;
|
| 97 |
}
|
|
@@ -111,85 +162,30 @@
|
|
| 111 |
}
|
| 112 |
|
| 113 |
/* Responsive Styles */
|
| 114 |
-
@media (
|
| 115 |
-
.hero-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
font-size: 0.875rem;
|
| 120 |
-
}
|
| 121 |
-
.hero-button {
|
| 122 |
-
height: 2rem;
|
| 123 |
-
font-size: 0.75rem;
|
| 124 |
-
padding: 0 0.75rem;
|
| 125 |
-
}
|
| 126 |
-
.indicator {
|
| 127 |
-
width: 15px;
|
| 128 |
-
height: 7px;
|
| 129 |
-
}
|
| 130 |
-
}
|
| 131 |
-
|
| 132 |
-
@media (max-width: 992px) {
|
| 133 |
-
.hero-section {
|
| 134 |
-
min-height: 400px;
|
| 135 |
}
|
| 136 |
.hero-title {
|
| 137 |
-
|
|
|
|
| 138 |
}
|
| 139 |
-
.hero-description {
|
| 140 |
-
font-size: 0.75rem;
|
| 141 |
-
}
|
| 142 |
-
.hero-button {
|
| 143 |
-
height: 1.75rem;
|
| 144 |
-
font-size: 0.675rem;
|
| 145 |
-
padding: 0 0.5rem;
|
| 146 |
-
}
|
| 147 |
-
.indicator {
|
| 148 |
-
width: 12px;
|
| 149 |
-
height: 6px;
|
| 150 |
-
}
|
| 151 |
-
}
|
| 152 |
-
|
| 153 |
-
@media (max-width: 768px) {
|
| 154 |
.hero-section {
|
| 155 |
-
min-height:
|
| 156 |
-
padding: 0.5rem;
|
| 157 |
-
padding-bottom: 2rem;
|
| 158 |
}
|
| 159 |
-
.hero-
|
| 160 |
-
font-size:
|
| 161 |
-
}
|
| 162 |
-
.hero-description {
|
| 163 |
-
font-size: 0.875rem;
|
| 164 |
-
}
|
| 165 |
-
.hero-button {
|
| 166 |
-
height: 1.5rem;
|
| 167 |
-
font-size: 0.75rem;
|
| 168 |
-
padding: 0 0.5rem;
|
| 169 |
-
}
|
| 170 |
-
.indicator {
|
| 171 |
-
width: 15px;
|
| 172 |
-
height: 8px;
|
| 173 |
}
|
|
|
|
| 174 |
}
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
min-height: 200px;
|
| 179 |
}
|
| 180 |
-
.hero-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
.hero-description {
|
| 184 |
-
font-size: 0.75rem;
|
| 185 |
-
}
|
| 186 |
-
.hero-button {
|
| 187 |
-
height: 1.25rem;
|
| 188 |
-
font-size: 0.625rem;
|
| 189 |
-
padding: 0 0.5rem;
|
| 190 |
}
|
| 191 |
-
|
| 192 |
-
width: 12px;
|
| 193 |
-
height: 6px;
|
| 194 |
-
}
|
| 195 |
-
}
|
|
|
|
| 12 |
.hero-container {
|
| 13 |
position: relative;
|
| 14 |
width: 100%;
|
| 15 |
+
overflow: visible;
|
| 16 |
}
|
| 17 |
|
| 18 |
.hero-section {
|
| 19 |
display: flex;
|
| 20 |
flex-direction: column;
|
| 21 |
+
min-height: 30rem;
|
| 22 |
+
width: 100dvw;
|
| 23 |
position: relative;
|
| 24 |
border-radius: 12px;
|
| 25 |
+
animation: fadeIn 1s ease-in-out;
|
|
|
|
| 26 |
justify-content: center;
|
|
|
|
| 27 |
}
|
| 28 |
|
| 29 |
.hero-image {
|
| 30 |
position: absolute;
|
| 31 |
top: 0;
|
| 32 |
left: 0;
|
| 33 |
+
width: 100dvw;
|
| 34 |
+
height: 100dvh;
|
| 35 |
background-size: cover;
|
| 36 |
background-position: center;
|
| 37 |
background-repeat: no-repeat;
|
| 38 |
transition: opacity 1s ease-in-out; /* Smooth transition */
|
| 39 |
opacity: 0;
|
| 40 |
+
z-index: -1;
|
| 41 |
+
animation: hero-anim-landscape 15s infinite;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
@keyframes hero-anim-portrait {
|
| 45 |
+
0% {
|
| 46 |
+
background-position: center;
|
| 47 |
+
background-size: 160% 140%;
|
| 48 |
+
}
|
| 49 |
+
25% {
|
| 50 |
+
background-position: top left;
|
| 51 |
+
background-size: 120% 100%;
|
| 52 |
+
}
|
| 53 |
+
50% {
|
| 54 |
+
background-position: bottom right;
|
| 55 |
+
background-size: 160% 140%;
|
| 56 |
+
}
|
| 57 |
+
75% {
|
| 58 |
+
background-position: top right;
|
| 59 |
+
background-size: 120% 100%;
|
| 60 |
+
}
|
| 61 |
+
100% {
|
| 62 |
+
background-position: center;
|
| 63 |
+
background-size: 160% 140%;
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
@keyframes hero-anim-landscape {
|
| 69 |
+
0% {
|
| 70 |
+
background-position: center;
|
| 71 |
+
background-size: 130% 150%;
|
| 72 |
+
}
|
| 73 |
+
25% {
|
| 74 |
+
background-position: top left;
|
| 75 |
+
background-size: 100% 120%;
|
| 76 |
+
}
|
| 77 |
+
50% {
|
| 78 |
+
background-position: bottom right;
|
| 79 |
+
background-size: 130% 150%;
|
| 80 |
+
}
|
| 81 |
+
75% {
|
| 82 |
+
background-position: top right;
|
| 83 |
+
background-size: 100% 120%;
|
| 84 |
+
}
|
| 85 |
+
100% {
|
| 86 |
+
background-position: center;
|
| 87 |
+
background-size: 130% 150%;
|
| 88 |
+
}
|
| 89 |
}
|
| 90 |
|
| 91 |
.hero-image.active {
|
|
|
|
| 95 |
.hero-text {
|
| 96 |
display: flex;
|
| 97 |
flex-direction: column;
|
|
|
|
| 98 |
color: white;
|
| 99 |
gap: 0.5rem;
|
| 100 |
text-align: left;
|
| 101 |
z-index: 1;
|
| 102 |
height: 100%;
|
| 103 |
+
margin-top: 30px;
|
| 104 |
+
margin-left: 20px;
|
| 105 |
+
width: 80%;
|
| 106 |
+
justify-content: space-around;
|
| 107 |
}
|
| 108 |
|
| 109 |
.hero-title {
|
| 110 |
color: white;
|
| 111 |
+
font-size: 7rem;
|
| 112 |
font-family: "Anton", sans-serif;
|
| 113 |
font-weight: 400;
|
| 114 |
font-style: normal;
|
| 115 |
line-height: 1;
|
| 116 |
transition: font-size 0.3s ease-in-out;
|
| 117 |
+
user-select: none;
|
| 118 |
+
width: auto;
|
| 119 |
}
|
| 120 |
|
| 121 |
.hero-section-play-button {
|
|
|
|
| 127 |
|
| 128 |
.hero-description {
|
| 129 |
color: white;
|
| 130 |
+
font-size: 1.2rem;
|
| 131 |
font-weight: normal;
|
| 132 |
line-height: 1.4;
|
| 133 |
overflow: hidden; /* Hide text overflow */
|
|
|
|
| 136 |
-webkit-box-orient: vertical; /* Set box orientation to vertical */
|
| 137 |
text-overflow: ellipsis; /* Add ellipsis (...) */
|
| 138 |
transition: font-size 0.3s ease-in-out;
|
| 139 |
+
user-select: none;
|
| 140 |
}
|
| 141 |
|
| 142 |
.hero-indicators {
|
| 143 |
position: absolute;
|
| 144 |
bottom: 1rem;
|
| 145 |
left: 50%;
|
|
|
|
| 146 |
display: flex;
|
| 147 |
gap: 0.5rem;
|
| 148 |
}
|
|
|
|
| 162 |
}
|
| 163 |
|
| 164 |
/* Responsive Styles */
|
| 165 |
+
@media (orientation:portrait){
|
| 166 |
+
.hero-image{
|
| 167 |
+
height: 85dvw;
|
| 168 |
+
width: 100dvw;
|
| 169 |
+
animation: hero-anim-portrait 15s infinite;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
}
|
| 171 |
.hero-title {
|
| 172 |
+
color: white;
|
| 173 |
+
font-size: 2.5rem;
|
| 174 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
.hero-section {
|
| 176 |
+
min-height: 14rem;
|
|
|
|
|
|
|
| 177 |
}
|
| 178 |
+
.hero-description{
|
| 179 |
+
font-size: .9rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
}
|
| 181 |
+
|
| 182 |
}
|
| 183 |
+
@media (orientation:landscape){
|
| 184 |
+
.hero-section{
|
| 185 |
+
height: 3.5rem;
|
|
|
|
| 186 |
}
|
| 187 |
+
.hero-text{
|
| 188 |
+
margin-top: 3rem;
|
| 189 |
+
margin-left: 4rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
}
|
| 191 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/components/HeroSection.js
CHANGED
|
@@ -1,116 +1,159 @@
|
|
| 1 |
-
|
| 2 |
-
import { useState, useEffect, useRef } from
|
| 3 |
-
import
|
| 4 |
-
import apiClient from
|
| 5 |
-
import SkeletonLoader from
|
| 6 |
-
import { FontAwesomeIcon } from
|
| 7 |
-
import { faPlay } from
|
| 8 |
-
import Link from
|
| 9 |
|
| 10 |
const HeroSection = () => {
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
|
|
|
|
|
|
| 16 |
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
| 41 |
|
| 42 |
-
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
intervalRef.current = setInterval(() => {
|
| 48 |
-
setFadeOut(true);
|
| 49 |
-
setTimeout(() => {
|
| 50 |
-
setCurrentIndex(prevIndex => (prevIndex + 1) % items.length);
|
| 51 |
-
setFadeOut(false);
|
| 52 |
-
}, 200);
|
| 53 |
-
}, 5000);
|
| 54 |
};
|
|
|
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
| 73 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
-
|
| 80 |
-
|
|
|
|
| 81 |
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
<div className="hero-section">
|
| 85 |
-
{items.map((item, index) => (
|
| 86 |
-
<div
|
| 87 |
-
key={index}
|
| 88 |
-
className={`hero-image ${index === currentIndex ? 'active' : ''} ${fadeOut ? 'fade-out' : ''}`}
|
| 89 |
-
style={{ backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.1) 0%, #11121f 100%), url("${item.imageUrl}")` }}
|
| 90 |
-
></div>
|
| 91 |
-
))}
|
| 92 |
-
<div className="hero-text">
|
| 93 |
-
<h1 className="hero-title">{title}</h1>
|
| 94 |
-
<Link href={linkPath}>
|
| 95 |
-
<button className="hero-section-play-button">
|
| 96 |
-
<FontAwesomeIcon icon={faPlay} size="lg" /> Play
|
| 97 |
-
</button>
|
| 98 |
-
</Link>
|
| 99 |
-
<p className="hero-description">{description}</p>
|
| 100 |
-
</div>
|
| 101 |
-
</div>
|
| 102 |
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
</div>
|
| 113 |
-
|
|
|
|
|
|
|
| 114 |
};
|
| 115 |
|
| 116 |
export default HeroSection;
|
|
|
|
| 1 |
+
"use client";
|
| 2 |
+
import { useState, useEffect, useRef } from "react";
|
| 3 |
+
import "./HeroSection.css";
|
| 4 |
+
import apiClient from "@/api/apiClient";
|
| 5 |
+
import SkeletonLoader from "@/skeletons/HeroSection";
|
| 6 |
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
| 7 |
+
import { faPlay } from "@fortawesome/free-solid-svg-icons";
|
| 8 |
+
import Link from "next/link";
|
| 9 |
|
| 10 |
const HeroSection = () => {
|
| 11 |
+
const [currentIndex, setCurrentIndex] = useState(0);
|
| 12 |
+
const intervalRef = useRef(null);
|
| 13 |
+
const [fadeOut, setFadeOut] = useState(false);
|
| 14 |
+
const [items, setItems] = useState([]);
|
| 15 |
+
const [loading, setLoading] = useState(true);
|
| 16 |
+
const [isDragging, setIsDragging] = useState(false);
|
| 17 |
+
const [startX, setStartX] = useState(0);
|
| 18 |
|
| 19 |
+
useEffect(() => {
|
| 20 |
+
const fetchRecentItems = async () => {
|
| 21 |
+
try {
|
| 22 |
+
const response = await apiClient.getRecent();
|
| 23 |
+
const movies = response.movies.map((film) => ({
|
| 24 |
+
title: film[0],
|
| 25 |
+
description: film[2],
|
| 26 |
+
imageUrl: film[3],
|
| 27 |
+
type: "Movie",
|
| 28 |
+
}));
|
| 29 |
+
const series = response.series.map((serie) => ({
|
| 30 |
+
title: serie[0],
|
| 31 |
+
description: serie[2],
|
| 32 |
+
imageUrl: serie[3],
|
| 33 |
+
type: "Series",
|
| 34 |
+
}));
|
| 35 |
+
setItems([...movies, ...series]);
|
| 36 |
+
} catch (error) {
|
| 37 |
+
console.error("Error fetching recent items:", error);
|
| 38 |
+
} finally {
|
| 39 |
+
setLoading(false);
|
| 40 |
+
}
|
| 41 |
+
};
|
| 42 |
+
|
| 43 |
+
fetchRecentItems();
|
| 44 |
+
}, []);
|
| 45 |
|
| 46 |
+
const startAutoSwitch = () => {
|
| 47 |
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
| 48 |
+
intervalRef.current = setInterval(() => {
|
| 49 |
+
setFadeOut(true);
|
| 50 |
+
setTimeout(() => {
|
| 51 |
+
setCurrentIndex((prevIndex) => (prevIndex + 1) % items.length);
|
| 52 |
+
setFadeOut(false);
|
| 53 |
+
}, 200);
|
| 54 |
+
}, 5000);
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
useEffect(() => {
|
| 58 |
+
if (items.length > 0) {
|
| 59 |
+
startAutoSwitch();
|
| 60 |
+
}
|
| 61 |
|
| 62 |
+
return () => {
|
| 63 |
+
clearInterval(intervalRef.current);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
};
|
| 65 |
+
}, [items]);
|
| 66 |
|
| 67 |
+
const handleSwipe = (direction) => {
|
| 68 |
+
setFadeOut(true);
|
| 69 |
+
setTimeout(() => {
|
| 70 |
+
setCurrentIndex((prevIndex) => {
|
| 71 |
+
if (direction === "left") {
|
| 72 |
+
return (prevIndex + 1) % items.length;
|
| 73 |
+
} else {
|
| 74 |
+
return (prevIndex - 1 + items.length) % items.length;
|
| 75 |
}
|
| 76 |
+
});
|
| 77 |
+
setFadeOut(false);
|
| 78 |
+
}, 100);
|
| 79 |
+
startAutoSwitch();
|
| 80 |
+
};
|
| 81 |
|
| 82 |
+
const handleTouchStart = (e) => {
|
| 83 |
+
const touchStartX = e.touches[0].clientX;
|
| 84 |
+
setStartX(touchStartX);
|
| 85 |
+
const handleTouchMove = (event) => {
|
| 86 |
+
const touchEndX = event.touches[0].clientX;
|
| 87 |
+
const diffX = touchStartX - touchEndX;
|
| 88 |
+
if (diffX > 50) {
|
| 89 |
+
handleSwipe("left");
|
| 90 |
+
document.removeEventListener("touchmove", handleTouchMove);
|
| 91 |
+
} else if (diffX < -50) {
|
| 92 |
+
handleSwipe("right");
|
| 93 |
+
document.removeEventListener("touchmove", handleTouchMove);
|
| 94 |
+
}
|
| 95 |
};
|
| 96 |
+
document.addEventListener("touchmove", handleTouchMove);
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
const handleMouseDown = (e) => {
|
| 100 |
+
setStartX(e.clientX);
|
| 101 |
+
setIsDragging(true);
|
| 102 |
+
};
|
| 103 |
|
| 104 |
+
const handleMouseMove = (e) => {
|
| 105 |
+
if (!isDragging) return;
|
| 106 |
+
const diffX = startX - e.clientX;
|
| 107 |
+
if (diffX > 50) {
|
| 108 |
+
handleSwipe("left");
|
| 109 |
+
setIsDragging(false);
|
| 110 |
+
} else if (diffX < -50) {
|
| 111 |
+
handleSwipe("right");
|
| 112 |
+
setIsDragging(false);
|
| 113 |
}
|
| 114 |
+
};
|
| 115 |
+
|
| 116 |
+
const handleMouseUp = () => {
|
| 117 |
+
setIsDragging(false);
|
| 118 |
+
};
|
| 119 |
|
| 120 |
+
if (loading) {
|
| 121 |
+
return <SkeletonLoader />;
|
| 122 |
+
}
|
| 123 |
|
| 124 |
+
const { title, description, imageUrl, type } = items[currentIndex];
|
| 125 |
+
const linkPath = `/${type.toLowerCase()}/${encodeURIComponent(title)}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
+
return (
|
| 128 |
+
<div
|
| 129 |
+
className="hero-container"
|
| 130 |
+
onTouchStart={handleTouchStart}
|
| 131 |
+
onMouseDown={handleMouseDown}
|
| 132 |
+
onMouseMove={handleMouseMove}
|
| 133 |
+
onMouseUp={handleMouseUp}
|
| 134 |
+
onMouseLeave={handleMouseUp}
|
| 135 |
+
>
|
| 136 |
+
<div className="hero-section">
|
| 137 |
+
{items.map((item, index) => (
|
| 138 |
+
<div
|
| 139 |
+
key={index}
|
| 140 |
+
className={`hero-image ${index === currentIndex ? "active" : ""} ${
|
| 141 |
+
fadeOut ? "fade-out" : ""
|
| 142 |
+
}`}
|
| 143 |
+
style={{
|
| 144 |
+
backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.1) 20%, #11121f 80%), url("${item.imageUrl}")`,
|
| 145 |
+
}}
|
| 146 |
+
></div>
|
| 147 |
+
))}
|
| 148 |
+
<div className="hero-text">
|
| 149 |
+
<Link href={linkPath}>
|
| 150 |
+
<h1 className="hero-title">{title}</h1>
|
| 151 |
+
</Link>
|
| 152 |
+
<p className="hero-description">{description}</p>
|
| 153 |
</div>
|
| 154 |
+
</div>
|
| 155 |
+
</div>
|
| 156 |
+
);
|
| 157 |
};
|
| 158 |
|
| 159 |
export default HeroSection;
|
frontend/src/components/Sidebar.css
CHANGED
|
@@ -5,7 +5,7 @@
|
|
| 5 |
top: 0;
|
| 6 |
left: 0;
|
| 7 |
height: 100dvh;
|
| 8 |
-
background-color:
|
| 9 |
color: white;
|
| 10 |
font-family: 'Inter', sans-serif;
|
| 11 |
transition: width .5s ,height .5s;
|
|
|
|
| 5 |
top: 0;
|
| 6 |
left: 0;
|
| 7 |
height: 100dvh;
|
| 8 |
+
background-color: var(--bg-secondary);
|
| 9 |
color: white;
|
| 10 |
font-family: 'Inter', sans-serif;
|
| 11 |
transition: width .5s ,height .5s;
|
frontend/src/skeletons/HeroSection.css
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
|
| 3 |
.skeleton-container {
|
| 4 |
position: relative;
|
| 5 |
-
width:
|
| 6 |
height: 480px; /* Set height to auto for responsiveness */
|
| 7 |
display: flex;
|
| 8 |
flex-direction: column;
|
|
@@ -89,7 +89,7 @@
|
|
| 89 |
|
| 90 |
@media (max-width: 576px) {
|
| 91 |
.skeleton-container {
|
| 92 |
-
height:
|
| 93 |
}
|
| 94 |
.skeleton-title {
|
| 95 |
width: 90%;
|
|
|
|
| 2 |
|
| 3 |
.skeleton-container {
|
| 4 |
position: relative;
|
| 5 |
+
width: 100dvw;
|
| 6 |
height: 480px; /* Set height to auto for responsiveness */
|
| 7 |
display: flex;
|
| 8 |
flex-direction: column;
|
|
|
|
| 89 |
|
| 90 |
@media (max-width: 576px) {
|
| 91 |
.skeleton-container {
|
| 92 |
+
height: 225px;
|
| 93 |
}
|
| 94 |
.skeleton-title {
|
| 95 |
width: 90%;
|