update public site

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-02-06 09:53:43 +01:00
parent b2e8398943
commit d1f12ca5e8
7 changed files with 273 additions and 4 deletions

View File

@@ -0,0 +1,74 @@
import * as React from 'react';
import type { SVGProps } from 'react';
export const Blob1 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M162.9 81.7c6.8 18.6-7.8 46.3-29.5 61.3-21.6 15-50.3 17.4-70.1 3.8-19.8-13.5-30.8-42.9-23.2-62.7 7.6-19.7 33.7-29.9 60.9-30.2 27.1-.3 55.2 9.2 61.9 27.8Z" />
</svg>
);
export const Blob2 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M142.7 86.2c9.4 28.8 11.5 60-2.1 70-13.6 9.9-42.8-1.5-63.9-18.2-21.2-16.7-34.2-38.8-28.9-62C53 52.9 76.5 28.7 96.6 29.8c20.1 1.1 36.8 27.5 46.1 56.4Z" />
</svg>
);
export const Blob3 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M135.5 88.9c4.3 12.9-2.5 29.9-18.7 44-16.2 14-41.6 25.1-54.7 16.3-13.1-8.8-14-37.6-5.6-56.1C64.9 74.7 82.4 66.4 99 66.8c16.6.3 32.2 9.2 36.5 22.1Z" />
</svg>
);
export const Blob4 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M161.5 88.5c9.2 20.1 1.7 54.1-18.1 67.6-19.8 13.5-51.9 6.6-76.8-11.2-25-17.9-42.8-46.7-36-63.3 6.7-16.6 38.1-21 66.8-20.2 28.7.9 54.8 7 64.1 27.1Z" />
</svg>
);
export const Blob5 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M144.6 81.1c3.8 15.9-9.2 32.9-27.5 47.4-18.4 14.6-42.2 26.7-58 17.6-15.7-9-23.5-39.3-15.3-61.3 8.1-21.9 32.2-35.6 54.4-35 22.2.5 42.7 15.4 46.4 31.3Z" />
</svg>
);
export const Blob6 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M158 83.8c9.5 26.6 4.2 60.6-14.8 74.1-19.1 13.5-52 6.5-68.5-8.9-16.5-15.3-16.6-39-9.7-62 7-23.1 21-45.5 40.1-47.2 19.1-1.7 43.4 17.5 52.9 44Z" />
</svg>
);
export const Blob7 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M163.8 81.2c6.3 17.6-9.8 44.3-28.5 55.1-18.8 10.7-40.3 5.4-58.3-7.1C58.9 116.6 44.2 96.9 48.6 82c4.4-14.9 27.9-24.9 54-25.7 26.1-.9 54.9 7.4 61.2 24.9Z" />
</svg>
);
export const Blob8 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M140.2 93.2c8.6 20.4 10.1 49.3-2.1 57.8-12.2 8.6-38.2-3.3-54.2-17.6s-22.1-31-17.8-45.5c4.4-14.5 19.1-26.6 34.4-26.8 15.3-.2 31 11.7 39.7 32.1Z" />
</svg>
);
export const Blob9 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M150.6 84.9c6.7 19.2-2 44.7-22.1 60.8-20.1 16.2-51.8 23-73.6 8.9C33 140.5 21 105.4 30.1 82.8 39.2 60.2 69.6 50 95.8 51.4c26.2 1.3 48.1 14.3 54.8 33.5Z" />
</svg>
);
export const Blob10 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M162 75.8c6.7 24.7-7.5 52.1-30.7 69.5s-55.4 24.8-77.8 10.4C31 141.4 18.3 105.4 27.7 77 37 48.6 68.5 27.9 98.1 28.5c29.5.6 57.2 22.6 63.9 47.3Z" />
</svg>
);
export const Blob11 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M164.3 77.3c7.7 25.5-5.2 55.9-26.2 69.9-21 14.1-50.2 11.8-66.2-1.5-16.1-13.3-19-37.7-12.2-62 6.9-24.3 23.6-48.7 46.1-50.6 22.5-1.9 50.8 18.7 58.5 44.2Z" />
</svg>
);
export const Blob12 = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" {...props}>
<path d="M140 81.8c5.8 23.1.4 44.7-14.1 55.7-14.6 11-38.2 11.4-59-1.5C46 123.1 27.8 96.9 33.8 73.6c6-23.4 36.1-43.8 59.7-41.7 23.6 2.1 40.7 26.8 46.5 49.9Z" />
</svg>
);

View File

@@ -13,6 +13,12 @@ export function Lead({ children, className }: Props) {
);
}
export function Lead2({ children, className }: Props) {
return (
<p className={cn('text-lg md:text-xl font-light', className)}>{children}</p>
);
}
export function Paragraph({ children, className }: Props) {
return <p className={cn('text-lg', className)}>{children}</p>;
}

View File

