done landing page

This commit is contained in:
2025-11-10 17:10:34 +05:30
parent 3852d46661
commit 483515e163
105 changed files with 3529 additions and 104 deletions

View File

@@ -0,0 +1,26 @@
import React from "react";
interface ButtonProps {
text: string;
className?: string;
}
const Button: React.FC<ButtonProps> = ({ text, className = "" }) => {
return (
<button
className={`group font-mium-reg text-b-2-17 bg-btn relative h-[52px] w-max min-w-40 cursor-pointer rounded-full px-6 py-2.5 text-center font-normal tracking-[-0.8px] text-white shadow-[inset_0_0_25px_#7ED38C,0_0_25px_rgba(126,211,140,0.6),0_0_50px_rgba(126,211,140,0.3)] transition-all duration-700 ease-[cubic-bezier(0.19,1,0.22,1)] hover:shadow-[inset_0_0_30px_#9CF1A5,0_0_35px_rgba(126,211,140,0.9),0_0_60px_rgba(126,211,140,0.7)] ${className} `}
>
{/* Smooth hover text animation */}
<span className="relative block overflow-hidden">
<span className="block transition-transform duration-[1.125s] ease-[cubic-bezier(0.19,1,0.22,1)] group-hover:-translate-y-6">
{text}
</span>
<span className="absolute top-6 left-0 transition-all duration-[1.125s] ease-[cubic-bezier(0.19,1,0.22,1)] group-hover:top-0">
{text}
</span>
</span>
</button>
);
};
export default Button;

View File

