feat: add basic webui
This commit is contained in:
53
apps/web/app/(home)/components/cases.tsx
Normal file
53
apps/web/app/(home)/components/cases.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Carousel,
|
||||
type CarouselApi,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
} from '@konobangu/design-system/components/ui/carousel';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const Cases = () => {
|
||||
const [api, setApi] = useState<CarouselApi>();
|
||||
const [current, setCurrent] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (api.selectedScrollSnap() + 1 === api.scrollSnapList().length) {
|
||||
setCurrent(0);
|
||||
api.scrollTo(0);
|
||||
} else {
|
||||
api.scrollNext();
|
||||
setCurrent(current + 1);
|
||||
}
|
||||
}, 1000);
|
||||
}, [api, current]);
|
||||
|
||||
return (
|
||||
<div className="w-full py-20 lg:py-40">
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col gap-10">
|
||||
<h2 className="text-left font-regular text-xl tracking-tighter md:text-5xl lg:max-w-xl">
|
||||
Trusted by thousands of businesses worldwide
|
||||
</h2>
|
||||
<Carousel setApi={setApi} className="w-full">
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 15 }).map((_, index) => (
|
||||
<CarouselItem className="basis-1/4 lg:basis-1/6" key={index}>
|
||||
<div className="flex aspect-square items-center justify-center rounded-md bg-muted p-6">
|
||||
<span className="text-sm">Logo {index + 1}</span>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
</Carousel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
35
apps/web/app/(home)/components/cta.tsx
Normal file
35
apps/web/app/(home)/components/cta.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Button } from '@konobangu/design-system/components/ui/button';
|
||||
import { env } from '@konobangu/env';
|
||||
import { MoveRight, PhoneCall } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
export const CTA = () => (
|
||||
<div className="w-full py-20 lg:py-40">
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col items-center gap-8 rounded-md bg-muted p-4 text-center lg:p-14">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h3 className="max-w-xl font-regular text-3xl tracking-tighter md:text-5xl">
|
||||
Try our platform today!
|
||||
</h3>
|
||||
<p className="max-w-xl text-lg text-muted-foreground leading-relaxed tracking-tight">
|
||||
Managing a small business today is already tough. Avoid further
|
||||
complications by ditching outdated, tedious trade methods. Our goal
|
||||
is to streamline SMB trade, making it easier and faster than ever.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-row gap-4">
|
||||
<Button className="gap-4" variant="outline" asChild>
|
||||
<Link href="/contact">
|
||||
Jump on a call <PhoneCall className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
<Button className="gap-4" asChild>
|
||||
<Link href={env.NEXT_PUBLIC_APP_URL}>
|
||||
Sign up here <MoveRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
55
apps/web/app/(home)/components/faq.tsx
Normal file
55
apps/web/app/(home)/components/faq.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from '@konobangu/design-system/components/ui/accordion';
|
||||
import { Button } from '@konobangu/design-system/components/ui/button';
|
||||
import { PhoneCall } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
export const FAQ = () => (
|
||||
<div className="w-full py-20 lg:py-40">
|
||||
<div className="container mx-auto">
|
||||
<div className="grid gap-10 lg:grid-cols-2">
|
||||
<div className="flex flex-col gap-10">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h4 className="max-w-xl text-left font-regular text-3xl tracking-tighter md:text-5xl">
|
||||
This is the start of something new
|
||||
</h4>
|
||||
<p className="max-w-xl text-left text-lg text-muted-foreground leading-relaxed tracking-tight lg:max-w-lg">
|
||||
Managing a small business today is already tough. Avoid further
|
||||
complications by ditching outdated, tedious trade methods. Our
|
||||
goal is to streamline SMB trade, making it easier and faster
|
||||
than ever.
|
||||
</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<Button className="gap-4" variant="outline" asChild>
|
||||
<Link href="/contact">
|
||||
Any questions? Reach out <PhoneCall className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Accordion type="single" collapsible className="w-full">
|
||||
{Array.from({ length: 8 }).map((_, index) => (
|
||||
<AccordionItem key={index} value={`index-${index}`}>
|
||||
<AccordionTrigger>
|
||||
This is the start of something new
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Managing a small business today is already tough. Avoid further
|
||||
complications by ditching outdated, tedious trade methods. Our
|
||||
goal is to streamline SMB trade, making it easier and faster
|
||||
than ever.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
63
apps/web/app/(home)/components/features.tsx
Normal file
63
apps/web/app/(home)/components/features.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { User } from 'lucide-react';
|
||||
|
||||
export const Features = () => (
|
||||
<div className="w-full py-20 lg:py-40">
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col gap-10">
|
||||
<div className="flex flex-col items-start gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="max-w-xl text-left font-regular text-3xl tracking-tighter md:text-5xl">
|
||||
Something new!
|
||||
</h2>
|
||||
<p className="max-w-xl text-left text-lg text-muted-foreground leading-relaxed tracking-tight lg:max-w-lg">
|
||||
Managing a small business today is already tough.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<div className="flex aspect-square h-full flex-col justify-between rounded-md bg-muted p-6 lg:col-span-2 lg:aspect-auto">
|
||||
<User className="h-8 w-8 stroke-1" />
|
||||
<div className="flex flex-col">
|
||||
<h3 className="text-xl tracking-tight">Pay supplier invoices</h3>
|
||||
<p className="max-w-xs text-base text-muted-foreground">
|
||||
Our goal is to streamline SMB trade, making it easier and faster
|
||||
than ever.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex aspect-square flex-col justify-between rounded-md bg-muted p-6">
|
||||
<User className="h-8 w-8 stroke-1" />
|
||||
<div className="flex flex-col">
|
||||
<h3 className="text-xl tracking-tight">Pay supplier invoices</h3>
|
||||
<p className="max-w-xs text-base text-muted-foreground">
|
||||
Our goal is to streamline SMB trade, making it easier and faster
|
||||
than ever.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex aspect-square flex-col justify-between rounded-md bg-muted p-6">
|
||||
<User className="h-8 w-8 stroke-1" />
|
||||
<div className="flex flex-col">
|
||||
<h3 className="text-xl tracking-tight">Pay supplier invoices</h3>
|
||||
<p className="max-w-xs text-base text-muted-foreground">
|
||||
Our goal is to streamline SMB trade, making it easier and faster
|
||||
than ever.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex aspect-square h-full flex-col justify-between rounded-md bg-muted p-6 lg:col-span-2 lg:aspect-auto">
|
||||
<User className="h-8 w-8 stroke-1" />
|
||||
<div className="flex flex-col">
|
||||
<h3 className="text-xl tracking-tight">Pay supplier invoices</h3>
|
||||
<p className="max-w-xs text-base text-muted-foreground">
|
||||
Our goal is to streamline SMB trade, making it easier and faster
|
||||
than ever.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
64
apps/web/app/(home)/components/hero.tsx
Normal file
64
apps/web/app/(home)/components/hero.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import { blog } from '@konobangu/cms';
|
||||
import { Feed } from '@konobangu/cms/components/feed';
|
||||
import { Button } from '@konobangu/design-system/components/ui/button';
|
||||
import { env } from '@konobangu/env';
|
||||
import { MoveRight, PhoneCall } from 'lucide-react';
|
||||
import { draftMode } from 'next/headers';
|
||||
import Link from 'next/link';
|
||||
|
||||
export const Hero = async () => {
|
||||
const draft = await draftMode();
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col items-center justify-center gap-8 py-20 lg:py-40">
|
||||
<div>
|
||||
<Feed queries={[blog.latestPostQuery]} draft={draft.isEnabled}>
|
||||
{/* biome-ignore lint/suspicious/useAwait: "Server Actions must be async" */}
|
||||
{async ([data]) => {
|
||||
'use server';
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="gap-4"
|
||||
asChild
|
||||
>
|
||||
<Link href={`/blog/${data.blog.posts.items.at(0)?._slug}`}>
|
||||
Read our latest article <MoveRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
);
|
||||
}}
|
||||
</Feed>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<h1 className="max-w-2xl text-center font-regular text-5xl tracking-tighter md:text-7xl">
|
||||
This is the start of something new
|
||||
</h1>
|
||||
<p className="max-w-2xl text-center text-lg text-muted-foreground leading-relaxed tracking-tight md:text-xl">
|
||||
Managing a small business today is already tough. Avoid further
|
||||
complications by ditching outdated, tedious trade methods. Our
|
||||
goal is to streamline SMB trade, making it easier and faster than
|
||||
ever.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3">
|
||||
<Button size="lg" className="gap-4" variant="outline" asChild>
|
||||
<Link href="/contact">
|
||||
Get in touch <PhoneCall className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
<Button size="lg" className="gap-4" asChild>
|
||||
<Link href={env.NEXT_PUBLIC_APP_URL}>
|
||||
Sign up <MoveRight className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
75
apps/web/app/(home)/components/stats.tsx
Normal file
75
apps/web/app/(home)/components/stats.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { MoveDownLeft, MoveUpRight } from 'lucide-react';
|
||||
|
||||
export const Stats = () => (
|
||||
<div className="w-full py-20 lg:py-40">
|
||||
<div className="container mx-auto">
|
||||
<div className="grid grid-cols-1 gap-10 lg:grid-cols-2">
|
||||
<div className="flex flex-col items-start gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="text-left font-regular text-xl tracking-tighter md:text-5xl lg:max-w-xl">
|
||||
This is the start of something new
|
||||
</h2>
|
||||
<p className="text-left text-lg text-muted-foreground leading-relaxed tracking-tight lg:max-w-sm">
|
||||
Managing a small business today is already tough. Avoid further
|
||||
complications by ditching outdated, tedious trade methods. Our
|
||||
goal is to streamline SMB trade, making it easier and faster than
|
||||
ever.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="grid w-full grid-cols-1 gap-2 text-left sm:grid-cols-2 lg:grid-cols-2">
|
||||
<div className="flex flex-col justify-between gap-0 rounded-md border p-6">
|
||||
<MoveUpRight className="mb-10 h-4 w-4 text-primary" />
|
||||
<h2 className="flex max-w-xl flex-row items-end gap-4 text-left font-regular text-4xl tracking-tighter">
|
||||
500.000
|
||||
<span className="text-muted-foreground text-sm tracking-normal">
|
||||
+20.1%
|
||||
</span>
|
||||
</h2>
|
||||
<p className="max-w-xl text-left text-base text-muted-foreground leading-relaxed tracking-tight">
|
||||
Monthly active users
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col justify-between gap-0 rounded-md border p-6">
|
||||
<MoveDownLeft className="mb-10 h-4 w-4 text-destructive" />
|
||||
<h2 className="flex max-w-xl flex-row items-end gap-4 text-left font-regular text-4xl tracking-tighter">
|
||||
20.105
|
||||
<span className="text-muted-foreground text-sm tracking-normal">
|
||||
-2%
|
||||
</span>
|
||||
</h2>
|
||||
<p className="max-w-xl text-left text-base text-muted-foreground leading-relaxed tracking-tight">
|
||||
Daily active users
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col justify-between gap-0 rounded-md border p-6">
|
||||
<MoveUpRight className="mb-10 h-4 w-4 text-primary" />
|
||||
<h2 className="flex max-w-xl flex-row items-end gap-4 text-left font-regular text-4xl tracking-tighter">
|
||||
$523.520
|
||||
<span className="text-muted-foreground text-sm tracking-normal">
|
||||
+8%
|
||||
</span>
|
||||
</h2>
|
||||
<p className="max-w-xl text-left text-base text-muted-foreground leading-relaxed tracking-tight">
|
||||
Monthly recurring revenue
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col justify-between gap-0 rounded-md border p-6">
|
||||
<MoveUpRight className="mb-10 h-4 w-4 text-primary" />
|
||||
<h2 className="flex max-w-xl flex-row items-end gap-4 text-left font-regular text-4xl tracking-tighter">
|
||||
$1052
|
||||
<span className="text-muted-foreground text-sm tracking-normal">
|
||||
+2%
|
||||
</span>
|
||||
</h2>
|
||||
<p className="max-w-xl text-left text-base text-muted-foreground leading-relaxed tracking-tight">
|
||||
Cost per acquisition
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
78
apps/web/app/(home)/components/testimonials.tsx
Normal file
78
apps/web/app/(home)/components/testimonials.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from '@konobangu/design-system/components/ui/avatar';
|
||||
import {
|
||||
Carousel,
|
||||
type CarouselApi,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
} from '@konobangu/design-system/components/ui/carousel';
|
||||
import { User } from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const Testimonials = () => {
|
||||
const [api, setApi] = useState<CarouselApi>();
|
||||
const [current, setCurrent] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (api.selectedScrollSnap() + 1 === api.scrollSnapList().length) {
|
||||
setCurrent(0);
|
||||
api.scrollTo(0);
|
||||
} else {
|
||||
api.scrollNext();
|
||||
setCurrent(current + 1);
|
||||
}
|
||||
}, 4000);
|
||||
}, [api, current]);
|
||||
|
||||
return (
|
||||
<div className="w-full py-20 lg:py-40">
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col gap-10">
|
||||
<h2 className="text-left font-regular text-3xl tracking-tighter md:text-5xl lg:max-w-xl">
|
||||
Trusted by thousands of businesses worldwide
|
||||
</h2>
|
||||
<Carousel setApi={setApi} className="w-full">
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 15 }).map((_, index) => (
|
||||
<CarouselItem className="lg:basis-1/2" key={index}>
|
||||
<div className="flex aspect-video h-full flex-col justify-between rounded-md bg-muted p-6 lg:col-span-2">
|
||||
<User className="h-8 w-8 stroke-1" />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col">
|
||||
<h3 className="text-xl tracking-tight">
|
||||
Best decision
|
||||
</h3>
|
||||
<p className="max-w-xs text-base text-muted-foreground">
|
||||
Our goal was to streamline SMB trade, making it easier
|
||||
and faster than ever and we did it together.
|
||||
</p>
|
||||
</div>
|
||||
<p className="flex flex-row items-center gap-2 text-sm">
|
||||
<span className="text-muted-foreground">By</span>
|
||||
<Avatar className="h-6 w-6">
|
||||
<AvatarImage src="https://github.com/shadcn.png" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<span>John Johnsen</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
</Carousel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user