Initial commit
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/* Tile clip-path animation */
|
||||
.navbar-fullscreen__tile {
|
||||
clip-path: polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%);
|
||||
transition: clip-path 1s cubic-bezier(.9, 0, .1, 1);
|
||||
}
|
||||
|
||||
[data-navigation-status="active"] .navbar-fullscreen__tile {
|
||||
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
|
||||
}
|
||||
|
||||
/* Link initial state and animation */
|
||||
.navbar-fullscreen__link {
|
||||
transform: translateY(100%) rotate(5deg);
|
||||
transition: transform 0.75s cubic-bezier(.7, 0, .3, 1);
|
||||
}
|
||||
|
||||
/* Link staggered delays (closing) */
|
||||
.navbar-fullscreen__li:nth-child(1) .navbar-fullscreen__link { transition-delay: 0.2s; }
|
||||
.navbar-fullscreen__li:nth-child(2) .navbar-fullscreen__link { transition-delay: 0.15s; }
|
||||
.navbar-fullscreen__li:nth-child(3) .navbar-fullscreen__link { transition-delay: 0.1s; }
|
||||
.navbar-fullscreen__li:nth-child(4) .navbar-fullscreen__link { transition-delay: 0.05s; }
|
||||
.navbar-fullscreen__li:nth-child(5) .navbar-fullscreen__link { transition-delay: 0s; }
|
||||
|
||||
/* Link animation (Navigation Open) */
|
||||
[data-navigation-status="active"] .navbar-fullscreen__link {
|
||||
transform: translateY(0%) rotate(0.001deg);
|
||||
}
|
||||
|
||||
/* Link staggered delays (opening) */
|
||||
[data-navigation-status="active"] .navbar-fullscreen__li:nth-child(1) .navbar-fullscreen__link { transition-delay: 0.3s; }
|
||||
[data-navigation-status="active"] .navbar-fullscreen__li:nth-child(2) .navbar-fullscreen__link { transition-delay: 0.35s; }
|
||||
[data-navigation-status="active"] .navbar-fullscreen__li:nth-child(3) .navbar-fullscreen__link { transition-delay: 0.4s; }
|
||||
[data-navigation-status="active"] .navbar-fullscreen__li:nth-child(4) .navbar-fullscreen__link { transition-delay: 0.45s; }
|
||||
[data-navigation-status="active"] .navbar-fullscreen__li:nth-child(5) .navbar-fullscreen__link { transition-delay: 0.5s; }
|
||||
|
||||
/* Link text duplicate effect */
|
||||
.navbar-fullscreen__link-text {
|
||||
text-shadow: 0 1.1em 0;
|
||||
transition: transform 0.5s cubic-bezier(.7, 0, .3, 1);
|
||||
transform: translateY(0%) rotate(0.001deg);
|
||||
}
|
||||
|
||||
.navbar-fullscreen__link:hover .navbar-fullscreen__link-text {
|
||||
transform: translateY(-100%) rotate(0.001deg);
|
||||
}
|
||||
|
||||
/* Hover dim effect on siblings */
|
||||
.navbar-fullscreen__li {
|
||||
transition: opacity 0.5s cubic-bezier(.7, 0, .3, 1);
|
||||
}
|
||||
|
||||
.navbar-fullscreen__ul:has(.navbar-fullscreen__li:hover) .navbar-fullscreen__li {
|
||||
opacity: 0.15;
|
||||
}
|
||||
|
||||
.navbar-fullscreen__ul:has(.navbar-fullscreen__li:hover) .navbar-fullscreen__li:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback, memo } from "react";
|
||||
import Logo from "../Logo";
|
||||
import HamburgerButton from "../HamburgerButton";
|
||||
import { NavItem } from "@/types/navigation";
|
||||
import { cls } from "@/lib/utils";
|
||||
import { useButtonClick } from "@/components/button/useButtonClick";
|
||||
import "./NavbarStyleFullscreen.css";
|
||||
|
||||
interface NavLinkProps {
|
||||
item: NavItem;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const NavLink = memo(function NavLink({ item, onClose }: NavLinkProps) {
|
||||
const handleClick = useButtonClick(item.id, onClose);
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="navbar-fullscreen__link text-background font-normal leading-[1.15] no-underline text-9xl bg-transparent border-none cursor-pointer"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span className="navbar-fullscreen__link-text block relative">{item.name}</span>
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
||||
interface NavbarStyleFullscreenProps {
|
||||
navItems: NavItem[];
|
||||
logoSrc?: string;
|
||||
logoAlt?: string;
|
||||
brandName?: string;
|
||||
bottomLeftText?: string;
|
||||
bottomRightText?: string;
|
||||
className?: string;
|
||||
topBarClassName?: string;
|
||||
}
|
||||
|
||||
const NavbarStyleFullscreen = memo(function NavbarStyleFullscreen({
|
||||
navItems,
|
||||
logoSrc,
|
||||
logoAlt = "",
|
||||
brandName = "Webild",
|
||||
bottomLeftText = "Global Community",
|
||||
bottomRightText = "hello@example.com",
|
||||
className = "",
|
||||
topBarClassName = "",
|
||||
}: NavbarStyleFullscreenProps) {
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
|
||||
const handleToggle = useCallback(() => {
|
||||
setIsActive((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setIsActive(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape" && isActive) {
|
||||
setIsActive(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
return () => document.removeEventListener("keydown", handleKeyDown);
|
||||
}, [isActive]);
|
||||
|
||||
return (
|
||||
<nav
|
||||
role="navigation"
|
||||
aria-label="Main navigation"
|
||||
data-navigation-status={isActive ? "active" : "not-active"}
|
||||
className={cls("fixed inset-0 z-[100] pointer-events-none", className)}
|
||||
>
|
||||
<div className={cls(
|
||||
"absolute z-1 w-content-width left-1/2 -translate-x-1/2 top-6 flex justify-between items-center",
|
||||
topBarClassName
|
||||
)}>
|
||||
<Logo
|
||||
logoSrc={logoSrc}
|
||||
logoAlt={logoAlt}
|
||||
brandName={brandName}
|
||||
textClassName={`transition-colors duration-700 ease-[cubic-bezier(0.5,0.5,0,1)] ${isActive ? "text-background" : "text-foreground"}`}
|
||||
/>
|
||||
<HamburgerButton isActive={isActive} onClick={handleToggle} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="navigation-menu"
|
||||
className="navbar-fullscreen__tile pointer-events-auto bg-foreground absolute inset-0 flex flex-col justify-center items-center"
|
||||
>
|
||||
<ul className="navbar-fullscreen__ul flex flex-col items-center m-0 p-0 list-none">
|
||||
{navItems.map((item) => (
|
||||
<li key={item.id} className="navbar-fullscreen__li flex justify-center items-center m-0 p-0 relative overflow-hidden">
|
||||
<NavLink item={item} onClose={handleClose} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div className="absolute bottom-0 w-content-width left-1/2 -translate-x-1/2 flex justify-between items-center py-10">
|
||||
<p className="text-background/50 mb-0 text-base relative">{bottomLeftText}</p>
|
||||
<p className="text-background/50 mb-0 text-base relative">{bottomRightText}</p>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
});
|
||||
|
||||
NavbarStyleFullscreen.displayName = "NavbarStyleFullscreen";
|
||||
|
||||
export default NavbarStyleFullscreen;
|
||||
Reference in New Issue
Block a user