feat: update Button component styles and themes; introduce new slate theme for consistent UI across Dropdown, SearchInput, and Navbar components, and enhance MovieList display type toggle functionality

This commit is contained in:
Norbert Maciaszek 2025-08-25 22:43:12 +02:00
parent 9079a52778
commit 3ed7b14f1b
7 changed files with 73 additions and 107 deletions

View File

@ -29,10 +29,14 @@ export const Button: FC<Props> = ({
const buttonColor = gradient ?? colors[theme]; const buttonColor = gradient ?? colors[theme];
if (theme === "slate" && !className.includes("shadow-")) {
className += " shadow-cyan-500/20 hover:shadow-cyan-500/40";
}
return ( return (
<Component <Component
className={`flex items-center justify-center gap-2 cursor-pointer text-white rounded-xl font-semibold shadow-2xl transition-colors duration-300 className={`flex items-center justify-center gap-2 cursor-pointer text-white rounded-xl font-semibold shadow-2xl transition-all duration-300
bg-gradient-to-r ${buttonColor?.from} ${buttonColor?.to} cursor-pointer ${sizes[size]} ${className}`} bg-gradient-to-br ${buttonColor?.from} ${buttonColor?.to} cursor-pointer ${sizes[size]} ${className}`}
onClick={onClick} onClick={onClick}
{...(href && { href })} {...(href && { href })}
> >
@ -45,7 +49,7 @@ const sizes = {
small: "px-4 py-2 text-sm", small: "px-4 py-2 text-sm",
medium: "px-8 py-4 text-lg", medium: "px-8 py-4 text-lg",
large: "px-12 py-6 text-xl", large: "px-12 py-6 text-xl",
icon: "p-3 [&>*]:w-5 [&>*]:h-5", icon: "w-12 h-12 !rounded-full border border-white/20 hover:scale-105 [&>svg]:w-5 [&>svg]:h-5 shadow-lg ",
}; };
const colors = { const colors = {
@ -55,30 +59,38 @@ const colors = {
}, },
secondary: { secondary: {
from: "from-purple-600 hover:from-purple-500", from: "from-purple-600 hover:from-purple-500",
to: "to-pink-600 hover:to-pink-500", to: "to-cyan-600 hover:to-cyan-500",
}, },
glass: { glass: {
from: "from-white/15 via-white/8 to-white/12 border border-white/20", from: "from-white/15 border border-white/20",
to: "to-white/15 hover:to-white/10", to: "to-white/5 hover:to-white/10",
}, },
rose: { rosePink: {
from: "from-rose-600/90 hover:from-rose-500/90", from: "from-rose-600/90 hover:from-rose-500/90",
to: "to-pink-600/90 hover:to-pink-500/90", to: "to-pink-600/90 hover:to-pink-500/90",
}, },
emerald: { emeraldTeal: {
from: "from-emerald-600/90 hover:from-emerald-500/90", from: "from-emerald-600/90 hover:from-emerald-500/90",
to: "to-teal-600/90 hover:to-teal-500/90", to: "to-teal-600/90 hover:to-teal-500/90",
}, },
purple: { purplePink: {
from: "from-purple-600/90 hover:from-purple-500/90", from: "from-purple-600/90 hover:from-purple-500/90",
to: "to-pink-600/90 hover:to-pink-500/90", to: "to-pink-600/90 hover:to-pink-500/90",
}, },
pink: { pinkEmerald: {
from: "from-pink-600/90 hover:from-pink-500/90", from: "from-pink-600/90 hover:from-pink-500/90",
to: "to-emerald-600/90 hover:to-emerald-500/90", to: "to-emerald-600/90 hover:to-emerald-500/90",
}, },
teal: { tealEmerald: {
from: "from-teal-600/90 hover:from-teal-500/90", from: "from-teal-600/90 hover:from-teal-500/90",
to: "to-emerald-600/90 hover:to-emerald-500/90", to: "to-emerald-600/90 hover:to-emerald-500/90",
}, },
cyanPurple: {
from: "from-cyan-600/90 hover:from-cyan-500/90",
to: "to-purple-600/90 hover:to-purple-500/90",
},
slate: {
from: "from-slate-800/95",
to: "to-slate-900/95",
},
}; };

View File

@ -32,7 +32,7 @@ export const Dropdown: FC<Props> = ({
return ( return (
<div ref={ref} className="relative inline-block"> <div ref={ref} className="relative inline-block">
<Button theme="glass" size="icon" onClick={() => setIsOpen(!isOpen)}> <Button theme="slate" size="icon" onClick={() => setIsOpen(!isOpen)}>
{icon || <FaFilter />} {icon || <FaFilter />}
</Button> </Button>

View File

@ -64,7 +64,7 @@ export const MovieRow: FC<Props> = ({
}; };
return ( return (
<div className="relative overflow-hidden"> <div className="relative overflow-hidden rounded-xl">
{/* Background actions */} {/* Background actions */}
<div className="absolute inset-0 flex"> <div className="absolute inset-0 flex">
<div className="absolute right-0 h-full w-24 bg-green-500/20 flex items-center justify-center cursor-pointer"> <div className="absolute right-0 h-full w-24 bg-green-500/20 flex items-center justify-center cursor-pointer">

View File

@ -1,6 +1,7 @@
"use client"; "use client";
import { FC, useEffect, useState } from "react"; import { FC, useEffect, useState } from "react";
import { IoSearch } from "react-icons/io5"; import { IoSearch } from "react-icons/io5";
import { Button } from "../Button";
type Props = { type Props = {
className?: string; className?: string;
@ -30,19 +31,21 @@ export const SearchInput: FC<Props> = ({
}, [value]); }, [value]);
return ( return (
<div> <div className="relative flex items-center gap-4">
<input <input
type="search" type="search"
name="search" name="search"
value={value} value={value}
placeholder={placeholder} placeholder={placeholder}
className={className} className={
"w-full bg-gradient-to-br from-slate-800/95 to-slate-900/90 border border-white/20 rounded-full h-12 px-6 shadow-lg shadow-purple-500/15 outline-none focus:shadow-purple-500/20"
}
onChange={(e) => setValue(e.target.value)} onChange={(e) => setValue(e.target.value)}
autoFocus={autoFocus} autoFocus={autoFocus}
/> />
<button type="submit" className="absolute right-0 top-1 mt-3 mr-4"> <Button theme="slate" size="icon" className="shrink-0">
<IoSearch /> <IoSearch />
</button> </Button>
</div> </div>
); );
}; };

View File

@ -211,8 +211,8 @@ export const MovieList: FC<Props> = ({
/> />
{!overrideDisplayType && ( {!overrideDisplayType && (
<Button <Button
theme="glass"
size="icon" size="icon"
theme="slate"
onClick={() => onClick={() =>
setDisplayType(displayType === "grid" ? "list" : "grid") setDisplayType(displayType === "grid" ? "list" : "grid")
} }

View File

@ -50,9 +50,9 @@ export const Search: FC<Props> = ({ onClose }) => {
<div className="fixed inset-0 z-[60] overflow-y-auto"> <div className="fixed inset-0 z-[60] overflow-y-auto">
{/* Close button */} {/* Close button */}
<Button <Button
theme="glass" theme="slate"
size="icon" size="icon"
className="absolute top-6 right-6 z-10 group hover:!bg-red-500/50" className="absolute top-6 right-6 z-10 group shadow-lg shadow-red-500/20 hover:shadow-red-500/40"
onClick={handleClose} onClick={handleClose}
> >
<IoClose className="text-white transition-transform duration-300 group-hover:rotate-90" /> <IoClose className="text-white transition-transform duration-300 group-hover:rotate-90" />
@ -71,15 +71,11 @@ export const Search: FC<Props> = ({ onClose }) => {
{/* Enhanced Search Input */} {/* Enhanced Search Input */}
<div className="relative max-w-2xl mx-auto"> <div className="relative max-w-2xl mx-auto">
<div className="absolute inset-0 bg-gradient-to-r from-purple-500/30 to-cyan-500/30 rounded-2xl"></div> <SearchInput
<div className="relative bg-gradient-to-br from-white/15 via-white/8 to-white/12 border border-white/20 rounded-2xl p-2 shadow-2xl shadow-purple-500/10"> onChange={handleSearch}
<SearchInput placeholder="Wpisz tytuł filmu..."
className="w-full px-3 bg-transparent border-none text-lg lg:text-xl placeholder-gray-400 text-white focus:outline-none" autoFocus={true}
onChange={handleSearch} />
placeholder="Wpisz tytuł filmu..."
autoFocus={true}
/>
</div>
</div> </div>
</div> </div>

View File

@ -4,16 +4,9 @@ import { useState } from "react";
import { HiSearch, HiHome, HiSparkles } from "react-icons/hi"; import { HiSearch, HiHome, HiSparkles } from "react-icons/hi";
import { Search } from "./components/Search"; import { Search } from "./components/Search";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { Button } from "@/components/atoms/Button";
const navigationItems = [ const navigationItems = [
{
label: "Strona Główna",
href: "/",
icon: HiHome,
emoji: "🏠",
color: "from-blue-500 to-purple-600",
description: "Twoja lista filmów",
},
{ {
label: "Odkrywaj", label: "Odkrywaj",
href: "/odkrywaj", href: "/odkrywaj",
@ -22,6 +15,14 @@ const navigationItems = [
color: "from-purple-500 to-pink-600", color: "from-purple-500 to-pink-600",
description: "Znajdź nowe filmy", description: "Znajdź nowe filmy",
}, },
{
label: "Strona Główna",
href: "/",
icon: HiHome,
emoji: "🏠",
color: "from-blue-500 to-purple-600",
description: "Twoja lista filmów",
},
]; ];
export const Navbar = () => { export const Navbar = () => {
@ -31,82 +32,36 @@ export const Navbar = () => {
return ( return (
<> <>
{/* Elegant Floating Navigation */} {/* Elegant Floating Navigation */}
<nav className="fixed bottom-0 left-0 right-0 z-50 pointer-events-none bg-black/90 lg:bg-transparent"> <nav className="fixed bottom-0 left-0 right-0 z-50 bg-gradient-to-t from-black to-transparent">
<div className="relative h-24 flex items-center justify-between px-6"> <div className="relative flex items-center justify-center px-6 py-4 gap-3">
{/* Brand Name - Floating Left */} {/* Desktop Navigation Orbs */}
<div className="pointer-events-auto"> {navigationItems.map((item, index) => {
<Link href="/" className="group flex items-center gap-3"> const isActive = pathname === item.href;
<div className="relative"> return (
<h1 className="text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-white via-purple-200 to-cyan-200 group-hover:from-purple-300 group-hover:to-cyan-300 transition-all duration-500"> <Link
MovieBox key={item.href}
</h1> href={item.href}
</div> className="relative group cursor-pointer"
</Link> >
</div> {/* Main orb */}
<Button theme={isActive ? "secondary" : "slate"} size="icon">
{/* Navigation & Action Orbs - Right Side */} {/* Icon */}
<div className="flex items-center gap-3 pointer-events-auto"> <item.icon
{/* Desktop Navigation Orbs */} className={`transition-colors duration-300
<div className="flex items-center gap-3">
{navigationItems.map((item, index) => {
const isActive = pathname === item.href;
return (
<Link
key={item.href}
href={item.href}
className="relative group cursor-pointer"
>
{/* Main orb */}
<div
className={`relative w-12 h-12 rounded-full border border-white/20 shadow-lg transition-all duration-300 hover:scale-105
${
isActive
? "bg-gradient-to-br from-purple-500/80 to-cyan-500/80 shadow-purple-500/40"
: "bg-gradient-to-br from-slate-800/95 to-slate-900/95 shadow-slate-500/20"
}`}
>
{/* Icon */}
<div className="w-full h-full flex items-center justify-center">
<item.icon
className={`w-5 h-5 transition-colors duration-300
${ ${
isActive isActive
? "text-white" ? "text-white"
: "text-gray-300 group-hover:text-white" : "text-gray-300 group-hover:text-white"
}`} }`}
/> />
</div> </Button>
</div> </Link>
);
})}
{/* Tooltip */} <Button theme="slate" size="icon" onClick={() => setSearchOpen(true)}>
<div className="absolute -bottom-12 left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none"> <HiSearch className="text-cyan-400 mx-auto" />
<div className="bg-black/90 text-white text-xs px-3 py-1 rounded-lg whitespace-nowrap border border-white/10"> </Button>
{item.label}
</div>
</div>
</Link>
);
})}
</div>
{/* Search Orb */}
<div className="relative group">
<div className="absolute inset-0 bg-gradient-to-r from-cyan-500/30 to-purple-500/30 rounded-full transition-all duration-300"></div>
<button
onClick={() => setSearchOpen(true)}
className="relative w-12 h-12 rounded-full bg-gradient-to-br from-slate-800/95 to-slate-900/95 border border-white/20 shadow-lg shadow-cyan-500/20 hover:shadow-cyan-500/40 transition-all duration-300 hover:scale-105"
>
<HiSearch className="w-5 h-5 text-cyan-400 mx-auto" />
</button>
{/* Tooltip */}
<div className="absolute -bottom-12 left-1/2 transform -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none">
<div className="bg-black/90 text-white text-xs px-3 py-1 rounded-lg whitespace-nowrap border border-white/10">
Szukaj filmów
</div>
</div>
</div>
</div>
</div> </div>
</nav> </nav>