@@ -0,0 +1,198 @@
"use client";
import Image from "next/image";
import Link from "next/link";
const Footer = () => {
const companyLinks = [
{ label: "Home", href: "/#home" },
{ label: "About Us", href: "/#about" },
{ label: "Product", href: "/#product" },
{ label: "Benefits", href: "/#benefits" },
{ label: "How it works", href: "/#how-it-works" },
{ label: "Use Cases", href: "/#use-cases" },
{ label: "Privacy Policy", href: "/privacy" },
];
const socialLinks = [
{ label: "LinkedIn", href: "https://linkedin.com", icon: "linkedin" },
{ label: "X", href: "https://x.com", icon: "x" },
{ label: "Facebook", href: "https://facebook.com", icon: "facebook" },
{ label: "Instagram", href: "https://instagram.com", icon: "instagram" },
];
return (
<footer className="bg-brand relative w-full text-white">
<Image
src="/images/png/grainy.png"
width={800}
height={900}
alt="Munich City with trees and sensor on it"
className="absolute top-0 left-0 h-full w-full rounded-2xl object-cover opacity-30 mix-blend-soft-light"
/>
<div className="tab:px-4 relative z-20 mx-auto max-w-[1420px] pt-16 sm:px-2.5 lg:px-6">
<div className="tab:flex-row tab:gap-5 flex items-center justify-between sm:flex-col sm:gap-8 md:gap-0">
{/* Left: Logo, Description, Contact */}
<div className="flex w-full flex-col gap-1">
<div className="mb-4 flex items-center gap-2">
<Image
src="/images/svg/whispering-logo.svg"
alt="Whispering Trees"
width={280}
height={68}
className="h-[68px] w-[280px] object-contain"
/>
</div>
<p className="font-mium-reg text-b-3-16 leading-b3 tab:mb-6 max-w-xl tracking-[-0.5px] text-white">
FalktronTrees is redefining urban forestry through IoT and AI
turning trees into living data sources for healthier, more
sustainable cities. Together, were shaping a greener, smarter
future.
</p>
<div className="tab:flex-col tab:mb-3 tab:gap-5 mt-6! flex items-start sm:mb-6 sm:flex-col sm:gap-2 md:flex-row">
<div className="flex items-center gap-2">
<span className="text-b-3-16 font-mium-reg flex items-center gap-1 font-normal tracking-[-0.5px] text-white">
<Image
width={20}
height={20}
src="/images/svg/proicons_call.svg"
className="h-5 w-5 object-cover"
alt="Call"
/>
Call us:
</span>
<a
href="tel:+492511234567"
className="text-b-3-16 font-mium-reg font-normal tracking-[-0.5px] text-white transition-colors hover:text-green-400"
>
+49 251 1234567
</a>
</div>
<div className="flex items-center gap-2">
<span className="text-b-3-16 font-mium-reg flex items-center gap-1 font-normal tracking-[-0.5px] text-white">
<Image
width={20}
height={20}
src="/images/svg/mage_email.svg"
className="h-5 w-5 object-cover"
alt="email"
/>
Email:
</span>
<a
href="mailto:info@falktrontrees.com"
className="text-b-3-16 font-mium-reg font-normal tracking-[-0.5px] text-white transition-colors hover:text-green-400"
>
info@falktrontrees.com
</a>
</div>
</div>
{/* <Button text="Contact Us" /> */}
</div>
{/* Right: Links */}
<div className="tab:w-max sm:w-full">
<div className="grid grid-cols-2 gap-8 md:grid-cols-2">
{/* Company Links */}
<div className="min-w-[180px]">
<h3 className="text-b-1-20 font-switzer mb-5 font-medium text-white">
Company
</h3>
<ul className="space-y-1.5">
{companyLinks.map((link) => {
// ← current route
const isHash = link.href.startsWith("/#"); // ← internal hash
const targetId = link.href.replace("/#", "");
return (
<li key={link.label}>
{isHash ? (
<a
href={link.href}
onClick={(e) => {
e.preventDefault();
const section = document.getElementById(targetId);
if (section) {
const yOffset = -80;
const y =
section.getBoundingClientRect().top +
window.pageYOffset +
yOffset;
window.scrollTo({ top: y, behavior: "smooth" });
}
}}
className="text-b-3-16 group font-mium-reg font-normal tracking-[-0.5px] text-white transition-colors hover:text-green-400"
>
<span className="relative block overflow-hidden">
<span className="block transition-transform duration-[1.125s] ease-[cubic-bezier(0.19,1,0.22,1)] group-hover:-translate-y-6">
{link.label}
</span>
<span className="absolute top-6 left-0 transition-all duration-[1.125s] ease-[cubic-bezier(0.19,1,0.22,1)] group-hover:top-0">
{link.label}
</span>
</span>
</a>
) : (
<Link
href={link.href}
className="text-b-3-16 group font-mium-reg font-normal tracking-[-0.5px] text-white transition-colors hover:text-green-400"
>
<span className="relative block overflow-hidden">
<span className="block transition-transform duration-[1.125s] ease-[cubic-bezier(0.19,1,0.22,1)] group-hover:-translate-y-6">
{link.label}
</span>
<span className="absolute top-6 left-0 transition-all duration-[1.125s] ease-[cubic-bezier(0.19,1,0.22,1)] group-hover:top-0">
{link.label}
</span>
</span>
</Link>
)}
</li>
);
})}
</ul>
</div>
{/* Social Links */}
<div>
<h3 className="text-b-1-20 font-switzer mb-5 font-medium text-white">
Social Links
</h3>
<ul className="space-y-1.5">
{socialLinks.map((link) => (
<li key={link.label}>
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="text-b-3-16 group font-mium-reg font-normal tracking-[-0.5px] text-white transition-colors hover:text-green-400"
>
<span className="relative block overflow-hidden">
<span className="block transition-transform duration-[1.125s] ease-[cubic-bezier(0.19,1,0.22,1)] group-hover:-translate-y-6">
{link.label}
</span>
<span className="absolute top-6 left-0 transition-all duration-[1.125s] ease-[cubic-bezier(0.19,1,0.22,1)] group-hover:top-0">
{link.label}
</span>
</span>
</a>
</li>
))}
</ul>
</div>
</div>
</div>
</div>
{/* Bottom Bar */}
<div className="font-switzer text-b-2-17 mt-12 border-t border-white/10 pt-6 pb-6 text-center font-normal text-white">
© {new Date().getFullYear()} Whispering Trees. All rights reserved.
</div>
</div>
</footer>
);
};
export default Footer;

View File

