Compare commits
24 Commits
version_4_
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d638367c9d | ||
|
|
834f1f4564 | ||
|
|
7d68c26fe4 | ||
| ff02c77644 | |||
|
|
af69450744 | ||
|
|
ad252e8c7c | ||
| 1c3d9bc4a2 | |||
| e2c897ab99 | |||
| 09c6cf4a4c | |||
| bd514e1cf1 | |||
| 00186d7e05 | |||
| 0d4ec5dbdb | |||
|
|
a9877bdfb3 | ||
|
|
50bf40d17c | ||
|
|
f441b5f6a0 | ||
|
|
ad070a142a | ||
| 5ef2263be8 | |||
|
|
d812539488 | ||
|
|
2c625df909 | ||
|
|
28d2012366 | ||
|
|
92bf0762d2 | ||
| 946d85c625 | |||
|
|
05c1e70b07 | ||
| 6fde3b761e |
@@ -9,6 +9,7 @@ import NavbarCentered from '@/components/ui/NavbarCentered';
|
||||
import PricingLayeredCards from '@/components/sections/pricing/PricingLayeredCards';
|
||||
import SocialProofMarquee from '@/components/sections/social-proof/SocialProofMarquee';
|
||||
import TestimonialRatingCards from '@/components/sections/testimonial/TestimonialRatingCards';
|
||||
import HeroTrustedBy from '@/components/ui/HeroTrustedBy';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
@@ -55,7 +56,9 @@ export default function App() {
|
||||
}}
|
||||
imageSrc="https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AM9hp4M6eDzEwMxDU5gYArbELf/a-sleek-modern-high-tech-marketing-offic-1776690837523-6e0bf547.png"
|
||||
/>
|
||||
<p className="hero-trust-badge">Trusted by over 2000 agencies</p>
|
||||
<div className="flex justify-center relative z-10" style={{ marginTop: '-4rem' }}>
|
||||
<HeroTrustedBy />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="about" data-section="about">
|
||||
|
||||
87
src/components/ui/FloatingNav.tsx
Normal file
87
src/components/ui/FloatingNav.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useButtonClick } from '@/hooks/useButtonClick';
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
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 (
|
||||
<AnimatePresence>
|
||||
{visible && (
|
||||
<motion.nav
|
||||
initial={{ y: -100, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
exit={{ y: -100, opacity: 0 }}
|
||||
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>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
20
src/components/ui/HeroTrustedBy.tsx
Normal file
20
src/components/ui/HeroTrustedBy.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
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={`avatar ${index + 1}`} className="avatar" />
|
||||
))}
|
||||
</div>
|
||||
<span>Trusted by over 2000 agencies</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroTrustedBy;
|
||||
25
src/components/ui/TrustedBy.tsx
Normal file
25
src/components/ui/TrustedBy.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
const TrustedBy = () => {
|
||||
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"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<span>Trusted by over 2000 agencies</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrustedBy;
|
||||
@@ -16,7 +16,7 @@
|
||||
--background-accent: #222222;
|
||||
|
||||
/* @layout/border-radius/rounded */
|
||||
--radius: 0.3rem;
|
||||
--radius: 0.5rem;
|
||||
|
||||
/* @layout/content-width/medium */
|
||||
--width-content-width: clamp(40rem, 80vw, 100rem);
|
||||
@@ -141,6 +141,22 @@ body {
|
||||
min-height: 100vh;
|
||||
overscroll-behavior: none;
|
||||
overscroll-behavior-y: none;
|
||||
padding-top: 6rem;
|
||||
}
|
||||
|
||||
#nav {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
right: 1rem;
|
||||
z-index: 1000;
|
||||
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,
|
||||
@@ -183,26 +199,46 @@ h6 {
|
||||
}
|
||||
|
||||
.primary-button:hover {
|
||||
transform: translateY(-3px);
|
||||
animation: button-hover-effect 0.3s ease-out forwards;
|
||||
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 25px -3px var(--primary-cta),
|
||||
0 0 10px var(--primary-cta);
|
||||
}
|
||||
|
||||
.secondary-button:hover {
|
||||
transform: translateY(-3px);
|
||||
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 25px -3px var(--secondary-cta-text),
|
||||
0 0 10px var(--secondary-cta-text);
|
||||
}
|
||||
|
||||
.hero-trust-badge {
|
||||
.glassmorphic-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem 1rem 0.5rem 0.5rem;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 9999px;
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
color: var(--foreground);
|
||||
font-size: var(--text-sm);
|
||||
margin-top: -4rem;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.avatar-stack {
|
||||
display: flex;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--background);
|
||||
object-fit: cover;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
@@ -188,3 +188,15 @@
|
||||
0 0 8px var(--secondary-cta-text);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes button-hover-effect {
|
||||
0% {
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-8px) scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-4px) scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user