Merge version_8_1776693468912 into main

Merge version_8_1776693468912 into main
This commit was merged in pull request #7.
This commit is contained in:
2026-04-20 14:00:03 +00:00
4 changed files with 109 additions and 23 deletions

View File

@@ -0,0 +1,84 @@
import { useState, useEffect } from 'react';
import { useButtonClick } from '@/hooks/useButtonClick';
import { motion } from 'motion/react';
type NavItem = {
name: string;
href: string;
};
type CtaButton = {
text: string;
href: string;
};
type FloatingNavProps = {
logo: string;
navItems: NavItem[];
ctaButton: CtaButton;
};
const NavLink = ({ name, href }: { name: string; href: string }) => {
const handleClick = useButtonClick(href);
return (
<button
onClick={handleClick}
className="text-sm font-medium text-foreground/80 hover:text-foreground transition-colors"
>
{name}
</button>
);
};
export default function FloatingNav({ logo, navItems, ctaButton }: FloatingNavProps) {
const [visible, setVisible] = useState(true);
const [lastScrollY, setLastScrollY] = useState(0);
const controlNavbar = () => {
if (typeof window !== 'undefined') {
if (window.scrollY > lastScrollY && window.scrollY > 100) {
setVisible(false);
} else {
setVisible(true);
}
setLastScrollY(window.scrollY);
}
};
useEffect(() => {
window.addEventListener('scroll', controlNavbar);
return () => {
window.removeEventListener('scroll', controlNavbar);
};
}, [lastScrollY]);
const CtaButtonHandler = useButtonClick(ctaButton.href);
return (
<>
{visible && (
<motion.nav
initial={{ y: -100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
className="fixed top-6 left-1/2 -translate-x-1/2 z-50"
>
<div className="flex items-center justify-between gap-8 px-4 py-2 border rounded-full border-accent bg-card/80 backdrop-blur-lg">
<span className="text-lg font-bold text-foreground">{logo}</span>
<div className="hidden md:flex items-center gap-6">
{navItems.map((item) => (
<NavLink key={item.name} name={item.name} href={item.href} />
))}
</div>
<button
onClick={CtaButtonHandler}
className="primary-button px-4 py-2 text-sm font-medium rounded-full text-primary-cta-text"
>
{ctaButton.text}
</button>
</div>
</motion.nav>
)}
</>
);
}

View File

@@ -1,20 +1,15 @@
const avatars = [
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AM9hp4M6eDzEwMxDU5gYArbELf/professional-headshot-of-a-japanese-male-1776690846328-d57aee35.png",
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AM9hp4M6eDzEwMxDU5gYArbELf/professional-headshot-of-a-female-busine-1776690854791-b9f5ea1f.png",
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AM9hp4M6eDzEwMxDU5gYArbELf/professional-headshot-of-a-young-japanes-1776690864881-b5f3321c.png",
];
const HeroTrustedBy = () => {
const avatars = [
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AM9hp4M6eDzEwMxDU5gYArbELf/professional-headshot-of-a-japanese-male-1776690846328-d57aee35.png",
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AM9hp4M6eDzEwMxDU5gYArbELf/professional-headshot-of-a-female-busine-1776690854791-b9f5ea1f.png",
"https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AM9hp4M6eDzEwMxDU5gYArbELf/professional-headshot-of-a-young-japanes-1776690864881-b5f3321c.png",
];
return (
<div className="glassmorphic-tag">
<div className="avatar-stack">
{avatars.map((src, index) => (
<img
key={index}
src={src}
alt={`Trusted by user ${index + 1}`}
className="avatar"
/>
<img key={index} src={src} alt={`avatar ${index + 1}`} className="avatar" />
))}
</div>
<span>Trusted by over 2000 agencies</span>

View File

@@ -16,7 +16,7 @@
--background-accent: #222222;
/* @layout/border-radius/rounded */
--radius: 0.25rem;
--radius: 0.5rem;
/* @layout/content-width/medium */
--width-content-width: clamp(40rem, 80vw, 100rem);
@@ -141,15 +141,22 @@ body {
min-height: 100vh;
overscroll-behavior: none;
overscroll-behavior-y: none;
padding-top: 5rem;
padding-top: 6rem;
}
#nav {
position: fixed;
top: 0;
width: 100%;
top: 1rem;
left: 1rem;
right: 1rem;
z-index: 1000;
background-color: var(--background);
background-color: rgba(18, 18, 18, 0.75);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: var(--radius);
border: 1px solid var(--accent);
margin: 0 auto;
max-width: 1200px;
}
h1,
@@ -196,16 +203,16 @@ h6 {
box-shadow:
color-mix(in srgb, var(--color-background) 15%, transparent) 0px 4px 10px 0px inset,
color-mix(in srgb, var(--color-background) 15%, transparent) 0px -4px 8px 0px inset,
0 8px 15px -3px color-mix(in srgb, var(--primary-cta) 30%, transparent),
0 0 8px var(--primary-cta);
0 0 25px -3px var(--primary-cta),
0 0 10px var(--primary-cta);
}
.secondary-button:hover {
animation: button-hover-effect 0.3s ease-out forwards;
box-shadow:
0 1px 2px 0 rgb(0 0 0 / 0.05),
0 8px 15px -3px color-mix(in srgb, var(--secondary-cta-text) 30%, transparent),
0 0 8px var(--secondary-cta-text);
0 0 25px -3px var(--secondary-cta-text),
0 0 10px var(--secondary-cta-text);
}
.glassmorphic-tag {

View File

@@ -194,9 +194,9 @@
transform: translateY(0) scale(1);
}
50% {
transform: translateY(-4px) scale(1.05);
transform: translateY(-8px) scale(1.1);
}
100% {
transform: translateY(-2px) scale(1.02);
transform: translateY(-4px) scale(1.05);
}
}