@@ -0,0 +1,112 @@
"use client";
import Image from "next/image";
import { useEffect, useRef, useState } from "react";
import { gsap } from "gsap";
import Button from "./Button";
import SmoothScrollLink from "@/components/ui/smooth-scroll-link";
import Link from "next/link";
import { usePageTransition } from "@/layout/Layout";
const Navbar = () => {
const navbarRef = useRef<HTMLDivElement>(null);
const [scrolled, setScrolled] = useState(false);
const [showNavbar, setShowNavbar] = useState(true);
const { startTransition } = usePageTransition();
const [lastScrollY, setLastScrollY] = useState(0);
// ── GSAP: Initial slide-in ─────────────────────────────────────
useEffect(() => {
const el = navbarRef.current;
if (!el) return;
// Start off-screen
gsap.set(el, { yPercent: -100, opacity: 0 });
// Animate in
gsap.to(el, {
yPercent: 0,
opacity: 1,
duration: 1.2,
ease: "expo.out",
});
}, []);
// ── Scroll: Hide/show + background ─────────────────────────────
useEffect(() => {
const handleScroll = () => {
const currentScroll = window.scrollY;
// Hide on scroll down
if (currentScroll > lastScrollY && currentScroll > 100) {
setShowNavbar(false);
} else {
setShowNavbar(true);
}
setScrolled(currentScroll > 30);
setLastScrollY(currentScroll);
};
window.addEventListener("scroll", handleScroll, { passive: true });
return () => window.removeEventListener("scroll", handleScroll);
}, [lastScrollY]);
const navLinks = [
{ label: "Home", href: "#home" },
{ label: "About Us", href: "#about" },
{ label: "Benefits", href: "#benefits" },
{ label: "How it works", href: "/#how-it-works" },
{ label: "FAQ", href: "#faq" },
];
return (
<header
ref={navbarRef}
className={`tab:block fixed top-0 right-0 left-0 z-50 sm:hidden ${showNavbar ? "translate-y-0" : "-translate-y-full"} ${
scrolled
? "top-0 border-white/30 bg-white/40 shadow-xs backdrop-blur-md"
: "top-6 border-transparent bg-transparent"
} `.trim()}
>
<nav className="mx-auto flex h-[75px] w-full max-w-[1420px] items-center justify-between px-6 py-3 transition-all duration-300">
{/* Logo */}
<div
onClick={() => startTransition(`/`)}
className="h-10 w-36 cursor-pointer"
>
<Image
src={
scrolled
? "/images/svg/dark-logo.svg"
: "/images/svg/whispering-logo.svg"
}
width={144}
height={40}
alt="Whispering Tree"
className="h-full w-full object-contain"
/>
</div>
{/* Desktop Links */}
<div className="tab:flex hidden">
<ul className="flex items-center gap-6">
{navLinks.map((link) => (
<li key={link.href} className="flex items-center justify-center">
<SmoothScrollLink href={link.href} scrolled={scrolled}>
{link.label}
</SmoothScrollLink>
</li>
))}
</ul>
</div>
{/* CTA */}
<Button text="Book a Demo" />
</nav>
</header>
);
};
export default Navbar;

View File

@@ -0,0 +1,36 @@
import React from "react";
interface SecondaryButtonProps {
text: string;
targetId: string; // ← NEW: pass the section ID
className?: string;
}
const SecondaryButton: React.FC<SecondaryButtonProps> = ({
text,
targetId,
className = "",
}) => {
const handleScroll = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
const section = document.getElementById(targetId);
if (section) {
const yOffset = -80;
const y =
section.getBoundingClientRect().top + window.pageYOffset + yOffset;
window.scrollTo({ top: y, behavior: "smooth" });
}
};
return (
<a
href={`/#${targetId}`} // ← valid internal hash link
onClick={handleScroll}
className={`font-mium-reg text-b-2-17 h-[52px] w-max min-w-40 cursor-pointer rounded-full border border-white bg-transparent px-6 py-3 text-center font-normal tracking-[-0.8px] text-white hover:border-white/80 hover:bg-white/10 active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 ${className} `.trim()}
>
{text}
</a>
);
};
export default SecondaryButton;