done landing page
This commit is contained in:
162
app/globals.css
162
app/globals.css
@@ -1,26 +1,154 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
@font-face {
|
||||
font-family: "Switzer Variable";
|
||||
src: url("/font/Switzer-Variable.ttf") format("truetype");
|
||||
font-weight: 100 900; /* Full variable range */
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Mium Regular";
|
||||
src: url("/font/miumAccess-Regular.ttf") format("truetype");
|
||||
font-weight: 300; /* Full variable range */
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Playfair Display";
|
||||
src: url("/font/PlayfairDisplay-Italic-VariableFont_wght.ttf")
|
||||
format("truetype");
|
||||
font-weight: 300; /* Full variable range */
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
--font-switzer: "Switzer Variable", system-ui, sans-serif;
|
||||
--font-mium-reg: "Mium Regular", system-ui, sans-serif;
|
||||
--font-playfair: "Playfair Display", Georgia, serif;
|
||||
|
||||
/* === HEADINGS === */
|
||||
--text-h-1-96: 96px;
|
||||
--text-h-2-60: 60px;
|
||||
--text-h-3-40: 40px;
|
||||
--text-h-4-34: 34px;
|
||||
--text-h-5-28: 28px;
|
||||
--text-h-6-38: 38px;
|
||||
--text-h-7-24: 24px;
|
||||
--text-h-mobile-30: 30px;
|
||||
--text-hero-mobile: 56px;
|
||||
|
||||
--leading-h1: 90px;
|
||||
--leading-h2: 63px;
|
||||
--leading-h3: 48px;
|
||||
--leading-h4: 42px;
|
||||
--leading-h5: 30px;
|
||||
--leading-mobile: 38px;
|
||||
|
||||
/* === BODY TEXT === */
|
||||
--text-b-1-20: 20px;
|
||||
--text-b-2-17: 17px;
|
||||
--text-b-3-16: 16px;
|
||||
--text-b-4-14: 14px;
|
||||
|
||||
--leading-b1: 25px;
|
||||
--leading-b2: 26px;
|
||||
--leading-b3: 23px;
|
||||
--leading-b4: 16px;
|
||||
|
||||
--color-background: #f8f8ff;
|
||||
--color-light-100: #d5ffdc;
|
||||
--color-light-200: #ecf9db;
|
||||
--color-light-300: #d5ffdc33;
|
||||
--color-brand: #274b2d;
|
||||
--color-hover: #2f5a36;
|
||||
--color-btn: #274b2d;
|
||||
|
||||
--color-border: #3a6f43;
|
||||
|
||||
--color-secondary: #636369;
|
||||
--color-gray: #423f3f;
|
||||
|
||||
--breakpoint-xl: 1600px;
|
||||
--breakpoint-lg: 1400px;
|
||||
--breakpoint-md: 1024px;
|
||||
--breakpoint-tab: 767px;
|
||||
--breakpoint-sm: 320px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
@keyframes marquee {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
}
|
||||
to {
|
||||
transform: translateX(calc(-100% - var(--gap)));
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
/* Base marquee container */
|
||||
.marquee {
|
||||
display: flex;
|
||||
gap: var(--gap);
|
||||
animation: marquee var(--duration) linear infinite;
|
||||
}
|
||||
|
||||
@keyframes marquee {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
}
|
||||
to {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
.marquee {
|
||||
display: flex;
|
||||
gap: var(--gap);
|
||||
animation: marquee var(--duration) linear infinite;
|
||||
}
|
||||
|
||||
/* Reverse direction support */
|
||||
.marquee.reverse {
|
||||
animation-direction: reverse;
|
||||
}
|
||||
|
||||
/* Pause on hover */
|
||||
.group:hover .marquee.pause {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
/* === PAGE TRANSITION FIX === */
|
||||
|
||||
.overlay {
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
position: fixed; /* instead of relative — ensures full viewport coverage */
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw; /* use viewport units explicitly */
|
||||
height: 100vh;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.overlay__path {
|
||||
fill: var(--color-brand, #274b2d);
|
||||
stroke: none;
|
||||
vector-effect: non-scaling-stroke;
|
||||
}
|
||||
|
||||
.view {
|
||||
position: relative;
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.view--2 {
|
||||
background: var(--color-bg-view-2, #cbb37e);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
.view--open {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,42 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import { Playfair_Display } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
import SmoothScrollProvider from "@/lib/useLenisScroll";
|
||||
import { LayoutWithTransition } from "@/layout/Layout";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
title:
|
||||
"Whispering Tree | Smart IoT & AI Solutions for Tree Health Monitoring",
|
||||
description:
|
||||
"Whispering Tree combines IoT sensors and AI analytics to monitor the health of trees in real time. Our smart environmental system helps cities, organizations, and individuals optimize irrigation, detect stress early, and promote sustainable growth through data-driven insights.",
|
||||
keywords: [
|
||||
"Whispering Tree",
|
||||
"tree health monitoring",
|
||||
"IoT for environment",
|
||||
"AI tree analytics",
|
||||
"smart irrigation",
|
||||
"urban forestry technology",
|
||||
"environmental intelligence",
|
||||
"FalktronTrees",
|
||||
"Matthias Mut",
|
||||
"AI for sustainability",
|
||||
"smart city solutions",
|
||||
"real-time tree monitoring",
|
||||
"IoT sensors for trees",
|
||||
"green technology",
|
||||
"water optimization system",
|
||||
],
|
||||
openGraph: {
|
||||
title:
|
||||
"Whispering Tree | Smart IoT & AI Solutions for Tree Health Monitoring",
|
||||
description:
|
||||
"Whispering Tree combines IoT sensors and AI analytics to monitor the health of trees in real time. Our smart environmental system helps cities, organizations, and individuals optimize irrigation, detect stress early, and promote sustainable growth through data-driven insights.",
|
||||
url: "https://whisperingtree.com",
|
||||
type: "website",
|
||||
},
|
||||
icons: {
|
||||
icon: "/fav.svg",
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -24,10 +46,10 @@ export default function RootLayout({
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
<body className={`antialiased`}>
|
||||
<LayoutWithTransition>
|
||||
<SmoothScrollProvider>{children}</SmoothScrollProvider>
|
||||
</LayoutWithTransition>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
89
app/page.tsx
89
app/page.tsx
@@ -1,65 +1,34 @@
|
||||
import Image from "next/image";
|
||||
"use client";
|
||||
import Footer from "@/components/shared/Footer";
|
||||
import FAQ from "@/sections/FAQ";
|
||||
import About from "@/sections/About";
|
||||
import Benefit from "@/sections/Benefit";
|
||||
import CaseStudy from "@/sections/CaseStudy";
|
||||
import CTA from "@/sections/CTA";
|
||||
import Hero from "@/sections/Hero";
|
||||
import HowWork from "@/sections/HowWork";
|
||||
import ProductPreview from "@/sections/ProductPreview";
|
||||
import SocialProff from "@/sections/SocialProff";
|
||||
import Testimonial from "@/sections/Testimonial";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
||||
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={100}
|
||||
height={20}
|
||||
priority
|
||||
/>
|
||||
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
||||
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
|
||||
To get started, edit the page.tsx file.
|
||||
</h1>
|
||||
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
||||
Looking for a starting point or more instructions? Head over to{" "}
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Templates
|
||||
</a>{" "}
|
||||
or the{" "}
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Learning
|
||||
</a>{" "}
|
||||
center.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Deploy Now
|
||||
</a>
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<>
|
||||
<div className="flex flex-col gap-5">
|
||||
{/* <Loader /> */}
|
||||
<Hero />
|
||||
|
||||
<SocialProff />
|
||||
<About />
|
||||
<Benefit />
|
||||
<HowWork />
|
||||
<ProductPreview />
|
||||
<CaseStudy />
|
||||
<Testimonial />
|
||||
<FAQ />
|
||||
<CTA />
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
46
app/sitemap.xml/route.ts
Normal file
46
app/sitemap.xml/route.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
// app/sitemap/route.ts
|
||||
|
||||
interface SitemapPage {
|
||||
loc: string;
|
||||
lastmod: string;
|
||||
}
|
||||
|
||||
export const GET = async () => {
|
||||
const BASE_URL = "https://trees.falktron.com";
|
||||
|
||||
const useCases = [
|
||||
"forestry",
|
||||
"research",
|
||||
"agriculture",
|
||||
"cities-communities",
|
||||
];
|
||||
|
||||
const pages: SitemapPage[] = [
|
||||
{ loc: `${BASE_URL}/`, lastmod: new Date().toISOString().split("T")[0] },
|
||||
...useCases.map((slug) => ({
|
||||
loc: `${BASE_URL}/use-cases/${slug}`,
|
||||
lastmod: new Date().toISOString().split("T")[0],
|
||||
})),
|
||||
];
|
||||
|
||||
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
${pages
|
||||
.map(
|
||||
(page) => `
|
||||
<url>
|
||||
<loc>${page.loc}</loc>
|
||||
<lastmod>${page.lastmod}</lastmod>
|
||||
</url>`
|
||||
)
|
||||
.join("")}
|
||||
</urlset>`;
|
||||
|
||||
return new Response(xml, {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/xml",
|
||||
"Cache-Control": "public, s-maxage=86400, stale-while-revalidate=3600",
|
||||
},
|
||||
});
|
||||
};
|
||||
83
app/use-cases/[slug]/page.tsx
Normal file
83
app/use-cases/[slug]/page.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import Image from "next/image";
|
||||
import { notFound } from "next/navigation";
|
||||
import { useCases } from "@/data/useCases";
|
||||
import Footer from "@/components/shared/Footer";
|
||||
import Navbar from "@/components/shared/Navbar";
|
||||
import MobileNavbar from "@/components/ui/mobile-navbar";
|
||||
import CTA from "@/sections/CTA";
|
||||
import HeroClient from "@/sections/HeroCase";
|
||||
|
||||
interface Props {
|
||||
params: Promise<{ slug: string }>; // ← Promise!
|
||||
}
|
||||
|
||||
export default async function UseCaseDetail({ params }: Props) {
|
||||
const { slug } = await params;
|
||||
const item = useCases.find((c) => c.slug === slug);
|
||||
if (!item) notFound();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
<MobileNavbar />
|
||||
<HeroClient item={item} />
|
||||
<section className="tab:py-16 tab:px-6 mx-auto max-w-5xl sm:px-2.5 sm:py-8">
|
||||
<div className="space-y-12">
|
||||
<div>
|
||||
<h2 className="font-switzer mb-3 text-3xl font-semibold text-black">
|
||||
Overview
|
||||
</h2>
|
||||
<p className="font-mium-reg text-b-2-17 leading-b2 tracking-[-0.4px] text-black">
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 className="font-switzer mb-3 text-3xl font-semibold text-black">
|
||||
Challenge
|
||||
</h2>
|
||||
<p className="font-mium-reg text-b-2-17 leading-b2 tracking-[-0.4px] text-black">
|
||||
{item.challenge}
|
||||
</p>
|
||||
</div>
|
||||
<Image
|
||||
src={item.image1}
|
||||
alt={`${item.title} use case`}
|
||||
width={600}
|
||||
height={480}
|
||||
className="mx-auto h-[480px] w-full rounded-xl object-cover"
|
||||
/>
|
||||
|
||||
<div>
|
||||
<h2 className="font-switzer mb-3 text-3xl font-semibold text-black">
|
||||
Our Solution
|
||||
</h2>
|
||||
<p className="font-mium-reg text-b-2-17 leading-b2 tracking-[-0.4px] text-black">
|
||||
{item.solution}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 className="font-switzer mb-3 text-3xl font-semibold text-black">
|
||||
Impact
|
||||
</h2>
|
||||
<p className="font-mium-reg text-b-2-17 leading-b2 tracking-[-0.4px] text-black">
|
||||
{item.outcome}
|
||||
</p>
|
||||
</div>
|
||||
<Image
|
||||
src={item.image2}
|
||||
alt={`${item.title} use case`}
|
||||
width={600}
|
||||
height={480}
|
||||
className="mx-auto h-[480px] w-full rounded-xl object-cover"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<div className="tab:mb-0 sm:mb-10">
|
||||
<CTA />
|
||||
</div>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user