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];
if (theme === "slate" && !className.includes("shadow-")) {
className += " shadow-cyan-500/20 hover:shadow-cyan-500/40";
}
return (
<Component
className={`flex items-center justify-center gap-2 cursor-pointer text-white rounded-xl font-semibold shadow-2xl transition-colors duration-300
bg-gradient-to-r ${buttonColor?.from} ${buttonColor?.to} cursor-pointer ${sizes[size]} ${className}`}
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-br ${buttonColor?.from} ${buttonColor?.to} cursor-pointer ${sizes[size]} ${className}`}
onClick={onClick}
{...(href && { href })}
>
@ -45,7 +49,7 @@ const sizes = {
small: "px-4 py-2 text-sm",
medium: "px-8 py-4 text-lg",
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 = {
@ -55,30 +59,38 @@ const colors = {
},
secondary: {
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: {
from: "from-white/15 via-white/8 to-white/12 border border-white/20",
to: "to-white/15 hover:to-white/10",
from: "from-white/15 border border-white/20",
to: "to-white/5 hover:to-white/10",
},
rose: {
rosePink: {
from: "from-rose-600/90 hover:from-rose-500/90",
to: "to-pink-600/90 hover:to-pink-500/90",
},
emerald: {
emeraldTeal: {
from: "from-emerald-600/90 hover:from-emerald-500/90",
to: "to-teal-600/90 hover:to-teal-500/90",
},
purple: {
purplePink: {
from: "from-purple-600/90 hover:from-purple-500/90",
to: "to-pink-600/90 hover:to-pink-500/90",
},
pink: {
pinkEmerald: {
from: "from-pink-600/90 hover:from-pink-500/90",
to: "to-emerald-600/90 hover:to-emerald-500/90",
},
teal: {
tealEmerald: {
from: "from-teal-600/90 hover:from-teal-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 (
<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 />}
</Button>

View File

@ -64,7 +64,7 @@ export const MovieRow: FC<Props> = ({
};
return (
<div className="relative overflow-hidden">
<div className="relative overflow-hidden rounded-xl">
{/* Background actions */}
<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">

View File

@ -1,6 +1,7 @@
"use client";
import { FC, useEffect, useState } from "react";
import { IoSearch } from "react-icons/io5";
import { Button } from "../Button";
type Props = {
className?: string;
@ -30,19 +31,21 @@ export const SearchInput: FC<Props> = ({
}, [value]);
return (
<div>
<div className="relative flex items-center gap-4">
<input
type="search"
name="search"
value={value}
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)}
autoFocus={autoFocus}
/>
<button type="submit" className="absolute right-0 top-1 mt-3 mr-4">
<Button theme="slate" size="icon" className="shrink-0">
<IoSearch />
</button>
</Button>
</div>
);
};

View File

@ -211,8 +211,8 @@ export const MovieList: FC<Props> = ({
/>
{!overrideDisplayType && (
<Button
theme="glass"
size="icon"
theme="slate"
onClick={() =>
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">
{/* Close button */}
<Button
theme="glass"
theme="slate"
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}
>
<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 */}
<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>
<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">
<SearchInput
className="w-full px-3 bg-transparent border-none text-lg lg:text-xl placeholder-gray-400 text-white focus:outline-none"
onChange={handleSearch}
placeholder="Wpisz tytuł filmu..."
autoFocus={true}
/>
</div>
<SearchInput
onChange={handleSearch}
placeholder="Wpisz tytuł filmu..."
autoFocus={true}
/>
</div>
</div>

View File

@ -4,16 +4,9 @@ import { useState } from "react";
import { HiSearch, HiHome, HiSparkles } from "react-icons/hi";
import { Search } from "./components/Search";
import { usePathname } from "next/navigation";
import { Button } from "@/components/atoms/Button";
const navigationItems = [
{
label: "Strona Główna",
href: "/",
icon: HiHome,
emoji: "🏠",
color: "from-blue-500 to-purple-600",
description: "Twoja lista filmów",
},
{
label: "Odkrywaj",
href: "/odkrywaj",
@ -22,6 +15,14 @@ const navigationItems = [
color: "from-purple-500 to-pink-600",
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 = () => {
@ -31,82 +32,36 @@ export const Navbar = () => {
return (
<>
{/* Elegant Floating Navigation */}
<nav className="fixed bottom-0 left-0 right-0 z-50 pointer-events-none bg-black/90 lg:bg-transparent">
<div className="relative h-24 flex items-center justify-between px-6">
{/* Brand Name - Floating Left */}
<div className="pointer-events-auto">
<Link href="/" className="group flex items-center gap-3">
<div className="relative">
<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">
MovieBox
</h1>
</div>
</Link>
</div>
{/* Navigation & Action Orbs - Right Side */}
<div className="flex items-center gap-3 pointer-events-auto">
{/* Desktop Navigation Orbs */}
<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
<nav className="fixed bottom-0 left-0 right-0 z-50 bg-gradient-to-t from-black to-transparent">
<div className="relative flex items-center justify-center px-6 py-4 gap-3">
{/* Desktop Navigation Orbs */}
{navigationItems.map((item, index) => {
const isActive = pathname === item.href;
return (
<Link
key={item.href}
href={item.href}
className="relative group cursor-pointer"
>
{/* Main orb */}
<Button theme={isActive ? "secondary" : "slate"} size="icon">
{/* Icon */}
<item.icon
className={`transition-colors duration-300
${
isActive
? "text-white"
: "text-gray-300 group-hover:text-white"
}`}
/>
</div>
</div>
/>
</Button>
</Link>
);
})}
{/* 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">
{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>
<Button theme="slate" size="icon" onClick={() => setSearchOpen(true)}>
<HiSearch className="text-cyan-400 mx-auto" />
</Button>
</div>
</nav>