From 5a90e7532a92ac41a172153eac7651ff6c4601e3 Mon Sep 17 00:00:00 2001 From: Chigozie Emmanuel Date: Wed, 15 Jul 2026 13:47:51 +0100 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20round=202=20UI=20upgrade=20?= =?UTF-8?q?=E2=80=94=20floating=20hero=20cards,=20404=20page,=20dashboard?= =?UTF-8?q?=20polish,=20movie=20details?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HeroFloatingCards: 4 animated glass cards with infinite y-bounce, gradient icons - NotFound 404: cinematic text-[14rem] gradient title, dot-grid bg, framer-motion entrance - Search: gradient heading, glass result cards with shimmer + colored hover rings, staggered entries - Wishlist: gradient heading, glass cards, floating backdrop-blur action buttons - Profile: gradient avatar + gradient name - Login/Register: gradient titles (Welcome Back / Create Account) - MovieHero: glass genre pills, gradient CTA, rating badge, line-clamp overview - MovieInfo: gradient headings, glass info panel, gradient trailer button - SimilarMovies: framer-motion staggered, glass cards with shimmer - MovieCast/MovieGallery/WatchProviders: gradient headings, glass containers - DashboardLayout: gradient logo, gradient active nav, all borders white/5 - All 8 dashboard pages: gradient headers (Admin/Manager/Staff) - All 4 chart components: gradient headings, ring-white/5, rounded-2xl - Reviews: gradient heading, gradient submit button, focus rings --- src/components/Hero/HeroFloatingCards.jsx | 67 ++++++- src/components/Movies/MovieCast.jsx | 31 ++- src/components/Movies/MovieGallery.jsx | 41 ++-- src/components/Movies/MovieHero.jsx | 87 +++----- src/components/Movies/MovieInfo.jsx | 99 +++------- src/components/Movies/SimilarMovies.jsx | 58 +++--- src/components/Movies/WatchProviders.jsx | 30 +-- src/components/Reviews/ReviewForm.jsx | 8 +- src/components/Reviews/ReviewList.jsx | 2 +- src/components/layout/DashboardLayout.jsx | 18 +- src/pages/Login/Login.jsx | 7 +- src/pages/NotFound/NotFound.jsx | 58 +++++- src/pages/Profile/Profile.jsx | 10 +- src/pages/Register/Register.jsx | 7 +- src/pages/Search/Search.jsx | 185 ++++++++++++------ src/pages/Wishlist/Wishlist.jsx | 41 ++-- src/pages/dashboard/Admin/Dashboard.jsx | 9 +- src/pages/dashboard/Admin/Orders.jsx | 7 +- src/pages/dashboard/Admin/Products.jsx | 7 +- src/pages/dashboard/Admin/Users.jsx | 7 +- .../Admin/components/CategoryPieChart.jsx | 4 +- .../Admin/components/OrderVolumeChart.jsx | 4 +- .../Admin/components/RevenueChart.jsx | 4 +- .../dashboard/Admin/components/StatsGrid.jsx | 4 +- src/pages/dashboard/Manager/Dashboard.jsx | 7 +- .../dashboard/Manager/StaffManagement.jsx | 7 +- src/pages/dashboard/Staff/Dashboard.jsx | 7 +- src/pages/dashboard/Staff/Orders.jsx | 7 +- 28 files changed, 453 insertions(+), 370 deletions(-) diff --git a/src/components/Hero/HeroFloatingCards.jsx b/src/components/Hero/HeroFloatingCards.jsx index 57f1cc0..f245fbd 100644 --- a/src/components/Hero/HeroFloatingCards.jsx +++ b/src/components/Hero/HeroFloatingCards.jsx @@ -1,9 +1,70 @@ +import { motion } from "framer-motion"; +import { FaFilm, FaBook, FaDragon, FaMasksTheater } from "react-icons/fa6"; + +const floatingCards = [ + { + icon: FaFilm, + title: "Movies", + gradient: "from-red-500 to-orange-500", + x: 0, + y: -20, + delay: 0, + }, + { + icon: FaBook, + title: "Books", + gradient: "from-violet-500 to-fuchsia-500", + x: 100, + y: 40, + delay: 0.3, + }, + { + icon: FaDragon, + title: "Manga", + gradient: "from-pink-500 to-rose-500", + x: -80, + y: 60, + delay: 0.6, + }, + { + icon: FaMasksTheater, + title: "Comics", + gradient: "from-emerald-500 to-teal-500", + x: 60, + y: -50, + delay: 0.9, + }, +]; + function HeroFloatingCards() { return ( -
- {/* Coming in the next phase */} +
+ {floatingCards.map((card) => ( + + +
+ +
+
+

{card.title}

+

Explore now

+
+
+
+ ))}
); } -export default HeroFloatingCards; \ No newline at end of file +export default HeroFloatingCards; diff --git a/src/components/Movies/MovieCast.jsx b/src/components/Movies/MovieCast.jsx index 9716b3b..1d2ecbb 100644 --- a/src/components/Movies/MovieCast.jsx +++ b/src/components/Movies/MovieCast.jsx @@ -4,32 +4,25 @@ function MovieCast({ cast }) { if (!cast || cast.length === 0) return null; return ( -
-

- Top Billed Cast +
+

+ Top Billed{" "} + Cast

- - {/* Smooth horizontal scroll container */} +
{cast.slice(0, 10).map((member) => ( -
- {/* Cast Profile Image */} -
+
{member.name}
- - {/* Names & Characters */}

{member.name}

@@ -43,4 +36,4 @@ function MovieCast({ cast }) { ); } -export default MovieCast; \ No newline at end of file +export default MovieCast; diff --git a/src/components/Movies/MovieGallery.jsx b/src/components/Movies/MovieGallery.jsx index 6d4297a..ad9d092 100644 --- a/src/components/Movies/MovieGallery.jsx +++ b/src/components/Movies/MovieGallery.jsx @@ -5,42 +5,29 @@ function MovieGallery({ images }) { if (!images?.backdrops?.length) return null; return ( -
-
+
+

- Gallery + Movie{" "} + Gallery

- -

- Official movie stills -

+

Official movie stills

- {images.backdrops.slice(0, 6).map((image) => ( + {images.backdrops.slice(0, 6).map((image, i) => ( Movie still ))} @@ -49,4 +36,4 @@ function MovieGallery({ images }) { ); } -export default MovieGallery; \ No newline at end of file +export default MovieGallery; diff --git a/src/components/Movies/MovieHero.jsx b/src/components/Movies/MovieHero.jsx index bc9424e..84a94ef 100644 --- a/src/components/Movies/MovieHero.jsx +++ b/src/components/Movies/MovieHero.jsx @@ -5,103 +5,64 @@ import heroBg from "@/assets/images/hero-bg.png"; function MovieHero({ movie }) { return (
- {/* Background */} {movie.title} { - e.target.src = heroBg; - }} + onError={(e) => { e.target.src = heroBg; }} /> +
+
+
- {/* Overlay */} -
- - {/* Gradient */} -
- - {/* Content */}
- - {/* Poster */} {movie.title} - {/* Movie Info */}
- -

+

{movie.title}

-
- - - +
+ + {movie.vote_average.toFixed(1)} - - - {movie.release_date?.split("-")[0]} - - - - {movie.runtime} min - - + {movie.release_date?.split("-")[0]} + {movie.runtime} min
- {/* Genres */} -
- +
{movie.genres?.map((genre) => ( - + {genre.name} ))} -
- {/* Overview */} -

+

{movie.overview}

- {/* Buttons */}
- - - - -
-
-
); } -export default MovieHero; \ No newline at end of file +export default MovieHero; diff --git a/src/components/Movies/MovieInfo.jsx b/src/components/Movies/MovieInfo.jsx index 2b85b8f..e3f7991 100644 --- a/src/components/Movies/MovieInfo.jsx +++ b/src/components/Movies/MovieInfo.jsx @@ -2,24 +2,19 @@ import { FaPlay } from "react-icons/fa"; function MovieInfo({ movie, videos }) { const trailer = videos?.find( - (video) => - video.site === "YouTube" && - video.type === "Trailer" + (video) => video.site === "YouTube" && video.type === "Trailer" ); return (
-
- - {/* Left */}
- -

- About this movie +

+ About{" "} + this movie

-

+

{movie.overview}

@@ -28,101 +23,53 @@ function MovieInfo({ movie, videos }) { href={`https://www.youtube.com/watch?v=${trailer.key}`} target="_blank" rel="noopener noreferrer" - className="mt-8 inline-flex items-center gap-3 rounded-xl bg-red-600 px-6 py-3 font-semibold transition hover:bg-red-700" + className="group mt-8 inline-flex items-center gap-3 rounded-xl bg-gradient-to-r from-red-600 to-rose-600 px-6 py-3 font-semibold text-white shadow-lg shadow-red-500/25 hover:from-red-500 hover:to-rose-500 transition-all duration-300" > - + Watch Trailer )} -
- {/* Right */} -
- +
-

- Original Language -

- -

- {movie.original_language.toUpperCase()} -

+

Original Language

+

{movie.original_language.toUpperCase()}

-
-

- Status -

- -

- {movie.status} -

+

Status

+

{movie.status}

-
-

- Runtime -

- -

- {movie.runtime} mins -

+

Runtime

+

{movie.runtime} mins

-
-

- Budget -

- -

- ${movie.budget.toLocaleString()} -

+

Budget

+

${movie.budget.toLocaleString()}

-
-

- Revenue -

- -

- ${movie.revenue.toLocaleString()} -

+

Revenue

+

${movie.revenue.toLocaleString()}

-
-

- Genres -

- +

Genres

{movie.genres?.map((genre) => ( - + {genre.name} ))}
-
-

- Rating -

- -

- ⭐ {movie.vote_average.toFixed(1)} / 10 -

+

Rating

+

⭐ {movie.vote_average.toFixed(1)} / 10

-
-
-
); } -export default MovieInfo; \ No newline at end of file +export default MovieInfo; diff --git a/src/components/Movies/SimilarMovies.jsx b/src/components/Movies/SimilarMovies.jsx index 5d4a1f2..ed35554 100644 --- a/src/components/Movies/SimilarMovies.jsx +++ b/src/components/Movies/SimilarMovies.jsx @@ -1,3 +1,4 @@ +import { motion } from "framer-motion"; import { IMAGE_BASE_URL } from "@/constants/tmdb"; import { ROUTES } from "@/constants/routes"; import { Link } from "react-router-dom"; @@ -6,41 +7,40 @@ function SimilarMovies({ movies }) { if (!movies || movies.length === 0) return null; return ( -
-

- Similar Movies You Might Like +
+

+ Similar{" "} + Movies

- - {/* Responsive grid for movie cards */} +
- {movies.slice(0, 5).map((simMovie) => ( - ( + - {/* Poster Wrapper with Zoom effect */} -
- {simMovie.title} -
- - {/* Movie Title */} -

- {simMovie.title} -

- + +
+
+
+ {simMovie.title} +
+
+

+ {simMovie.title} +

+ + ))}
); } -export default SimilarMovies; \ No newline at end of file +export default SimilarMovies; diff --git a/src/components/Movies/WatchProviders.jsx b/src/components/Movies/WatchProviders.jsx index ca28eca..77f35a9 100644 --- a/src/components/Movies/WatchProviders.jsx +++ b/src/components/Movies/WatchProviders.jsx @@ -6,41 +6,27 @@ function WatchProviders({ providers }) { if (!nigeria?.flatrate?.length) return null; return ( -
-
+
+

- Where to Watch + Where to{" "} + Watch

- - - Available on - +

Available on

{nigeria.flatrate.map((provider) => (
{provider.provider_name} - - - {provider.provider_name} - + {provider.provider_name}
))}
@@ -48,4 +34,4 @@ function WatchProviders({ providers }) { ); } -export default WatchProviders; \ No newline at end of file +export default WatchProviders; diff --git a/src/components/Reviews/ReviewForm.jsx b/src/components/Reviews/ReviewForm.jsx index 6c89638..8848b46 100644 --- a/src/components/Reviews/ReviewForm.jsx +++ b/src/components/Reviews/ReviewForm.jsx @@ -50,8 +50,8 @@ function ReviewForm({ productId, onReviewAdded }) { } return ( -
-

Write a Review

+ +

Write a Review

{[1, 2, 3, 4, 5].map((star) => ( @@ -79,13 +79,13 @@ function ReviewForm({ productId, onReviewAdded }) { onChange={(e) => setComment(e.target.value)} placeholder="Share your thoughts about this product..." rows={3} - className="w-full rounded-lg border border-slate-700 bg-slate-800/50 px-3 py-2 text-sm text-white outline-none focus:border-violet-500 resize-none" + className="w-full rounded-xl border border-slate-700/50 bg-slate-800/50 px-3 py-2 text-sm text-white outline-none focus:border-violet-500/50 focus:ring-2 focus:ring-violet-500/10 resize-none transition-all" /> diff --git a/src/components/Reviews/ReviewList.jsx b/src/components/Reviews/ReviewList.jsx index f5ba052..e7014a2 100644 --- a/src/components/Reviews/ReviewList.jsx +++ b/src/components/Reviews/ReviewList.jsx @@ -57,7 +57,7 @@ function ReviewList({ productId, refreshKey }) { ) : (
{reviews.map((review) => ( -
+
diff --git a/src/components/layout/DashboardLayout.jsx b/src/components/layout/DashboardLayout.jsx index 98d651d..6d3eab7 100644 --- a/src/components/layout/DashboardLayout.jsx +++ b/src/components/layout/DashboardLayout.jsx @@ -40,9 +40,9 @@ function DashboardLayout({ children }) { /> )} -