Skip to content

Commit 473abd4

Browse files
committed
feat: implement website landing page
1 parent 10ffc31 commit 473abd4

8 files changed

Lines changed: 730 additions & 119 deletions

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { useEffect, useMemo, useState } from 'react'
2+
3+
interface Point {
4+
x: number
5+
y: number
6+
}
7+
8+
export function BackgroundAnimation() {
9+
const [points, setPoints] = useState<Point[]>(() =>
10+
Array(16)
11+
.fill(0)
12+
.map(() => ({
13+
x: Math.random(),
14+
y: Math.random(),
15+
})),
16+
)
17+
18+
const poly = useMemo(
19+
() => points.map(({ x, y }) => `${x * 100}% ${y * 100}%`).join(', '),
20+
[points],
21+
)
22+
23+
const jumpVal = (val: number) => {
24+
return Math.random() > 0.5 ? val + (Math.random() - 0.5) / 2 : Math.random()
25+
}
26+
27+
function jumpPoints() {
28+
setPoints((prevPoints) =>
29+
prevPoints.map((point) => ({
30+
x: jumpVal(point.x),
31+
y: jumpVal(point.y),
32+
})),
33+
)
34+
}
35+
36+
useEffect(() => {
37+
jumpPoints()
38+
const timeout = setTimeout(jumpPoints, 2000 + Math.random() * 1000)
39+
const interval = setInterval(jumpPoints, 3000 + Math.random() * 1000)
40+
41+
return () => {
42+
clearTimeout(timeout)
43+
clearInterval(interval)
44+
}
45+
}, [])
46+
47+
return (
48+
<div className="bg absolute inset-0 -z-10 blur-3xl overflow-hidden" aria-hidden="true">
49+
<div
50+
className="aspect-[1.7] h-full w-full bg-gradient-to-r from-primary/50 to-white/10 lg:opacity-20 lg:dark:opacity-40 xs:opacity-50"
51+
style={{
52+
clipPath: `polygon(${poly})`,
53+
transition: 'clip-path 3s',
54+
}}
55+
/>
56+
</div>
57+
)
58+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
import { Icon } from "@iconify/react";
3+
import { Button } from "@explainer/ui";
4+
5+
const title = "Ready to get started?";
6+
const description =
7+
"Start building your documentation in minutes. Free, open source, and yours to customize.";
8+
9+
const action = {
10+
label: "Read the docs",
11+
href: "/docs/documentation/getting-started/getting-started",
12+
};
13+
---
14+
15+
<div class="w-full max-w-6xl mx-auto px-5 py-16 sm:py-24 lg:py-32">
16+
<div
17+
class="relative overflow-hidden border rounded-2xl bg-primary/5 px-8 py-16 sm:px-16 sm:py-20 text-center"
18+
>
19+
<!-- Decorative circles -->
20+
<div class="absolute inset-0 pointer-events-none" aria-hidden="true">
21+
<div
22+
class="absolute -top-16 -left-16 w-56 h-56 rounded-full border-2 border-primary/10"
23+
>
24+
</div>
25+
26+
<div
27+
class="absolute -bottom-20 -right-20 w-64 h-64 rounded-full border-2 border-primary/10"
28+
>
29+
</div>
30+
<div
31+
class="absolute -bottom-12 -right-12 w-44 h-44 rounded-full border border-primary/[0.07]"
32+
>
33+
</div>
34+
35+
<div class="absolute top-8 right-1/4 size-2.5 rounded-full bg-primary/10">
36+
</div>
37+
<div
38+
class="absolute bottom-10 left-[30%] size-2 rounded-full bg-primary/[0.08]"
39+
>
40+
</div>
41+
</div>
42+
<h2 class="text-3xl font-semibold text-foreground sm:text-4xl">
43+
{title}
44+
</h2>
45+
<p class="mt-4 text-lg text-muted-foreground max-w-xl mx-auto text-balance">
46+
{description}
47+
</p>
48+
<div class="mt-8 flex justify-center">
49+
<Button size="lg" className="cursor-pointer" client:load>
50+
<a href={action.href} class="flex gap-2" rel="noopener noreferrer">
51+
{action.label}
52+
<Icon
53+
icon="mdi:arrow-right"
54+
aria-hidden="true"
55+
className="size-5"
56+
client:load
57+
/>
58+
</a>
59+
</Button>
60+
</div>
61+
</div>
62+
</div>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
import { Icon } from "@iconify/react";
3+
4+
const title = "Everything you need, out of the box";
5+
const description = "Explainer gives you the tools to focus on your content, not your tooling.";
6+
7+
const features = [
8+
{
9+
icon: "mdi:language-markdown",
10+
title: "Markdown & MDX",
11+
description:
12+
"Write content in Markdown or MDX with custom components, directives, and JSX support.",
13+
},
14+
{
15+
icon: "mdi:flash-outline",
16+
title: "Lightning fast",
17+
description:
18+
"Static site generation for instant page loads. Zero JavaScript shipped by default.",
19+
},
20+
{
21+
icon: "mdi:code-braces",
22+
title: "Rich code blocks",
23+
description:
24+
"Dual-theme syntax highlighting, line diffs, focus mode, and 60+ language icons.",
25+
},
26+
{
27+
icon: "mdi:magnify",
28+
title: "Built-in search",
29+
description:
30+
"Command palette search so your readers find any page instantly.",
31+
},
32+
{
33+
icon: "mdi:search-web",
34+
title: "SEO ready",
35+
description:
36+
"Auto-generated OG thumbnails, sitemap, robots.txt, and RSS feed.",
37+
},
38+
{
39+
icon: "mdi:theme-light-dark",
40+
title: "Dark mode",
41+
description:
42+
"Full light and dark theme support with system preference detection.",
43+
},
44+
];
45+
---
46+
47+
<div class="relative w-full py-16 sm:py-24 lg:py-32">
48+
<!-- Decorative circles -->
49+
<div
50+
class="absolute inset-0 -z-10 pointer-events-none overflow-hidden"
51+
aria-hidden="true"
52+
>
53+
<div
54+
class="absolute top-1/2 -left-24 w-72 h-72 rounded-full border-2 border-primary/[0.08] -translate-y-1/2"
55+
>
56+
<div
57+
class="absolute inset-0 m-auto w-52 h-52 rounded-full border border-primary/[0.06]"
58+
>
59+
</div>
60+
</div>
61+
62+
<div class="absolute top-16 left-[22%] size-2.5 rounded-full bg-primary/10">
63+
</div>
64+
<div
65+
class="absolute bottom-20 right-[18%] size-2 rounded-full bg-primary/[0.08]"
66+
>
67+
</div>
68+
<div
69+
class="absolute top-1/3 right-[10%] size-1.5 rounded-full bg-primary/[0.09]"
70+
>
71+
</div>
72+
</div>
73+
74+
<!-- Content -->
75+
<div class="relative w-full max-w-6xl mx-auto px-5">
76+
<div class="text-center mb-16">
77+
<p
78+
class="text-sm font-semibold text-primary uppercase tracking-wide mb-3"
79+
>
80+
Features
81+
</p>
82+
<h2 class="text-3xl font-semibold text-foreground sm:text-4xl">
83+
{title}
84+
</h2>
85+
<p
86+
class="mt-4 text-lg text-muted-foreground max-w-2xl mx-auto text-balance"
87+
>
88+
{description}
89+
</p>
90+
</div>
91+
92+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">
93+
{
94+
features.map((feature) => (
95+
<div class="bg-background relative">
96+
<div class="flex flex-col gap-4 border rounded-xl p-6 bg-primary/5 h-full">
97+
<div class="flex items-center justify-center size-11 rounded-lg bg-primary/10">
98+
<Icon
99+
icon={feature.icon}
100+
className="size-5 text-primary"
101+
client:load
102+
/>
103+
</div>
104+
<div>
105+
<h3 class="text-base font-semibold text-foreground">
106+
{feature.title}
107+
</h3>
108+
<p class="text-sm text-muted-foreground mt-1.5 leading-relaxed">
109+
{feature.description}
110+
</p>
111+
</div>
112+
</div>
113+
</div>
114+
))
115+
}
116+
</div>
117+
</div>
118+
</div>

0 commit comments

Comments
 (0)