public: improve headline on hero
This commit is contained in:
@@ -38,6 +38,7 @@
|
|||||||
"react-animate-height": "^3.2.3",
|
"react-animate-height": "^3.2.3",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
|
"react-type-animation": "^3.2.0",
|
||||||
"tailwind-merge": "^1.14.0",
|
"tailwind-merge": "^1.14.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
|
|||||||
46
apps/public/src/app/animated-text.tsx
Normal file
46
apps/public/src/app/animated-text.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import { TypeAnimation } from 'react-type-animation';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
className?: string;
|
||||||
|
texts: { text: string; color: string }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const AnimatedText = ({ texts }: Props) => {
|
||||||
|
const [currIndex, setCurrIndex] = useState(0);
|
||||||
|
const sequence = useMemo(() => {
|
||||||
|
return texts.reduce((acc, { text }, index) => {
|
||||||
|
return [
|
||||||
|
...acc,
|
||||||
|
() => setCurrIndex(index),
|
||||||
|
text,
|
||||||
|
index === 0 ? 3000 : 2000,
|
||||||
|
];
|
||||||
|
}, [] as any[]);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: texts[currIndex]?.color,
|
||||||
|
height: 60,
|
||||||
|
display: 'block',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TypeAnimation
|
||||||
|
cursor={false}
|
||||||
|
preRenderFirstString={true}
|
||||||
|
sequence={sequence}
|
||||||
|
wrapper="span"
|
||||||
|
repeat={Infinity}
|
||||||
|
omitDeletionAnimation
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AnimatedText;
|
||||||
@@ -2,6 +2,7 @@ import { ALink } from '@/components/ui/button';
|
|||||||
|
|
||||||
import { chQuery } from '@openpanel/db';
|
import { chQuery } from '@openpanel/db';
|
||||||
|
|
||||||
|
import AnimatedText from './animated-text';
|
||||||
import { Heading1, Lead2 } from './copy';
|
import { Heading1, Lead2 } from './copy';
|
||||||
|
|
||||||
function shortNumber(num: number) {
|
function shortNumber(num: number) {
|
||||||
@@ -31,7 +32,23 @@ export async function Hero() {
|
|||||||
<Heading1 className="mb-4 text-slate-950">
|
<Heading1 className="mb-4 text-slate-950">
|
||||||
An open-source
|
An open-source
|
||||||
<br />
|
<br />
|
||||||
alternative to Mixpanel
|
alternative to{' '}
|
||||||
|
<AnimatedText
|
||||||
|
texts={[
|
||||||
|
{
|
||||||
|
text: 'Mixpanel',
|
||||||
|
color: '#5028C0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Google Analytics',
|
||||||
|
color: '#FAAE17',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Plausible',
|
||||||
|
color: '#5850EC',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</Heading1>
|
</Heading1>
|
||||||
<Lead2 className="mb-12">
|
<Lead2 className="mb-12">
|
||||||
The power of Mixpanel, the ease of Plausible and nothing from Google
|
The power of Mixpanel, the ease of Plausible and nothing from Google
|
||||||
@@ -47,7 +64,7 @@ export async function Hero() {
|
|||||||
Get started
|
Get started
|
||||||
</ALink>
|
</ALink>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-8 flex gap-8">
|
<div className="mt-8 flex justify-center gap-8 md:justify-start">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm uppercase text-muted-foreground">
|
<div className="text-sm uppercase text-muted-foreground">
|
||||||
Collected events
|
Collected events
|
||||||
@@ -66,7 +83,7 @@ export async function Hero() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative mt-12 h-[max(90vh,650px)] w-full md:mt-24">
|
<div className="relative mt-12 h-[max(90vh,650px)] w-full md:mt-36">
|
||||||
<div className="absolute inset-0 flex rounded-2xl ring-8 ring-slate-300">
|
<div className="absolute inset-0 flex rounded-2xl ring-8 ring-slate-300">
|
||||||
<div className="absolute inset-0 w-full animate-pulse overflow-hidden rounded-2xl bg-slate-100" />
|
<div className="absolute inset-0 w-full animate-pulse overflow-hidden rounded-2xl bg-slate-100" />
|
||||||
<iframe
|
<iframe
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function Navbar({ darkText = false, className }: Props) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'fixed left-0 right-0 top-0 z-10 flex h-20 items-center border-b border-border bg-white',
|
'fixed left-0 right-0 top-0 z-10 z-50 flex h-20 items-center border-b border-border bg-white',
|
||||||
textColor,
|
textColor,
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -632,6 +632,9 @@ importers:
|
|||||||
react-syntax-highlighter:
|
react-syntax-highlighter:
|
||||||
specifier: ^15.5.0
|
specifier: ^15.5.0
|
||||||
version: 15.5.0(react@18.2.0)
|
version: 15.5.0(react@18.2.0)
|
||||||
|
react-type-animation:
|
||||||
|
specifier: ^3.2.0
|
||||||
|
version: 3.2.0(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0)
|
||||||
tailwind-merge:
|
tailwind-merge:
|
||||||
specifier: ^1.14.0
|
specifier: ^1.14.0
|
||||||
version: 1.14.0
|
version: 1.14.0
|
||||||
@@ -14959,6 +14962,7 @@ packages:
|
|||||||
|
|
||||||
/osenv@0.1.5:
|
/osenv@0.1.5:
|
||||||
resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==}
|
resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==}
|
||||||
|
deprecated: This package is no longer supported.
|
||||||
dependencies:
|
dependencies:
|
||||||
os-homedir: 1.0.2
|
os-homedir: 1.0.2
|
||||||
os-tmpdir: 1.0.2
|
os-tmpdir: 1.0.2
|
||||||
@@ -15995,6 +15999,18 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-type-animation@3.2.0(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-WXTe0i3rRNKjmggPvT5ntye1QBt0ATGbijeW6V3cQe2W0jaMABXXlPPEdtofnS9tM7wSRHchEvI9SUw+0kUohw==}
|
||||||
|
peerDependencies:
|
||||||
|
prop-types: ^15.5.4
|
||||||
|
react: '>= 15.0.0'
|
||||||
|
react-dom: '>= 15.0.0'
|
||||||
|
dependencies:
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-use-websocket@4.7.0(react-dom@18.2.0)(react@18.2.0):
|
/react-use-websocket@4.7.0(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-YjR62jB7vB94IZy5UPBGZSR3c0hxu796q9IuJ0vbNg7InJ7Z84NHOd/LHzVI5nAKtaGy1oqvf8EmjKxX+cNz4A==}
|
resolution: {integrity: sha512-YjR62jB7vB94IZy5UPBGZSR3c0hxu796q9IuJ0vbNg7InJ7Z84NHOd/LHzVI5nAKtaGy1oqvf8EmjKxX+cNz4A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user