@@ -1,17 +1,27 @@
import { Logo } from '@/components/Logo';
import { Button } from '@/components/ui/button';
import type { LucideIcon } from 'lucide-react';
import {
BarChart2,
BellIcon,
ClockIcon,
CloudIcon,
CompassIcon,
ConeIcon,
CookieIcon,
DollarSignIcon,
Globe2Icon,
KeyIcon,
LayoutPanelTopIcon,
LockIcon,
UserRoundSearchIcon,
UsersIcon,
} from 'lucide-react';
import { HomeCarousel } from './carousel';
import { Heading1, Heading2, Lead, Paragraph } from './copy';
import { Heading1, Heading2, Lead, Lead2, Paragraph } from './copy';
import { JoinWaitlist } from './join-waitlist';
import { Section, Sections } from './section';
const features = [
{
@@ -71,6 +81,7 @@ export default function Page() {
</div>
</div>
</div>
<Sections />
<div className="bg-blue-800 p-4 py-8 md:py-16 text-center">
<Heading2 className="text-slate-100 mb-4">
Get a feel how it looks

View File

@@ -0,0 +1,168 @@
'use client';
import { cn } from '@/utils/cn';
import type { LucideIcon, LucideProps } from 'lucide-react';
import {
BellIcon,
ClockIcon,
CloudIcon,
CompassIcon,
ConeIcon,
DollarSignIcon,
KeyIcon,
UserRoundSearchIcon,
} from 'lucide-react';
import {
Blob1,
Blob2,
Blob3,
Blob4,
Blob5,
Blob6,
Blob7,
Blob8,
Blob9,
} from './blob';
import { Heading2, Lead2 } from './copy';
interface SectionItem {
title: string;
description: string;
icon: LucideIcon;
color: string;
soon?: string;
blob: React.ComponentType<LucideProps>;
}
const sections: SectionItem[] = [
{
title: 'Own Your Own Data',
description:
'Take control of your data privacy and ownership with our platform, ensuring full transparency and security.',
icon: KeyIcon,
color: '#2563EB',
blob: Blob1,
},
{
title: 'Cloud or Self-Hosting',
description:
'Choose between the flexibility of cloud-based hosting or the autonomy of self-hosting to tailor your analytics infrastructure to your needs.',
icon: CloudIcon,
color: '#ff7557',
blob: Blob2,
},
{
title: 'Real-Time Events',
description:
'Stay up-to-date with real-time event tracking, enabling instant insights into user actions as they happen.',
icon: ClockIcon,
color: '#7fe1d8',
blob: Blob3,
},
{
title: 'Deep Dive into User Behavior',
description:
"Gain profound insights into user behavior with comprehensive analytics tools, allowing you to understand your audience's actions and preferences.",
icon: UserRoundSearchIcon,
color: '#f8bc3c',
blob: Blob4,
},
{
title: 'Powerful Report Explorer',
description:
'Explore and analyze your data effortlessly with our powerful report explorer, simplifying the process of deriving meaningful insights.',
icon: CompassIcon,
color: '#b3596e',
blob: Blob5,
},
{
soon: 'Coming soon',
title: 'Funnels',
description:
'Track user conversion funnels seamlessly, providing valuable insights into user journey optimization.',
icon: ConeIcon,
color: '#72bef4',
blob: Blob6,
},
{
soon: 'Coming with our native app',
title: 'Push Notifications',
description:
'Stay informed about conversions, events, and peaks with our upcoming push notification tool, empowering you to monitor and respond to critical activities in real-time.',
icon: BellIcon,
color: '#ffb27a',
blob: Blob7,
},
{
title: 'Cost-Effective Alternative to Mixpanel',
description:
'Enjoy the same powerful analytics capabilities as Mixpanel at a fraction of the cost, ensuring affordability without compromising on quality.',
icon: DollarSignIcon,
color: '#0f7ea0',
blob: Blob8,
},
{
soon: 'Something Plausible lacks',
title: 'Great Support for React Native',
description:
'Benefit from robust support for React Native, ensuring seamless integration and compatibility for your projects, a feature notably lacking in other platforms like Plausible.',
icon: (({ className }: LucideProps) => {
return (
<img src="/react-native.svg" alt="React Native" className={className} />
);
}) as unknown as LucideIcon,
color: '#3ba974',
blob: Blob9,
},
];
interface SectionProps extends SectionItem {
reverse?: boolean;
}
export function Section({
title,
description,
icon: Icon,
blob: Blob,
color,
soon,
reverse,
}: SectionProps) {
return (
<div key={title} className={'border-b border-border'}>
<div className="w-full max-w-6xl mx-auto px-4">
<div className={cn('flex py-16', reverse && 'flex-row-reverse')}>
<div className="w-1/2 flex-shrink-0 justify-center items-center flex">
<div className="bg-slate-50 rounded-3xl">
<Blob
style={{ fill: color }}
className="w-[600px] opacity-20 transition-transform animate-[spin_60s_ease-in-out_infinite] -m-[100px]"
/>
</div>
<Icon className="w-40 h-40 absolute" strokeWidth={2} />
</div>
<div className="justify-center flex-col flex">
{!!soon && (
<div className="rounded-full border border-border p-2 px-4 leading-none mb-4 self-start">
{soon}
</div>
)}
<Heading2 className="mb-4">{title}</Heading2>
<Lead2>{description}</Lead2>
</div>
</div>
</div>
</div>
);
}
export function Sections() {
return (
<>
{sections.map((section, index) => (
<Section key={index} {...section} reverse={index % 2 === 1} />
))}
</>
);
}