continue re-design
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
import CurvyRect from "@/components/shared/layout/curvy-rect";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { ArrowUpRight } from "lucide-react";
|
||||
|
||||
interface Props {
|
||||
navigationItems: {
|
||||
label: string;
|
||||
items: {
|
||||
icon: React.ReactNode;
|
||||
label: string;
|
||||
description: string;
|
||||
href: string;
|
||||
target?: string;
|
||||
big?: boolean;
|
||||
ctas?: { label: string; href: string; target?: string }[];
|
||||
sectionLabel?: string;
|
||||
iconClassName?: string;
|
||||
}[];
|
||||
}[];
|
||||
sideLabel: string;
|
||||
sideContent: React.ReactNode;
|
||||
sideItem: {
|
||||
icon: React.ReactNode;
|
||||
label: string;
|
||||
description: string;
|
||||
href: string;
|
||||
target?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export default function HeaderDropdownContent({
|
||||
navigationItems,
|
||||
sideLabel,
|
||||
sideContent,
|
||||
sideItem,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="lg-max:max-w-[unset] container lg:flex gap-16">
|
||||
{navigationItems.map((item, index) => (
|
||||
<div className="flex-1" key={index}>
|
||||
<GroupLabel label={item.label} />
|
||||
|
||||
{/* Default section (items without sectionLabel) */}
|
||||
<div
|
||||
className={cn(
|
||||
"grid gap-x-16",
|
||||
navigationItems.length === 1 && "lg:grid-cols-2",
|
||||
)}
|
||||
>
|
||||
{item.items
|
||||
.filter((it) => !it.sectionLabel && !it.big)
|
||||
.map((it) => (
|
||||
<Item item={it} key={it.label} />
|
||||
))}
|
||||
{item.items
|
||||
.filter((it) => !it.sectionLabel && it.big)
|
||||
.map((it) => (
|
||||
<ItemBig item={it} key={it.label} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Additional sections within the same column */}
|
||||
{Array.from(
|
||||
new Set(
|
||||
item.items
|
||||
.map((it) => it.sectionLabel)
|
||||
.filter(Boolean) as string[],
|
||||
),
|
||||
).map((section) => (
|
||||
<div key={section}>
|
||||
{/* <GroupLabel label={section} /> */}
|
||||
<div
|
||||
className={cn(
|
||||
"grid gap-x-16",
|
||||
navigationItems.length === 1 && "lg:grid-cols-2",
|
||||
)}
|
||||
>
|
||||
{item.items
|
||||
.filter((it) => it.sectionLabel === section && !it.big)
|
||||
.map((it) => (
|
||||
<Item item={it} key={it.label} />
|
||||
))}
|
||||
{item.items
|
||||
.filter((it) => it.sectionLabel === section && it.big)
|
||||
.map((it) => (
|
||||
<ItemBig item={it} key={it.label} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="h-42 border-t border-border-faint border-x -mt-1 relative lg-max:hidden">
|
||||
<CurvyRect
|
||||
className="-top-1 absolute -left-1 w-[calc(100%+2px)]"
|
||||
top
|
||||
/>
|
||||
<CurvyRect
|
||||
className="bottom-full absolute -left-1 w-[calc(100%+2px)]"
|
||||
bottom
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="flex-1 max-w-360 relative">
|
||||
<div className="h-full w-1 absolute top-0 left-0 bg-border-faint" />
|
||||
<GroupLabel label={sideLabel} />
|
||||
|
||||
<div className="hidden lg:contents">{sideContent}</div>
|
||||
|
||||
<Item item={sideItem} />
|
||||
|
||||
<div className="h-42 border-t border-border-faint border-r -mt-1 relative lg-max:hidden">
|
||||
<CurvyRect
|
||||
className="-top-1 absolute left-0 w-[calc(100%+1px)]"
|
||||
top
|
||||
/>
|
||||
<CurvyRect
|
||||
className="bottom-full absolute left-0 w-[calc(100%+1px)]"
|
||||
bottom
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const GroupLabel = ({ label }: { label: string }) => {
|
||||
return (
|
||||
<div className="text-body-medium py-16 lg:py-20 lg:border-x border-b border-border-faint px-24 lg:px-44 text-black-alpha-64">
|
||||
{label}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Item = ({
|
||||
item,
|
||||
}: {
|
||||
item: {
|
||||
icon: React.ReactNode;
|
||||
label: string;
|
||||
description: string;
|
||||
href: string;
|
||||
target?: string;
|
||||
iconClassName?: string;
|
||||
};
|
||||
}) => {
|
||||
return (
|
||||
<a
|
||||
className="flex items-start gap-16 py-16 pl-24 lg-max:[&_svg]:size-24 lg:pl-44 group border-x hover:bg-black-alpha-2 border-b border-border-faint transition-all hover:text-heat-100"
|
||||
href={item.href}
|
||||
key={item.label}
|
||||
target={item.target}
|
||||
>
|
||||
<div className={item.iconClassName}>{item.icon}</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-label-medium">{item.label}</div>
|
||||
|
||||
<div className="text-body-medium mt-4 text-black-alpha-64 lg-max:hidden">
|
||||
{item.description}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
const ItemBig = ({
|
||||
item,
|
||||
}: {
|
||||
item: {
|
||||
icon: React.ReactNode;
|
||||
label: string;
|
||||
description: string;
|
||||
href: string;
|
||||
target?: string;
|
||||
ctas?: { label: string; href: string; target?: string }[];
|
||||
iconClassName?: string;
|
||||
};
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className="flex items-start gap-16 py-22 pl-24 lg-max:[&_svg]:size-24 lg:pl-44 group border-x border-b transition-colors border-border-faint"
|
||||
key={item.label}
|
||||
>
|
||||
<div className={item.iconClassName}>{item.icon}</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<a
|
||||
href={item.href}
|
||||
target={item.target}
|
||||
className="text-label-medium inline-block hover:text-heat-100 transition-colors"
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
|
||||
<div className="text-body-medium mt-4 text-black-alpha-64 lg-max:hidden">
|
||||
{item.description}
|
||||
</div>
|
||||
|
||||
{item.ctas && item.ctas.length > 0 && (
|
||||
<div className="mt-12 flex items-center gap-8 lg-max:hidden">
|
||||
{item.ctas.map((cta) => (
|
||||
<a
|
||||
key={cta.label}
|
||||
href={cta.href}
|
||||
target={cta.target}
|
||||
className="inline-flex items-center gap-6 px-12 py-6 rounded-6 text-label-small text-heat-100 bg-heat-4 hover:bg-heat-8 transition-colors whitespace-nowrap shrink-0"
|
||||
>
|
||||
<span>{cta.label}</span>
|
||||
<ArrowUpRight className="size-14" aria-hidden="true" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
import { ArrowUpRight } from "lucide-react";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
export interface NavItemRowProps {
|
||||
icon: React.ReactNode;
|
||||
label: string;
|
||||
description: string;
|
||||
href: string;
|
||||
target?: string;
|
||||
iconClassName?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function NavItemRow({
|
||||
icon,
|
||||
label,
|
||||
description,
|
||||
href,
|
||||
target,
|
||||
iconClassName,
|
||||
className,
|
||||
}: NavItemRowProps) {
|
||||
return (
|
||||
<a
|
||||
className={cn(
|
||||
"flex items-start gap-16 py-16 pl-24 lg-max:[&_svg]:size-24 lg:pl-44 group border-x hover:bg-black-alpha-2 border-b border-border-faint transition-all hover:text-heat-100",
|
||||
className,
|
||||
)}
|
||||
href={href}
|
||||
target={target}
|
||||
>
|
||||
<div className={iconClassName}>{icon}</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-label-medium">{label}</div>
|
||||
|
||||
<div className="text-body-medium mt-4 text-black-alpha-64 lg-max:hidden">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
export interface NavItemRowBigProps extends Omit<NavItemRowProps, "target"> {
|
||||
ctas?: { label: string; href: string; target?: string }[];
|
||||
}
|
||||
|
||||
export function NavItemRowBig({
|
||||
icon,
|
||||
label,
|
||||
description,
|
||||
href,
|
||||
iconClassName,
|
||||
ctas,
|
||||
}: NavItemRowBigProps) {
|
||||
return (
|
||||
<div className="flex items-start gap-16 py-22 pl-24 lg-max:[&_svg]:size-24 lg:pl-44 group border-x border-b transition-colors border-border-faint">
|
||||
<div className={iconClassName}>{icon}</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<a
|
||||
href={href}
|
||||
className="text-label-medium inline-block hover:text-heat-100 transition-colors"
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
|
||||
<div className="text-body-medium mt-4 text-black-alpha-64 lg-max:hidden">
|
||||
{description}
|
||||
</div>
|
||||
|
||||
{ctas && ctas.length > 0 && (
|
||||
<div className="mt-12 flex items-center gap-8 lg-max:hidden">
|
||||
{ctas.map((cta) => (
|
||||
<a
|
||||
key={cta.label}
|
||||
href={cta.href}
|
||||
target={cta.target}
|
||||
className="inline-flex items-center gap-6 px-12 py-6 rounded-6 text-label-small text-heat-100 bg-heat-4 hover:bg-heat-8 transition-colors whitespace-nowrap shrink-0"
|
||||
>
|
||||
<span>{cta.label}</span>
|
||||
<ArrowUpRight className="size-14" aria-hidden="true" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
"use client";
|
||||
|
||||
import { HTMLAttributes, useEffect, useRef } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
|
||||
import data from "./data.json";
|
||||
|
||||
export default function GithubFlame(attrs: HTMLAttributes<HTMLDivElement>) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let index = 0;
|
||||
|
||||
const interval = setIntervalOnVisible({
|
||||
element: wrapperRef.current,
|
||||
callback: () => {
|
||||
index++;
|
||||
if (index >= data.length) index = 0;
|
||||
|
||||
const newStr = data[index];
|
||||
|
||||
if (!ref.current) return;
|
||||
|
||||
ref.current!.innerHTML = newStr;
|
||||
},
|
||||
interval: 60,
|
||||
});
|
||||
|
||||
return () => interval?.();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="absolute -top-20 left-180 w-194 h-192"
|
||||
style={{
|
||||
maskImage: "url('/assets-original/github-mask.png')",
|
||||
maskSize: "100% 100%",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
{...attrs}
|
||||
className={cn(
|
||||
"w-308 h-380 -top-20 -left-40 absolute pointer-events-none select-none",
|
||||
attrs.className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="text-black-alpha-20 relative top-0 left-0 font-ascii fc-decoration"
|
||||
ref={ref}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: 8,
|
||||
lineHeight: "10px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
[
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ''.-_,.'' \n '.:;==+^_.' \n '-\";+;:,' \n ''''' \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ''' \n '-:\"\":,.' \n .:;+++;^:-' \n '-\"+===+;\"-' \n ',^+==++;:.' \n ',\"^^\":,.' \n ''''' \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n .::,'' \n '-\";;^\"\":,' \n '.:\";++;;;\"_-'' \n .:;+===++;\",' \n '_;+====+;:,'' \n '_;++=++;\",.' \n '-\"^^^\":_.'' \n '.--.''' \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '-::,' \n ':;+;^^\",.' \n .:\";+++;;^\":. \n '-\"^;+====+;\":-''' \n '-::;=====++;^:-'' \n ',\"+======+^:,-' \n '-:;+=====;\",.'' \n ._^;++=+;\"-'' \n '-::::,.''' \n ''-..'' \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '-_:_' \n -^;++++;;;. \n .\"+======+^:,_' \n .\";;+=====+;:__- \n -:_^+=====+;\"::,''' \n .-.\"+=======+^:__-.' \n '.._\"+======+\",-.'' \n '..,;======;_'''' \n '.._;+===++:.' \n '',::^\":.''' \n '''..'' \n ''' \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n -\"^++\". \n ';++=====+;^:- \n '\"+========+;;^' \n -;;;;++====+;\",,,. \n ':,__:;;;+===+^___-. \n '...-^;++++==+;::^:,' \n ''--,\"++=====;\"_,,-'' \n ''''_+++===++;-.,_-' \n '''.\";;+;^\"^_-''''' \n ''._;\"\":_--' \n ''._:_-' ' \n ''''''' \n ''' \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '-_,-' \n '':^+=====^' \n ':++========+;. \n ^+============+^;;- \n ,;;;;;+++====+^\";^: \n ';;^\":\";++++++;;:::_' \n ,,:_-,,\";^\"^;+=+;:::_-' \n '-.'''..,--,:,-_:;;+;^_ \n ''''--.-..'._:\";\"_.' \n '''..-,_-''.''..-.'' \n ''.-:,:_'''''''..' \n ' ''.,_,-'' \n '''--.' \n '..' \n ' \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '^+++\"::- \n ''':^;+=======^ \n '++=============+ \n -;;++===+======++^: \n .++++++++;;+++++++^\"\"\", \n '_\";;;;++;;^;;^;++;;;;;. \n ';;:_,_\"^\"_,_^++;;;;^:- \n \"\":,--:+;_-,,---,__\"^::.' \n '.-,.''..-.''''''''.-\";++^. \n ''''-----,.'''''',:\"\"^, \n '',--,-.'''''.-_,'' \n ''-.'''''''''' ' \n ''-.''' '' \n '.,' \n '.--' \n ''''' \n ' \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '''' \n '\"+====^;+\"- \n ''-+=============+' \n :+==========+=+====+- \n '+========++++++++==+ \n :^+++==++;;+;;+=====+;- \n '++++++++;^\"\"\";++;+;\"\"^\":- \n -^;;;;++;\"__:\";;^;;\":\";++: \n '.\"^;^:::\"\"::\":::\"\":::\";+:. \n .:\":_,,__:,--''--,___::;;:' \n -_,,-,,__--.'''''..._:;++;- \n ''-::::_::--....''-,:\"^;\" \n '''':^\":__----...-,::^- \n '''''--'''''.'-:-' \n '.' ''' \n '.-' \n '.-'' \n '..-.' \n '..'' \n '' \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n '-:_' \n '.' -;+++++:-\":' \n ,+===++==++++=====+- \n .:^+=========;+===+====' \n ';+=========++++;;++++==+- \n .;====++++++;;;;;+++++++. \n '-:;==++;^;;;;^;;+++==++=+ \n '+++++++;;;;^^\"^^^^^;++^\"^^_'' \n ,:;+;;;+;;\"_:::::\"\"::__::^;;+: \n .,:\"^;;^:,::_:,,_:\":_,__\"\";;- \n ,:\"\":_,___,-...---_,,___::;\"' \n .::_,,::::_-..,-.--,__,:^;+;' \n ''.,:\"\"\";:-,,---...,:^\";;;:' \n '-'\"^_\":_::_-----,,:\"^: \n ''''.....''.--,,-_: \n ''' '-_- \n ''''' \n '.-'' \n '.---.' \n '---' \n ''..' \n ' \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n '-,.' \n '..' ':++++++_ \n '+====+;+++++;+;+;;;^' \n +=====++=++=+;;++;+===+_ \n '\";=======++++++;;++=++===+' \n ,++=======++++;;;;;;+++++=+: \n '++==++++++++;;^;;;;+++++++^- \n '\"==+++;;;;^^\":::^;+++;;++;' \n -;;+++;;;^^^\":::::\"^+++++\"^\"::-,.' \n _++;;;^;;;;;\"::_:\"\"\"::_:\":___:\"^;^ \n -.,\"^^^^^\"::___::::__,--,,:::\"^\":' \n .-:\";\"::::_:::__,-,_,,-----_:_, \n .:\"^\"::_::::::::,,--,,,---,:^^- \n .,_::__,_\"\":\"^:--_,,,,_:\"^;;^' \n '--.-,_\"\"::__,_,,-,::\"\"\"\", \n '''------,___,-,:_\"\"' \n '' ''',,.''.' \n ''' \n .--'' \n '..--' \n '.--' \n .---. \n ''..' \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n '' \n ''' '-;;++;;\"' \n .^+++++::;;;;;;;;;+^.' \n ';======++++++;+;;;;;;;^\"' \n .+====+++++++++++;;;^;;++=+\"' \n -:+==++=+==+++;;;;^;;++++===+: \n ,;+====+++++++;;;;;;;;++++++++, \n ,+++++++++;++++;;;;;;;;++++;;\"' \n :+==++;;+;;;;^^^\"^;;;;;;;;;;^: \n ':+++;;;;;;^^\"\"::_::\";;;^,:_,-_,:,-' \n -;;;;;^^^;^\"\"\"::::___::^^:,,----,:^\":' \n ';;^:::::\"\":::::::::_,,_::-,,__:\"\"::-' \n '''-_:\"\"\"^\"::\"::__:::_-,,,,:----_:,' \n '.-:\"^^^^\":::_:\":\":___,_:_-,-,:_. \n ._:^\"\"\":,,__::::____-----_:_:^_ \n '''''.-.-::_,,--,---_::\"\"^^\"' \n ' ''---..-:::,____,,,_- \n '' '''''.'.--,- \n '' \n '.-.' \n ''.-' \n '..'' \n '.-..' \n ...-' \n ''''' \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n .^^^;\".'' \n '_^;^-''',:^;;;+;;;;;, \n '\"+==++++++;;^\"\"^;;;;;;;\". \n '+======+++++;;;;^;^\"^;^^;^_' \n \"+++===++++++++++;++\"\"^;^;;;++\" \n -\"+++++++++=++++;;;;;;^;++++++++: \n :;+===++++++++++;;;;;;;;;+++++++\"' \n .^+++++++;;+++;;^;;^;;;;;;++;;;;^. \n _+++++;;+;;;;;;;;^^^^^;;;;;;^:,. \n _++++;;;;;;;^^^\"\"::::\"\"::\"\"::,..-,,'' \n ,++;;^^^^^\":::::______:_-------..-:::- \n -^;;^::::::::\"\"\":_______,,---__,-_:::__' \n :^:,,_::::\"\"^^^:_:::__,__,,-,,__:__.'' \n '.,::\"\"^^\"::_::\":::__,::_,_:_,,-' \n '',:\"^^^:.--,::_____,,,__,_,,__- \n ''-,-.'''''',-----__,,____,_::- \n ''''''__---_,__:::- \n '''''''.-..-. \n ''' '''' \n '''' \n '''' \n ''''' \n ''''''' \n '''''' \n ''''' \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n .--.--' \n '''' ',\"^^;;;;:,-' \n ,;++;;\"\"..__\"\"\"\"^;;;^^^;\"' \n :+===++;;;;;;;\"\"\":::\"^^;^\"\"_' \n ';+====+++;;;++;;;^:::\"\"^^^^^\":' \n :++++++++++;;++++++^\";;\"^^^;;\"^;;\"' \n .;;+++++;;++++++;;;;;^^^^^^;;;;+++\"' \n ,\"+++=+++;;++++;;;;;;;;;\"\"^;++;+++;;' \n :;+++=++;;;;++;;;;^^;;;;;^;;;;;;;;-' \n -^;++;;+;;^^;;^^\"^^^^^;;;;;;;^\"::_- \n '^+++;;;;;;;^^^\"^;\"\":\":::\"::,--''''''' \n :++;^\"^^^\"\"\"\"\":::,,-,_,,------.'''.---. \n _;^\"::__:::::\"::,,,--------''------,,_, \n ':\"\":__,,:::\"::___:_,------..-,__,-,,,,-' \n '--..-_:::\"\":---_:::,-,_:,----,,--.'' \n ''-_:\"\"\"_''.__::,,,,,,,--.-.---' \n '-_\"_. '''''-_,---,-..--,,- \n '--.'..----,,-' \n '''''''''....' \n ''''' \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n '_:::\"^^\"_ \n '._-'' -\"\"\"\"\"^;;;:_-' \n '\"++;;^^\"\"\":_:\"^\"\"\":\"\"\"^^\"\"^:. \n -+===++;;;;;;;;^\"::::_:\"\"\"\"\"::-' \n ,+=====++;;;;;+;;^^::_:\"\"\"\"\"\"^^\":' \n '++==++=++;;;;+++;++;^_::::\"^^^^\":\":,- \n \"++++++;;;;;++++;;;;;:\"\":\"\"\"^^^^\";++\" \n ':++==+;;;;;++++;;;;;;\"\"^\"::^;+;^\";++_ \n _^++++=+;;;;++++;;;^^^^^^\"::\";;;;;;\"\"\"- \n -^+++++++;;^;+;;^^;^\"^^^^;^^^\"\":\"\":.' \n _;++;;;;;;;^^^\"\"\"\"\"^\"^^\"\"^^^\":_,-.'' \n ':++;;^\"\"^^\"\"::_______,---,,.'''..''''' \n .;;\"::::__:___,-,,--......''''...-.''''. \n '-___----_:::_-,_-,-..-....''.-......-.' \n '.__---,::::::,,_,-------.......''''.-.' \n '..-,_::::-'-__-.--,-...'''..'..' \n '.--_:' '.'''.--''''''''''..' \n '--.'''''''..'' \n '' ''''.'' \n \n \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n '''''''' \n ._::_:\"^^^, \n '...__.' ',_\":::\"\"^^^:,' \n '_+++;;;\"::__::\"^\"\"::____:\"\":::_' \n -;==++;;;;;;^;;^^^\"\":_,,_:::::,_,. \n .;+=+++;;;^;^;;^^^:::_,_::::::::\":- \n ^+++=++=+;^^^^^++;^;;^\",---:\"\"\"^\"\":_.' ' \n :;;++++;;;;^\"\"^;+;^;^^\":_,,,::\"\":__,:\"^:' \n -\"+++++;;;^\":\";;;^;;^;^::_:::\"^\"\"^-,\"^^' \n -;+;++++;^^;;;;;;;;^;^\":::.-\"^^\"\"_:^^^: \n -:;+;;;;;;^^^;;+;;\"^\"::::\":,-_\"^^^:\"_-,-' \n '_^;;;;;;;;\"\"^;;;^\"\"\":::\"\"\"\"::::____' \n ,;;;;;\"::^^^\"\":_:_:______::\"_-.'''' \n -;;^\":::::::_,----.'''''....'''''''' \n ,,--,,--,::,-,--..''''''''''' '''' ' \n ''.-...-_::,---..-.''..''''''' '''''' \n ''...--_--,-'-.''...''''' '''''' ''' \n '''''.'.. '.'''.''''' ''''''' \n ''''''' ''' \n '' ''''' \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n '.-,-'.,..' \n '-,::__:\"\"\"\"- \n '..-\":.' '_::::_::::::_.' \n .\";+;;;;;^\"\"\"::\"\"^^\"::_,-,:_:::_,-' \n -;+==+;;;;^^^^^^;^\":::_,-..-___,----' \n _;++;;;^^\"\"^\"\";^\"::,-.,-.--_:::,-__,' \n -\";;;;++;^^\"^\"\"\";;^:\"::__-'.,_::\"\":::. \n .;;;++++;;^^\":::^+;;^\"\"\"::,''---_::-,,..--.. \n -:\";;+;;^\"\"\"::_:\"^\"^^\":::,----,,_:,-.'.,_- \n ',;;;;;;;^^\"::::^^^^^^^\":_--,::::-,.'-::^. \n '_;;;;;^\"\":^;^\"^;;^^\"\"\"::,,._:::__--,__,' \n '-_^;;+;;\"::::^;;;;^\":_:___-..,,::_,,-''.' \n '-\"^;;;\"\"\"\"::\"\"^\"^\"\":_,__,,,_,-----. \n '_\":\"^\"::::\"\"\":,.-,-.'''..-,_.' '''' \n ''-:_--.--,_:-....'' ''''''' ' \n ''...''.-_,-.'''.''''''' \n '''...-.'''''''' \n ''''''' '''' \n '''' \n ' \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n '.,--.-_-.' \n ' '-_:__,_:::_,' \n ..._^\"-' ' .:;\"_,,,,_,---'' \n -\";++;;;;^^^^\":^^^;^\",-.-..---,__.'' \n \"+==++;;;;^\"\"^\"\"\"^^:_--.'''''.-,,-'''' \n ':;++;;^^^^^\"::_\"^^:,-..''.'''.___-.''-. \n ,^^^^^;;\"\"\"\":_:\"\"\"::,---..''-,,__::::.' \n ':^;;;;;;;\"::::::;+;;^\":\"__-'''..-,_--_,' \n ':\"\"^;;;^\":,_:_,_\"\":\"^\":_,--''.''''..'.' '..'' \n '.-:;+;^\"\":___,--_:\"^^\":::_.'-_-.--.'' '.,. \n ._\";;;;;\":::_:_::^^\"^\"\"\":-'._::,...' .,.,-' \n ',^;;+;\"_,_:\"\":\";;^\":::_-.'-,---..'''.''' \n '.-:\";+;^:-_,_:\"^;;^:_---..''''.--.'''''' \n '.-_\"\"\"::::___::_:\":_''...--.'''''' \n ',-.,_...-,__:,.''''' '''' \n '-.'''''..''''' \n ''''''''' ' \n '' \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" '.,--.'-.'' \n '' ''_:,..-,__'-' \n '..'::^_'''' '-_\"^-..''..''''' \n '^;+++;;^\"\"^\":-:\"^^\"\":-''''''''''''' \n ':+==++;+;;;^\"\"^\":::_-.''' '' ''.--' \n _+==+;\"^^^^^\"_,-,_:\"-..''' ' '-,,' \n ',:^\":\"\"::::::,,___:,-_,' '' '''---.-,,.-' \n ,^^::\"^;:____,_^;^\"\"::,,..''''''''...--' \n ::\"^\"^^\"\"_-.----,\":::\":__..'' '' '''''.' \n .,_,\";^^\"_-.'''..--_\"^:_,,-''''' '' ' '' \n '-^;+;;;\":-,_,--.,\"^:::::,''-,.'''' '' \n .-\";;;;\"_-,_____::;^\"::_'''.,.''''' '''''' \n '':^;;;\"::,___,_:;^:_--'''''''''' \n ''._:\"\"\"\":_,,,::\"^\":.''''''' '' \n '.----.--..---''._-' \n ''''''''''''' \n '' \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" '-' '.:,' ''''' ' \n ''',::,''''' '.-,. '' \n '\";;+;;^\":::_,,'-,,,,-.. \n .\"++++;;;;;::,,_:,,,.'''' \n _+==;^\"\":::::,..-_---''' '..' \n _^;;\":__-..--.'.'..--.''.' ''''.''' \n '.__-,_,-......'-_.'..'.''' ''' ''''' \n ..---_-__-''.''-::---.-,.' \n '--,,::::,''''''''.'.,_-..'' \n '''.\"^;;^:..'--.'''-::..--'''' \n .:\";+;;:----..'.._::_:-'''''' \n '.,:^^^^\":,,..-.--:\"_-.' '' \n '.-_:_,,:_-.--.-::-' \n '.-.'''''''.''--. \n '.'''' '.' \n '' \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" '-__.' '' ''''' ' \n _;+++;^\"_--.'''''''''''' \n _;++++;;;\"_,..'..-,''''''' \n ':++^\"\":-..'.'''.'.-''' ' \n :==+^:_-' ''' ''''''''' ' \n '_\"^_.-.' '''''' ''''' \n '''''''''''''''..''''''' \n ''''----''''''..''''''''' \n ''''-\"^\"\"_.''..''''''--'''' \n ':^;+;^-'.-.''''-,-...' \n -:;++;^::::-''''.-:_.' \n ''_:,,:,..__'''''':-' \n '''''''' '''.-' \n '.'''' '' \n ''' \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" ':;;+\"::' \n .;+++=;:,.''' '' \n ,:\"\"^\",'' ' '' \n ,\"=^:_--. '.' ' \n :++;:-'' '' \n '-:-' ' \n '' '''''''' \n ',\":,-..'.''' ' \n ._\"^\"_-'''-.-' '' \n ':;=++:.'.'.' ''''-' \n .\"+;;\"__,.-' ',. \n '''''' '' \n ''' \n '' \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" '_;^;=;'' \n '-,:^^,' \n '.'-_-' '' \n '-+_.' '' \n ,\"^^,' \n '.' ''' \n ..'''''''' \n ',,'' \n .._,,' \n ';=+;. ' ''' \n '''-,''' \n \n '' \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n "
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
import Image from "@/components/shared/image/Image";
|
||||
|
||||
import GithubFlame from "./Flame/Flame";
|
||||
|
||||
export default function HeaderDropdownGithub() {
|
||||
return (
|
||||
<div className="py-24 px-44 border-b border-border-faint relative overflow-clip">
|
||||
<div className="size-40 relative mb-17">
|
||||
<Image
|
||||
alt="Firecrawl icon (blueprint)"
|
||||
className="cw-80 ch-80 absolute top-0 left-0 max-w-[unset]"
|
||||
height={80}
|
||||
src="developer-os-icon"
|
||||
width={80}
|
||||
raw
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="text-label-large">
|
||||
Firecrawl is open source. <br />
|
||||
Star us to show your support!
|
||||
</div>
|
||||
|
||||
<GithubFlame />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
"use client";
|
||||
import { AnimatePresence, cubicBezier, motion } from "motion/react";
|
||||
import { useState } from "react";
|
||||
|
||||
import {
|
||||
ConnectorToLeft,
|
||||
ConnectorToRight,
|
||||
} from "@/components/shared/layout/curvy-rect";
|
||||
import { NAV_ITEMS } from "@/components/shared/header/Nav/Nav";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
export default function HeaderDropdownMobileItem({
|
||||
item,
|
||||
}: {
|
||||
item: (typeof NAV_ITEMS)[number];
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<a
|
||||
className="p-24 flex group relative"
|
||||
href={item.href}
|
||||
onClick={() => {
|
||||
setOpen((v) => !v);
|
||||
}}
|
||||
>
|
||||
<div className="h-1 bottom-0 absolute left-0 w-full bg-border-faint" />
|
||||
<ConnectorToRight className="-top-11 left-0" />
|
||||
<ConnectorToRight className="-bottom-10 left-0" />
|
||||
<ConnectorToLeft className="-top-11 right-0" />
|
||||
<ConnectorToLeft className="-bottom-10 right-0" />
|
||||
|
||||
<span className="px-4 flex-1 text-label-medium text-accent-black">
|
||||
{item.label}
|
||||
</span>
|
||||
|
||||
{item.dropdown && (
|
||||
<svg
|
||||
className={cn(
|
||||
"transition-all duration-200",
|
||||
open ? "rotate-180 text-accent-black" : "text-black-alpha-48",
|
||||
)}
|
||||
fill="none"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.4001 10.2L12.0001 13.8L15.6001 10.2"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</a>
|
||||
|
||||
<AnimatePresence>
|
||||
{open && (
|
||||
<motion.div
|
||||
animate={{ height: "auto", opacity: 1, filter: "blur(0px)" }}
|
||||
className="overflow-hidden"
|
||||
exit={{ height: 0, opacity: 0, filter: "blur(4px)" }}
|
||||
initial={{ height: 0, opacity: 0, filter: "blur(4px)" }}
|
||||
transition={{ duration: 0.3, ease: cubicBezier(0.4, 0, 0.2, 1) }}
|
||||
>
|
||||
{item.dropdown}
|
||||
|
||||
<div className="h-44 relative">
|
||||
<ConnectorToRight className="-top-11 left-0" />
|
||||
<ConnectorToRight className="-bottom-10 left-0" />
|
||||
<ConnectorToLeft className="-top-11 right-0" />
|
||||
<ConnectorToLeft className="-bottom-10 right-0" />
|
||||
<div className="h-1 bottom-0 absolute left-0 w-full bg-border-faint" />
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Fragment } from "react";
|
||||
|
||||
import Button from "@/components/ui/shadcn/button";
|
||||
import {
|
||||
ConnectorToBottom,
|
||||
ConnectorToLeft,
|
||||
ConnectorToRight,
|
||||
} from "@/components/shared/layout/curvy-rect";
|
||||
import HeaderGithubClient from "@/components/shared/header/Github/GithubClient";
|
||||
import { NAV_ITEMS } from "@/components/shared/header/Nav/Nav";
|
||||
|
||||
import HeaderDropdownMobileItem from "./Item/Item";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function HeaderDropdownMobile({
|
||||
ctaHref = "/signin/signup",
|
||||
ctaLabel = "Sign up",
|
||||
}: {
|
||||
ctaHref?: string;
|
||||
ctaLabel?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="container relative">
|
||||
<div className="overlay border-x pointer-events-none border-border-faint" />
|
||||
<ConnectorToBottom className="-top-1 -left-10" />
|
||||
<ConnectorToBottom className="-top-1 -right-10" />
|
||||
|
||||
<div>
|
||||
{NAV_ITEMS.map((item) => (
|
||||
<Fragment key={item.label}>
|
||||
<HeaderDropdownMobileItem item={item} />
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="p-24 flex flex-col gap-8 border-b border-border-faint relative -mt-1">
|
||||
<HeaderGithubClient />
|
||||
<Link href={ctaHref}>
|
||||
<Button variant="secondary"> {ctaLabel} </Button>
|
||||
</Link>
|
||||
|
||||
<ConnectorToRight className="left-0 -bottom-11" />
|
||||
<ConnectorToLeft className="right-0 -bottom-11" />
|
||||
</div>
|
||||
|
||||
<div className="h-36" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
"use client";
|
||||
|
||||
import { HTMLAttributes, useEffect, useRef } from "react";
|
||||
|
||||
import data from "@/components/app/(home)/sections/hero-flame/data.json";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
|
||||
export default function StoriesFlame(attrs: HTMLAttributes<HTMLDivElement>) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let index = 0;
|
||||
|
||||
const interval = setIntervalOnVisible({
|
||||
element: wrapperRef.current,
|
||||
callback: () => {
|
||||
index++;
|
||||
if (index >= data.length) index = 0;
|
||||
|
||||
const newStr = data[index];
|
||||
|
||||
if (!ref.current) return;
|
||||
|
||||
ref.current!.innerHTML = newStr;
|
||||
},
|
||||
interval: 60,
|
||||
});
|
||||
|
||||
return () => interval?.();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="absolute right-10 bottom-10 w-194 h-165"
|
||||
style={{
|
||||
maskImage: "url('/assets-original/replit-mask.png')",
|
||||
maskSize: "100% 100%",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
{...attrs}
|
||||
className={cn(
|
||||
"w-308 h-380 -top-20 -left-40 absolute pointer-events-none select-none",
|
||||
attrs.className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="text-black-alpha-20 relative top-0 left-0 font-ascii fc-decoration"
|
||||
ref={ref}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: 8,
|
||||
lineHeight: "10px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import ArrowUp from "./_svg/ArrowUp";
|
||||
import Replit from "./_svg/Replit";
|
||||
import StoriesFlame from "./Flame/Flame";
|
||||
|
||||
export default function HeaderDropdownStories() {
|
||||
return (
|
||||
<a
|
||||
className="pt-32 pr-32 pl-44 pb-48 group block border-b border-border-faint relative overflow-clip"
|
||||
href="/blog/how-replit-uses-firecrawl-to-power-ai-agents"
|
||||
>
|
||||
<div className="flex mb-40 justify-between items-center">
|
||||
<div className="py-4 px-8 text-heat-100 text-[12px]/[16px] font-[450] bg-heat-8 rounded-6">
|
||||
Customer story
|
||||
</div>
|
||||
|
||||
<div className="p-2 text-black-alpha-56 group-hover:text-heat-100 transition-all group-hover:translate-x-1 group-hover:translate-y-[-1px]">
|
||||
<ArrowUp />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Replit />
|
||||
|
||||
<div className="text-title-h5 mt-31 pr-32">
|
||||
How Replit uses <span className="text-heat-100">Firecrawl</span> to
|
||||
power Replit Agent
|
||||
</div>
|
||||
|
||||
<StoriesFlame />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function ArrowUp() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17.2083 14.7082V6.7915M17.2083 6.7915H9.29167M17.2083 6.7915L7 16.9998"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
export default function Replit() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
width="32"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M15.54 10.8196H5.27864C4.26819 10.8196 3.4668 10.0148 3.4668 9.03879V3.11427C3.4668 2.12115 4.28561 1.3335 5.27864 1.3335H13.7281C14.7386 1.3335 15.54 2.13827 15.54 3.11427V10.8196Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M26.5452 21.1531H15.5508V10.8047H26.5452C27.6091 10.8047 28.4864 11.6811 28.4864 12.7439V19.214C28.4864 20.2955 27.6091 21.1531 26.5452 21.1531Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M13.7281 30.6668H5.27864C4.28561 30.6668 3.4668 29.8635 3.4668 28.8892V22.9583C3.4668 21.9841 4.28561 21.1807 5.27864 21.1807H15.54V28.8892C15.54 29.8635 14.7212 30.6668 13.7281 30.6668Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// @ts-nocheck
|
||||
"use client";
|
||||
|
||||
import { AnimatePresence, cubicBezier, motion } from "motion/react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { Connector } from "@/components/shared/layout/curvy-rect";
|
||||
import { useHeaderContext } from "@/components/shared/header/HeaderContext";
|
||||
import { lockBody } from "@/components/shared/lockBody";
|
||||
import AnimatedHeight from "@/components/shared/layout/animated-height";
|
||||
export default function HeaderDropdownWrapper() {
|
||||
const {
|
||||
dropdownContent,
|
||||
resetDropdownTimeout,
|
||||
clearDropdown,
|
||||
dropdownKey,
|
||||
headerHeight,
|
||||
headerTop,
|
||||
} = useHeaderContext();
|
||||
|
||||
useEffect(() => {
|
||||
lockBody("header-dropdown", !!dropdownContent);
|
||||
}, [dropdownContent]);
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{dropdownContent && (
|
||||
<motion.div
|
||||
animate={{ opacity: 1 }}
|
||||
className="h-screen w-screen fixed left-0 z-[2000] bg-black-alpha-40"
|
||||
exit={{
|
||||
opacity: 0,
|
||||
transition: {
|
||||
duration: 0.3,
|
||||
delay: 0.1,
|
||||
ease: cubicBezier(0.4, 0, 0.2, 1),
|
||||
},
|
||||
}}
|
||||
initial={{ opacity: 0 }}
|
||||
style={{
|
||||
top: headerTop.current + headerHeight.current + 1,
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: cubicBezier(0.4, 0, 0.2, 1) }}
|
||||
>
|
||||
<div
|
||||
className="overlay"
|
||||
onClick={() => {
|
||||
if (window.innerWidth < 996) {
|
||||
clearDropdown(true);
|
||||
}
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
if (window.innerWidth > 996) {
|
||||
clearDropdown(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<AnimatedHeight
|
||||
animate={{
|
||||
transition: { duration: 0.5, ease: cubicBezier(0.4, 0, 0.2, 1) },
|
||||
}}
|
||||
className="overflow-clip relative"
|
||||
exit={{
|
||||
height: 0,
|
||||
transition: { duration: 0.3, ease: cubicBezier(0.4, 0, 0.2, 1) },
|
||||
}}
|
||||
initial={{ height: 0 }}
|
||||
>
|
||||
<AnimatePresence mode="popLayout">
|
||||
<motion.div
|
||||
className="bg-background-base hide-scrollbar relative overflow-x-clip overflow-y-auto"
|
||||
key={dropdownKey}
|
||||
style={{
|
||||
maxHeight: `calc(100vh - ${headerTop.current + headerHeight.current + 1}px)`,
|
||||
}}
|
||||
onMouseEnter={resetDropdownTimeout}
|
||||
onMouseLeave={() => {
|
||||
if (window.innerWidth < 996) return;
|
||||
clearDropdown();
|
||||
}}
|
||||
>
|
||||
<div className="cmw-[1112px] absolute h-full pointer-events-none top-0 border-x border-border-faint">
|
||||
<Connector className="absolute -left-[11.5px] -top-11" />
|
||||
<Connector className="absolute -right-[11.5px] -top-11" />
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0, pointerEvents: "none" }}
|
||||
initial={{ opacity: 0 }}
|
||||
transition={{
|
||||
duration: 0.3,
|
||||
ease: cubicBezier(0.4, 0, 0.2, 1),
|
||||
}}
|
||||
>
|
||||
{dropdownContent}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</AnimatedHeight>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user