v3
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
export enum Endpoint {
|
||||
Scrape = "scrape",
|
||||
Crawl = "crawl",
|
||||
Search = "search",
|
||||
Map = "map",
|
||||
Extract = "extract",
|
||||
}
|
||||
|
||||
export enum AgentModel {
|
||||
FIRE_1 = "FIRE-1",
|
||||
}
|
||||
|
||||
export enum FormatType {
|
||||
Markdown = "markdown",
|
||||
Summary = "summary",
|
||||
Json = "json",
|
||||
RawHtml = "rawHtml",
|
||||
Html = "html",
|
||||
Screenshot = "screenshot",
|
||||
ScreenshotFullPage = "screenshot@fullPage",
|
||||
Links = "links",
|
||||
}
|
||||
|
||||
export enum SearchFormatType {
|
||||
Web = "web",
|
||||
Images = "images",
|
||||
News = "news",
|
||||
}
|
||||
|
||||
type Prev = [never, 0, 1, 2, 3, 4, 5];
|
||||
|
||||
type Join<K, P> = K extends string | number
|
||||
? P extends string | number
|
||||
? `${K}.${P}`
|
||||
: never
|
||||
: never;
|
||||
|
||||
export type Paths<T, D extends number = 5> = [D] extends [never]
|
||||
? never
|
||||
: T extends object
|
||||
? {
|
||||
[K in keyof T]-?: K extends string | number
|
||||
? T[K] extends object
|
||||
? K | Join<K, Paths<T[K], Prev[D]>>
|
||||
: K
|
||||
: never;
|
||||
}[keyof T]
|
||||
: "";
|
||||
@@ -0,0 +1,394 @@
|
||||
"use client";
|
||||
|
||||
import { animate } from "framer-motion";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
interface AnimatedDotIconProps {
|
||||
active?: boolean;
|
||||
alwaysHeat?: boolean;
|
||||
triggerOnHover?: boolean;
|
||||
size?: number;
|
||||
className?: string;
|
||||
pattern?:
|
||||
| "usage"
|
||||
| "api-keys"
|
||||
| "settings"
|
||||
| "overview"
|
||||
| "team"
|
||||
| "billing"
|
||||
| "account-settings"
|
||||
| "admin"
|
||||
| "domain-checker"
|
||||
| "extract-playground"
|
||||
| "extract"
|
||||
| "logs"
|
||||
| "playground"
|
||||
| "teams";
|
||||
}
|
||||
|
||||
const initCanvas = (canvas: HTMLCanvasElement) => {
|
||||
const { width, height } = canvas.getBoundingClientRect();
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
|
||||
canvas.style.width = `${width}px`;
|
||||
canvas.style.height = `${height}px`;
|
||||
|
||||
const upscaleCanvas = () => {
|
||||
const scale = window.visualViewport?.scale || 1;
|
||||
const dpr = (window.devicePixelRatio || 1) * scale;
|
||||
|
||||
canvas.width = width * dpr;
|
||||
canvas.height = height * dpr;
|
||||
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
canvas.dispatchEvent(new Event("resize"));
|
||||
};
|
||||
|
||||
upscaleCanvas();
|
||||
|
||||
const handleResize = () => {
|
||||
setTimeout(upscaleCanvas, 500);
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
window.visualViewport?.addEventListener("resize", handleResize);
|
||||
|
||||
return ctx;
|
||||
};
|
||||
|
||||
// Pattern definitions for different pages
|
||||
const patterns = {
|
||||
usage: {
|
||||
grid: [
|
||||
[10, 11, 12, 14, 15, 16],
|
||||
[3, 7, 19, 23],
|
||||
[0, 2, 24, 26],
|
||||
[27, 28, 29, 31, 32, 33],
|
||||
],
|
||||
gridSize: 7,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
"api-keys": {
|
||||
grid: [[12], [10, 14], [8, 16], [6, 18], [4, 5, 19, 20]],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
settings: {
|
||||
grid: [
|
||||
[0, 1, 2, 3, 4],
|
||||
[5, 9],
|
||||
[10, 14],
|
||||
[15, 19],
|
||||
[20, 21, 22, 23, 24],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
overview: {
|
||||
grid: [
|
||||
[24],
|
||||
[16, 18, 30, 32],
|
||||
[8, 12, 36, 40],
|
||||
[0, 3, 6, 21, 27, 42, 45, 48],
|
||||
],
|
||||
gridSize: 7,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
team: {
|
||||
grid: [
|
||||
[6, 7, 8],
|
||||
[11, 12, 13],
|
||||
[16, 17, 18],
|
||||
[0, 4, 20, 24],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
teams: {
|
||||
grid: [
|
||||
[6, 7, 8],
|
||||
[11, 12, 13],
|
||||
[16, 17, 18],
|
||||
[0, 4, 20, 24],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
billing: {
|
||||
grid: [
|
||||
[0, 4],
|
||||
[5, 6, 8, 9],
|
||||
[10, 11, 13, 14],
|
||||
[15, 19],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
"account-settings": {
|
||||
grid: [
|
||||
[2, 7, 12, 17, 22],
|
||||
[5, 10, 15, 20],
|
||||
[8, 13, 18],
|
||||
[11, 16],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
admin: {
|
||||
grid: [
|
||||
[0, 1, 2, 3, 4],
|
||||
[5, 14],
|
||||
[10, 11, 12, 13],
|
||||
[15, 24],
|
||||
[20, 21, 22, 23, 24],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
"domain-checker": {
|
||||
grid: [
|
||||
[12, 13, 14],
|
||||
[7, 11, 15, 19],
|
||||
[2, 6, 20, 24],
|
||||
[0, 1, 25, 26],
|
||||
],
|
||||
gridSize: 6,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
"extract-playground": {
|
||||
grid: [
|
||||
[5, 10, 15, 20],
|
||||
[6, 11, 16, 21],
|
||||
[7, 12, 17, 22],
|
||||
[8, 13, 18, 23],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
extract: {
|
||||
grid: [[12], [7, 17], [2, 6, 18, 22], [0, 1, 3, 4, 20, 21, 23, 24]],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
logs: {
|
||||
grid: [
|
||||
[0, 5, 10, 15, 20],
|
||||
[1, 6, 11, 16, 21],
|
||||
[2, 7, 12, 17, 22],
|
||||
[3, 8, 13, 18, 23],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
playground: {
|
||||
grid: [
|
||||
[6, 8, 16, 18],
|
||||
[10, 11, 12, 13, 14],
|
||||
[5, 9, 15, 19],
|
||||
[0, 4, 20, 24],
|
||||
],
|
||||
gridSize: 5,
|
||||
cellSize: 2,
|
||||
spacing: 2,
|
||||
offset: 3,
|
||||
},
|
||||
};
|
||||
|
||||
export function AnimatedDotIcon({
|
||||
active = true,
|
||||
alwaysHeat = false,
|
||||
triggerOnHover = false,
|
||||
size = 20,
|
||||
className,
|
||||
pattern = "usage",
|
||||
}: AnimatedDotIconProps) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
const fnRefs = useRef<{
|
||||
activate: () => void;
|
||||
deactivate: () => void;
|
||||
}>({ activate: () => {}, deactivate: () => {} });
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
|
||||
const ctx = initCanvas(canvas);
|
||||
const config = patterns[pattern];
|
||||
|
||||
let isRunning = false;
|
||||
let isActive = false;
|
||||
|
||||
let activeGroup = 0;
|
||||
const rowAlphas = [0.2, 0.4, 1, 0.04];
|
||||
|
||||
const scaler = size / 20;
|
||||
|
||||
const render = () => {
|
||||
ctx.fillStyle = "#fa5d19";
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
for (const group of config.grid.slice(0, 4)) {
|
||||
const groupIndex = config.grid.indexOf(group);
|
||||
ctx.globalAlpha = rowAlphas[groupIndex];
|
||||
|
||||
for (const index of group) {
|
||||
ctx.fillRect(
|
||||
(config.offset + (index % config.gridSize) * config.spacing) *
|
||||
scaler,
|
||||
(config.offset +
|
||||
Math.floor(index / config.gridSize) * config.spacing) *
|
||||
scaler,
|
||||
config.cellSize * scaler,
|
||||
config.cellSize * scaler,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isRunning) {
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
};
|
||||
|
||||
const timeouts: number[] = [];
|
||||
let runCount = 0;
|
||||
|
||||
const cycle = () => {
|
||||
isRunning = true;
|
||||
activeGroup = (activeGroup + 1) % 5;
|
||||
|
||||
rowAlphas.forEach((alpha, index) => {
|
||||
let targetAlpha = alpha;
|
||||
|
||||
if (index === activeGroup) targetAlpha = 1;
|
||||
else if (index === (activeGroup + 1) % 4) targetAlpha = 0.12;
|
||||
else if (index === (activeGroup + 2) % 4) targetAlpha = 0.2;
|
||||
else if (index === (activeGroup + 3) % 4) targetAlpha = 0.4;
|
||||
|
||||
animate(alpha, targetAlpha, {
|
||||
duration: 0.05,
|
||||
onUpdate: (value) => {
|
||||
rowAlphas[index] = value;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
timeouts.forEach((timeout) => {
|
||||
window.clearTimeout(timeout);
|
||||
});
|
||||
|
||||
timeouts.push(
|
||||
window.setTimeout(() => {
|
||||
isRunning = false;
|
||||
}, 300),
|
||||
);
|
||||
|
||||
if (activeGroup === 3) runCount += 1;
|
||||
|
||||
if ((runCount === 2 || !isActive) && activeGroup === 2) return;
|
||||
|
||||
timeouts.push(
|
||||
window.setTimeout(() => {
|
||||
cycle();
|
||||
}, 50),
|
||||
);
|
||||
};
|
||||
|
||||
fnRefs.current = {
|
||||
activate: () => {
|
||||
if (isActive) return;
|
||||
|
||||
isActive = true;
|
||||
runCount = 0;
|
||||
cycle();
|
||||
render();
|
||||
},
|
||||
deactivate: () => {
|
||||
if (!isActive) return;
|
||||
isActive = false;
|
||||
},
|
||||
};
|
||||
|
||||
render();
|
||||
canvas.addEventListener("resize", render);
|
||||
|
||||
if (triggerOnHover) {
|
||||
const group = canvasRef.current!.closest(".group");
|
||||
|
||||
if (group) {
|
||||
group.addEventListener("mouseenter", fnRefs.current.activate);
|
||||
group.addEventListener("mouseleave", fnRefs.current.deactivate);
|
||||
|
||||
return () => {
|
||||
group.removeEventListener("mouseenter", fnRefs.current.activate);
|
||||
group.removeEventListener("mouseleave", fnRefs.current.deactivate);
|
||||
};
|
||||
}
|
||||
}
|
||||
}, [triggerOnHover, size, pattern]);
|
||||
|
||||
useEffect(() => {
|
||||
if (triggerOnHover) return;
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting && active) {
|
||||
fnRefs.current.activate();
|
||||
} else {
|
||||
fnRefs.current.deactivate();
|
||||
}
|
||||
},
|
||||
{ threshold: 0.5 },
|
||||
);
|
||||
|
||||
observer.observe(canvasRef.current!);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [active, triggerOnHover]);
|
||||
|
||||
return (
|
||||
<canvas
|
||||
className={cn(
|
||||
alwaysHeat
|
||||
? ""
|
||||
: [
|
||||
"[&.grayscale]:opacity-60 transition-[filter,opacity]",
|
||||
!active && "grayscale",
|
||||
],
|
||||
className,
|
||||
)}
|
||||
ref={canvasRef}
|
||||
style={{ width: size, height: size }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
"use client";
|
||||
|
||||
import React, { useRef, useEffect, ReactNode, useState } from "react";
|
||||
|
||||
// Smoothly animates its container to match the natural height of its content.
|
||||
// Fixes previous behavior where the component observed itself, causing height 0
|
||||
// with overflow hidden (content clipped) or visible overflow that overlapped
|
||||
// following sections like the footer.
|
||||
export default function AnimatedHeight({
|
||||
children,
|
||||
overflow = true,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
overflow?: boolean;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const [measuredHeight, setMeasuredHeight] = useState<number | null>(null);
|
||||
const hasAnimatedOnceRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const contentEl = contentRef.current;
|
||||
const containerEl = containerRef.current;
|
||||
if (!contentEl || !containerEl) return;
|
||||
|
||||
const updateHeight = () => {
|
||||
// Use scrollHeight to capture full natural height, including overflowed content
|
||||
const height = contentEl.scrollHeight;
|
||||
setMeasuredHeight((prev) => (prev === height ? prev : height));
|
||||
|
||||
// Enable transition after the first measurement to avoid initial jank
|
||||
if (!hasAnimatedOnceRef.current) {
|
||||
containerEl.style.transition = "height 300ms ease-in-out";
|
||||
hasAnimatedOnceRef.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Initial measure
|
||||
updateHeight();
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => updateHeight());
|
||||
resizeObserver.observe(contentEl);
|
||||
|
||||
return () => resizeObserver.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
style={{
|
||||
overflow: overflow ? "hidden" : "visible",
|
||||
height: measuredHeight === null ? undefined : `${measuredHeight}px`,
|
||||
}}
|
||||
>
|
||||
<div ref={contentRef}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
const asciiPatterns = [
|
||||
`· · · · · · · · · · · · · · · · · · · ·
|
||||
· · · · · · · · · · · · · · · · · · ·
|
||||
· · · · · · · · · · · · · · · · · · · ·
|
||||
· · · · · · · · · · · · · · · · · · ·
|
||||
· · · · · · · · · · · · · · · · · · · ·`,
|
||||
`· · · · · · · · · · · · · · · · · · · ·
|
||||
· · · · ▪ · · · · · · · · ▪ · · · · ·
|
||||
· · · · · · · · · · · · · · · · · · · ·
|
||||
· · · · · · · · · · · · · · · · · · ·
|
||||
· · · · ▪ · · · · · · · · ▪ · · · · · ·`,
|
||||
`· · · · · · · · · · · · · · · · · · · ·
|
||||
· · · ▪ ▄ ▪ · · · · · · ▪ ▄ ▪ · · · ·
|
||||
· · · · ▪ · · · · · · · · ▪ · · · · · ·
|
||||
· · · · · · · · · · · · · · · · · · ·
|
||||
· · · ▪ ▄ ▪ · · · · · · ▪ ▄ ▪ · · · · ·`,
|
||||
`· · · · · · · · · · · · · · · · · · · ·
|
||||
· · ▪ ▄ █ ▄ ▪ · · · · ▪ ▄ █ ▄ ▪ · · ·
|
||||
· · · ▪ ▄ ▪ · · · · · · ▪ ▄ ▪ · · · · ·
|
||||
· · · ▪ · · · · · · · · · ▪ · · · · ·
|
||||
· · ▪ ▄ █ ▄ ▪ · · · · ▪ ▄ █ ▄ ▪ · · · ·`,
|
||||
];
|
||||
|
||||
interface AsciiBackgroundProps {
|
||||
className?: string;
|
||||
variant?: "dots" | "grid" | "flame";
|
||||
}
|
||||
|
||||
export function AsciiBackground({
|
||||
className,
|
||||
variant = "dots",
|
||||
}: AsciiBackgroundProps) {
|
||||
const [frameIndex, setFrameIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setFrameIndex((prev) => (prev + 1) % asciiPatterns.length);
|
||||
}, 2000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute inset-0 pointer-events-none select-none overflow-hidden",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<pre className="text-heat-100/3 font-mono text-[10px] leading-tight whitespace-pre absolute top-0 left-0 w-full h-full flex items-center justify-center">
|
||||
{asciiPatterns[frameIndex]}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
import data from "@/components/shared/effects/flame/explosion-data.json";
|
||||
|
||||
interface AsciiFlameBackgroundProps {
|
||||
className?: string;
|
||||
colorClassName?: string;
|
||||
fontSizePx?: number;
|
||||
lineHeightPx?: number;
|
||||
}
|
||||
|
||||
// Reusable ASCII flame background (same frames used by CoreReliableBarFlame)
|
||||
export default function AsciiFlameBackground({
|
||||
className,
|
||||
colorClassName = "text-heat-100/30",
|
||||
fontSizePx = 10,
|
||||
lineHeightPx = 12.5,
|
||||
}: AsciiFlameBackgroundProps) {
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let index = 0;
|
||||
const stop = setIntervalOnVisible({
|
||||
element: wrapperRef.current,
|
||||
callback: () => {
|
||||
index += 1;
|
||||
if (index >= (data as string[]).length) index = 0;
|
||||
if (ref.current) ref.current.innerHTML = (data as string[])[index];
|
||||
},
|
||||
interval: 80,
|
||||
});
|
||||
|
||||
return () => stop?.();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className={cn("relative pointer-events-none select-none", className)}
|
||||
>
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"font-ascii absolute inset-0 fc-decoration",
|
||||
colorClassName,
|
||||
)}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: `${fontSizePx}px`,
|
||||
lineHeight: `${lineHeightPx}px`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
.button {
|
||||
transition: all 0.2s cubic-bezier(0.25, 0.1, 0.25, 1),
|
||||
scale 0.1s cubic-bezier(0.25, 0.1, 0.25, 1),
|
||||
box-shadow 0.1s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
||||
|
||||
.button:active {
|
||||
transition: all 0.2s cubic-bezier(0.25, 0.1, 0.25, 1),
|
||||
scale 0.05s cubic-bezier(0.25, 0.1, 0.25, 1),
|
||||
box-shadow 0.05s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
background: #ff4c00;
|
||||
background: color(display-p3 0.9816 0.3634 0.0984);
|
||||
|
||||
box-shadow: 0px -6px 12px 0px rgba(255, 0, 0, 0.2) inset,
|
||||
0px 2px 4px 0px rgba(255, 77, 0, 0.12),
|
||||
0px 1px 1px 0px rgba(255, 77, 0, 0.12),
|
||||
0px 0.5px 0.5px 0px rgba(255, 77, 0, 0.16),
|
||||
0px 0.25px 0.25px 0px rgba(255, 77, 0, 0.2);
|
||||
|
||||
box-shadow: 0px -6px 12px 0px color(display-p3 0.9804 0.1127 0.098 / 0.2) inset,
|
||||
0px 2px 4px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
||||
0px 1px 1px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
||||
0px 0.5px 0.5px 0px color(display-p3 0.9804 0.3647 0.098 / 0.16),
|
||||
0px 0.25px 0.25px 0px color(display-p3 0.9804 0.3647 0.098 / 0.2);
|
||||
}
|
||||
|
||||
.button-primary:hover {
|
||||
box-shadow: 0px -6px 12px 0px rgba(255, 0, 0, 0.2) inset,
|
||||
0px 4px 8px 0px rgba(255, 77, 0, 0.16),
|
||||
0px 1px 1px 0px rgba(255, 77, 0, 0.12),
|
||||
0px 0.5px 0.5px 0px rgba(255, 77, 0, 0.16),
|
||||
0px 0.25px 0.25px 0px rgba(255, 77, 0, 0.2);
|
||||
box-shadow: 0px -6px 12px 0px color(display-p3 0.9804 0.1127 0.098 / 0.2) inset,
|
||||
0px 4px 8px 0px color(display-p3 0.9804 0.3647 0.098 / 0.16),
|
||||
0px 1px 1px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
||||
0px 0.5px 0.5px 0px color(display-p3 0.9804 0.3647 0.098 / 0.16),
|
||||
0px 0.25px 0.25px 0px color(display-p3 0.9804 0.3647 0.098 / 0.2);
|
||||
}
|
||||
|
||||
.button-primary:active {
|
||||
box-shadow: 0px -6px 12px 0px rgba(255, 0, 0, 0.2) inset,
|
||||
0px 2px 4px 0px rgba(255, 77, 0, 0.12),
|
||||
0px 1px 1px 0px rgba(255, 77, 0, 0.12),
|
||||
0px 0.5px 0.5px 0px rgba(255, 77, 0, 0.16),
|
||||
0px 0.25px 0.25px 0px rgba(255, 77, 0, 0.2);
|
||||
box-shadow: 0px -6px 12px 0px color(display-p3 0.9804 0.1127 0.098 / 0.2) inset,
|
||||
0px 2px 4px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
||||
0px 1px 1px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
||||
0px 0.5px 0.5px 0px color(display-p3 0.9804 0.3647 0.098 / 0.16),
|
||||
0px 0.25px 0.25px 0px color(display-p3 0.9804 0.3647 0.098 / 0.2);
|
||||
}
|
||||
|
||||
.button-background {
|
||||
background: linear-gradient(to bottom, white, transparent);
|
||||
|
||||
opacity: 0.06;
|
||||
|
||||
transition: opacity 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
||||
|
||||
.button:hover .button-background {
|
||||
opacity: 0.08;
|
||||
}
|
||||
|
||||
.button:active .button-background {
|
||||
opacity: 0;
|
||||
|
||||
transition: opacity 0.05s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Children, ButtonHTMLAttributes } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: "primary" | "secondary" | "tertiary" | "playground" | "destructive";
|
||||
size?: "default" | "large";
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export default function Button({
|
||||
variant = "primary",
|
||||
size = "default",
|
||||
disabled,
|
||||
...attrs
|
||||
}: Props) {
|
||||
const children = handleChildren(attrs.children);
|
||||
|
||||
return (
|
||||
<button
|
||||
{...attrs}
|
||||
type={attrs.type ?? "button"}
|
||||
className={cn(
|
||||
attrs.className,
|
||||
"[&>span]:px-6 flex items-center justify-center button relative [&>*]:relative",
|
||||
"text-label-medium lg-max:[&_svg]:size-24",
|
||||
`button-${variant} group/button`,
|
||||
{
|
||||
"rounded-8 p-6": size === "default",
|
||||
"rounded-10 p-8 gap-2": size === "large",
|
||||
|
||||
"text-accent-white active:[scale:0.995]": variant === "primary",
|
||||
"text-accent-black active:[scale:0.99] active:bg-black-alpha-7": [
|
||||
"secondary",
|
||||
"tertiary",
|
||||
"playground",
|
||||
].includes(variant),
|
||||
"bg-black-alpha-4 hover:bg-black-alpha-6": variant === "secondary",
|
||||
"hover:bg-black-alpha-4": variant === "tertiary",
|
||||
},
|
||||
variant === "playground" && [
|
||||
"inside-border before:border-black-alpha-4",
|
||||
disabled
|
||||
? "before:opacity-0 bg-black-alpha-4 text-black-alpha-24"
|
||||
: "hover:bg-black-alpha-4 hover:before:opacity-0 active:before:opacity-0",
|
||||
],
|
||||
)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{variant === "primary" && (
|
||||
<div className="overlay button-background !absolute" />
|
||||
)}
|
||||
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
const handleChildren = (children: React.ReactNode) => {
|
||||
return Children.toArray(children).map((child) => {
|
||||
if (typeof child === "string") {
|
||||
return <span key={child}>{child}</span>;
|
||||
}
|
||||
|
||||
return child;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { LucideIcon } from "lucide-react";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import AnimatedWidth from "@/components/shared/layout/animated-width";
|
||||
|
||||
interface CapsuleButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
icon?: LucideIcon | React.ComponentType<{ className?: string }>;
|
||||
iconPosition?: "left" | "right";
|
||||
children: React.ReactNode;
|
||||
size?: "sm" | "md" | "lg";
|
||||
fullWidth?: boolean;
|
||||
variant?: "primary" | "secondary" | "tertiary" | "ghost";
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
export function CapsuleButton({
|
||||
icon: Icon,
|
||||
iconPosition = "left",
|
||||
children,
|
||||
className,
|
||||
size = "md",
|
||||
fullWidth = false,
|
||||
variant = "primary",
|
||||
loading = false,
|
||||
disabled,
|
||||
...props
|
||||
}: CapsuleButtonProps) {
|
||||
const [isPressed, setIsPressed] = React.useState(false);
|
||||
|
||||
const sizeClasses = {
|
||||
sm: "h-32 px-16 text-label-small gap-6",
|
||||
md: "h-40 px-20 text-label-medium gap-8",
|
||||
lg: "h-40 px-20 text-label-medium gap-8",
|
||||
};
|
||||
|
||||
const iconSizes = {
|
||||
sm: "w-14 h-14",
|
||||
md: "w-16 h-16",
|
||||
lg: "w-16 h-16",
|
||||
};
|
||||
|
||||
const variants = {
|
||||
primary: [
|
||||
"bg-heat-100 text-white",
|
||||
"hover:bg-heat-200",
|
||||
"active:scale-[0.98]",
|
||||
"shadow-[0_1px_2px_rgba(0,0,0,0.05)]",
|
||||
"hover:shadow-[0_4px_12px_rgba(250,93,25,0.25)]",
|
||||
],
|
||||
secondary: [
|
||||
"bg-black text-white",
|
||||
"hover:bg-black/90",
|
||||
"active:scale-[0.98]",
|
||||
"shadow-[0_1px_2px_rgba(0,0,0,0.05)]",
|
||||
"hover:shadow-[0_4px_12px_rgba(0,0,0,0.15)]",
|
||||
],
|
||||
tertiary: [
|
||||
"bg-white text-black border border-black-alpha-8",
|
||||
"hover:bg-black-alpha-4 hover:border-black-alpha-12",
|
||||
"active:scale-[0.98]",
|
||||
],
|
||||
ghost: [
|
||||
"bg-transparent text-black-alpha-60",
|
||||
"hover:text-black hover:bg-black-alpha-4",
|
||||
"active:scale-[0.98]",
|
||||
],
|
||||
};
|
||||
|
||||
const isDisabled = disabled || loading;
|
||||
|
||||
return (
|
||||
<button
|
||||
className={cn(
|
||||
// Base styles
|
||||
"inline-flex items-center justify-center rounded-full transition-all duration-200",
|
||||
// Size
|
||||
sizeClasses[size],
|
||||
// Variant
|
||||
variants[variant],
|
||||
// Full width
|
||||
fullWidth && "w-full",
|
||||
// Disabled state
|
||||
isDisabled && [
|
||||
"opacity-50 cursor-not-allowed",
|
||||
"hover:shadow-none hover:bg-current",
|
||||
],
|
||||
// Pressed state
|
||||
isPressed && "scale-[0.98]",
|
||||
className,
|
||||
)}
|
||||
disabled={isDisabled}
|
||||
onMouseDown={() => !isDisabled && setIsPressed(true)}
|
||||
onMouseUp={() => setIsPressed(false)}
|
||||
onMouseLeave={() => setIsPressed(false)}
|
||||
{...props}
|
||||
>
|
||||
<AnimatedWidth initial={{ width: "auto" }}>
|
||||
<AnimatePresence initial={false} mode="popLayout">
|
||||
{loading ? (
|
||||
<motion.div
|
||||
key="loading"
|
||||
animate={{ opacity: 1, filter: "blur(0px)", scale: 1 }}
|
||||
className="flex gap-8 items-center justify-center"
|
||||
exit={{ opacity: 0, filter: "blur(2px)", scale: 0.9 }}
|
||||
initial={{ opacity: 0, filter: "blur(2px)", scale: 0.95 }}
|
||||
>
|
||||
<span>Loading...</span>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key="content"
|
||||
animate={{ opacity: 1, filter: "blur(0px)", scale: 1 }}
|
||||
className="flex gap-8 items-center justify-center"
|
||||
exit={{ opacity: 0, filter: "blur(2px)", scale: 0.9 }}
|
||||
initial={{ opacity: 0, filter: "blur(2px)", scale: 0.95 }}
|
||||
>
|
||||
{Icon && iconPosition === "left" && (
|
||||
<span
|
||||
className={cn(
|
||||
iconSizes[size],
|
||||
"flex-shrink-0 inline-flex items-center justify-center",
|
||||
)}
|
||||
>
|
||||
<Icon className="w-full h-full" />
|
||||
</span>
|
||||
)}
|
||||
<span>{children}</span>
|
||||
{Icon && iconPosition === "right" && (
|
||||
<span
|
||||
className={cn(
|
||||
iconSizes[size],
|
||||
"flex-shrink-0 inline-flex items-center justify-center",
|
||||
)}
|
||||
>
|
||||
<Icon className="w-full h-full" />
|
||||
</span>
|
||||
)}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</AnimatedWidth>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import Link from "next/link";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
interface FireActionLinkProps {
|
||||
href?: string;
|
||||
label: string;
|
||||
className?: string;
|
||||
variant?: "link" | "button";
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export function FireActionLink({
|
||||
href,
|
||||
label,
|
||||
className,
|
||||
variant = "link",
|
||||
onClick,
|
||||
}: FireActionLinkProps) {
|
||||
const baseClasses =
|
||||
variant === "button"
|
||||
? cn(
|
||||
"inline-block py-4 px-8 rounded-6",
|
||||
"text-label-small text-heat-100 bg-heat-4",
|
||||
"hover:bg-heat-8 transition-all",
|
||||
"active:scale-[0.98]",
|
||||
className,
|
||||
)
|
||||
: cn(
|
||||
"text-label-small text-secondary hover:text-heat-100 transition-all",
|
||||
"hover:underline underline-offset-4",
|
||||
"active:scale-[0.98]",
|
||||
className,
|
||||
);
|
||||
|
||||
if (onClick) {
|
||||
return (
|
||||
<button onClick={onClick} className={baseClasses}>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={href || "#"} className={baseClasses}>
|
||||
{label}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// Button Components
|
||||
export { SlateButton } from "./slate-button";
|
||||
// export { HeatButton } from "./heat-button";
|
||||
export { FireActionLink } from "./fire-action-link";
|
||||
@@ -0,0 +1,120 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { LucideIcon } from "lucide-react";
|
||||
|
||||
interface SlateButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
icon?:
|
||||
| LucideIcon
|
||||
| React.ComponentType<{
|
||||
className?: string;
|
||||
isHovered?: boolean;
|
||||
isOpen?: boolean;
|
||||
}>
|
||||
| React.ReactNode;
|
||||
iconPosition?: "left" | "right";
|
||||
children: React.ReactNode;
|
||||
size?: "sm" | "md" | "lg";
|
||||
fullWidth?: boolean;
|
||||
isLoading?: boolean;
|
||||
isOpen?: boolean;
|
||||
}
|
||||
|
||||
export const SlateButton = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
SlateButtonProps
|
||||
>(
|
||||
(
|
||||
{
|
||||
icon: Icon,
|
||||
iconPosition = "left",
|
||||
children,
|
||||
className,
|
||||
size = "md",
|
||||
fullWidth = false,
|
||||
isLoading = false,
|
||||
isOpen = false,
|
||||
disabled,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const [isHovered, setIsHovered] = React.useState(false);
|
||||
|
||||
const sizeClasses = {
|
||||
sm: "h-32 px-12 text-body-small gap-6",
|
||||
md: "h-40 px-16 text-body-medium gap-8",
|
||||
lg: "h-48 px-24 text-body-large gap-10",
|
||||
};
|
||||
|
||||
const iconSizes = {
|
||||
sm: "w-14 h-14",
|
||||
md: "w-16 h-16",
|
||||
lg: "w-20 h-20",
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
className={cn(
|
||||
// Base styles
|
||||
"inline-flex items-center justify-center rounded-12 transition-all",
|
||||
// Colors
|
||||
"bg-black-alpha-4 text-accent-black",
|
||||
"hover:bg-black-alpha-6",
|
||||
"active:scale-[0.98]",
|
||||
// Border
|
||||
// "border-0",
|
||||
// Size
|
||||
sizeClasses[size],
|
||||
// States
|
||||
disabled && "opacity-50 cursor-not-allowed",
|
||||
isLoading && "cursor-wait",
|
||||
// Full width
|
||||
fullWidth && "w-full",
|
||||
className,
|
||||
)}
|
||||
disabled={disabled || isLoading}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
{...props}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className={cn("animate-spin rounded-full", iconSizes[size])} />
|
||||
) : (
|
||||
<>
|
||||
{Icon &&
|
||||
iconPosition === "left" &&
|
||||
(React.isValidElement(Icon) ? (
|
||||
Icon
|
||||
) : (
|
||||
//@ts-expect-error - Icon component type allows JSX element
|
||||
<Icon
|
||||
className={cn(iconSizes[size], "flex-shrink-0")}
|
||||
isHovered={isHovered}
|
||||
isOpen={isOpen}
|
||||
/>
|
||||
))}
|
||||
{children}
|
||||
{Icon &&
|
||||
iconPosition === "right" &&
|
||||
(React.isValidElement(Icon) ? (
|
||||
Icon
|
||||
) : (
|
||||
//@ts-expect-error - Icon component type allows JSX element
|
||||
<Icon
|
||||
className={cn(iconSizes[size], "flex-shrink-0")}
|
||||
isHovered={isHovered}
|
||||
isOpen={isOpen}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
SlateButton.displayName = "SlateButton";
|
||||
@@ -0,0 +1,31 @@
|
||||
import colors from "@/styles/colors.json";
|
||||
|
||||
const TYPED_COLORS = colors as unknown as Record<
|
||||
string,
|
||||
Record<"hex" | "p3", string>
|
||||
>;
|
||||
|
||||
const hslValues = Object.entries(TYPED_COLORS).map(([key, value]) => {
|
||||
// Fix hex values - they need # prefix
|
||||
const hexValue = value.hex.startsWith("#") ? value.hex : `#${value.hex}`;
|
||||
return `--${key}: ${hexValue}`;
|
||||
});
|
||||
|
||||
const p3Values = Object.entries(TYPED_COLORS)
|
||||
.filter(([, value]) => value.p3)
|
||||
.map(([key, value]) => `--${key}: color(display-p3 ${value.p3})`);
|
||||
|
||||
const colorsStyle = `
|
||||
:root {
|
||||
${hslValues.join(";\n ")}
|
||||
}
|
||||
|
||||
@supports (color: color(display-p3 1 1 1)) {
|
||||
:root {
|
||||
${p3Values.join(";\n ")}
|
||||
}
|
||||
}`;
|
||||
|
||||
export default function ColorStyles() {
|
||||
return <style dangerouslySetInnerHTML={{ __html: colorsStyle }} />;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
import { animate, AnimatePresence, cubicBezier, motion } from "motion/react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
import { lockBody } from "../lockBody";
|
||||
import PortalToBody from "../utils/portal-to-body";
|
||||
|
||||
export default function Combobox({
|
||||
placeholder,
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
className,
|
||||
}: {
|
||||
placeholder?: string;
|
||||
options: { label: string; value: string }[];
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
className?: string;
|
||||
}) {
|
||||
const selected = useMemo(() => {
|
||||
return options.find((option) => option.value === value);
|
||||
}, [options, value]);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [bounds, setBounds] = useState<DOMRect | null>(null);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
lockBody("combobox", isOpen);
|
||||
}, [isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("click", (e) => {
|
||||
if (ref.current && e.composedPath().includes(ref.current)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsOpen(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={cn("w-full", className)} ref={ref}>
|
||||
<button
|
||||
className={cn(
|
||||
"relative bg-accent-white flex w-full gap-4 rounded-8 p-6 pl-10",
|
||||
"inside-border before:border-black-alpha-8 hover:before:border-black-alpha-12 hover:bg-black-alpha-2",
|
||||
"text-body-medium",
|
||||
isOpen &&
|
||||
"!bg-accent-white before:!border-heat-100 before:!border-[1.25px]",
|
||||
)}
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setIsOpen(!isOpen);
|
||||
setBounds(ref.current?.getBoundingClientRect() ?? null);
|
||||
}}
|
||||
>
|
||||
<div className={cn("flex-1", !selected && "text-black-alpha-40")}>
|
||||
{selected?.label || placeholder}
|
||||
</div>
|
||||
|
||||
<motion.svg
|
||||
animate={{ rotate: isOpen ? 180 : 0 }}
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7 8.5L10 11.5L13 8.5"
|
||||
stroke="#262626"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeOpacity="0.56"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</motion.svg>
|
||||
</button>
|
||||
|
||||
<PortalToBody>
|
||||
<AnimatePresence initial={false}>
|
||||
{isOpen && bounds && (
|
||||
<motion.div
|
||||
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
||||
className="fixed bg-accent-white rounded-12 z-[401]"
|
||||
exit={{ opacity: 0, y: 0, filter: "blur(4px)" }}
|
||||
initial={{ opacity: 0, y: -12, filter: "blur(4px)" }}
|
||||
style={{
|
||||
top: bounds.top + bounds.height + 8,
|
||||
left: bounds.left,
|
||||
width: bounds.width,
|
||||
boxShadow:
|
||||
"0px 32px 40px 6px rgba(0, 0, 0, 0.02), 0px 12px 32px 0px rgba(0, 0, 0, 0.02), 0px 24px 32px -8px rgba(0, 0, 0, 0.02), 0px 8px 16px -2px rgba(0, 0, 0, 0.02), 0px 0px 0px 1px rgba(0, 0, 0, 0.04)",
|
||||
}}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<div className="p-4">
|
||||
<Items
|
||||
options={options}
|
||||
onChange={(value) => {
|
||||
onChange(value);
|
||||
setIsOpen(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</PortalToBody>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Items = ({
|
||||
options,
|
||||
onChange,
|
||||
}: {
|
||||
options: { label: string; value: string }[];
|
||||
onChange: (value: string) => void;
|
||||
}) => {
|
||||
const backgroundRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div
|
||||
className="absolute top-0 opacity-0 left-0 bg-black-alpha-4 rounded-8 w-full h-32 pointer-events-none"
|
||||
ref={backgroundRef}
|
||||
/>
|
||||
|
||||
{options.map((option) => (
|
||||
<button
|
||||
className="w-full group py-6 px-10 text-label-small"
|
||||
key={option.value}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onChange(option.value);
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
const t = e.target as HTMLElement;
|
||||
|
||||
let target =
|
||||
t instanceof HTMLButtonElement
|
||||
? t
|
||||
: (t.closest("button") as HTMLButtonElement);
|
||||
target = target.closest(".group") as HTMLButtonElement;
|
||||
|
||||
animate(backgroundRef.current!, { scale: 0.995 }).then(() =>
|
||||
animate(backgroundRef.current!, { scale: 1 }),
|
||||
);
|
||||
|
||||
animate(
|
||||
backgroundRef.current!,
|
||||
{
|
||||
y: target.offsetTop,
|
||||
opacity: 1,
|
||||
},
|
||||
{
|
||||
ease: cubicBezier(0.165, 0.84, 0.44, 1),
|
||||
duration: 0.2,
|
||||
},
|
||||
);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
animate(backgroundRef.current!, { opacity: 0 });
|
||||
}}
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
# Flame Effects Rules
|
||||
|
||||
When working with visual effects components in components-new/shared/effects:
|
||||
|
||||
## Flame ASCII System
|
||||
|
||||
The flame effects are data-driven ASCII animations that create subtle, fire-inspired backgrounds.
|
||||
|
||||
### How It Works
|
||||
1. **data.json Files**: Each flame component has an accompanying `data.json` file containing ASCII art frames
|
||||
2. **Frame Animation**: Components cycle through frames at specified intervals (40-85ms)
|
||||
3. **Visibility-Based**: Uses `setIntervalOnVisible` to only animate when in viewport
|
||||
4. **innerHTML Rendering**: ASCII frames are inserted as HTML to preserve formatting
|
||||
|
||||
### Available Flames
|
||||
|
||||
#### CoreFlame
|
||||
- Frame Speed: 80ms
|
||||
- Size: 1110px × 470px
|
||||
- Color: `text-black-alpha-20`
|
||||
- Usage: Background texture for sections
|
||||
|
||||
#### AsciiExplosion
|
||||
- Frame Speed: 40ms (faster)
|
||||
- Initial Delay: 30 frames (1.2s)
|
||||
- Color: `text-[#FA5D19]` (heat orange)
|
||||
- Usage: Dramatic accent for CTAs or empty states
|
||||
|
||||
#### HeroFlame
|
||||
- Frame Speed: 85ms
|
||||
- Features: Mirrored flames on both sides
|
||||
- Usage: Hero sections with dual flames
|
||||
|
||||
#### FlameBackground (Wrapper)
|
||||
- Intensity based on metrics (0-100)
|
||||
- Dynamic color (black → orange)
|
||||
- Speed increases with intensity
|
||||
- Optional pulse animation
|
||||
|
||||
### Usage Examples
|
||||
```tsx
|
||||
import { CoreFlame } from '@/components/shared/effects/flame';
|
||||
import { FlameBackground } from '@/components/shared/effects/flame';
|
||||
|
||||
// Static flame
|
||||
<div className="relative">
|
||||
<CoreFlame />
|
||||
<YourContent />
|
||||
</div>
|
||||
|
||||
// Dynamic intensity flame
|
||||
<FlameBackground intensity={cpuUsage} animate={cpuUsage > 80}>
|
||||
<DashboardCard />
|
||||
</FlameBackground>
|
||||
```
|
||||
|
||||
### Performance Considerations
|
||||
- **Viewport Detection**: Only animates when visible
|
||||
- **GPU Acceleration**: Use `transform` for positioning
|
||||
- **Frame Caching**: Frames are pre-loaded from JSON
|
||||
- **Cleanup**: Intervals cleared on unmount
|
||||
|
||||
### Design Guidelines
|
||||
- **Subtlety**: Keep opacity low (10-30%) for backgrounds
|
||||
- **Context**: Use sparingly, match intensity to data
|
||||
- **Accessibility**: Ensure contrast ratios maintained
|
||||
- **Mobile**: Consider reducing/disabling on mobile for performance
|
||||
|
||||
### Custom Utility Classes
|
||||
- `cw-*`: Custom width (e.g., `cw-720` = 720px)
|
||||
- `ch-*`: Custom height (e.g., `ch-470` = 470px)
|
||||
- `font-ascii`: Monospace font for ASCII art
|
||||
- Colors from heat scale: `text-heat-*`, `text-black-alpha-*`
|
||||
@@ -0,0 +1,57 @@
|
||||
"use client";
|
||||
|
||||
import { HTMLAttributes, useEffect, useRef } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
|
||||
import data from "./hero-flame-data.json";
|
||||
|
||||
export default function CoreFlame(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];
|
||||
|
||||
ref.current!.innerHTML = newStr;
|
||||
},
|
||||
interval: 80,
|
||||
});
|
||||
|
||||
return () => interval?.();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="absolute inset-10 -z-[10] overflow-clip">
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
{...attrs}
|
||||
className={cn(
|
||||
"cw-[1110px] ch-470 absolute pointer-events-none select-none",
|
||||
attrs.className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="text-black-alpha-20 relative left-0 font-ascii fc-decoration"
|
||||
ref={ref}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: 8,
|
||||
lineHeight: "10px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { HTMLAttributes, useEffect, useRef, memo } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
|
||||
import data from "./explosion-data.json";
|
||||
|
||||
function AsciiExplosion(attrs: HTMLAttributes<HTMLDivElement>) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let index = -30;
|
||||
|
||||
const interval = setIntervalOnVisible({
|
||||
element: wrapperRef.current,
|
||||
callback: () => {
|
||||
index++;
|
||||
if (index >= data.length) index = -40;
|
||||
if (index < 0) return;
|
||||
|
||||
if (ref.current) {
|
||||
ref.current.innerHTML = data[index];
|
||||
}
|
||||
},
|
||||
interval: 40,
|
||||
});
|
||||
|
||||
return () => interval?.();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
{...attrs}
|
||||
className={cn(
|
||||
"w-[720px] h-[400px] absolute flex gap-16 pointer-events-none select-none",
|
||||
attrs.className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="text-[#FA5D19] font-mono fc-decoration"
|
||||
dangerouslySetInnerHTML={{ __html: data[0] }}
|
||||
ref={ref}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: "10px",
|
||||
lineHeight: "12.5px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Memoized version to prevent re-renders on parent state changes
|
||||
const MemoizedAsciiExplosion = memo(AsciiExplosion);
|
||||
|
||||
// Named export
|
||||
export { AsciiExplosion };
|
||||
|
||||
// Default export for backward compatibility
|
||||
export default MemoizedAsciiExplosion;
|
||||
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { HTMLAttributes, useEffect, useRef } from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
import data from "./pulse-data.json";
|
||||
|
||||
interface AuthPulseProps extends HTMLAttributes<HTMLDivElement> {
|
||||
interval?: number;
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
export function AuthPulse({
|
||||
interval = 100,
|
||||
opacity = 0.15,
|
||||
className,
|
||||
...attrs
|
||||
}: AuthPulseProps) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
const frameIndex = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
const animate = () => {
|
||||
if (ref.current) {
|
||||
ref.current.innerHTML = data[frameIndex.current];
|
||||
frameIndex.current = (frameIndex.current + 1) % data.length;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize first frame
|
||||
animate();
|
||||
|
||||
const cleanup = setIntervalOnVisible({
|
||||
element: wrapperRef.current,
|
||||
callback: animate,
|
||||
interval,
|
||||
});
|
||||
|
||||
return () => cleanup?.();
|
||||
}, [interval]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
{...attrs}
|
||||
className={cn(
|
||||
"absolute inset-0 pointer-events-none select-none overflow-hidden",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
ref={ref}
|
||||
className="font-mono text-heat-100 absolute inset-0 flex items-center justify-center fc-decoration"
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: "9px",
|
||||
lineHeight: "11px",
|
||||
opacity,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
[
|
||||
" \n \n \n \n \n ░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░ \n \n \n \n \n ",
|
||||
" \n \n \n \n ░░░░░░ \n ░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░ \n ░░░░░░ \n \n \n \n ",
|
||||
" \n \n \n ░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░▒▒░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░▒▒░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n \n ░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▒▒░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▒▒░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n ",
|
||||
" \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ \n \n \n \n "
|
||||
]
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,58 @@
|
||||
"use client";
|
||||
|
||||
import { HTMLAttributes, useEffect, useRef } from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
import data from "./core-flame.json";
|
||||
|
||||
export function CoreFlame(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];
|
||||
|
||||
ref.current!.innerHTML = newStr;
|
||||
},
|
||||
interval: 80,
|
||||
});
|
||||
|
||||
return () => interval?.();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="absolute inset-10 -z-[10] overflow-clip">
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
{...attrs}
|
||||
className={cn(
|
||||
"cw-[1110px] ch-470 absolute pointer-events-none select-none",
|
||||
attrs.className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="text-black-alpha-20 relative left-0 font-ascii"
|
||||
ref={ref}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: 8,
|
||||
lineHeight: "10px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Export default for backward compatibility
|
||||
export default CoreFlame;
|
||||
@@ -0,0 +1,27 @@
|
||||
[
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '_^_ ,^_' \n '.\"\"\"+=\"\"=+\"\"^-'' \n ''..:::,_::::::_,:::..'' \n ''.-_\"::___:^^\"___::\":-.''' \n '.'-_:::\"+^\"\"\"+^:::_-'.' \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '-''''-' \n ',::_-'-:\"-'_++++^^^^++++:'-\":-'._::,' \n '''''^+++^^\"^++^\"\"^++^^++++^^++^\"\"^++^\"\"^+++^.'''' \n '''-:^^^^+++===+++^\"\"\":^^^\":\"\"\"\":\"^^^:\"\"\"^++++==+++^^^^:-''' \n ''.-_\"^^++++===++^-'''''-:\",....,::,'''''-^++===++++^^\":-.'' \n '''.-_^^+^++=+++:_-..._^^^:\"\":^^^:...-_:+++=++^+^^_-.''' \n '''''.,,_+++^^:_...' '' '..._:^^+++:,,''''''' \n '-' '-' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '''-''''-''' \n '.:+^\"\"''_+^_-:^+++^^^^+++^:-,^+_''\"\"^+:.' \n ' '' ''-.-:..^++=^\"\"\"\"^^\":::\"++^++++^^+^:::\"^^\"\"\"\"^=+++..:-.-'' '''' \n -:::\"\"-,^+++=++++==++^^\"::--_\"^\"^^\"\"\"\"^^\"^\"_--_:\"^^^+==++++=+++^--:\":::- \n '_:^^^^+^^++++++==++^:'''''''.:\"^,--,^\":.'''''''_^++==+++++++^+^^^\":_. \n ''-\"^\"_:_:^++++++++\".'---...:\"^\",,\"^\":-..---'.:+++++++++:_:::^^,'' \n '.'' '-\",.-.'-\"^^^,:^\"_:-' ' ' '-:_\"^:,^^^^-'.-.,\"-' ''.' \n '''.,- -_.''' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ','' ''' '.'.' '.'.' ''' ''-' \n .''''''' '' ',_\"^\"\"^\"\":^^:\"^^^^^^^^^^^^^^^^^:^^:\"\"^\"\"^\"_,' '' ''''' '. \n ':++:++^^:'' ''-,\"_:::\"^++^^\"\"^\"\"_\"^+^^++^\"\"^++^^+^\"_:^^\"\"^^++^\":::_\",-'' '':^^++:^+:' \n '_^++===++^\":.,:+++^^\"\"^^^:::::\"::_,:\"\":::-__-::::\":,,::\":::::^^^\"\"^^+++:,.:\"^++====+^_' \n ',\"+++=++\"_:++++++^\"\"^^^\"-_,,_::-..-_,:\"::,,::\":,_-..-::_,,_,\"^^^\"\"^++++++:_\"++=+++\"_. \n '_-.\"^:-^:,,-.:\"^^^^__::::_,:___:\"::__''''__:\"\":___:,_::::__^^^^\":.-,,:^-:^\".-_' \n -.' .' '.:_::-'''-\"^\"--,_,\"\"^' '^^\"__,--:^\"-'''-::_:-'' '. ''- \n '-.'' ''' '' ''.-. \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ' '_.' ''.'' ''.'.' '.'-'' ''.'' '._. ' \n ':.'' '' '' '' ''._::\"^\":^^^\"^^\"^^+^^^^^::^^^^^+^^\"^^\"^^^:\"^\":::.'' '' '' '' ''.:' \n '-^++++^\"\".' ''_^^:_--_:^^^^^^\"\"^^^\"++++^^^\",,:^^^++++\"^^^\"\"\"^^^^^:_--_:^^:'' '.\"\"\"++++^-' \n ,^+++===+^\"_:--\"^^^\"\"\"\"\"\"\":::_::::::\"\"\":::,-,,-,:::\"\"\":_::::_:::\"\"\"\"\"\"^^^^^--:_\"^++==+++^: \n '^^^++++++\",\"++++^\"\":--::_,__:::\":,-,,__:::,''-:::__,,--:::::__,_::,-:\"\"^++++^,:++++++^\"^' \n ':,._^-:'''--,_::_,\"--_:::_::::\"^\"^^:-' '-:^^\"^\"\":::_:::_--\"__::_---''':-^_.,:' \n .' ''-:^\"_.----:^:,,:\"_._\". .\"_.,::,,:^\"----._:^:,'' '. \n ''''' '--,' ',--' ''''' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n .'' ''''''.''':-___.' '''' ' '''' '.___-_.''.'''''' ''. \n '\"\"^'' .\"^\"++\":_^\"^^^+++^^++++^\"\"++:_:_:- .:_:_:++\"\"^++++^^+++^^^\"^__\"++^^\"- ''\"\"\"' \n '^+++^\"_,-_\"::\"\"\"\":^^^^^\"^+++++++=++++^-',_.' ._,'-^++++=++++++++\"^^^^^:\"\"\"\"::\"_-,_:^++++' \n '^+=++^\"^^\"^:_:\"^^^^^^^^^\"^^++^++++^\"::_-''' '' '''-_::\"^++++^++^^\"^^^^^^^^^^:_:^\"^^\"^++=++' \n ':^+++++++^:,,\"^^:_:_:\"\"\"\"^^^^\"^^^^::\":,-' '-,:\"::^^^^^\"^^^\"\":\":_:_:^^\"_,:^+++++++^:' \n ' '' ''...-,::_::,,,_\"\"^++++^^++++^^\"\"\"' ':\"\"^+++++^^++++^\"\"_,_,::_::,-...'' '' ' \n .-\"-,:::_:::\":\"^^^^^^+\"' ':+^^^^^^\":\":::_:::,-\"-. \n '.--.,^\"_''' '-,,' ',,-' '''_\"^,.---' \n '' '' \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n ' ' \n '' :^,-..'-''-,...-.,__^:-' '.:\"_,_.-.-.,-''-'..-,\": '' \n '::^'' ..\"\"+++++^^+^++++++=+++++++^\":-'_-.- ---_'-:\"^+++++++=++++++++^^+++++\"\".- ''^::' \n \"++++_,,_^^^\"\"^\"^+++++++++++++++==+^^^:.'''' '.''.:^^^+====+++++++++++++^\"^\"\"^^^:,__^+++\" \n \"==++^\"^^^_,:\"^+++++++++^++^++++++^:::-'' '''..''' ''-:::^++++++^++^+++++++++^\":,:^^^\"^++==\" \n .:^++++++^\"-,:^+^:\"\"^^^^^+++^^+^^+^::,-,' ',-,_:^+^^+^^^++^^^^^\"\"\"^+^:,-\"^++++++^\". \n '' .::_:\"\"\"_:\":\"^^^++++=+++++===+:.''' '''':^===++++++++++^^^\":\":_\"\"\":__:- '' \n ''''''_::,:\"^^++^^++++++++^. '^++++++++^^++^^\":,::_'''''' \n -_,--\"^^_:-' ''''.,- -,.'''' '-:_^^\",-,_-' \n ''''' ''''' \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n '_:' ' ' ''' '' ' ''' ' ' ':_' \n .,' -_:::-.:+^__^^^::.'--,\"^:''' ''':^\"_-,'._:^^^__\"+:..:::_- ',. \n '..\"\"\":\"^\"\"^^++++^^^\":\"^++^+++++++^^-''' '''-^^+++++++^++^\":\"^^^++++^^\"\"^\":^\"^..' \n .^^+^^+^^++^^+++^^^^^^^\"^^^^^\"\"^+++^::..' '..::^+++^\"\"^^^^^\"^^^^^^^+++^^++^^+^^+^^. \n '++^^++^\"^+^^^^^^^^^^+^\"::^^\":::\"++^_,.''''''' '''''''.,_^++^::_\"^^:::^++^^^^^^^^^+^\"^++^^+=' \n '_^^^^^+++^\"\"^^::\"^+^\"\"^^+++^::::\"\"^^,'' ' ' ''-^^\"\"::::^+++^^\"\"^+^^::^^\"\"^+++^^^^^:' \n , .:^++^_,--_::^++++^+==+==+=^^^\"::. '::\"^^^++==+==+^++++^::_--,_^++^:. ,' \n -\"^^. ''--_,_\"^++++^^++:\"+^+^+^- -^+^+^+^:++^^++++^\"_,_--' .^^^, \n .'',,_^++\"-'' ' '''' '''' ' ''-\"++^_-_''.' \n '' ' ' ''' \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n '' '' \n ' ''-- ''.',-' '' '' '-,'.'' .-'' ' \n ''.,.'''_::'':+^\":\"^:::-''__:^::. ' ' .::^:__''-:::^\":\"^+:.':\"_'''',-'' \n '-.^++++=+^++^^^+^^^^^^\"^^^^^^^^++:,, ,,:+++^^^^^^^\"^^^^^^+^^^++^+=++++^--' \n '^^==++^+++++++^^^\"\"^^::::\":\"^++^\":\":-.'' ' ' '''-:\"::^++^^:\"::::^^\"\"^^^^++++++^++==+^' \n '+++++++^^+=+^\"^^+++^^:,:::\"\":\"^\"^^^\".''.'' '''''' ''.''.\"^^^\"^\":\"\":::,:^^+^+^^\"^+=++^+++++++' \n ^+++++++^^^^::\"^++^^\"^^++\"\":,,::\"\"^^_- ' ' ._^^\"\"::,,:\"\"++^^\"^^++^\"::^^^^+++++++^ \n :-\"^^++\"_,_::\"\"^+++++++++++^^^++\":_' '_:\"^+^^^+++++++^+++^\"\"::___\"+++^^-: \n -^+++: '-::_:\"^+++^^:^++,'-::::^_ _^:_::,'.++\":\"^+++^\":_::-' _+++^, \n ''' ' .,__\"\"_. '' '' -_\"\"__,. ' ''' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n ' .' '. '' \n '-''' '''''-,\"^_. '' '' .,\"\",-''''' '''.' \n '-:^+^^\"-..::^:^^\"^,-.'.'.'''_,:,.' '.,_,_.''.'.'.--\"\"^^:^::..-\"^^+^:-' \n .,^++===+^^:_:^^^:_:::,,___\"^^\"^^\":--.. ..--:\"^^\"^^\"___,,:::_\"^^^:_:^\"+===++^,. \n :\"^^+++=+^^\"\"\"\"^\":_-,,___::^^^^^\":_\"^:-'''''''' '''' ''''''''-:^\"_:\"^^^^^::___,,-,:\"^\":\"\"^^+=+++^^\":' \n _\"^++^++++^^^^^^^++::_:___:_:\"::\":_\"::--.''''.'' '''' '.''''.--::\"_:\"::\"\"_:___:__:++^^^^^^^+^++^++^^_ \n -_^\"+++++^+^+^^^^^,-.'.-._::^::_.'''..'''' ' ' '''.-''''_::^::_.-.'.-,\"^^^^+^+^+++++\"^_, \n ':^:^+++^\"^^^^::^^:_-.-,:^^:_''.-.' .-.''_:^^:,-.-_:^^\":\"^^^^^+++^:^:' \n '_:::^:.-_,'-:_:::_--..'._:' ''' ''' ':_.'..--_:::,:-',_-._^:::_' \n -.' '' ' ' '' '.- \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n ' ' \n '-,.''..'''''-,' '--''''''.''.,-' \n ''''-:^^^::\"\":_::\"__.'' ' ' ' ' ''.__\"\":_::\"::^^^:-''.' \n '-\"^^+=++++^_:\":+^^^:_-..'''''''-__-' '.__-'''''''..-_:^^^+\"\":_\"^+++=+^^:,' \n ',:^^+==++++:\"^++++:_--,::::::^+++++:.' '.-.''' ' '.--'' '.:^++++^::::::,-._:+++^^\":^++++=+^^\"_' \n _^^+++++++++^\"^^\"^\"\"\"::\"^:\"^++++^++^\":,. ''--,:-_''''''''_-:,--'' ',_\"^^+^++++^\":^\"::\"\"\"^\"\"^\"^+++++++++^^_' \n ':+++++++++++^^^+^:^^^^^+^\"^+^\":\"\"+^:_\"_.'''..''\"-_,..-_-\".'..'''._\"_:^+\"\":\"^+^\"^++^^^^:^+^^^+++++++++++\"' \n ,^^+++++==+^+:::::::::^^:---_-..-.' '.'''''' '''''''''' ''''''.' '.-..-_---:^^:::_:::::^^+==+++++^^_ \n _\"\"++++^+^\"^__::_,_,_\":.-.-,..-.' ''' ''' ' '.-..,,.-._\"_,_,_::__^\"^+^++++^\": \n ':\"+^\"-_.'' ''''''-_''' ' ' '''_,.' '''' ''._,:^+^:' \n ''-,...' ''..,-.' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n '-' ' ' '.' \n '-:^^_-.'''' .' '.' ''''.-_^^:,' \n ',_,'_^++++\"_:^:\"\"__' '__\"\":^:,\"++++^:',_,' \n ':\"\"^+++++++^\"\"^^:_::----..--_--'-__ -_-'.-_,--.----::_:^+^\"^+++++++^\"\":' \n _\"\"^^++==++^^+++^_-_:_::_:\"\"++++=+^\"-.'' :^^, -^\": ''.-\"^^=++++\"\":_::,::-_^++++^++==++^^\"\"_' \n _\"^^+++==+++++^^\"\"^^^\"\"\"\"\"^++==+\"\"^++\"^:-'^+:' '-' ''__'' '-' ':+^'.:^\"++^:\"^===+^\"\"^\":^^^^\"^^+++++==+++^^:_' \n '\"^++++++++++++++^^^+^\"^\"::++^+:--:+^\"\"_.,\":-.'.----''''----.'.-_\",._\"\"^+:--:+^++\":\"^\"\"++^^++++++++++++++^\"' \n -:^++++++^+^^+^^\"\"^^,_:,_\"++^:_-'''-.-,,:^\".''.''.' '.''.''.:^:,,-.-.''-_:^++\"_,:_,\"^\"\"^^+^^+^^+++++^\"- \n ::^+++\":\":\"\":^^\"^\":\"-'''--,,--' ''''' ' ' ''''' '--,,,-.''.\":\"^\"^^:\"\":\":\"+++^:: \n ':\"^^:_-' ''.-.' '.-.'' '-_:^^\"\"' \n '_:^,.-' '-.,^:_' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n '' '' \n ''..::- -:\"..'' \n ''' '.,^:\"\":-'' ' ' ''-:\"\":^_.' ''' \n '-_::____:\"\"\"^\"_,---..''' ' ''' ''' ' ''...---,_:^\"\"\"\"____::_-' \n -::::\":\"\"\"^^\"^:_---:_..----.''.\"^^- .^^\".''.----..,:---_:^\"^^\"\"\":\"::::, \n -:\":\"\":\"^^+++^\",,_:_:^\"^^\"\"^\":^+\"^+^-'''-^. ' ' '^,'''-\"+^\"+^:\"^\"\"^^\"\":_:_-,:^+++^^\":\"\":\":- \n .._:^^^^^^+++^:,-\"^\"^+++^^^:^^^^+=+++-.\"_,..' ''' ''' '..,,\"--+++=+^^^^:^^^+++^\"^\"-,:^+++^^+^^^:_.' \n ':\"^\"^^^^^++^^_-:^^^+++++:\"\":\"\"+++++^:^^\"_'''''___''' ''',__''''',\"^^:^+++++\"\":\"\":+++++^^^:,_^^++^^^^^\"^\"\"' \n ,\"\"^^^^^^^++\"_,_-_:\"\"\"++++:_.._-:,,--,_,.'''''-:-'''' ''''-:-'''''.,_,--,,:,_.'_:++++^\"^:_-_,_\"++^^^^^^^\"\"_ \n '-_\"^^+\":::\"\"--,__-:-'''-,. ''''''',.' ''' '''' '''' ''' '.-''''''' .,-'''-:-__,--\"\":::\"+^^\"_-' \n ._:::_,' '''' ' ' '''' ',_:::_- \n .,::,,'' '',,_:,. \n ''.'' ''.'' \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n '-. .-' \n '.-,.\"_.' .,\".--.' \n '-,'''._^^:^:.' '' '' .:^\"^^:.'''--' \n ',\"::::\"_:^^^^\"\",,_-.' '.' '.' '.-__,\"\"^^^^:_\"::::\"_' \n ,\"\"\"::::^^^^^\"\":,_\":_:_-.-''..::+\"'' '':+::.-''-.._:_:\"_,:\"\"^^^^^::::\"\"\", \n -:::\"\"\"\"^^++++^:\":\"^^\"^\":^^^^+^+++++' ''..-. '-.''' '+++++^+^^^^\"\"^\"^^^:\":^++++^^\"\"\"\":::, \n ..-_\"^^^+++++^^^^^++^^+^^^^^++^+===+\"\"\"^\"_-'.'' ' ' ''.'-_\"^\"\"\"+===+^++^^^^^+^^+++^^^^+++++^^^\"_-.. \n ',\"^^^^^+++++^^^^^^^++==+^^^++=+++\":^^,--' '-:,,. .,,:-' '.--^^:\"+++=++^^^+=++++^^^^^^+++++^+^^^\"_' \n '\"^++^^^^^++^+\"\"\"\"^\":^^++\"_\":-,\"^^::::-''''''-_:-' '-:_-.'''''-_\"::^^\",-::_\"++^^:\"^\"\"\"\"^^++^^^^^++^^' \n -,\"++^^\"\"\",'-::\":\"_.' '' '.' ''-_,,.' ''''''' ''''''' '.,,_-'' '.' ' '._\":\"::-'-\"\"\"^^++\"_- \n '-\"^:::-' -.'' ''' ''' ''.-' '-:::\"\",' \n ',__::,' ',::__,' \n '.--' '--.' \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n ''-.''.' '.''.-'' \n '' '---,'.'' ''.'-,--' '' \n ''-__,,.',:^:-'.' '.'-:^:,..,,__-.' \n '-:\":::::_:\"\"\":_,+^:_ ' ' _:^+,,:\"\"\":_:::::\":-' \n ',:\"::__\"^^^^^\"::++^,-''''''-_.''.' ' '-''._-'''' '--^++::\"^^^^^\"__::\":,' \n ',_::\"\"\"\"\"^+^+++++++++++^\"\":^^^:::__'.'.' ' ' .'''__:::^^^:\"\"^+++++++++++^+^\"\"\"\"\"\":_,' \n .-_:\"\"^^^+++++++^^^++++^^\"\"+++:--.'..--.'' ''.--..'..-_+++\"\"\"^++++^^^+++++++^^^\"\":_-. \n '-_:^^^+++++^\":\",-.:^_\"\"+++=+==^^^..:^_.''--_'',_'.' '''__''_--''._\":..^^^==+=+++^\"_^:.--\"_\"^+++++^^^:_-' \n ':^^+++++^\"\":-. ' '-'..\"^++\"^--_\":'-\"\"\":,^,''''' ''''',\",:^\"\"-':\"_--^\"^+^\"..'-' ' '-:\"\"^+++++^^:' \n .\"^^^^^:. '''''' '\"^_+: ''.'-,-:\":.'' ' ' ''._\":-,-'.'' _^_^\"' '''''' .:^^^^^\". \n -,\":\"__,-.' '-''. ',:_'''''' ' ' ''''''_\",' '''-' ''-,__\":\"_- \n '-_\"\",__,.' '' '' '.,__-\":_-' \n '...'' ''...' \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n ' \n '''.''''' '''''.''' \n '''' '.-..''' '''..--' '''' \n '.,,,,--.'_^\"::_: ____\"^_'.--,_,,-' \n '.:\"::\":_::\"\"\":^^,''' ' ' ' ' ''',^^:\"\"\"::_:\"::\":-' \n ',_:\"\"\"\"\"^++^++++=+^+:'-^''-_,' ' ' ',_-''\"-'_+^+==+++^++^\"\"\"\"\"::,' \n'._::\"^^^^++++++++=+^++^\"^^^\":,..'''-:_\"' '\"_:-'''..-:\"^^^\"^^+++=++++++++^^^^^::_-'\n ',_::\"^^^^^++^^^^^+^^++^:++::\"\"_-.:^^^, .-,' ',-. -^^^:--_\"\"::++:^++^\"++^^^^++^+^^^\"::_,. \n ',:\"^^+++^^\":_''''''.._+^\"^^++++=++^^::,-,:\":- ' ' -:^:,,,::^^++=++++^^\"^+_..''''''_:\"^^+++^^\":,' \n ':^++++^\"::,. '''''',\"^:+^_:::_^^^^\".'' ''.:^^^^_:::,^+\"^^,.''''' .,:::^++++^:' \n '\"^+++:-'' .::''' '_:^,^^:,-' '-,:^^,^:_' '''::. ''.:+++^\"' \n .::^^:,--.'' '\"^..-_,.'' ''.,_-.'^^' '.--,:^^\":.' \n '-_::::--.' ' ' ' ' '.--_:\":_-' \n ' '.-.'' ''.-.' '' \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n '' '' \n '--.''' '' '' ''.--' \n '.\"^^\"--' '_-'' '.-_' '--:+^^.' \n^\"++^\"^^:'' ''',\"^\"' ' ' '\"^\":'.' '':^^\"^++\"\"\n++=+=+^^+:.''.':=+:'' ' ' '':^=\"'-''.:+^^+=+=++\n++++++\"\"^:' '' ' ' '''' '.-'' ''-.' '''' ' ' '' ':+\"\"^+++++\n^+++++^::' ''.:' '' '' ':.'' '::^+++++^\n\"^^++^^-'' '' - '' '' - '' ''-^^++^^\"\n_++^^^^\",''' '' ' '''-\"^^^^++_\n'^+^^:\"++^-..-.' '.-'.-^++\":^^+^'\n '-^+++^^\".---' '-,-.:^^+++^-' \n '-_,,-''.'' ''.''-,,:-' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n ''' ''' \n ._'.' ' ' '.'_. \n..\"^^_:.''''''--.' '.--''''''-:_^^\"-.\n+^+\"\"::-''' '+^''''' ''''':+' '''-::\":+^+\n==++^::^+- '''' ' ' '''' -^^:_^+++=\n=++++^\"^\"' ' ' ' ' ':^\"^++++=\n+=++++^-- '' '' .-\"++++=+\n^+++++^-' '' '' '-^++^++^\n_^^+^^^+-' ''' ''' '.+^^^+^+_\n.^\":\"^\"++:-'..'' ''..'.:++^^\":\"^.\n '.-\"^+++^\".'.'' ''.'.:^^++^\"-.' \n '.-,-.' ' ' '-,-.' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n ''' '' '' ''' \n ''-' '-'' \n:_-'.' ' ' '.'-_:\n:''':+_'''' ' ' '''',+:''':\n\".'',^+_.'' '._+^,'''\"\n^^,\"+^_'' ''_^+\",^^\n+=+^+^' '^+^+=+\n\"++==^_.'''.'' '.'''.,^==++\"\n:^++=+++_,' ' ' ',,++^==++:\n :^_^^++\":-' ' ' '-_:++^^:^\" \n '''':--\":-' '.:\"--:'''' \n '''' ''''' \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n . .' \n '' ' ' '' \n'.''' '''.'\n' -_-:. ':-,-''\n' '..'.-.' '.-.'..' '\n:::\"^_' ',^\":_:\n+++^:- '' .' .:^+++\n^^++=^-'''' ''''.\"=++^^\n:+++=+++^.' '.^+++==++:\n ,::+^:^^:.' '.:\"^:\"+\":: \n '''.''--' '-,''.''' \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n ' ' \n -' '-' \n^\"'' '' '' '':^\n\"\"-- ' ' --\"\"\n++\":' '_\"++\n\"++=+^_.-' '-._^+=++\"\n-\"^+==+^\":_ ,:\"^+==+^^-\n \"^:-_.--' '--._-:^\"' \n '.' '' ''' ''' \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n:.' ' ' '':\n::_' '_\":\n+^:.'. .'':^+\n_++++^_--' '--,^++++_\n.::+=+^^\"-.. ..-\"^^+=+\":-\n .+_'.'' ''.'_+. \n '' '. \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n.' '.\n=: _=\n:-,.',. '_'',-:\n':,,:--'''''' '''.'',-:__:'\n '.^^^++_.''' '''._++^^^.. \n -'' ''-' \n ' ' \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n.' .\n=. ' ' ' '=\n:::'',' ','':::\n'.._:.:,'--',' ','.-',:.::.-'\n '':_++:.''' '''.:+=__'' \n '' '' \n \n \n \n \n \n \n \n \n \n \n ",
|
||||
" \n \n \n \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,41 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { CoreFlame } from "./core-flame";
|
||||
|
||||
interface FlameBackgroundProps {
|
||||
intensity?: number; // 0-100, like CPU usage
|
||||
animate?: boolean;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function FlameBackground({
|
||||
intensity = 0,
|
||||
animate = false,
|
||||
className,
|
||||
children,
|
||||
}: FlameBackgroundProps) {
|
||||
// Convert 0-100 to 0-0.3 opacity
|
||||
const opacity = Math.min((intensity / 100) * 0.3, 0.3);
|
||||
|
||||
// Speed increases with intensity
|
||||
const speed = Math.max(80 - (intensity / 100) * 40, 40);
|
||||
|
||||
// Color gets more orange with intensity
|
||||
const color =
|
||||
intensity > 80 ? "heat-100" : intensity > 50 ? "heat-40" : "black-alpha-20";
|
||||
|
||||
return (
|
||||
<div className={cn("relative", className)}>
|
||||
<CoreFlame
|
||||
className={cn(
|
||||
"transition-opacity duration-1000",
|
||||
animate && "animate-pulse",
|
||||
)}
|
||||
/>
|
||||
{children && <div className="relative z-10">{children}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
" \n \n \n \n \n . . \n .. ..+ \n .:. \n .. .. .:: \n +.. ..: :. \n .:..::. .. .. \n .--:::. .. ... .:. .. \n .. .:+=-::.:. . ...-.::. .. \n ::.... .:--+::..: ......:+....:. :.. .. \n ....... ::-=:::: ..:-:-...: .--..:: ......... \n .. . . . ..::-:-.. .-+-:::.. ...::::. .: ...::.:.. \n . -... ....: . . .--=+-::. :-=-:.... . .:..:: .:---:::::-::.... \n ..::........::=..... ...:-.. .:-=--+=-:. ..--:..=::.... . .:.. ..:---::::---=:::..:... \n ..........::::.:::::::-::.-.. ...::--==:. ..-::-+==-:... .-::....... ..--:. ..:=+==.---=-+-:::::::-.. \n . .....::......:: ::::-::.---=+-:..::-+==++X=-:. ..:-::-=-== ---.. .:.--::.. .:-==::=--X==-----====--::+:::+... \n ..-....-:..::-::=-=-:-::--===++=-==-----== X+=-:.::-==----+==+XX+=-::.:+--==--::. .:-+X=----+X=-=------===--::-:...:. .... \n ....::::...:-:-==+++=++==+++XX++==++--+-+==++++=-===+=---:-==+X:XXX+=-:-=-==++=-:. .:-=+=- -=X+X+===+---==--==--:..::...+....+ \n ..:::---.::.---=+==XXXXXXXX+XX++==++===--+===:+X+====+=--::--=+XXXXXXX+==++==+XX+=: ::::--=+++X++X+XXXX+=----==++.+=--::+::::+. ::.=... \n .:::-==-------=X+++XXXXXXXXXXX++==++.==-==-:-==+X++==+=-=--=++++X++:X:X+++X+-+X X+=---=-==+=+++XXXXX+XX=+=--=X++XXX==---::-+-::::.:..-..\n",
|
||||
" \n \n \n \n .. \n . .+. \n \n .: \n : .. :. \n .. ... .. .. \n :...+. . .. :. . \n .=-::... . . ... .. \n .. .--=-::... .....=+.:. . . \n -:.... .:-=:...: .::...... .:. .. . ... \n .. .. . .:: :.:: .:-::.. . .-..:.: ........... \n ..= . .. .::-==.. .-=-::... ..:.. . ..:::.::.:... \n .+.:.:. ..-.:: . . ..:. .:=-==-::. .:--.. .. .. ... .:---:::::--::..... \n .. ..+::.......-::..: . ::--.. ..:::-==-:. ..::.. .:... ..-.. =..:=== ::::-+-=:...+.=.. \n .....= ....:::..:::::- ::=:. ..:=--==+:. .:-::-=-=--:... .:-..... .:-=:...-+==--:+:-+-=-:-:.:+... \n .....:...::.:: ::::-::----=+-::--:---+=XX=-:. ..-=-=::--==X==-:....-.:--::.. .::++-::--+=---:-:---=-=::...-.. \n ....:..:....:=:- ==--=-:--===++====---- -==+==-::--==-:-::--=XX ++=-:::---+===-:. .:-X+ ----=X==----: :=--.--::........... \n .+.:::::-..:-:-===++=++=++++X++=====-.--=X==++==----=--::+:-=+XXXXX++---=-==+++=:. ..:-+++---=+XX+++=-::-===-+=--:...:.......... \n ...::--- ::::--=+=+XXXXXXXX+++=====+===--=---==++==-=+=--::-==++XX+XXX++=+X==+XX+=-::-::--==++X++XXXXXXX=-::-+=++X+=-:::::::::-:=+..... \n ..: :-===----=-=+++++XX+XX-XX++X+==++==+=--:--==.XX+==++.===+++XX.++++XX++=X+=++XX+==--=--===+ +XXXXXXXXX+=--=X++.XX==--=-:---:::::::..:.\n",
|
||||
" \n \n . \n . \n \n . : \n . .. \n . .. . \n . \n :.. . . \n .::... . \n ==-:: : . \n . . .-.=::. .:: ..+ . .=. \n . :.. ..+:..:-. .:.. .: .+. . .. \n . . .:.:-:. .-=-... ..-. ...:.. .. .. \n . . .. .. :. ..::--:.. .::-. . .: .:::-:....-...:. \n .. ......:: ::. .::+:::: .:=::==:.. ...... ... . . .::----:...::::::.... \n . .:.....:::::=:-. ..::--=-.. :-::--==.::.. . .: .. .::-:..:==--::..:::::.:.....: . \n +.. ...:-+...:.: :=---::..:::::-=+=:.. .::.:::--.++--:.. ..-:..+. .:=-::::==-:::::::-=-:.::... . \n -... .. .. .:---:+:-:-::-=+==--=-::.::-X=--::..::::.:.:--=XX+==--::::.:-+=-:. ..-=-::-::=++-::-::.:---::.. . \n ......... .:::-=+== -==+= =====--=-:::::-+=+=--:.:::..::.:-===XXX+=--::--+==+=-. ..-==-:.:-=XX=----:.:-=-=--:.. .+..... \n ...:::+:...:=:-+++XX++++.=-=-==-- ===-:.:=---=+=-:::--::..:-==++X+X+==--=+==+X+-:.......:-==++==++X:X++=-:::-==+=--:.......::::..+. \n ...:---::+:::--==++-XX++XX+=:=++=--====-:::+--==+=---== ---==++XXX++XX+.+XX===+X+=-:::-:--=====XX+-++XXX+-:--++=+X+--::::.:::::::..... \n ..::.-==---+- ++++.+++XXX-XX++:X+=-=X+==:-::.=+X+XXX+=+X++++XXXXXXXX=XX=- +++-==++X+==-==-=:=++XXXXXXXXXX++==+ ++X X+=---.--.-:.:::.:... \n",
|
||||
" \n \n . \n : \n . \n . \n . \n \n \n :. . \n :-....:. .- \n ....... .. \n . .. .. :. \n .. ..:.:. .-.. . ...:... \n . .. ..... .:--:.. .::... . . .. ........ .:. . \n .. ..... ...: ..=..::-. .:.:=-:. . ... .. .:.:..:-...-:......... \n . .:: ..::.:.:.. . .:.::-.. ..=.:--==:.. . .::..+==::::+........ . \n .:.......:.:::.....:::..::==:.. :.....::-+X-:::. .-.:... ..-:..::=::-:-...:.:::... \n .. :::.:.-.:::-=---::=::...:--==-:. ..= ....:-++=--=-::.+...==-::. .--:....:=-:-:::.... ::.. \n +.... .::-==+-----------------:::..-==--::. ... ..::-=+:+++=-:::.-- =+=-:. ..=--:::::=++-=::-::.:=-::... .. \n ..:-.... :..:-+++=+=-===-------::--.::..:------:... :....::-=++XX+=--::----+X-:. ..-==-----+X+==-=-:::-=+=-::.. .....:...- \n ...:::::....:-- ==+X+====-----=+::-==-:::::----=-:.::-::::--=+XXXXXX+=-=+=-==++--:-:::.::=--=-==X++++X+=-:=:===++--::......:...... \n ...:----:::--.====+=++X+++======---=+=--:-::=+++X++=-====== ++XXXX.XXX +++-=--=+X+--::--:---==+XX+++XXXX+=--=+=++X+=-:::-::-:::....... \n .. ...:::--==:---++=+=====++ XXXXX++===+X+===+==-+X++++++++X+X++.XXXXXXXXXXXX ++======X+==-=--===+XXXXXXXXXXXX+=+++++X+XX=.--==--::-....:....\n",
|
||||
" . \n . \n \n \n \n \n \n \n . ..: \n :. . .. \n ::.. \n . .. \n .: :::. :. .. \n .:..:. .:-. ::. . .: .. ..... \n ... . ... . . ... ..::-:. . . ... .:........:. \n .. =.... . ... .. .:.:-+-.. ....-=:....:.=... .. \n ... -..=::... . ......:::-: .::=+-:::+. ::-.. .:..::=:...:.......... \n ....:. ...:....:::=:.:-.. .::=--: ..:==:-::::. . .:---:. .:=:::. :::-.-...:...=. \n ..:.--::::::::::::::--:-:....--:::... ..:-==++---:.=.-::-=+-:. .:::.....--=-:.-.::.--:... \n ....... ..-=---==-=-==-::.-::+:--::..-:---:::....... ..---=+XXX+=-+:::--+X-:.. :--:.::::-++-::::::::==-:..: +.... \n ..:...:....:-=-=+:+=--==::--::-=::--:...:--.:-::....::::---+=+XXX.+=-:-----+=-::..... .::--:---=+++==--:..:-==+-:::.. ......+-. \n ..:-::::..::---=====+=== -:--:--::-==-::-::-==-==----=--::-==+:XXXXXX+==+=--==+=::..:::.::---++.+=+++X+=-:=:===+=--::...:..::...:. \n ....:-------==-=+=====XX+X+==------+=---=:==+=.==+=+++++X+==+XXXXXXXXXXX+++==--==+=-:-:-:---=X XX++XXXXX++===+==+++=------::: :....... \n .....-.:+:--==+======= ++=++X:XXXX+=:==XX==:++=-=++==+X+=+++:+XXXXX:-X.XXXXX+X++==-++++X+======++XXXXX-XXXX--XXX+==+++++X++==.---::::..=:. ..\n",
|
||||
" \n \n \n \n \n \n \n . \n . . \n :. \n .. . .. \n . .. ::. . . \n . . .:+.. : .. . \n . . . ..-- .. .. ..: \n . .. .. . ...-:... . ...:-.. ... \n . ....-.-. ..:.. .. :: ...-::...... .. .. .:.:::=....:. .. \n -... .....:...:.:-. ...=.:: .:=-::::::. .::--. ....:.:. ..:.. ..: .. \n .::::::.:..+:....:..-=:-:. ..:..::. ..=------::...:..:=-.. ........::-:.. ..::.:. \n . . :::----:::::=::....+:=-:-..-::-::-... . .:-==++++++-:.-::-+-... .::.... .:==::.....:--+:.. . . \n .... .. .:-=-=+==---:-:=:::..::::-:..:-:::::::....=.:..::--=+XXX-=-:-:-:=--::.. :.::..:::-++--::...::==-:.:.. ....+. \n ...-.:.. ...:-==--=+--:-::::..::.:--:..:=:-+-:---::--:::+:-==++X:XX+-==--:--==-::.... ..::::-++==++:-::..:-==-:::.. .....+=. . \n -..:::::::--::--==--++=+==--::::::-=-:: =-=-- --=+=+++=++-==++XXXXX- X+==+-----==::..:-.::--=+.++=++XX++=-:-======:--::.:.-...:... \n ......:=:--=----=- -=-===XX+XX+=----.-+=-:-==-+==-.-=+=====-+ X+XXXXXXX:XXX+========++=------+++XXX+.+X=XXX.XX+======+++---:::-.:.=..:.... \n .......::::-=:===++ ==++=++XXXXXX:++++++=====++=+X++:=++=====++XXXXXXXXXXXXX+X++-===++XXX++=+==+X++XX++X-XXXX-XXX+==+++=+X:===-+-:::=..::....\n",
|
||||
" \n \n \n \n \n \n \n \n \n . .. \n ...... \n ..::. \n : . . . \n ... : ....+: . . .. \n . .:. .... . .:. .... . ...:. ..-:.. .. \n . . ..- ...=.: ..:. .:-::::..=.. .:-. ...... .:. :.. \n ....::. .. -.......=: :::. ...-.. .- --+::::---.. ..:.. . .. +..::. ...:. \n . .:::::-:....::-........---:-...::..:. ....:--=--===+=:....:-.... .. .. .:-:.. ..::. . \n . .:::--:--::=:::::. ..::-: ..::-....: ..:......:--===+=X=-::.---::-.. ..:....::.==-::.. :---... . .-. \n .. ...::-:-:--::-::-::. ....::-...----:::::.:=:::-:::-====+XX+=--:::=--::. .::::-=== =+=::....:=-:..-. .... \n .+...... :::::-----=.--:-::...=..:=:...:---::.:--==+--=+:--+:+XXXXXXX=-==:+:---:::...:...-:--++===+XX=-::::=----:::...:...... . \n .....:=:- :::-:::-+--++===+=-::-.::-=:::-=+=--:.::-==+-:=++ +XXXXXXXXX++==+=-=+--=--::::::---+++==++XX-X+=+ ==---===--::.+....=.... \n .=....:.::.==--:-==--====XX XXX++=++=== ==--==+X+==---------==+XXXXXXXXXXXX++==== =+==++-=.=-=+++:=++=++XXXXXXXXX+=====++---:-::..:...:.... \n ......:::--=++= ====-===++XX-X XXXXX:X+====-==+XX:+++========+XXXXXXXXXXXXXXX++=++XX +++++=+++X:X+XX.++XXXXX .XX+++=:+++X+=.---::::...:=:...\n",
|
||||
" \n \n \n \n \n \n \n \n .: . \n . .... \n \n :. ... \n . . ..:. . \n . ..:.. .. .:: .. . \n . .. .:. ..: .:...... .:.. .. :.. .. \n ..-::: .:... .:=:. .. :. ..::=.:: :::=:. . .=. .. . \n ......:.. ..:-.. .. .:-:.. :.... . . .::=-------+-:......:. .. .+.:. .. \n ...::......-:.::. ..:-:....:::.. .: ....:--=--=-=+-:.::::.... .. .::-=-::. :.... \n ..:::.:.::..:..::.. ....--=....=::=:.:...-..:-:.::==--=+++--::---:.... ...::-:--=+:.. .:.:.. . \n .....:: ..:-::--:+:.:-.. .:=..:-..=.--:....::-+-::=-:-.-=++==+XX+=-=-::-::... ... :.::-=-=++X=-:..:::-::.:....... \n ....::.........---====--=-::.:=:.:--=::-=.::....::--::==== XX +-++XX++==.-=-:. :::-..:...:-- =-.==+X++------------:..... .. .. \n .....+.-:::::::-:::+--=X++ ++=====+==---:--=X+=-::.::::--:--=+XXXXXX++X++-====--==:--==--=:-=-=+==+-==+X.XX++++:=----=-::..:.. ....=.. \n . .. ...::+-==------:--==XXXXXXXXXXXX+=------+++X+===--=-----==+XX-XXXXXX:-++==+=++=--==++=++XX++==++==++XXXX:X++++=-===+=--:+::.....=-.... \n ......::--==.+++=+===.=++XXXXXXXXXXXX=++=.=--=+++X+++==+=====+X-X-XXXXXXX X+++++++++++===:==:++XX+XXX++XXXXXXXX.+++++XX+XX+=-=-:::+:::.:.:..\n",
|
||||
" \n \n \n \n \n \n \n . .. \n . \n .. \n . \n .. .:. ... \n ... ...... .. . \n . .. :. . ..:. .:: :. \n +... . ..:. . . .. .:.:..:=:. . . . \n .. ..: .:: ... . ..::-::::.:.:=-. ... .. ...::... \n .:.... ..+.: . ::. .::.. . ..::.::::==::--:..:.. . . .::-:-:. . \n . ........... .-.. .. .:. .-:...... .. ....::-=-::--=-::.:::. .. ....:+:-==.. .. .. \n :...... .:.-:.+....-....:. ..:: .::-.. ..::-:..=::::--+=--==+==-=-:.:...=. ...::---+=::... :::......... \n .. ...- ......::==----:-::.::=::+:-:.::-:.... ...-:::---=+==+:====+++++=:: . ...:: .-. .=.::--=-+=--::::::=-.:::. \n .......:......:..:--X+==:=+=:--=-=-:::--==+=--:....::-:.::-=XXXX++++X+===-:-::-:::.-:::-:=::-=------==++==-=+==-::+::.. .. .. \n +:......:-- ::-::::--+XXXXX++===--=-=-::-+++++==--::::::::-=+XXXXXXXX++==-==-----::--=++++++===--=---==+X++++====----=-:..... ......... \n .....:::::-=+==-+=+--==+X-XXXXX+=X+==--=---==+XX+==+--------=++X+XXXXX+XX++=-==++==------=++++X+=+++==++XXXX=X++==+===:+== :--:............\n .......:--.-====++.X+=++XXXXXXXXXXXXX+==---.===X+.+X+X++=.++++=XXX.XXXX+XX=X++++ +XX+X+==--====+XX+XXX XXXX XXX X+=+X++++++===-=-: :::=::....\n",
|
||||
" \n \n \n \n \n \n . \n \n \n . \n .. \n .. ..... .... \n . .. ..: .::. . \n . .: . .... .:-. .. \n . ::. .=.:..::.. .-=. .. .. -.. \n ..: .: :..= .: :-::+:::.:-::-... .. ..:-:-:. \n . . ..:: .. .: .-:.. . ..+..::--:::--:::=:.. . .. ..=::=-. . \n .......::... ..:.=. .. .: .:.......... .-...::-+-:--=--:-:::. .. .=..: :=-.. ..:.. \n . .:.:=::=:..::....::..::: ...:.. ..+::.::.:-:--==:--== ++==:.:...... :... ...:=:-=-::.:.:::-:.-... \n .... .. ...:=+--=--=--:::---:::::::--.... ..:::::::-+X+===--==+===:-:: :...:-:::... ..::::-:-===---:::-- ::::. . \n .......:....::..::-XX+:+++=---------::=++===--:..-::.:.::-=XXXX+.++++=----.::::::+--===---:---:::::==+=======--::+:::.. .. .. \n =.....+::--:::=::+:-=+XXXXXX+=-=::-:-=:--==+X+==--::.:=:::-=+X=XXXX+X+==--=--=- -.::--==XX+==+===---+==+++:-=====--.-=-::.:.. ...-....= \n ....=.::+::---===X==-===XXXXXXXX+=X+---------=++++==++---==+=++XXXXXXXXXXX++====++==-------===+X+==+++++XXXXXX+=+=++====+=-=-=-::..-.::.... \n .... .:.---=:====+X++.+XXXXXXX+.+++++=-- -==++XX++X+XX+++XXXXXXXXXXXX+=+XX.++++=XXXXX+==--=-==++X.XXXXX XX= XXXX++.X+++ += =--=-::::::::.-..\n",
|
||||
" \n \n \n \n \n \n . \n . \n \n . . \n . . . ..: \n . .:. :: \n .: .+. :: \n .. ... .. . .. ...= .:.:: .. .:. \n .: .. .:.. ....:..::..-.:..:.. ..:::+ \n ..: .. .:. ... .. :-..::..::. . . ...:. . \n .::. :. . : . .. . ...+::--:.:----+.... . . ...:: .. \n ..-:..... .-.....-..::... .::. .:..::..::----.:.:--+-=+:.::. .. .: ...-::... ....:+.. \n . .. ..:=-:--: :-:....:----....:::.. :.:.....:-=++=-:::----:=:.. :...::..-.. . ...::- -+::::::=:.....+ \n ...........:=X=++++==-:..::::=:-+=--:-::.....+..=.:-X.++X+=-===-:--:....:.:: :-=-:-:.-::..::---------.::.:..... .. . \n ......-:::=-:.::-=+XXXXX++--::..::-:==-==+=--:::...:..:-++XXXX++++=--::-:::::.:..::-++=---+---::::--==.==-----::::+:..::. ..... \n ......-::::--==-:-=-=+XX=XX+=--=-:::::::-=:=++=--:=:.:-====+XX:X-XXXX+==----+=.--: ::::====++==-----+=+++++++==------.:----:. . ...... \n ...:..:::::-----==+===++XX XXXX+=+==--:::---=++X+X++==--=++XX X++XXXXXXXXX+++=+XXX++=--:::--==-= ++++ XXXXXXXX:+++X+ ===----=--.:::..::..: \n .....:::--===--==+XX++XXXXXXXXX+++===------==+X+++XXXX:++XXXXXX+++++++=+XXXXX+++XXX-+X+= ----=.=+XXXXXXXXXXXXXX++XXXXX+++=.---==-:--:::-... \n",
|
||||
" \n \n \n \n . \n . \n \n . . \n . \n : \n . . . \n .. . .: : \n .. . . . .. ... . . \n .. . . ....+ .. ... . . \n .. . . ... . ..::. :...:-. . . \n ... .. .. .:. :.. . .::.. ::.:::.::-. . \n ......... ..: ::..:-. .:. ... .. :-::.....::-.-:.... .: .... .. \n .:--::::..::. .::-:.=....:. ........:.:-=-:...:::::: .:.-....:. . ..... ....+.=...: \n .:.. ..:++=-=X=--:.......::=:---:::+.. ..=.:-==:-==++=:::::::. ....::::-::::.... ..:::=.::-::.... .. \n ...::-: ..:-+X+XX +==--.. ..:-==-----:-:.: .:---++++++++++=-::..:.. .......:====--:::::...::-:--:-::.::+..::..... +.. \n ..+....::--:::.:-=+XXXX++=--:.....::-=---=+--:.:....:-==+++X++=++=-::::::--:::+....-==---=--=:.:::--===+==-:-:::::::::::.. ..... \n :.. ......::+::-=--- ==+XX:XX+=----:-:.:::-==+=++=-:::+:-==+X:X+++X++X++==-==+X++==-:...:-=---=========++X-XXX+=+==----:+:::::......==.. \n ...+.::::---.::-=+XX=+X=:XXXXX+===--=--:=:-- ====X+===-=++=+XX+X++++XXXXX+X.+++++X++==-::=:-+-==++=+++XXXXXXXXX. :XX++++=-:- -==:::::::... \n .....::--=====--=+XXXXXXXXXXXX-+++++X+=---=++++-+XX++++XX++XXXX+++++++=+XX=XXX+XXXXXX++=------==+XXXXXXXXXXXXXXX+XXXXXXX+=---==----::=::... \n",
|
||||
" \n \n \n \n \n \n \n . \n . \n . \n . . \n . .. \n . . .. .. .. \n : .. ....... . ..:. \n . .-. .. .:. ....:.::. \n . . .. .. .. .. +..:.. ..-::...- . ..= \n .::....:+..: .:. ....... ...........:::::...:.:.. ..- . . ..:... \n . . .-=-:-===--:. .:+::--=.... .:-==---:------::..... .....-.+.:::. . .......... . \n ...... .=.-++==+X++=-.. .:.--:::::.:.. ..-X==-===+==-- ::.... ...-------...... :..:.::::-.+... ..... \n .+..::....:-=++++X++---.. ...--.:-:--:-: .. ..-== +X++====--:..::::........:--:::::::-:.. :::--==++-.::.......... . \n .............::-::: ==+=+XX++--::::....::--==:=--:.=...:-==++:++++====-::-=X+=-=-.-:..+--+:.:-::----=--==++XXX ==-::::::...::.. ...... \n ....::::::-=::=-===-=+:XXXXX+=-=-:::: :..::-=+=+==-.::========++.+XXX:+X++==+==X+==--....:-:---=-=--=+:++X=XXXXXX.+====+::::-::..:+:.... \n .+..::::-==----:+X++++XXXXXX+== ==++=-::--=++X++X+==++X++-++==+++++XXXXXXXX++++X.X++=--::.:::-=++++++=X=XXXXX+XXX+X++XX+--::=--::::::... \n ....:: --=====---=+++XX.X=XXX++=+++X+=====+XX XX+XXXXXXXXXXX++= ++++X+=+XXXXXXXXX+X-XX..=-- =-==XXXXXXXXXXXXXXX+.XXXX-XXX=--------:::::.-. \n",
|
||||
" \n \n \n \n \n \n \n \n \n \n . . \n . . .. .. \n .: . . .. \n . . .:.. .. .. \n .. . .. .+... . \n .. .::..: .. ... ..............:.+. . .. . \n .:..::::---=. ..:---:. . .=--=-:.-::..=:-:. . .. ..... . . .-. \n . .:==-----+=-:. :--:.=.-..... . .-===::---:-:::::. ..::-:--:. . .:.=.::--.. . \n ..... ..:-=== ===.-:: .::::..:: .:.... ..:==-=+=+=-=-=::.+.:.... .:-:::.. ...+... .:.:::-=++::.. .=.. \n . .. ..-...:..::+====.++=-:+::.... .::::---=::.. ..:::-=+==-+X+===-:.:-+=--::=:: ..::.:. .:..:+::=:::--=+XX+---:...::.... .. \n ..:.+....:--.::-:---=+X++++==-:::::......::==++--:..:==--=-=--==+X==++=---+-=+==--::. .:::: :-::::--+=--=+XXXXX++=---:=-:.:....=.... \n .. ..::::-=-::=++==+XX.XX+X+----==.--::.:-=+X+X+===-=X+===----== XXXX++++==++++++==-:....:::.==-=--==XXX=XXXX-X:++==-++=:::--:::::....= \n ...:.-::-====-.-=++:+XXXXXX+==-==++=----- =XXXXXXXXXXXXX++=---:==+X.XX.+XXXXXX+X+XX++++-:.::--=X++:X =XXXXX++.XX++X++X+++--::--:-::::.:. \n .-..::.-=====-=-=+++XXXXXXXX+:+++XX+=+===+XXXXXXXXXXXXXXX+======++XXX++XX XX.XXXXXX=++X=--====+XXXXXX+XX+X X++++XXXXXX++=--- ---- :::.: .. \n",
|
||||
" \n \n \n \n \n \n \n \n \n . \n \n .. \n . \n . . .. \n ... : .. ......... .:.:. \n .:..+....-:. .:::-:. .:-:--=:.+.... .. . .:... \n .:==-::::-=:: .:::..... . .:==--:--::.-::.... .-.-:::. ... .::-:. \n . ..--=-------:.. ..::....:::.-. ......==--:--=-:=-+.+....... .:-:....- . .....:-==-:. \n .:......::-==--==--:..........::::=---.. ..:==--==---=-----...:=-+--:......:.... .. ........::--=++=-:.....:.. \n .....-.:::::::::-==+==--:-:.:.:... ...::-++=--:...:=---.-=---+=-==-::+==----.:-::....::..-:....::==::--=+X++=-::::+:-:.... -.. \n .......::-=-:=+=--++X++==-=-::-==::::.:.:-+XX+==---+==--=::::--+X=====--====-=+:--... ....:-=-:-::-=++++++XX++==.----==-::-:...=... \n ..:.::::------====+XX+X.++=---.==-:-::.:-=XXXXXXXX+++=- --:::--+XXXX+++.==++++++==-=-:....--++:===+XXX++XX+++X++==-===--:::::::::.... \n ....::---------==+=+X+++XX+=====+++==-:--=+XXXX+XXXX-++==--::--=+XXXXXXXXXXXXXXXXX+= =-:=:-- +XXXXXXXXXXXXX++=++++++++=--::-- :::....+ \n ....::-=====--=-++++X++++XXXXXXXXXX+++==+XXX:X+XXXXXXXXX=--.-==+XX-+XXXXXXXX+XX+XXX+++++=+++=+XXXXXXXXXXXX+++==+.++XX++=-=--=--- ::..:. . \n",
|
||||
" \n \n \n \n \n \n \n \n \n . \n \n \n .. .. \n .. . ...:. \n . .:. ...... .:=:-=-:. . . \n .:--::..-.::. ........ .. :-=-::::::.-..... ....:. .....:. \n .::--:=:::::.. ..- ...:.:. .::---:::::::--+.... .... .. .... ::-.. \n .... ...:--:-::-::.::.. .......--::.. ..:=.---:::--:::....:--:-=. . ..... .. ...:..:.:+:--- .. .. \n +...::.=..::-==--:::::::::.... .::=+=-::.....:::--.---=----:..:--::::.:.::...-+...=-.:. ..:==:. ::- ===-::....-:.. \n . .-.:-:--=--:=+X+=--=:::::---:....::-=+X+=--::.--:+:..:+:=+==---:--=--::-::-:... ..-=:::::::-===--=+++==-:::::::::::....... \n .......:: ------==++X+== ---::==-+::.:.:=+XX=X+++==--::....-:-XX+=++++========---:-:. .:-+=---=++++ +=+X+=====-------:::........ \n ... .:::-:---==:===++XX+==---+++X==-:.:-=+XX=X+XXX+==-::.:+:-=XXXXXXXXXXXXXX-++==--:....:--X+XXX-XXXX-XXX+==+====-=---::::::..-=.... \n ..::=.-------=+-===+++XX++==+X.XX+:+---=+XX:XXXXX:++:=-:::-:==+XXXXXXXXXXXX++ X+=====--===:+XXXXXXXXXXXX+==--=++X++.=--::--=:::...... \n .... ::-==--=-=+X+XX+== ++XXXXXXXXXX+++++++X++:XXXXXXX+X+==---=++=XXXXXX:XXX++ ==XXXXXXXXXXX++XXXXXXXXXXXXX++====++XX:+==-= ===--:.....:.:.\n",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n . . \n . .....: \n . .:-:--::. . \n .::=-... .. .......... .:-::....=. . . . . \n ..:::::....... . ... . :.:-: :.::. .... . . ... . . ... ...... \n .. ..::=:::.......... .-=..:. .:::-:::.::..... .::---:. :. .:.+.:....:::. \n .-....::-=--::.:....:.:. .-.---==-.. ...:..:::::=-:.::..:--::..... =.. ...=-. ..::.....::--+-:... .. \n ..:---::--=X=--:.:.:.:-:-:.....:--=+X=::..=:::.=...:-+=---------::-::..::.......:-:....=.:----::-==-=--:......:::.. . \n .-..:--:::-=--++=-:+::::---=::...:--=+XX+=++=--::.....::+X+++=+X+=====-.-:::::. .:--:::-==-+-=:==+.+---:.::.::::.....- .. \n .......::-::------=+++==-.--=-+X+==:..:-=+XXXX++X==-::..:::-+XXX-XX+XXXX+===+-=-:.. ..:::=X++.XX++++++++++--=--::::::-:-:. ...:... \n ..:::::--::-+==-==-=+++=====++XX=++::.:-++XXX.++++==-:...:--=+XXXXXX X+XX===X+==-+--:--:-=+XXXXXXXXXX+++= ----+==--=-:::--:........ \n ..:---=---==X+++=-===+XX++==+XXX===.===+++ +XX++====+--::--=+XXXXXXXXXX++.==+X-XXX+++===-=XXXXXXXXXXXXX+=----=+X++=-----==-::........ \n ....=:--======+XX+X+=----=+.XX+.XXXXX+=+=++X+=+XX XX+==--=---=+XXXX-X=XXXX++===.=+XXXXX.X.++++XXXXXXXXXXXXX-+++=++X XX++==++===-:..........\n",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n .. \n :::::.. \n .... . -=...... .::..:...+ \n ..::.... .. .: .. .--:::.+... .. .. . .. . \n . ...:..-... .. .. .=.. .. .:=:::::.:. ... .:::.. .: .. . .... \n . ..:--::...:...::..: .:-:..-:... ....:::::-:....+..:-:.::. .=. .. .:....::::. \n ..:.:..::-=--:..+....::::. ...: --+-:.-. .......::+-::::: ---::::... ... ..:::. . ..::::.. ::--- -.. .. \n ..::-:::---+=-:..::..:::-:....::--=++=-:-:-:::-....:-+=-=+==++=-.-+::..:::..= ..::.....:::-:-=-----=-:......+:...= . \n .-.:::::::--.+===--:::-=:.==-:.+.::-+XX+++++-- :.. ..:-XX++++XX++++==-=-::.. ..=:=+--:++=:=-=====:=-:::...=.::......+ .. \n ......::-:--=----=++==---==-=+XX=-:..:-=+XXX+++:==--:...:--+XX:XXX+XX++=-==+-+-:=...::: +X++XX++=+++ +=+=----=:.::::-::-..... .. \n .:::::-::--+=--=---+X+===-=-=+XX++=:::-=+XXX.+++===-:-..:-=+X:X:XXXXX XX===XX-++=--+-::-=+XX++:XXXXXX++=-::--====---:::--:...+ ... \n ..:-----:-==X++==-.--+XX++==+X=X++==+==+XXXXX+++==----: :-=+XXXXXXXXXX+=====+XXXXX+++=---+XXXXXXXXXXXXX+=----=+X++==--=-=--:.+..=.... \n .+.::--==-==++XXX+=----+=+XXXXXXXXX++==+++++=XXX=XXX==------=+XXXXXXX XX.+===== +X-XXX+XX===+XXX=XX=XXX=XX+.++++XXXXX:+++++==-:.... .....-\n",
|
||||
" \n \n \n \n \n \n \n \n \n \n \n . ...... \n . .. .. ...=::.. \n .+.. . .:. . .:.. .=... : \n ...:.-.. .: . .:. =.. ..:.....:. . . . \n ...:::..:... ..... .:.....-: ........-+:... ..:.:::. .: .... \n ......-:--::. +.. ... . ..:::::=:...... -..:==:.:::..:=-:::. . .. ... ......: ::... . \n ..:...:-=--::...:.:+:..-::..::.---==-=-:.:.:.. ..:==----:-=+==--::.. ... .::. ...+:::---=:::-:.. .... \n ...:::=::-=--:--=::--::-==::..:.-+++===+=-::.. ..:-X++++++++++=--+-:.. ...:-:::-==------==----::.-... ..... \n .. -..::-:: ::-=------------X=-:....-+XX++====:--: .:=X =XXXXXX+==--=+-::::..:....-+====+===-= ===---::-::....+.....= \n ..+:..::::-=--::::-++==--:::--+X+=-:..:-=+XX+=------:. ..-=+XXXXXXXX+=+=--=X==:=-=::..::+++==+++++++++=--:::==---::::.::.... .. \n .:::::::--=== -:-:-=X:X==::-=++++=-=====+-XX++==-::-:..+:-=+.X+XXXXX+=-=--+XXX-X+==-:::-=XXXXXXXXXXX++=-=:::-++===-:::--::.. ..+ \n ..:---===-==+++=-.:::-++XX+==+XX++==-====+XXXXX+++=---::::-=+XXXXXXXX++=-:-==++XX+++=+=--=X:XXXXXXXX=X+++=-=-=+XXXXX+===--+:... ...= \n ...::.--+==++X+ +++=--.:=++XXXXXXXX+.+==++====++XXXXX+==+=-==+X:X-XXXXXXX+==--+==+XX.+=-=+==++XXX ++XXX-XXX: XX X-XXXXXX+ +=--+:...:......=\n",
|
||||
" \n \n \n \n \n \n \n \n \n \n . \n . .. . ........ \n .. . . .. ..:.. :. \n .... . .. .. +...-=.. .. \n ....... .. . .. .-. .. ....--:.. . ..: :... \n .. . .:::.. . : .+...::. ..:-:.........::-........:-=-::-.. . .. -... :..... \n ..=...--::-=.....=+....-:..:.....:----:.:... ..:=-:::::--=-==--:. ... ......:.:--....... \n ...:...:--=:..:::-...:::+-...:.:--=-----:::. ..:+X+==++ ++== -=-:... ...:-..---:--:.:---:::=:.. . \n ...-::..::-=:+::=::::::=-+-:....-+X+===----:.. .-+ XXXXX++X==-:-=-::..... ..-=---=---::::---- :=::.:.. ..... \n . ......:::--:.::.-+=--+:..:::-=+--::.:-=X++==----:::...:-=+XXXXX+++=-=-:-==---:.+. .:=+X=:===-.-===--::: :-:::-:........ \n ...:::.::-=---::::-=X+=--::::-==+=--==--+XX++=--=:::....:-=+XXXXX+=+---:--XX-XX+=-::..:-=++++++--XX+=--:..-:-==---:-::-:=.. . \n ..::----:-=-== -::.:=+=++=---===+= --===+XX+++===X---:..:-=+XXXXXX+==--::--=+X++==-=-::-=+XX+XX+X XXX+==-:::-=X++++=----:::.. .+. \n ...:: -----=====+=-::::-=++X++++XXX+=--==+=+:++XX:+++ ==-:--=+=XX=XXXX++==-:-==+X++==--==--+XXXX+=++XXX XX+++++XXXX ++====-.--... +.... \n ...-.:: ----:===.+==X+=-===++X.XXXXX++X+XX+=-==-==+XXXX++====+XX=X XXXX+XXX+======XXX++=-=-===++XXXX++X XXXX+XXX=XXXXX ++++===-:--:..........\n",
|
||||
" \n \n \n \n \n \n \n \n . \n . \n . ..:: \n . .. ::. . \n . . . .. .: ::. \n +... . .:.. .: .:::. .. ::...:.. . \n ::.. :.... ..::.:.. ..:-::.. .:: --:.:. . . \n =....-::.... . :-::. ..::.::-.::. .:--::.:-::-----+-.. .. .. .....:. . \n .... ::-.:....:.. . ..:=:.:..::::::..::-.. ..=+=--=+X+--=--==:... . ...... :::.. ... ::..... \n .-... ..:-=:...:::......--:=..:=++=--:::::. ..=XX++XX++===:----::.. ..-::.--:........::::-:.. . \n .....-::-...:-+:::::..-...:--::-::==++=--:.::......:-=+XX-++==-=-:::-+-::-:.:. ..:+X+==---:-::-::::.:::............ \n .. .:..---:::...:=+--::...:.:-=-::-==-=+++==-:-=::....:-=XX:X++=-=-::-:=X+=++=-:....:-=========++=-:. ...:-:::::::.:: .. \n .::-:.:::--=--::..:-=+=--:+:----=-=::-+XX.X+==---=-- ..:-+XXXXX++=--:..:--+X+==----:..:-+:+++++++=X+---:..::=X====-::.:::. \n ..:::-:::- ---+=:...:--=++=+=.==++=-:---++X+X+===-=--=:::-+XXX==XXX+=-- ::--=+:+==-:-=:-=+XXXX+=++++XX++== ==++.X+=----:::::. \n ..+...::-----------+=::--=+X+++++==:++====----===X+=+=+=+==-=XXXXXXXXXXXX+===+==+XX+==-:-=-=+++XXX+=:++XXXXXX+X-X+++++=+=---:::+:......... \n .....::::-----------=++==+:XXXX-X.XXXX+X+=-::-:--==XX+X+XX+ ++XX+:+XXXXX-X:+++++.+XXXX=--=.====+XXXX++XXXXXXXXXXXXXX+XX++==--::::--...::.....\n",
|
||||
" \n \n \n \n \n \n \n . \n .: \n . :. \n . . .. . \n . . .. \n .. ... .. .:. .::- \n :.. .:. ......: .::. ...::-:. \n ::.. .. .-. . . ..... ..:::.. ---:: =---:. .. \n . ..:::. . . ..:-.. .:..:........ .:----=+-+=----::-:. . ..... . ..:. \n .. ....::-:. ..... ..::-:.-====-:.:.... .:+X+=:++=-----:--:.. .:.:.::.... .. .:.. \n .. :.. ....--:..: .. .::..:-=--===::..::: .=.:==X+X+==--- -:.:-:...-: .:-++==--:.:..::........ . . .. \n ..::-::...:.:--:.....:. ..: ::.:-=.===-=-::--:.=.:-=+XXXX+=- -+:::-+=--+-::. .:--=-=-----=+=-:.. .=.::..- .....+. \n ...::....::--:+....:--:::::.::+::::..:-+XX+=-:-::--::..:+XXXXX=+=--::..:-=++==-::.:...:-=+=+=====++=::.....:==-:-::....... \n ....:..::::::--:....:-=---===:--==-:+::=++X++-:-:-:=--::=XXXXX++++=-:::=-:-=++=--::-=::=+XX+X+=-==+X+==-----=++==-:::::..... \n ....-::::::::::::=-..:-==X++=====-==---.::-=+=X+--- -==--:-+ ++XX+X+X+=---==-=+XX==-::-=--=++XXX+==+=+XXXXXX++++==+=--::::...:. ... \n ...-..::::----:::-:-=---=+XX-XX++++====+-:..: ---++=-+=+====+X++=++XXXXXX+===+++X=++=-::--=-==-+X++=+-+XXXXXXXXX++++ +=+=-::.:..:.-...-... \n -.....::----==-------=== +XXXXXXXXXX++-++-::.::====XX++++==+++XX ++++XX X XXXXXX++++++=--==+==-+++XXXXXXXXXXXXXXX++-XXX+++=--:::: :.:-::::.:.\n",
|
||||
" \n \n \n \n \n \n \n : \n . \n \n . . ... .. \n . ... . :. ::. \n .. .. . .... .::.:..:-.:.. \n .:... .:. . . +..=::===--::-:.. \n ..::. .::......... . . ..:--:--X+=-::::- .. \n .. ..:. . .-...:===--:.... .: ..-XX+====:-::::::.. ... :...:. \n .:.:. .::. .. . .....-==:- -:...:.:....:-+X++++=----::..-:...:.. .-=+=--:..::::... .. . \n .:::... .::. .. .. ::....--+=--::: ..-:...:=+:++X++=-+:::::-=-::.-... .---=----::-+=::.. .... .. \n .. ...::.. :: .=.::...........:=+X+=-:.:..--:::-+XXXX+===-::..:--+X=--::... ..:-+==+=---==--::.....:+:....+ .... \n ...... ..:.:.::. .:----::-=:.:=:::::.-=+X=-:. .::::..:-+=XXX+==-::.=.--:-++=--::.::.:-=++ X=----=+=--:::+-==-:::.+.. . \n ..............:-....:--=++=---==---:::::--=X=-:.:::---:::-X+++XX+==-::::==-=++==-:.:- --==+X++=---==XX++XX+==-==--=:::... . \n .-....:-:-:-::+::::-::--=+XX++=======-=::..:---+=--:==-----.+X+==+XX+X+=--===.XX:==::..:-=-===X+==-= =+XXXXXXXX+==+==+--:........ .... \n .... ::: . ------:=::--=+XXXXX-X++X==---:....:-=+++=-==-----++X+==++XXXXXXXXXXX++++=-::.:-=--==+XX+=++++XXXXXXXX++XX+:++=--:.:......:::.... \n ......::--======.----==+XXXX-XXXXX-====--:::::===+XX ++====+++X++XX++-+X=XX+XXX+:++X+=- -=.====+XX:XX+XXXXXXXXXX++++.XXX+==--::::::::::::.+.\n",
|
||||
" \n \n \n \n \n . \n . \n . \n \n .. ..+ \n . . . .::.::..:: \n . . :. ..:--=-:::.. \n .. . . ..-..:--=-:::::. \n . .. .....-. . .-::+::--=:::.:.. \n . .. .:-=--:...... .:...-=XX+=-==-:.:+:.. .. :+...... \n .. .. . ..:-:==-:::. .. :..:-=++======-:.:. ....: :--=-::.-..::. . \n .... :. ..= .....:--==--:... ..:..::-+++=====-...:::--:.. .-:=--:-=-:--:::.. \n .... ::....+:. .. ...:-+==-..... ..:..:-++++==--:...:--=X+=-::. .. ..--=---=----.:::. -....:.. \n . .. ..::==::.::=........:=++=-... .:....-+XXX+=--:....:---== =-:....:..:-+===-::-:--.:.:::::-=::+.. \n ......... .:. ..::-===-:::-=--:..:.--++--:..:.::::.:=+X++X+---:...:=--===:--..::--:-=++=---::-=X=-=++======--:..:. \n .......::.:.::...::..:-===-++=-:===---:..:.:-=+-::.--:.:::-=++==+X===--::-==++X+=-....:----=.++-::.-==XX+X++XX+=====-::....: \n ....::::::-:::-:.::--+XXXXXX++==+=--:-...:.::-=X=-::-:::::-==+===++XX++==X++X+-++-:..=.------++=======+XX.XXXX++++==--=::.:. ....:..... \n ...:.:::-==- -=.::--=+XXXXXXXX+++:---:. .::=-:-+X+=-----:=.====++++XXXX+++.X++==++=:::-= --==+XXXX.+++XXX:XXX-XX++++=++=-:- .....::::.... \n ......::--==+.==+=--=++XXXXXXXXXXX==---::: ==X+===+XX++==+++.==++++XX+=+.XX++:+==++XX+=-=+=.===++XXXXX-X.XX=XX++==-++X+XX+==.-::: ::-:::=...\n",
|
||||
" \n \n \n \n \n \n \n \n . .. ..- .... \n .::-:::. . \n . :..::-:.. \n .. .......::.::... \n .... .. ..::==--::-:.... \n .:---.-.. ...-=+:+==-::::..+.. .. .. \n . :::=-::... .=.---+==----+:..:. .. ::=-:....::.. . \n . . . . .:--=--:: .-..--=+===---:..::.::.. :::=-:.::-::.... \n . ....= . . ..-=--:. . .:-=X+==--:.. .:-=+++=-.. .:=:--:.:::::.. . . \n ..:--:=.....=. .-.== -:.. -... .-=+XX=--::. :-+===--:.. .-. ..-==--::.:=:...-.::::-::.. \n . . ...::-----.. :--. +..:====-..:..:.+..:-==+X=-:::..=.:=--==--:...::-:: +===-::..:--:: =---==--:.-.. \n ........... .=...::---==--:::=-:-:.....:-+=-:..::.....:==++.+=---::.:==-++X=-:. ..-::-:=++=-=:::-++======X= =--::..... \n +:........::::..-.:=XXX+XXX=--::--:=:. .=..:-++--..::...:---====+==+--:=:=+ +++=:. .-----=X+==----==X++++=+++==--:::::... ..... \n .=.:=::::=-:--::.:-=+XXXXX=+==--:::.. .:.:--=+X=-::::.------==+XXXX++==+ ====++-:...-=:-=--=XX++====+XXXX+++X+++==-==-:::.. ....::.... \n ....::.--==--=-----=+XXXXX-X++=+--:::::..--=X+-=+X+====--=--===++XXXXXX++=-++= =++=: :-----==++XX+=++XXXXXXX++ ++=+++++=-- ::...:::::.=. \n ......::-===+=+++===++XXXXXXXXX+++===-:::.-=+XX+==+XXX===:+X==+XX+XXXXX+XX++======++X+=---== ++-=+XXXXXXXXXXXX++==+.+XXXX+=+==--::--::::....\n",
|
||||
" \n \n \n \n \n \n \n . .... . \n ..:--::.. \n ....::.. \n .. . ..-:... \n ... ..:--:--:.::: . \n .::::.. . ...:---+=--:..... . . \n .::-+-.... ...==++=----::.... .--:.. . .. \n .-::---:.. ..:--==.---::..::=..... .=.--:..=.::=.. \n .. . .::--::. . .:-=+==--::=.. ::--:-::. .:::-:....::.. \n ..::. .. . .:-=--... .:-=X+=--::. .:-:++=--.. . .::--:::..::. ...=... \n ..:::-:.:..::-. ..:+=--:.-. .. .-==X+=-::.. .::====--:... ::.::==--::..:::....::::-=-:.. \n .. ........::-=---:.:-:::. .:-=+--:..:+.....: ==+X=-:: ....=--==+=-:=....::--+==-::..::=--:-::-=+--::.... \n .....+.::... ..:-== =-==--:..:::-:. ...:=+-::..... :-=-=.=+=--+.::-=--++X=-:. .:----+X=-:+:---++====.++==--:..:::.. . \n ........:-:::...:-+X XXXXX+--: :::.. .-.::-=X=-:..:..---:--==+X++.=----:== ++-:. .-:-:--+X++=---=++++++==++++--: :-::.. ...... \n .=..:::-:------..:-+XXXXXXX+==-::.... ..:-=+=++==---::.--:-=:=+.XXX++==-===--++-:..:-::----=+X+==-==XXXXX+=++ ++==--==::::. ...+:..... \n ....::-:-== ==-=--==+XXXXXX-+++=--::.:..:--+X+.==++=======- -=+++XXXXXXX+=======++=-::-:--.==++.X+=++XXXXXX++=+++=X+-++=-=--::..:::::... \n .....::-=-=+=++++++++XXXXXXXX++X+ +=--::--=+XX+==+XX+===.=+=++XX.++++XXXXX+====:==+X+= --==-+X==++XXXXXXXXXX++==.++:XXXX++===--.:--::::-.. \n",
|
||||
" \n \n \n \n \n ... \n ......::.. \n .:..= \n .. \n . ...... .. \n ....=..--:+:. . .. \n .:--:.. ..-=--=-:.... . . \n ..::--:. .---==--:: .. .: .:-::.. \n ..:--.: ..---=-=--::....-=.... . .:::....:.. \n .:--::. .:-===-:::=.. ..:-::-:.. ..:::- ..... \n ..- . . ..==-:... ..-=+=-:-... ..==++-::. . ::-::..-... ..... \n .:::: .. .:+=-::. .. .-=++=-:... .:---=-::+......:.:X--:..:.....= ....:--::. \n .........-::::..:+::.. ..-==::.-.. .:===++=- ... :-:--==-::... .::-+==::...::-:..-..:----:.. \n .:.=. ..:--+=-----:::....:. .::=+-.=. ::::--+=-:: ..:-::-==+-:. :.::-++= --::-+X=-=----=---:.. .... \n .-... .:::: ..:=+XX++==+=:.:..... ..:-++::::.-. .:::--=XX==-::::.:--+X-:. .:.: :-=X=--:::-=+= ==--==+--:.-..::.. ...=. \n ........::=-::..:-++XX++-+=--:.-. .:-++++-:.:--..::::--=+XXX+=--::-+--==-:. .::.::: :-=+--::-=+X+-+==:==+=-::::-::... . .... \n .+..::::-:---:-:::-+ XXXX++==+-::...=. .::-+X ===-::::-------==++X.XX+==--=---=+=:..:..::::--==+=--+XXXXX+=====++=-==----::...:.::.:. \n .:.::--=====++====XXXXXXX+==+==+=-:::::-==++==++==--=::--==++==+XXX-XX++.======X+-::.::=-=++==++++XXXXXXX+==-=+=++ ++==----::::::::.=. \n .. ..::-===+==++XX+XXXXXXXXX++=++X+X+=-=== +=++=++XX:==---=+++++++=+++XXXX++=====-+XX==-===-+X==++XXXXXXXXXX+=-==++X+X+-+===+=-----::.... \n",
|
||||
" \n \n \n .:. \n \n ...=. \n \n \n .:.... \n .-..::... \n .:---::. .:-=--:=.... .. . \n .:=::. ::.:=-- ::.-. ..::-:.. \n ..-:.. .-::=--:.... ..:... ..-... . \n ..=::. .::---::.... :--::.. ...-:... . \n .. ..+-:.. .-=--::. :--+-:... .::+:...... ... \n :..:.-. ..==:.. .. :-++==-::. .---:=-:.=. .::+-:..=. .:::... \n .:::..:.... ... .-==-. . .::-=+=--:. .:: :-=--... ..::=+--::...:........:::-:. \n .......::::+-:.::.... . ::==:..: .::--=X=-::...::.::-==-:. ...:-=+=---::-+==-:::::--::.. ... \n . ..-:.=.:-++++=--+-:-.. .:-+-:...... ...::-=X+=--:...:.:=+=-:. ...:.::==-:::+-==:----::--=-:. ...... .. \n . . ...:: =...-==+X++===-:-.... .:=++=:...::. ..:---=+XX+=-::..::--==:. .:... ...:=-::.::=+=====--==+-:.....:+.. ..+.. \n .......::::::..:-=+XX+=.=-==:::... ..:-==+=-:.....:..:---==++XXX=-:---::-+=::. . ..=:+:-.-::.=+XXXX====-=+=-:-:::::.. ...... \n ..:::------=--- =+X:X++==-== =++=:.:.:::--=:===-::....:+:-= ==++XXXX+==--===.X+-:.. ...:-=---=--=+XXX.XX+=--====+=+=----:.......... \n . .=.:------==+X++++XXXX++.==-==+XX+-+-=-===-=.=+++==::::-=X++++=++XXXXXX+=--==-=+X=-::--:-=X===+=++XXXXX=X+=-=+=+XX+=====-=--:::::=... \n . . ...:--======+++XXXXXXXXXX++++++XXX++===:+++==+XXX.++=---=+XXXXX+-+++XXXXX+=======+X+====++=+.++XXXXXXXXXXXX==+++XXXX++ ======---:.::..- .\n",
|
||||
" . \n .. \n \n \n \n \n . \n .... \n . ..--....... . \n ..:==+::. .::--+.. . . .. \n .+.-.+. ...:--.:. .. =..-:... \n ..-:. .:-:---.. . . . .:... \n :+-. ..:--+... .:-::.. ..:-:. \n .==:.. ..-+--:... .::-=-.. .:=-.. \n .:-.... .-+-:. ..:++--::.:. .::----:. ..==:::. ....: \n .::...... .--=:. .:-=+--::.. .....::--:.. ..-+-::.. .. .. ...+::.. \n .. ...:-::.... . .:-:.. . .. ..:-=XX-::. ......:=--.. ..:-=:-:..:==-:::.=.-:::.. \n +..:..:-=:=+--:::.... .:==:... .. ...--=X+--:.. ..:==--:. ..-:..::--=-- ::-:-::-:. . \n .......:--=+==-:-:::... .:--==-.. . ..:--=+XX+=-::...:-=+-:. .. . ..:-::..:--==-==::.:=-:... ..=. \n .........:....::=:=X+=-----:--:.:. ..:-=.=:.-. -...:--==+XXX=-::--::+=+-:. .:::+:...:-=X++X=----==-:::::..-. ..+. \n .+..:::::-::::.:-=+X+==-:----+==+=:+..::=--==---::. ..:-=:--==:++XX-=-:--==-=X=:. .:--::-:::-=+=XXX++=--=======- :::....=:... \n .. :--:-:--==+++=+X+X+==-- :--=+XX=-:---=--= ====--...::-+==+XX++XXX:X=--::- -=+=:..:-:::-==--=-==+XXX:++=+-===+XX==.-----::::=...: \n . ..+:----=--==+++=XXXXX+==++===-+++=---=+==-+XXXXX+=-::--==+ XX+XXXXXXX++=---=--=++-::--==-=X=:+++XXXXXXXX++-== +X-X++=---- -:::+::.. \n . ..:::--=++= =+=+=XX+XXX:X++XX++++++==++X++==+XXXX-X++=-==++XXXX:X X-XXXXXX+=+===+-++==+-===+X+X:XXXXXXXX.X+===+XX++XXX+==.--=--:::+:+....\n",
|
||||
" \n \n \n \n \n \n . \n .-:. .:----:.. \n .:--:=.. ...::=-:.. .:. \n . ::.. .:--::. ..... \n .-=:. ..:--::. . ..::. \n :=:.. ..==::. .:--::. .:-:.. \n ... .-=:. :..++-:.. . .:.:-::. .-:.. \n ... :=:. ..=+-::... . ...::--: .--:+.. .. \n ...=... .::. ..--+==-.. .:. ..::-::. :-::.. . . .... \n .. ::-.. . .::. .:-=++-:.. ..==::. .::... :--::.....::.-.. \n . ...+:::--:::..= ..---.. ..:-=++-::. ..==-:.. ..::. .=::-:::::-.. ::.. \n . . ..::::----.::::.-. . .- --:. ..:--=++=-:....+.-=+-.. ...:. ..::-----+-:.:-:: .... \n -...... ..:---==-::.::-:::.::. +..:==--:.. .:=::--=+++X--:::::::=+-.. .:..:.-...:=+===+=-:.--:::...... \n ...::..:.:: ---=++=-::.::-++--:==:..::-:-+--:-.. ..:-::--++++ +=:..::--:=+-.. . ..:-..:::::-+X=++=--::-==-==-:=........=:. \n ..:::::::--:-=-++X+=--:::::--=====-::-= --=--=-:. ..:-=---=+.++XX+=::...-::-=:. ..:::.:-::=::--=+XX+====-=--=++=-+::::.. ....- \n ..:=------:-=-=+X+X+=--=-----=.=--:--X--=+X+++==-:..::-==++XXXXXXXX+=-::::-:--=-.. .:-:--+--=-=++X+XX+++==---=++==---=:::=:::...+ \n +..::--=---===+==+++++++=-++========-=XX+==+XXXXXX+=:::--=+XXXXXXXXXXXXX+-----====-::-:-==+XXX-XXXXX.XX X+=---==+++-=------:::::..=. \n ..: :..:::-==.=--=+X++++XX+-XXXXXX+:==++++XX+++=+XXXXXXXX=--=+XX-XXXX XXX.XX+++ ++==+XX++==-=-=+ X-XXXX+XXXXXX+==.++=++XXX=----=--::=:::: ...\n",
|
||||
" \n \n \n \n \n .. ...... . \n .::.. ..::=+-::. \n .--... .. ...-:.. ..- \n ..:-. ..-:.+. .:. \n .-..- ..=-:. .. ..: \n -:. ..+-:.. .:---::. .:.. \n ..- ::. ..-+:::. .:=::. :... \n .-. ..-+=--:. . .+.-:.. ::.. \n . .. .:. .--====:.. ..=-:. .:+.. ... \n ...... ..-. .:-==-: : .+=:.. ... ::- .....:.... . \n ... ..... . ..:::. .:.:-===-:. ...-+-:. .. .:.:-:....:...:.. \n .......::........ .:=-:: .::.::==++=:=..:..--=-. ... . .::-:: :--:.:-.:. .. \n . . ..::::---:. ..:.:....--:.....::--:--: ..:+-:-:-==++=::...:::-=:. . ........:-+-:-=-:::::...=.. \n -...-......-::--+=-:....:---.-=--=:+:-=--:-::.. . .:-::::=====+-:. .: :--. .. . . ....+..-++===--::::--::-:..+. \n .-.::...:...::-=+=-::.-.:.:---.=--::-+-:---:-:.. . .:-=--== == ==:.. ..:--. ..:..:......:-+++===--::::-=-:-:... . :.. \n .::::::::.::--==+=--:::+ :::-----::-++==++=---:......:-+X++X+++X++=-:......--:. ..::=-:.:--=++++==--=: :-==---:::......... \n ..:::-::+:--=--====+===+==--------:-=X++ XX+++X++=-:..:-=+ XXXXXXX X++-:::: -.--:..:.:-=+X+++ +=+XX+X++==:::--= ==--.:::::..... . \n ....::---.::-++===.+XX:XXXX+++--=====+++==++.XXXX++==-::-==+XXXXXXXXXXXX+=.==-==+==+--:--=+XXXXX-XX.XXXX=+=--==-==++=-:.:--:: ..:.:... \n .+...::-:--===--=++=+++++XXXXXXXXX+===+X+++++=+=+XX=XX++====++XXXXXXXXXXXX=++==+=+XX-XX++=-:==++XXXXXXXXXXXXXX+==+X=++XX+=-:-=-:::: :::=..:.\n",
|
||||
" \n \n \n \n ... ..+-:.... \n ::. ...::-::.. \n .::. . ..-... . \n .. .-=:: .. \n : .:=-:.. ... .. \n :. .-+:::. .::-=::. . \n . .:X-::-. .. ...:... . \n .. .:=--:-.. ..-:. . \n . ::=-=--.. .+-: . . \n .... ...:---=-:.. . .-=:.. . ..::. .. \n . ..:... .-:..:--==-.. ..+.:+-:. ... ...::.. ..... \n ..... . .:::=-:. .::...-=-==:. ..::-=:. ... .:.::.:..:...:. \n ....--:..... .. ..-:.. :=::.::. . :--:.:----=-:. ...-:. . . . ..-::.:.::..::-.. . \n .. ..::-::. ........-:-=::==::..:..: .:--::--=----.. ..::. .. . .-=----::....::.::.. \n .... .. .:::-=-:.. ...::-:-=-:-::=-:=::.. .:-=---=====-. . .-.. . .. ..-==---:.:-....::::... \n ...........::--=-:::..-::.:-::--:.:-+==--:..-... .:-++XX++++==-:. . .::.. ..:.=. ...:-=++- -::::..:--:-:=.. . . . \n ....::.:..:-::--=:=----:+:-=--:-:.:-++XXX+=-=+=---:...:-=+XXXX=XX+==:....+:::::. ....:=+==-::--==+XX==--:..::----::. ......=.. \n ....:-:::::+=----==++X++====+-:----.==+=+++X++=+==--=:.:--=+X=XXX=XXX++-:+::--=-:--:..:-+XXX+:++==+XX XX=-:-.----+=-::..::......... \n .. .. :::----:::-=--= =+XXXXXXXXX+=--===+-====++XX++=+=-----==+++XXXXXXXX+++==+=XXXX++=-::--=+X+X++X++XXXXXXX=-==+===++=-::::::::...::.... \n ......::-===+=-=-====++-+XXXXXXX..++==+X+======+XXX-+=+=--=+X++++XXXXXXXX++======XXXXXX++-===+++=XXXXXX=XXXXX++==-++XX+XX+= ---::::::::::. .\n",
|
||||
" \n \n .. :+:. \n ... .--::. . \n . ..--:. \n .. .--:. \n .. .:=:+.. \n . .--...:. .-:.. \n :=:..:... .::-:. . \n .=:. .. . :-:. \n .::::::. .:=:. \n .. ::-::::--: .. .--.. .. \n .. .-. .:..::+:--.. . .:+:. . ..... \n . .:...: .. :.:=::: ..:=:. . .... . .. \n .. .. .--::.:. :.:. ::.:::.. .::. ..:.. ..... \n .:...+ ::...:=-.....:. ..-=..::-:=::. ..: .:-....... .-... \n . ..:.. ..:-:::..-:...=.. .:--:::::=-:. :. .-=::::... .:... .. \n .. ....:::. .+.:+:::-.:-::-:. .. .:-=--:::--.. ... .. .-=-:-:.... ........ \n ..... ..:..::---:+.. ..:==:::- ..:==-::.. .-.:. ..:-=+=====--:. . ..:.. ..:. :--++-::.... .::..- \n ..:..- :...::---=-::...:-+:::-:..:-++X++-::--:-::. ..-+XXXXXXXX+=-. . ....::. .:--=-:..::--=++-:::....:-:-:.. . \n :..::......:.::-=X++==--:-++-::-::---=+++X==-----:-:..:-++X=XXXXX:+=-.-..:::::::.....=+XX+=---=--=+X++=-:: :-:-=-:.. .. ..+. \n ..+::-::..:::=:--=+XXXXX+=+X=-:--:=:---==+XX+===--::-----==XXXXXXXXX+=-+-=+X++++--:..:=-++X+=====.=+XXXX+=---=--==-:....: ........ \n .. ..:=---==::-:--====+XXXXXXXX+==-=- ==+---=+XX.+==--:=--===++XXXXXXXXX+==-==+XXXXX+=--:--.++XX++++.X+XXXXX+=--=++++++=-:.:::::...+:..-. \n ....::--=++=+=---.==++.+XXXXXXXXX++=+==+-====:XXXX+++=--====+XX-XX:XXXXX+====:==+=XXXXX+==-=++XXX-X==XXXXXXXX++==+X=XXX++=-:::::::::.::...-\n",
|
||||
" \n . .:: \n .+. .-::. \n .:--:. . \n ..--.. \n . .:-:.. \n .-:...::. .:. \n :-....... .--:.. \n .-.. .. ..:-.. \n .:+:=.. .:-:. \n . ::+::..:=: .-:.. \n . . ..:.:::-. :-.. . .:.. \n .:..-. . ..:.... .:.-. .... \n .. .:-:... . .. :.::... .-:. ..... . \n .. -.. ..-::.... ..:-..-.::+.. .:. .::.. . .. \n .. ..:..:..-::.. .. +:::.=.:.:::. . .--:. .... ... \n . +.... ....:: :-:.:..-:=.. .::-:::..:-:. :. .-=::::... .. .. \n .. ..:::=.. ..-=:::::.:.:--... . .:--------::. ..:. .. .--=--:. ....-. \n . .. ..+..=:::.... ..:+-:-::.+.:=+=--:. .:.:.. ..:=+++++++=--. ..... :...:. ..:-=+-::.-.. .:::.. \n ..::.. ....:-==--::.=.:-=-=:::..:-=++XX=---=:-::. .:-+X+XX.XXX+=-.:. ....... . .-++==:..=::--==--::..:..::-:.. \n ..-.::... ..::::-=XX X+=---+=-::::-- -=+++X++==---::-:::-++:XXXXXX-+==:..:-=--:-:.. .:==+X+=------== +++=:::--::--:.. .... ..-. \n . ...:::-:...::-- ==+X-XXX:+++=-:---.-::-==+X+X+=---: ----==+ XXXXXXX:==---+XXXX-X=-:..:-++ X+====-=++XXX+X=::--= =-=-:.............. \n .. .:.--====--::---==-++XXXXXXX+==-=--==----+XXXX+==--:==--=++XX.XXX-XX++=---=+XXXX-++=-:--+++X+++ ++XX=XXX++=--+XXX+++=-:.....::.+.:..+. \n ......:--==+===-:--=++XX+XXXXXXXXX++++=====++== XXX-++=---===++XX+:XXXXXX+=======+XXXX++=====+XXX++XXXXXXXXXXX++==+XXXXX++=-::::::-:::.....=\n",
|
||||
" ::.. \n .-:. \n .::. \n ..: .. \n : .:.: .. \n :.. . .::. \n :. .--.. \n .::. . .::. \n . :. . .. .:. \n -...:...:: :.. \n ..: . .:. .... \n .:-::. . . ..-. .:. . \n .::. .. ..:.. .. .. \n ... .:.... ....:....... .. :.. \n .:..:...: .:. ..=:.. ..... . .:-...+. \n .. .:=::::... .:. .::::. ..... .. . .=:.. \n .=... .-=:....... ::.. . .::::::--:.. .. .:-=-:.. ... \n . ...::.+. .-::......::-.--:.......... .-==+==--=+=:. .... ..:--:.. . :..:. \n .. ..::-+=-:.. ..=-::-...-==+==+-:--::-.....:++XX+:+ XX=-:. . .:==-=:. ...::---.. ..:...::. \n ..:.. ..+:-+XX++=::::-=-:....:---==++===--:::::::-=+XXXXXXXX+=-:... :=:-.. . .--==+=-::..:::-===+=:.:::::+-:. ... \n . ....::.. .:.::=++XX++==-==- ::-::--::==++=+=--:-=: ::--=XX=XX-XX++=--:-XX+===+-....:=+=++--::----=++=.++::::---:-:. ..... \n . ..::-----:..-::--==+X-X+++==--::--:-::-:-+X+=+=--::-=:::-==XX X-XXX++=+--=+XX+ ++=--..:-=++ ==--==+XXX++-+=--+++++==-:.............. \n ....::--====--::==++XXXXXXXXX++==-=--::-=++=X++=+.==-::-:--==+X+XXX:XX+===--=++XXXX++==----+XX+====+XXXXX=X++= =+XX+XX+=-:..:::::::..-.. \n .....+::--======--= XXXXXX.X-XX+XXXX+=---===+XX+=+XX.++=--===-++XXXXXX=X.-++====++XXX.X++---=++X=X=++XXXXX-XX.XX++++XXXXX+==-::===-- :::.....\n",
|
||||
" -.. \n .. . \n .. .. \n . ... \n . .:: \n .:. :. \n ..: .. \n ... : \n .:.. .: .. \n ..:.. .. . \n .:::.. . . . \n . .. .. . :. \n .. ... .. . .. .. . :. \n .:-:... .. :.. . .-. \n .-::.... ...-..:=:. .-:. \n . ..::.. . . ..-.. .. ..:....::-=:. .::.+.. . \n ..:-:. .-:. . .::=:--:..::.+.....:-=-----::-=:.. =.. ..::.. . . \n .. .:-++=-.. .-:.. ::-.-:-::=-:......:=+X:X+===+X+-:. .::--. . .:::-:.........: \n ... ...:=XX+==-:.:..-::.. .:--------=-:::...::-+XXXX++++X+--... ... .-----:......-: --+=:.......:. . \n .:... ..::-=+++=--:.:-::..:::::--==+=---:::-..=:=:=++XXX+.++==--::=+==-::.:. .:-+-=--:..:::.-==-==+=::.:::.:. . \n ....:::::....:::--=+X++====-::..::...:-:-+X=--=:-:-==:::--=+XXXX+X+==--:-++XX====-:....-==+=-:::--++++====-====-==--:. . ....... \n ..::::-:--:::=X=== =+X++:+++--:.::.-.:-==+-+=-==-::.::::--=+X-XX++++==--:-=++XX+====-:.:-=XX=--::-=+XXX++===.=XX+==+=-:..:-::.....-. \n ......::-----==--+X+=+X:XXX+++XXX==--:::.-==+XX++==++.-:: -- ==+X+XX+XX++=+=-==++.XX+=+=-:--=+++=--==+XXXXXXXX+===++X+++==:::-=-:::: :.... \n ...+..:::-=+=----===+++XXXX X+XXX+X+=---- ++=++X++XXXXX+=====+X+++++XX+XXX+++===+XXXXX+==---=+.++X++XXXXXXXXXXXX++++XXX++=--------::-- ::....\n",
|
||||
" \n . \n . .-. \n . \n . . \n .. . \n .. . \n .:. . \n .:.... \n .. \n . . . \n .:::.-.. . .. \n .:.. .:.. . \n ...... . . ....::. .:. \n .. .:. . .:..= ..... ...:.+..:=+. . ... \n .::-:. ..: .:..=:..:--:......::-:::-+:::-:.. ..- ..= \n ..--=--. . . .::..:..::.. . .:=++XX+==-=-=:. ..... :..-:. . \n .:==== -::.. ....-. .::.:-::.+::.-....:-=++XX=====--:. .. .::..: . .:::---:. . \n . . . .:=====-::.::++......:--+-=-:.:::......::=++XX+=+==--::.:==--:. ..-.:-::. . ..:--------:..+:... \n .. .........-:.:::-====-=:--:.. .....:::-==-:.::::::::::--++XX+==-=+--::==+XX=--::.. .:--==-:+..::--==------=-::--:.. .. \n ......::::..--=-:---=+==-===-:.. .. ..:====+-::-::..=:+:::-+XXX===+==-::-=+++X+=---::..--=+=-:...:-=.+++===-=+++=--=-:..:::.-.. .. \n ...:::::---:-==--=++X+-++=+==-::.:..::-=+X++=-=--=-..::-::-=+XX+=++=+=--:-=++XX+=-=-::-:=+==-::::-=+XXXXX+===++X+=:=---::-::...:.... \n ......::-.---:----==++XXX XXX++:++=--:::----=++XX.++++=:::-:-==+==+XX+XX++-=-==+XX++===-::=== -======+XXXXXXXXX+==+XX++=---=::-::=-::::=.. \n .. ..::-=----::-:===++.XXXX-XXX=XXXX==--.====+=++XXX.X++====+.++++ +X++XXX:+=.=++XX+:++==--==+ +:XX-XX-XXXXXX:XX++XXXX++=- ::-:-::::::::..=.\n",
|
||||
" \n \n . \n \n \n .: \n \n ... \n . \n -.... \n ::.. \n .. .... . \n . .. . ...:--: \n . . .. ..-.::.. ......:::-: .. \n .::=. .. . .::.. -...:-:--::..... . . ..: \n .::=:--:. . ...... ... .:-===+=:: :::. . . ....::. \n .::::::.. ... .. ...::=. .:. .:----+++--=::-.. ... . ...::::.. . \n . .:------....... . .::::-:...:. .:-==++==------::..-.--:. ...:::. . .:::::--:. ..-. \n .. :....:.:-----:.... .:-::--:.:. ... . .::-=+X+=------::+=+==+-::. .::--:.. ..:::-:::-:-:+..... \n ......:-..:::::::---=---=---:. . .:=+-=-:::....-.:.:::-+X+=----- -::-++=++--:::.+..::-.-:. .::-==++-=-====-::-::...... \n ...:...+::+::::::-+++ +=----::.......::-=+==-=-::-:. ...::-+++=- -=+=-:::-==++=-::-::=:.-=--::...:-++XXX++=-==++=--:::............ \n .. .+.:::::.::+----=XXXXXX++======:::..:--+-++.++-==--:.:---:-===++==++.=----=+X+==+--::-=-----------+XXXX:XX+====+-+=--::.:::..::::..= \n ......::---::.::-- -=+X=XXXX+:++++XX+-::-=====++XXXXX+=----==:====+XXX:XX X==-=++X==-+=-::=--=-=+X++++XX-XXX:XX+==+XX+==-::::::::::::::.. \n ......::--==---::-==+.+++XXXXXXXXXXXXX+==++X+ ==++XXXXXX+-==.+++XX ++XX+XXXXX++=+=+X++X+=-: --=++XXXXXXXXXXXXXXX+-+XXXXX+=--::-.-::-::::.....\n",
|
||||
" \n \n \n . \n . \n \n \n .. \n ..... \n . \n .=. \n . .. ..::: \n .:.. . .::. .... .: . \n .... . .. .:::::.. .. . \n . ..... . . . .-::---:..+. .... \n ......... . .:+: . ..-::-----:::... .. . . ..+.:. \n .....:.. ...::...+ .::--=+=-:::::-:...:::-: ::. ...::-:.. . \n ....:::::::- . . .:=:.::.... .::-=X+--:-::-=-==:--:-:.. ...::.. ..:-:::::...... \n :.. .. -...:.:---::::.::. ..----:::: ........:-=X=-::::.::.:==-----:.+. .:-::. ...: ------.--:.::. . \n ...:...:.....:-=+X+=--::.:.. .- -=-.-:..-::. . ..:=== --::-=-:..:-==+=-:..::-...=::::.. ..-====+==-----=-:::::... . . \n .......::.::.::=++XX-X+=-+--=-::. ..:-=-=+===--:::.. ::-:-=====- ===-:.::-+X=-- ::::-=:::--.:..:-+XXXXXXX+= ===--::::............. \n .....:: :::..--::-==++XX:X====+++==:.=.:-==.=+XXX+=--::::-----==+XXXX-++=-::=++=.---::..::.--=++=--=+XXXXXXX++===++=--::.::........... \n ....:::----::-:--.===-++XXX++X++X+X++-:-=++:===+XX-X+==--===++++++XXXXXXXX+=--==+==++=-:.-::==+XX.-XX:XXXXXXX++=++X++X+-:::::::::::..+... \n .....::---===---=+XX:+++X+++XXXXXXXX++===+XX+-==+XXXXXX=+++XXX:XX.X+XX+:XXX++=++==+XXX+=--:--=+++XX:XX-+XXXXX:++=+XXX+XX+=-:-===-:::::.=....\n",
|
||||
" \n \n \n \n \n .. \n \n \n \n :. .. \n :. . .... \n . . .... . \n .. ...:.. . . \n . .. ....=::.. . .. \n . .. . .:-:-:....... :.. .. ..:. \n ..: ... .:..... .::+:-=-::..:::+.....=:. .. .=.:. \n ...::.+... ..--:.. .. .::--=-::....::=-:--:.:. ... -.....:..-. .. \n .. ..:-=--:: .. .. ...--::+:. .. ..:-=--:.. ..:.:--::-::. . ..::.. ....::..::..-.... \n ..........:+==--.:.:..:. .:.:-+-::.. ... .:--=--+:::::. .:--+=-:...:. ..::.. ..::--==--::::::..... \n :......:..:...:-+=:==+--:::+=:.. ...-==+==-:.-.. ...:---===---=-:-..:-=+-:...=.:::::::::....-=+X++++.+=--+-::...... .. \n :...+....::-::-=====:++=======+-:. ..:-==+.XX++-:....:+::--==+XX++-=-::.:==+--::+......:--++=-::-++XXX.++X ==+=--::..::=:+....... . \n ...+.::--:::+===+= ==+++X+=+.+==++=:.::-====+XX++==--::--==++=+XX.XX=XX+-::--==-==--.....:-=XXX +=++XXXX.+X+++++=== =::.::-::........ \n ....::+:-=----=+ ====+:++=+++:++++= =---+X+==++XX++====-=+XXXXX+XXX.X-XXX++--+==+X++=-:..::-++XX++XX+XXXXXX++==++++=+X=--:-:-::..:...... \n . ....::--=+++==+X=++=+===+++XXXXX++:==+++++XX++XXXX+++++-+X.XXXXXXXX+-XXX:++++X+=XXXX-+=-:--=++ XXXXXXXXXXXX++=-+++XXXXXX=-==---+::...:. ..\n",
|
||||
" \n \n \n \n \n \n \n . . \n .. \n .. \n .. \n . . . \n . . .:.. . \n .. . .--:...:. .. =.. .. \n . .. .::... . ..-::....-: .. . . . \n .:-::...: --::. ..-:-:.... .:.:...=. . . -.... \n .--:::::.. .:--:. .::-:.::.. .....:-::-:. . .. ........ \n . ..:- --:--....=. .:-+-:.. .::--:-:..... =:::-:.. . .. =..:-=-:.:..... \n .. ...... -----=--:::--.. .:-=+++-:.. ..:-----+::-:. .::--:.. ......:::.. .:=:===--=+-::::.. ... \n .+.. :...:--:::---+==+=--==--=-. ..:-=+XX+==:. .::.-=-=XX++=--:.. .: -- ::.. .+.:-+X=-:.:--=++-===+==-=--:..+...::.. \n ......::..::=-------====:-+===-==-.. .:---=+X+==-::::: --==X=XX XXXXX=-:.:------:::. ..::+X+ ==--=++X++=++==+=--:--:..:::..... . \n .....::=--::=------==-= ====++==:--:::=+===++X+==--:-::=++XX -:XXXXXXX+-::---=++=-:.. .:-=++==+===+XXXXX+===++=--=+=-::-::.+.....: \n ....::- ===--======-+-===++XXXX+=---+====+X++:XX++++=--=+XXXXXXXXXXXXXX++==+X++XXXX+-::.:--==+X++++=XXXX.++=====++ XX++=:--::::..+.. .. .\n ....:::-:==++==== ==+-===+=+XXXXX+==-= =+==XXXXXXXX++XX===+XXXXXXXXXXXXXXX+==+++-XXXXX =--===++XXX=X.X.XXXXX++:==++XX+XX+=.--:::.:.........\n",
|
||||
" \n \n \n \n \n \n \n \n . \n \n \n ..- \n .. .::. . . \n .:. .::.......... \n .:... -:..+ . .:...=. .. \n .::..:.. .:-:. ..=::.:... ..........: . \n ..: -:::::....-. .:--:.. ..::---:..... ::..-:. . .::...:. \n ....-::--:-=:::.::. ..:.==::. .::----::: .. .:.::..: .... .::--:::-:... . \n ...::::..::=-=---.--:--:. .:--XX+=-:.. ..::-=====--:=:. ..:-::.+. ...:==-:-..:- -=----==-:::...-.. .. \n . ......::-:::::::- -=---.---=-:. ..:--+X+==--::. ..::-=+X+XXXXX+=:....:-----:.. ..:-XX==-::---====-=+=---:::......:... \n .-....:-::-:--:--: --==---.--==-- .. :-=--==++=--::::::--==+X XXXXX-X+-:::=--:=-:::. ..:-=+=--=--==+++==++==+=-+--=-:.::..... \n ....:::---:-----=--=====-===-+==----+--=++==+X====-::--=++XXXXXXXXXXXX+=+--==+XX+=-:....:-==+====+=+XX+X+==+==-==.===-::::::.:.... \n ...+:---===---.======-===+X:XX++==-----==+XXXXXX+==----==+XXXXXXXXXXXXX++=+X+ +XXXX+=-:+:--=+++++X++XXXXX+++=====+X++.==-::-::......... .\n .....::-==++.==-==-++=+==+++XXXXXX+========XXXXXXXX-+++++XX-X:XXX+XXXXXX ++=++==+XXXX:X+==.=++XXXXXXXXXXXXXXX+===:+XX=XX+=--:-::::.........\n",
|
||||
" \n \n \n \n \n \n \n \n \n \n . .. \n . .. \n . ..+ \n .. ..:.. ....... \n ....-..- . :-:. . ...::.=. .. ... \n ...=..+.::. .::. : :.. ..::-::....... . ..: .... \n .. ........:::::..::. ..:-=-:.. ..:-----::..-... .... :... .:.:.....:. .. \n ........:.+.::.::.:-:. ...:=+==-:..- ..:-=+X+=--::..+ . ....:. .:.:=-:.. .:..::::::-:. ... . \n ............::::::--::-=-.. ..:-=++=--:::... ..::-=+:XX+-+=-:.....::-::.. .:==-:-::+::::----.-=-::..:.....+. \n .....:..::::::::::--:+::::--.=:..-:-:-==:=+=-:..+.:.::-==+XXX++XX+-:..::-==--:.. ..:-==--:::-=-==-=--=--+-::::::.... . \n ......: ::.::::.---.-=---.=-+-----:::::--++====--:..-::-==++XXXXXXXX+=--::-=+XX+=-:.....:--=------==X==:==--=-==-----:......... \n .:.:::.---::.--+:--+-==++======-:--::---=+X-+++==-.::-=++++:XXX:XXXXX+======++XXX+=-::.::-========++X++++==+====++==--::... -..... \n .....:--:===+------=--====+XX.++X+=-==---=+XXXXXXX+==----=++:X:X=XXXXXXX+=++===+X.X++==---=++XX+++ XXXX==XX++=-==+XXX++=-::::::.......... \n ......::-=.=+ ==--=++++====+X=XX:XXX+ +X==++++X XXXXX++===-+XXX.XXXXX.-XX++=+==.=+XX-+++:+=++XXXXXX.XX.XXXXX+.X+=+++XXX X+=--::--::.........\n",
|
||||
" \n \n \n \n \n \n \n \n .. \n \n \n \n .: .-.. \n . .... .. ::.. \n ..... :.. .::. ...::::......... \n . ...:.. ..:. ..= ::.. ....:--==-- ::.. ... ... . .. \n ... .......::. ..:----::=..= ..:-+XX= =--:... ..=.::. .=.:.:.. .. ..=...::. \n . +......:.........:: . ..:-----=::.. ..:--=XX+====::.=....::::. ..:--::=....-....:::::::.... .. \n .... .. .=.::-::::::....:::..=.::-------::....:.:---=++===++==-:..:-==--::.. .:----::::::::--::--+:::::....=.. \n ...............::----- -:: ::::.:=:::-===----:.=..::-=-=+X+X++++==-:::=-+XX+=--. ...:::--:::=::-=--=---:----.::.::. . \n ....::::....::::+:---:==---=-=-::+::::--=X+===-:+:..::-==++X XXXXX+==:--=-=+X+=+=-::..::------:--==+=++==---====---::.-.... \n ...:::--:-:::::------===++====++-----++-=+X+X+=:=-:.:::-=+-+XXXXXXX++++-==-=+-+===---:: -=+++== =:+++XX+++===+=+X+==--::... .-... \n ..+...:----------=========XX=X++-+X+===---==++=XX+==+==--==+++XXXXXXXXX+++==--==+X++===---++XXXX+.++XXXXXXXXX++===+XX++==--:::::.-.......- \n ....=..::-========-=:++++ +++XXXXXXXX++=====+-=++XXXXX+++++XX++XX:XXXXXX.X+======+XX.+++++++==+X:XXXXXXXX+X:XXX-X+++XXXX++==--:--:::::.......\n",
|
||||
" \n \n \n \n \n \n \n \n \n \n . \n .. ..... \n . .::..:. \n .. .:.. .. ..-:-:::.. .. \n . .-. ....... . ..:::=---::::.. ... . ... \n ... . ... .:::...... .. ..:--++=-----:. ...:.. .. ...... . . \n :..: ..:. ... ..:=--::.... . .:: -=++==-=---:=....:::... .:::..... . +....... \n ..:-:.::.. .. ..-...:-:-- :::.....::---+====- ----::..:--=:-:.. .:--::.......+=:.:::........ \n . . ..:-:::::+.....+=.::-...-=--::::....:.::- -+=====+=+-::+:-=-++=--:. ..:-::.:.. ..::=::-::=-:::::..... \n ...............::------+::::::..::::::-=+==-::... .::--=+X+++ +X+=-: :--++==---::...::=--::.=.::--====--:--==-::.... \n ..:-::::..-.::-:-=-- =+==--:--=-:::::---=++=-::::....::-=++XXXX++++=+=-.--===.---: ::.:-=++=--:-==+++++-==-=-=+==--::.......... \n ...:::.:::::-:----- ==+XX+=====++---.:--=++++=---=-+::---=+XXXXXXXX+==--:---=++===- ::---+X++=-===++XXXX++=-==+++==--::::.:...... .:. \n ....:.::----------===-===+XXX X++ +X+===--+-==:+XX+==:====++=+++XX.XXXXX+===--==+XX+= ==--===+XX+++++X=XX XXXXX+++++X++==-.-:+:::.......... \n ..=...::---.-==+=+==++++++++-=XXXXXX X++++:+==:=++XXX++ +XXXX+XXXXXXX+.+XX++===+XXXX=X+.==--:==+XXXXXXXXXXXXXXXXX+++XX=++++-=-----.::........\n",
|
||||
" \n \n \n \n \n \n \n \n \n :... \n .:..: \n .. .:.:..+. \n .. . .. ...::.:.. . .. \n . .:-:-:--:...:. . . \n .. . .:..... . .::+===--:.::-:=.. ...:.. . \n .. . .:=-:::.. -.. .::-+===--::---:.....::+.. .:.... . ... \n .:...... ...::--::-:..... ..::==-=--::-:-.::.::--:::... .--::.. . .... . \n .::::........ ......----... .. .:+::==-------=-::::-===-::::. .::--:. .. ......::........ \n .. ..+.::-::--:..:.:...+..:..::==-:....: .::::-++========::.:-+=.=-::::.-..:-.-:::. ...::-----:: ---::.. \n .....-.+..:.:.:::--+==--::::-:-:..:::::-=--:+...+...:+:-=++X++== =--:::-+--=-:::..:..:-==--::.:--=+++==-----==--::.. . \n .....-.=..:::-:::--=-=+=-----:-=::.: ::--==--:::::..::+--+XXXX-====--:.::-=-==---::.::::=+==-----=+XX++-==:-===.--::........ \n ....-:::::::.------= -=+X++===+=.==-- --:--==++=-+--::-:====+XXXX+-+==-::=--=++==---:.:--==++==--=++ XXXXX++===+++===-::-:::....+:... \n ....-.::-:------====+=.=++:XX+X++++ ===+ ======+XX+==-== ++++++X+XXXXX=+==-==++XXXX==--::+--==XX++-+X XXXXXX:++++++++====-+-::::::........ \n ...=.::--=-=== ===++XXX++XXXXXXXXXX+XXX:++======+X XX+.++X++XX+++X+XX++XXX++=++ XXXX+===--:--=++XXXXXXXXXXXXXX++++XX+X+++.=-------::::......\n",
|
||||
" \n \n \n \n \n \n \n :.... \n . . \n . ....- \n .:..:::::.. \n .:..+.::... . \n =::::.::... . +...::.. \n .. .:-==-:-:....::... .::. \n .:-::... .:-+=---::..:::......::.. ....+ . \n . . :..:-:::.... .:--=--::::::::-:.::+:-:.. :=-::. .. \n ....... ..::-:::.. .:::=--::::::.-:---=---:...:.:.:--:...- ..::..=. ..... \n . ..:::::::..... .. ...-:-::. ...-::-+=-=-::::::.:-+--=--::.....::-::... -..:------:.:.:... \n .. . ....:=::-::-:-...:..:..::..:--::. . .:::--+ +=----::.=.:-=:--::.+....+.-=::.=...:-=:==--+- ---::=... \n ............::::::--:-+-::=:::-:..=:...:--:::.... ..+---=++X+=-=-::..:.:==:=--:....::::==--::---=++.====--=---=:-:..: ... \n .....::::-::.:--::---====-------::.:::.---==--:.: ..-==--==-++====-::...::==----=::.:.::-==-::--=+=++++++======----: :. .... \n ....-:=::::: --:==----=+==++=+==+=- --=.=+=.==X+=--:: -===+==+++X+-+==-::--==.++=-:::. ..:-==++===+++XX+++X====+===----:::::.:...:.. \n ....::---------==:++==+++++++++X+=++XX+=======+XX++ ===+==-++==++X XXX++==++++++++=--:.:.::-==XX++.XXXXXXXX++=++:XX++==--::+: :::.... . \n .. .::---=========+X++XXX+XXXXXXX++:XXXX+=+=== =+X=X++X+-+.+++++XXXX++XXXX+++==++XX+==----- -=+XXXXXXXXXXXXX+++++X-XXX++=--------.:::......\n",
|
||||
" \n \n \n \n \n \n . \n . . \n :. .:.. \n .. .. ..::. \n . .....:: ..:. \n .-:...-.:.. . .. .. \n . .:-=-::... ...+. :+.. \n ... .:-+=-::::. ........:--.. ..-.. \n . .=-:.... .::==::::......-::::..-:. .::... \n .... ..::=. .:-==:=:.......::---::-. .:-::::. ........ \n ........ . ..=.:. .=::==--:+......:-+.--::. .+. ..::-:. .:-::::-:::.:. \n .....:-:.::-.. .. .. :. ..:.. .::--+=--:. .. ..:=::=::.......::-:.. ..:-----:::-=-:.:.:. \n ...... .::::::::.::--...... .....:-:.. .::--=+=.=::.... ..:=::.:-..:....::--+....:-=+=--==-==-::::::... \n ....-:.....::::::::::--- :::::.=....::--==-:.. . ..:=--+====--::.......-+-:.::+.. ...:=-:..::-.=======+-==----:::...: .. \n ......::...:-::--::--------==-=-:::---=++==++=-::-..:--:-=:==++===-:..::::==- ::.... .--=+.---=+X===+==+==+= ----::........ \n ...=:::-::::--=-==-=+==--====+++-:===-=-==.++X+=----=---======+XXXX+=-:-===++==--::. . .:--X+===.:XX+.+=+===+++====-::.::-:.+.... \n ...:::------+=-==+.++X+=++XXXXXX++=+X+===+=-==+XX++=+=++ =====+XXXXXX +===+==++X+==::....::-++X ++XXXXXXX+===-=++-+++=-=--=::::::=.-.... \n ...:-----=----==+X++XXXXXXXXXXX+XX+++++==+==-==+XX.+=++-=====+++XX:XXX-X+=+++=+XXX+=--======+++XXXXXXXXXX+===+++XX++++=+------::::=:.....\n"
|
||||
]
|
||||
@@ -0,0 +1,67 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, memo } from "react";
|
||||
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
import data from "./hero-flame-data.json";
|
||||
|
||||
function HeroFlame() {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const ref2 = useRef<HTMLDivElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let index = 0;
|
||||
|
||||
const interval = setIntervalOnVisible({
|
||||
element: wrapperRef.current,
|
||||
callback: () => {
|
||||
if (!ref.current || !ref2.current) return;
|
||||
|
||||
index++;
|
||||
if (index >= data.length) index = 0;
|
||||
|
||||
ref.current.innerHTML = data[index];
|
||||
ref2.current.innerHTML = data[index];
|
||||
},
|
||||
interval: 85,
|
||||
});
|
||||
|
||||
return () => interval?.();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="cw-686 h-190 top-408 absolute flex gap-16 pointer-events-none select-none lg-max:hidden"
|
||||
ref={wrapperRef}
|
||||
>
|
||||
<div className="flex-1 overflow-clip relative">
|
||||
<div
|
||||
className="text-black-alpha-20 font-ascii absolute bottom-0 -left-380 fc-decoration"
|
||||
dangerouslySetInnerHTML={{ __html: data[0] }}
|
||||
ref={ref}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: "9px",
|
||||
lineHeight: "11px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-clip relative">
|
||||
<div
|
||||
className="text-black-alpha-20 font-ascii absolute bottom-0 -right-380 -scale-x-100 fc-decoration"
|
||||
dangerouslySetInnerHTML={{ __html: data[0] }}
|
||||
ref={ref2}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: "9px",
|
||||
lineHeight: "11px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(HeroFlame);
|
||||
@@ -0,0 +1,7 @@
|
||||
export { CoreFlame } from "./core-flame";
|
||||
export { AsciiExplosion } from "./ascii-explosion";
|
||||
export { default as HeroFlame } from "./hero-flame";
|
||||
export { SubtleExplosion } from "./subtle-explosion";
|
||||
|
||||
// Convenience wrapper for dashboard usage
|
||||
export { FlameBackground } from "./flame-background";
|
||||
@@ -0,0 +1,17 @@
|
||||
[
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ ░ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ ▒ │ ░ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ░ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ ▓ │ ▒ │ ░ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▒ │ ░ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ░ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ ▒ │ ▓ │ ▒ │ ░ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▓ │ ▒ │ ░ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▒ │ ░ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ░ │ │ │ │ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ ░ │ ▒ │ ▓ │ ▒ │ ░ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▒ │ ▓ │ ▒ │ ░ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▓ │ ▒ │ ░ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▒ │ ░ │ │ │ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ │ ░ │ ▒ │ ▓ │ ▒ │ ░ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ░ │ ▒ │ ▓ │ ▒ │ ░ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▒ │ ▓ │ ▒ │ ░ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▓ │ ▒ │ ░ │ │ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ │ │ ░ │ ▒ │ ▓ │ ▒ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ ░ │ ▒ │ ▓ │ ▒ │ ░ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ░ │ ▒ │ ▓ │ ▒ │ ░ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ▒ │ ▓ │ ▒ │ ░ │ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ │ │ │ ░ │ ▒ │ ▓ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ ░ │ ▒ │ ▓ │ ▒ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ ░ │ ▒ │ ▓ │ ▒ │ ░ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ ░ │ ▒ │ ▓ │ ▒ │ ░ │ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ │ │ │ │ ░ │ ▒ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ ░ │ ▒ │ ▓ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ ░ │ ▒ │ ▓ │ ▒ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ ░ │ ▒ │ ▓ │ ▒ │ ░ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ │ │ │ │ │ ░ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ ░ │ ▒ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ ░ │ ▒ │ ▓ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ ░ │ ▒ │ ▓ │ ▒ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\n│ │ │ │ │ │ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ │ ░ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ │ ░ │ ▒ │\n├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤\n│ │ │ │ ░ │ ▒ │ ▓ │\n└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘",
|
||||
"┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐\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,65 @@
|
||||
"use client";
|
||||
|
||||
import { HTMLAttributes, useEffect, useRef } from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
import data from "./grid-data.json";
|
||||
|
||||
interface SlateGridProps extends HTMLAttributes<HTMLDivElement> {
|
||||
interval?: number;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
export function SlateGrid({
|
||||
interval = 200,
|
||||
color = "text-black-alpha-12",
|
||||
className,
|
||||
...attrs
|
||||
}: SlateGridProps) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
const frameIndex = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
const animate = () => {
|
||||
if (ref.current) {
|
||||
ref.current.innerHTML = data[frameIndex.current];
|
||||
frameIndex.current = (frameIndex.current + 1) % data.length;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize first frame
|
||||
animate();
|
||||
|
||||
const cleanup = setIntervalOnVisible({
|
||||
element: wrapperRef.current,
|
||||
callback: animate,
|
||||
interval,
|
||||
});
|
||||
|
||||
return () => cleanup?.();
|
||||
}, [interval]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
{...attrs}
|
||||
className={cn(
|
||||
"absolute inset-0 pointer-events-none select-none overflow-hidden",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("font-mono fc-decoration", color)}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: "10px",
|
||||
lineHeight: "12px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
"use client";
|
||||
|
||||
import { HTMLAttributes, useEffect, useRef } from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
import data from "./explosion-data.json";
|
||||
|
||||
interface SubtleExplosionProps extends HTMLAttributes<HTMLDivElement> {
|
||||
interval?: number;
|
||||
delay?: number;
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
export function SubtleExplosion({
|
||||
interval = 80,
|
||||
delay = 30,
|
||||
opacity = 0.08,
|
||||
className,
|
||||
...attrs
|
||||
}: SubtleExplosionProps) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let index = -delay;
|
||||
|
||||
const animate = () => {
|
||||
index++;
|
||||
if (index >= data.length) index = -delay;
|
||||
if (index < 0) return;
|
||||
|
||||
if (ref.current) {
|
||||
ref.current.innerHTML = data[index];
|
||||
}
|
||||
};
|
||||
|
||||
const cleanup = setIntervalOnVisible({
|
||||
element: wrapperRef.current,
|
||||
callback: animate,
|
||||
interval,
|
||||
});
|
||||
|
||||
return () => cleanup?.();
|
||||
}, [interval, delay]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
{...attrs}
|
||||
className={cn(
|
||||
"absolute inset-0 pointer-events-none select-none",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
ref={ref}
|
||||
className="text-black-alpha-20 font-mono absolute inset-0 flex items-center justify-center fc-decoration"
|
||||
dangerouslySetInnerHTML={{ __html: data[0] }}
|
||||
style={{
|
||||
whiteSpace: "pre",
|
||||
fontSize: "10px",
|
||||
lineHeight: "12.5px",
|
||||
opacity,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
import data from "./wave-data.json";
|
||||
|
||||
export default function SubtleWave({ className = "" }: { className?: string }) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const frameIndex = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
const animateWave = () => {
|
||||
if (containerRef.current) {
|
||||
containerRef.current.innerHTML = data[frameIndex.current];
|
||||
frameIndex.current = (frameIndex.current + 1) % data.length;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize first frame
|
||||
animateWave();
|
||||
|
||||
// Start animation when visible
|
||||
const cleanup = setIntervalOnVisible({
|
||||
element: containerRef.current,
|
||||
callback: animateWave,
|
||||
interval: 150, // Slower for subtlety
|
||||
});
|
||||
|
||||
return () => {
|
||||
cleanup?.();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`font-mono text-white/10 whitespace-pre select-none fc-decoration ${className}`}
|
||||
style={{
|
||||
fontSize: "10px",
|
||||
lineHeight: "1",
|
||||
letterSpacing: "0.05em",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
[
|
||||
"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░",
|
||||
"▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒",
|
||||
"▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒",
|
||||
"▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒",
|
||||
"░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░",
|
||||
"░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░",
|
||||
"░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░",
|
||||
"░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░",
|
||||
"░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░",
|
||||
"░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░",
|
||||
"░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░",
|
||||
"░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░",
|
||||
"░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░",
|
||||
"░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░",
|
||||
"░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒░░▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░",
|
||||
"░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░"
|
||||
]
|
||||
@@ -0,0 +1,3 @@
|
||||
// Effect Components
|
||||
export { CoreFlame } from "./flame/core-flame";
|
||||
export { AsciiExplosion } from "./flame/ascii-explosion";
|
||||
@@ -0,0 +1,71 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useMemo } from "react";
|
||||
import { setIntervalOnVisible } from "@/utils/set-timeout-on-visible";
|
||||
|
||||
export default function SubtleAsciiAnimation({
|
||||
className = "",
|
||||
}: {
|
||||
className?: string;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Simple ASCII pattern for subtle animation
|
||||
const asciiFrames = useMemo(() => [
|
||||
"░░░░░░░░░░░░░░░░",
|
||||
"▒░░░░░░░░░░░░░░░",
|
||||
"▒▒░░░░░░░░░░░░░░",
|
||||
"░▒▒░░░░░░░░░░░░░",
|
||||
"░░▒▒░░░░░░░░░░░░",
|
||||
"░░░▒▒░░░░░░░░░░░",
|
||||
"░░░░▒▒░░░░░░░░░░",
|
||||
"░░░░░▒▒░░░░░░░░░",
|
||||
"░░░░░░▒▒░░░░░░░░",
|
||||
"░░░░░░░▒▒░░░░░░░",
|
||||
"░░░░░░░░▒▒░░░░░░",
|
||||
"░░░░░░░░░▒▒░░░░░",
|
||||
"░░░░░░░░░░▒▒░░░░",
|
||||
"░░░░░░░░░░░▒▒░░░",
|
||||
"░░░░░░░░░░░░▒▒░░",
|
||||
"░░░░░░░░░░░░░▒▒░",
|
||||
"░░░░░░░░░░░░░░▒▒",
|
||||
"░░░░░░░░░░░░░░░▒",
|
||||
], []);
|
||||
|
||||
useEffect(() => {
|
||||
let frameIndex = 0;
|
||||
|
||||
const animateAscii = () => {
|
||||
if (containerRef.current) {
|
||||
containerRef.current.innerHTML = asciiFrames[frameIndex];
|
||||
frameIndex = (frameIndex + 1) % asciiFrames.length;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize first frame
|
||||
animateAscii();
|
||||
|
||||
// Start animation when visible
|
||||
const cleanup = setIntervalOnVisible({
|
||||
element: containerRef.current,
|
||||
callback: animateAscii,
|
||||
interval: 150, // Slightly slower for subtlety
|
||||
});
|
||||
|
||||
return () => {
|
||||
cleanup?.();
|
||||
};
|
||||
}, [asciiFrames]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`font-mono text-white/20 whitespace-pre select-none ${className}`}
|
||||
style={{
|
||||
fontSize: "10px",
|
||||
lineHeight: "1",
|
||||
letterSpacing: "0.05em",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { HTMLAttributes } from "react";
|
||||
|
||||
export default function FirecrawlIconStatic({
|
||||
fill = "var(--heat-100)",
|
||||
className = "",
|
||||
...attrs
|
||||
}: HTMLAttributes<HTMLOrSVGElement> & { fill?: string }) {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
style={{ fill: fill }}
|
||||
{...attrs}
|
||||
>
|
||||
<path
|
||||
d="M13.7605 6.61389C13.138 6.79867 12.6687 7.21667 12.3251 7.67073C12.2513 7.76819 12.0975 7.69495 12.1268 7.57552C12.7848 4.86978 11.9155 2.6209 9.20582 1.51393C9.06836 1.4576 8.92527 1.58097 8.96132 1.72519C10.1939 6.67417 5.00941 6.25673 5.66459 11.8671C5.67585 11.9634 5.56769 12.0293 5.48882 11.973C5.2432 11.7967 4.96885 11.4288 4.78069 11.1702C4.72548 11.0942 4.60605 11.1156 4.5807 11.2063C4.43085 11.7482 4.35986 12.2586 4.35986 12.7656C4.35986 14.7373 5.37333 16.473 6.90734 17.4791C6.99522 17.5366 7.10789 17.4543 7.07804 17.3535C6.99917 17.0887 6.95466 16.8093 6.95128 16.5203C6.95128 16.3429 6.96255 16.1615 6.99015 15.9925C7.05438 15.5677 7.20197 15.1632 7.44985 14.7948C8.29995 13.5188 10.0041 12.2862 9.73199 10.6125C9.71453 10.5066 9.83959 10.4368 9.91846 10.5094C11.119 11.6063 11.3567 13.0817 11.1595 14.405C11.1426 14.5199 11.2868 14.5813 11.3595 14.4912C11.5432 14.2613 11.7674 14.0596 12.0113 13.9081C12.0722 13.8703 12.1533 13.8991 12.1764 13.9667C12.3121 14.3616 12.5138 14.7323 12.7042 15.1029C12.9318 15.5485 13.0529 16.0573 13.0338 16.5958C13.0242 16.8578 12.9808 17.1113 12.9082 17.3524C12.8772 17.4543 12.9887 17.5394 13.0783 17.4808C14.6134 16.4747 15.6275 14.739 15.6275 12.7662C15.6275 12.0806 15.5075 11.4085 15.2804 10.7787C14.8044 9.45766 13.5966 8.46561 13.9019 6.74403C13.9166 6.66178 13.8405 6.59023 13.7605 6.61389Z"
|
||||
fill="inherit"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,216 @@
|
||||
"use client";
|
||||
|
||||
import copy from "copy-to-clipboard";
|
||||
import { animate, cubicBezier } from "motion";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import Link from "next/link";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
import FirecrawlIcon from "@/components/shared/firecrawl-icon/firecrawl-icon";
|
||||
import Logo from "@/components/shared/header/_svg/Logo";
|
||||
import { useHeaderContext } from "@/components/shared/header/HeaderContext";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
import Download from "./_svg/Download";
|
||||
import Guidelines from "./_svg/Guidelines";
|
||||
import Icon from "./_svg/Icon";
|
||||
|
||||
export default function HeaderBrandKit() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const { dropdownContent, clearDropdown } = useHeaderContext();
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("click", () => {
|
||||
setOpen(false);
|
||||
});
|
||||
}, [open]);
|
||||
|
||||
useEffect(() => {
|
||||
if (dropdownContent) {
|
||||
setOpen(false);
|
||||
}
|
||||
}, [dropdownContent]);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<Link
|
||||
className="flex items-center gap-2 relative brand-kit-menu"
|
||||
href="/"
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
setOpen(!open);
|
||||
|
||||
if (!open) {
|
||||
clearDropdown(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FirecrawlIcon className="size-28 -top-2 relative" />
|
||||
<Logo />
|
||||
</Link>
|
||||
|
||||
<AnimatePresence initial={false} mode="popLayout">
|
||||
{open && <Menu setOpen={setOpen} />}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Menu = ({ setOpen }: { setOpen: (open: boolean) => void }) => {
|
||||
const backgroundRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const timeoutRef = useRef<number | null>(null);
|
||||
|
||||
const onMouseEnter = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
const t = e.target as HTMLElement;
|
||||
|
||||
const target =
|
||||
t instanceof HTMLButtonElement
|
||||
? t
|
||||
: (t.closest("button") as HTMLButtonElement);
|
||||
|
||||
if (backgroundRef.current) {
|
||||
animate(backgroundRef.current, { scale: 0.98, opacity: 1 }).then(() => {
|
||||
if (backgroundRef.current) {
|
||||
animate(backgroundRef.current!, { scale: 1 });
|
||||
}
|
||||
});
|
||||
|
||||
animate(
|
||||
backgroundRef.current,
|
||||
{
|
||||
y: target.offsetTop - 4,
|
||||
},
|
||||
{
|
||||
ease: cubicBezier(0.1, 0.1, 0.25, 1),
|
||||
duration: 0.2,
|
||||
},
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onMouseLeave = useCallback(() => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
timeoutRef.current = window.setTimeout(() => {
|
||||
if (backgroundRef.current) {
|
||||
animate(backgroundRef.current, { scale: 1, opacity: 0 });
|
||||
}
|
||||
}, 100);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
animate={{ opacity: 1, y: 0, scale: 1, filter: "blur(0px)" }}
|
||||
className="absolute w-220 whitespace-nowrap rounded-16 p-4 bg-white left-0 top-[calc(100%+8px)] z-[2000] border border-border-faint"
|
||||
exit={{ opacity: 0, y: 8, scale: 0.98, filter: "blur(1px)" }}
|
||||
initial={{ opacity: 0, y: -6, filter: "blur(1px)" }}
|
||||
style={{
|
||||
boxShadow:
|
||||
"0px 12px 24px rgba(0, 0, 0, 0.08), 0px 4px 8px rgba(0, 0, 0, 0.04)",
|
||||
}}
|
||||
transition={{
|
||||
ease: cubicBezier(0.1, 0.1, 0.25, 1),
|
||||
duration: 0.2,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="absolute top-4 opacity-0 z-[2] pointer-events-none inset-x-4 bg-black-alpha-4 rounded-8 h-32"
|
||||
ref={backgroundRef}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
window.open("/", "_blank");
|
||||
setOpen(false);
|
||||
}}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<svg
|
||||
className="w-16 h-16"
|
||||
fill="none"
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 4.5V12.5C12 13.0523 11.5523 13.5 11 13.5H4C3.44772 13.5 3 13.0523 3 12.5V4.5C3 3.94772 3.44772 3.5 4 3.5H7.5M10.5 2.5H13.5M13.5 2.5V5.5M13.5 2.5L8.5 7.5"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
Open in new tab
|
||||
</Button>
|
||||
|
||||
<div className="px-8 py-4">
|
||||
<div className="h-1 w-full bg-black-alpha-5" />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
copy(`<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.7605 6.61389C13.138 6.79867 12.6687 7.21667 12.3251 7.67073C12.2513 7.76819 12.0975 7.69495 12.1268 7.57552C12.7848 4.86978 11.9155 2.6209 9.20582 1.51393C9.06836 1.4576 8.92527 1.58097 8.96132 1.72519C10.1939 6.67417 5.00941 6.25673 5.66459 11.8671C5.67585 11.9634 5.56769 12.0293 5.48882 11.973C5.2432 11.7967 4.96885 11.4288 4.78069 11.1702C4.72548 11.0942 4.60605 11.1156 4.5807 11.2063C4.43085 11.7482 4.35986 12.2586 4.35986 12.7656C4.35986 14.7373 5.37333 16.473 6.90734 17.4791C6.99522 17.5366 7.10789 17.4543 7.07804 17.3535C6.99917 17.0887 6.95466 16.8093 6.95128 16.5203C6.95128 16.3429 6.96255 16.1615 6.99015 15.9925C7.05438 15.5677 7.20197 15.1632 7.44985 14.7948C8.29995 13.5188 10.0041 12.2862 9.73199 10.6125C9.71453 10.5066 9.83959 10.4368 9.91846 10.5094C11.119 11.6063 11.3567 13.0817 11.1595 14.405C11.1426 14.5199 11.2868 14.5813 11.3595 14.4912C11.5432 14.2613 11.7674 14.0596 12.0113 13.9081C12.0722 13.8703 12.1533 13.8991 12.1764 13.9667C12.3121 14.3616 12.5138 14.7323 12.7042 15.1029C12.9318 15.5485 13.0529 16.0573 13.0338 16.5958C13.0242 16.8578 12.9808 17.1113 12.9082 17.3524C12.8772 17.4543 12.9887 17.5394 13.0783 17.4808C14.6134 16.4747 15.6275 14.739 15.6275 12.7662C15.6275 12.0806 15.5075 11.4085 15.2804 10.7787C14.8044 9.45766 13.5966 8.46561 13.9019 6.74403C13.9166 6.66178 13.8405 6.59023 13.7605 6.61389Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>`);
|
||||
|
||||
setOpen(false);
|
||||
}}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<Icon />
|
||||
Copy logo as SVG
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<Download />
|
||||
Download brand assets
|
||||
</Button>
|
||||
|
||||
<div className="px-8 py-4">
|
||||
<div className="h-1 w-full bg-black-alpha-5" />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<Guidelines />
|
||||
Visit brand guidelines
|
||||
</Button>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
const Button = (attributes: React.ButtonHTMLAttributes<HTMLButtonElement>) => {
|
||||
return (
|
||||
<button
|
||||
{...attributes}
|
||||
className={cn(
|
||||
"flex gap-8 w-full items-center text-label-small group text-accent-black p-6",
|
||||
attributes.className,
|
||||
)}
|
||||
>
|
||||
{attributes.children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
export default function Download() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
className="group-hover:stroke-heat-100 duration-[200ms] transition-all"
|
||||
d="M12.8334 10.8334L10.4715 13.1953C10.2111 13.4557 9.78904 13.4557 9.52869 13.1953L7.16675 10.8334M10.0001 3.83337V13.1667M14.8334 16.1667H5.16675"
|
||||
stroke="#262626"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export default function Guidelines() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
className="group-hover:stroke-heat-100 duration-[200ms] transition-all"
|
||||
d="M10.0001 7.16663C10.0001 6.06206 10.8955 5.16663 12.0001 5.16663H15.8334C16.3857 5.16663 16.8334 5.61434 16.8334 6.16663V13.8333C16.8334 14.3856 16.3857 14.8333 15.8334 14.8333H12.1847C11.7311 14.8333 11.2865 14.9427 10.9006 15.1812C10.5148 15.4197 10.2029 15.7609 10.0001 16.1666M10.0001 7.16663C10.0001 6.06206 9.10465 5.16663 8.00008 5.16663H4.16675C3.61446 5.16663 3.16675 5.61434 3.16675 6.16663V13.8333C3.16675 14.3856 3.61446 14.8333 4.16675 14.8333H7.81541C8.26902 14.8333 8.71367 14.9427 9.09953 15.1812C9.48539 15.4197 9.79722 15.7609 10.0001 16.1666M10.0001 7.16663V16.1666"
|
||||
stroke="#262626"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export default function Icon() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
className="group-hover:fill-heat-100 duration-[200ms] transition-all"
|
||||
d="M13.7605 6.61389C13.138 6.79867 12.6687 7.21667 12.3251 7.67073C12.2513 7.76819 12.0975 7.69495 12.1268 7.57552C12.7848 4.86978 11.9155 2.6209 9.20582 1.51393C9.06836 1.4576 8.92527 1.58097 8.96132 1.72519C10.1939 6.67417 5.00941 6.25673 5.66459 11.8671C5.67585 11.9634 5.56769 12.0293 5.48882 11.973C5.2432 11.7967 4.96885 11.4288 4.78069 11.1702C4.72548 11.0942 4.60605 11.1156 4.5807 11.2063C4.43085 11.7482 4.35986 12.2586 4.35986 12.7656C4.35986 14.7373 5.37333 16.473 6.90734 17.4791C6.99522 17.5366 7.10789 17.4543 7.07804 17.3535C6.99917 17.0887 6.95466 16.8093 6.95128 16.5203C6.95128 16.3429 6.96255 16.1615 6.99015 15.9925C7.05438 15.5677 7.20197 15.1632 7.44985 14.7948C8.29995 13.5188 10.0041 12.2862 9.73199 10.6125C9.71453 10.5066 9.83959 10.4368 9.91846 10.5094C11.119 11.6063 11.3567 13.0817 11.1595 14.405C11.1426 14.5199 11.2868 14.5813 11.3595 14.4912C11.5432 14.2613 11.7674 14.0596 12.0113 13.9081C12.0722 13.8703 12.1533 13.8991 12.1764 13.9667C12.3121 14.3616 12.5138 14.7323 12.7042 15.1029C12.9318 15.5485 13.0529 16.0573 13.0338 16.5958C13.0242 16.8578 12.9808 17.1113 12.9082 17.3524C12.8772 17.4543 12.9887 17.5394 13.0783 17.4808C14.6134 16.4747 15.6275 14.739 15.6275 12.7662C15.6275 12.0806 15.5075 11.4085 15.2804 10.7787C14.8044 9.45766 13.5966 8.46561 13.9019 6.74403C13.9166 6.66178 13.8405 6.59023 13.7605 6.61389Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -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,105 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import Button from "@/components/ui/shadcn/button";
|
||||
import GithubIcon from "./_svg/GithubIcon";
|
||||
|
||||
export default function HeaderGithubClient() {
|
||||
return (
|
||||
<a
|
||||
className="contents"
|
||||
href="https://github.com/firecrawl/firecrawl"
|
||||
target="_blank"
|
||||
>
|
||||
<Button variant="tertiary">
|
||||
<GithubIcon />
|
||||
21.5k
|
||||
</Button>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function GithubIcon() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M9.97616 2C5.56555 2 2 5.59184 2 10.0354C2 13.5874 4.28457 16.5941 7.45388 17.6583C7.85012 17.7383 7.99527 17.4854 7.99527 17.2727C7.99527 17.0864 7.9822 16.4478 7.9822 15.7825C5.76343 16.2616 5.30139 14.8247 5.30139 14.8247C4.94482 13.8934 4.41649 13.654 4.41649 13.654C3.69029 13.1618 4.46939 13.1618 4.46939 13.1618C5.27494 13.215 5.69763 13.9866 5.69763 13.9866C6.41061 15.2104 7.55951 14.8647 8.02171 14.6518C8.08767 14.1329 8.2991 13.7737 8.52359 13.5742C6.75396 13.3879 4.89208 12.6962 4.89208 9.60963C4.89208 8.73159 5.20882 8.01322 5.71069 7.45453C5.63151 7.25502 5.35412 6.43004 5.79004 5.32588C5.79004 5.32588 6.46351 5.11298 7.98204 6.15069C8.63218 5.9748 9.30265 5.88532 9.97616 5.88457C10.6496 5.88457 11.3362 5.9778 11.9701 6.15069C13.4888 5.11298 14.1623 5.32588 14.1623 5.32588C14.5982 6.43004 14.3207 7.25502 14.2415 7.45453C14.7566 8.01322 15.0602 8.73159 15.0602 9.60963C15.0602 12.6962 13.1984 13.3745 11.4155 13.5742C11.7061 13.8269 11.9569 14.3058 11.9569 15.0642C11.9569 16.1417 11.9438 17.0065 11.9438 17.2725C11.9438 17.4854 12.0891 17.7383 12.4852 17.6584C15.6545 16.594 17.9391 13.5874 17.9391 10.0354C17.9522 5.59184 14.3736 2 9.97616 2Z"
|
||||
fill="#262626"
|
||||
fillOpacity="0.48"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
"use client";
|
||||
|
||||
import { usePathname } from "next/navigation";
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
interface HeaderContextType {
|
||||
dropdownContent: React.ReactNode;
|
||||
setDropdownContent: (content: React.ReactNode) => void;
|
||||
clearDropdown: (force?: boolean) => void;
|
||||
resetDropdownTimeout: () => void;
|
||||
dropdownKey: number;
|
||||
headerHeight: React.RefObject<number>;
|
||||
headerTop: React.RefObject<number>;
|
||||
}
|
||||
|
||||
const HeaderContext = createContext<HeaderContextType | undefined>(undefined);
|
||||
|
||||
export const HeaderProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [dropdownContent, setDropdownContent] = useState<React.ReactNode>(null);
|
||||
const [dropdownKey, setDropdownKey] = useState(0);
|
||||
const headerHeight = useRef(0);
|
||||
const headerTop = useRef(0);
|
||||
const pathname = usePathname();
|
||||
const timeout = useRef<number | null>(null);
|
||||
|
||||
const clearDropdown = (force?: boolean) => {
|
||||
if (force) {
|
||||
setDropdownContent(null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeout.current) {
|
||||
clearTimeout(timeout.current);
|
||||
}
|
||||
|
||||
timeout.current = window.setTimeout(() => {
|
||||
setDropdownContent(null);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const resetDropdownTimeout = () => {
|
||||
if (timeout.current) {
|
||||
clearTimeout(timeout.current);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const header = document.querySelector(".header") as HTMLElement;
|
||||
|
||||
if (header) {
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
headerHeight.current = entry.contentRect.height;
|
||||
}
|
||||
});
|
||||
|
||||
resizeObserver.observe(header);
|
||||
headerHeight.current = header.clientHeight;
|
||||
headerTop.current = header.getBoundingClientRect().top;
|
||||
|
||||
const onScroll = () => {
|
||||
headerTop.current = header.getBoundingClientRect().top;
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", onScroll, { passive: true });
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
window.removeEventListener("scroll", onScroll);
|
||||
};
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<HeaderContext.Provider
|
||||
value={{
|
||||
dropdownContent,
|
||||
setDropdownContent: (content) => {
|
||||
resetDropdownTimeout();
|
||||
|
||||
if (content === dropdownContent) return;
|
||||
setDropdownKey((prev) => prev + 1);
|
||||
setDropdownContent(content);
|
||||
},
|
||||
clearDropdown,
|
||||
resetDropdownTimeout,
|
||||
dropdownKey,
|
||||
headerHeight,
|
||||
headerTop,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</HeaderContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useHeaderContext = () => {
|
||||
const context = useContext(HeaderContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useHeaderContext must be used within a HeaderProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
export const useHeaderHeight = () => {
|
||||
const [headerHeight, setHeaderHeight] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const header = document.querySelector(".header");
|
||||
|
||||
if (header) {
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
setHeaderHeight(entry.contentRect.height);
|
||||
}
|
||||
});
|
||||
|
||||
resizeObserver.observe(header);
|
||||
setHeaderHeight(header.clientHeight);
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
return { headerHeight };
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import { JSX } from "react";
|
||||
|
||||
import { useHeaderContext } from "@/components/shared/header/HeaderContext";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
import ChevronDown from "./_svg/ChevronDown";
|
||||
|
||||
export default function HeaderNavItem({
|
||||
label,
|
||||
href,
|
||||
dropdown,
|
||||
}: {
|
||||
label: string;
|
||||
href: string;
|
||||
dropdown?: JSX.Element;
|
||||
}) {
|
||||
const { dropdownContent, setDropdownContent, clearDropdown } =
|
||||
useHeaderContext();
|
||||
|
||||
const active = dropdownContent === dropdown;
|
||||
|
||||
return (
|
||||
<a
|
||||
className="p-6 relative flex h-32 group rounded-8 active:scale-[0.98] transition-all duration-[50ms] active:duration-[100ms]"
|
||||
href={href}
|
||||
onMouseEnter={() => {
|
||||
if (dropdown) {
|
||||
setDropdownContent(dropdown);
|
||||
} else {
|
||||
clearDropdown(true);
|
||||
}
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
if (!dropdown) return;
|
||||
|
||||
clearDropdown();
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"overlay pointer-events-none group-hover:bg-black-alpha-4 transition-all scale-95 group-active:duration-[100ms] duration-[150ms] group-hover:scale-100 group-active:bg-black-alpha-7",
|
||||
active && "!scale-100 !bg-black-alpha-4",
|
||||
)}
|
||||
/>
|
||||
|
||||
<span className="px-4 text-label-medium text-accent-black">{label}</span>
|
||||
|
||||
{dropdown && <ChevronDown />}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export default function ChevronDown() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 18 20"
|
||||
width="18"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 9.5L9 12.5L12 9.5"
|
||||
stroke="#262626"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeOpacity="0.56"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
import EndpointsCrawl from "@/components/app/(home)/sections/endpoints/EndpointsCrawl/EndpointsCrawl";
|
||||
import EndpointsScrape from "@/components/app/(home)/sections/endpoints/EndpointsScrape/EndpointsScrape";
|
||||
import EndpointsSearch from "@/components/app/(home)/sections/endpoints/EndpointsSearch/EndpointsSearch";
|
||||
import EndpointsExtract from "@/components/app/(home)/sections/endpoints/Extract/Extract";
|
||||
import EndpointsMcp from "@/components/app/(home)/sections/endpoints/Mcp/Mcp";
|
||||
import { RenderEndpointIcon } from "@/components/shared/header/Nav/RenderEndpointIcon";
|
||||
import HeaderDropdownContent from "@/components/shared/header/Dropdown/Content/Content";
|
||||
import HeaderDropdownGithub from "@/components/shared/header/Dropdown/Github/Github";
|
||||
import HeaderDropdownStories from "@/components/shared/header/Dropdown/Stories/Stories";
|
||||
|
||||
import Affiliate from "./_svg/Affiliate";
|
||||
import Api from "./_svg/Api";
|
||||
import ArrowRight from "./_svg/ArrowRight";
|
||||
import Careers from "./_svg/Careers";
|
||||
import Changelog from "./_svg/Changelog";
|
||||
import Chats from "./_svg/Chats";
|
||||
import Lead from "./_svg/Lead";
|
||||
import Platforms from "./_svg/Platforms";
|
||||
import Research from "./_svg/Research";
|
||||
import Student from "./_svg/Student";
|
||||
import Templates from "./_svg/Templates";
|
||||
import HeaderNavItem from "./Item/Item";
|
||||
import MCPIcon from "./_svg/MCP";
|
||||
import Image from "@/components/shared/image/Image";
|
||||
import GithubFlame from "@/components/shared/header/Dropdown/Github/Flame/Flame";
|
||||
import EndpointsMap from "@/components/app/(home)/sections/endpoints/EndpointsMap/EndpointsMap";
|
||||
|
||||
export default function HeaderNav() {
|
||||
return (
|
||||
<div className="flex gap-8 relative lg-max:hidden select-none">
|
||||
{NAV_ITEMS.map((item) => (
|
||||
<HeaderNavItem key={item.label} {...item} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const NAV_ITEMS = [
|
||||
{
|
||||
label: "Products",
|
||||
href: "#",
|
||||
dropdown: (
|
||||
<HeaderDropdownContent
|
||||
navigationItems={[
|
||||
{
|
||||
label: "Endpoints",
|
||||
items: [
|
||||
{
|
||||
icon: (
|
||||
<RenderEndpointIcon
|
||||
icon={EndpointsScrape}
|
||||
alwaysHeat
|
||||
triggerOnHover
|
||||
/>
|
||||
),
|
||||
label: "Scrape",
|
||||
description: "Turn any url into clean data",
|
||||
href: "https://docs.firecrawl.dev/features/scrape",
|
||||
iconClassName: "-mt-1",
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<RenderEndpointIcon
|
||||
icon={EndpointsCrawl}
|
||||
alwaysHeat
|
||||
triggerOnHover
|
||||
/>
|
||||
),
|
||||
label: "Crawl",
|
||||
description: "Crawl entire websites",
|
||||
href: "https://docs.firecrawl.dev/features/crawl",
|
||||
iconClassName: "-mt-1",
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<RenderEndpointIcon
|
||||
icon={EndpointsSearch}
|
||||
alwaysHeat
|
||||
triggerOnHover
|
||||
/>
|
||||
),
|
||||
label: "Search",
|
||||
description: "Search and get page content",
|
||||
href: "https://docs.firecrawl.dev/features/search",
|
||||
iconClassName: "-mt-1",
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<RenderEndpointIcon
|
||||
icon={EndpointsMap}
|
||||
alwaysHeat
|
||||
triggerOnHover
|
||||
/>
|
||||
),
|
||||
label: "Map",
|
||||
description: "Get all links from a website",
|
||||
href: "https://docs.firecrawl.dev/features/map",
|
||||
iconClassName: "-mt-1",
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<RenderEndpointIcon
|
||||
icon={EndpointsMcp}
|
||||
alwaysHeat
|
||||
triggerOnHover
|
||||
/>
|
||||
),
|
||||
label: "MCP",
|
||||
description: "Connect Firecrawl to agents",
|
||||
href: "https://docs.firecrawl.dev/features/mcp",
|
||||
iconClassName: "-mt-1",
|
||||
},
|
||||
|
||||
// Extract section in the same column, highlighted as a separate product
|
||||
// {
|
||||
// icon: <RenderEndpointIcon icon={EndpointsExtract} alwaysHeat triggerOnHover />,
|
||||
// label: 'Extract',
|
||||
// description: 'Get structured data from single pages or entire websites with AI.',
|
||||
// href: '/extract',
|
||||
// big: true,
|
||||
// sectionLabel: 'Extract Product',
|
||||
// iconClassName: 'mt-4',
|
||||
// ctas: [
|
||||
// { label: 'View Extract', href: '/extract' },
|
||||
// { label: 'Try it now', href: '/playground?mode=extract' }
|
||||
// ]
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Use Cases",
|
||||
items: [
|
||||
{
|
||||
icon: <Chats />,
|
||||
label: "AI Platforms",
|
||||
description: "Let customers build AI apps",
|
||||
href: "https://docs.firecrawl.dev/use-cases/ai-platforms",
|
||||
target: "_blank",
|
||||
},
|
||||
{
|
||||
icon: <Lead />,
|
||||
label: "Lead Enrichment",
|
||||
description: "Enhance sales data",
|
||||
href: "https://docs.firecrawl.dev/use-cases/lead-enrichment",
|
||||
target: "_blank",
|
||||
},
|
||||
{
|
||||
icon: <Platforms />,
|
||||
label: "SEO Platforms",
|
||||
description: "Power SEO/GEO tools",
|
||||
href: "https://docs.firecrawl.dev/use-cases/seo-platforms",
|
||||
target: "_blank",
|
||||
},
|
||||
{
|
||||
icon: <Research />,
|
||||
label: "Deep Research",
|
||||
description: "Build research agents",
|
||||
href: "https://docs.firecrawl.dev/use-cases/deep-research",
|
||||
target: "_blank",
|
||||
},
|
||||
{
|
||||
icon: <ArrowRight />,
|
||||
label: "View more",
|
||||
description: "Explore all use cases",
|
||||
href: "https://docs.firecrawl.dev/use-cases/overview",
|
||||
target: "_blank",
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
sideContent={<HeaderDropdownStories />}
|
||||
sideItem={{
|
||||
icon: <ArrowRight />,
|
||||
label: "Customer stories",
|
||||
description: "Browse Firecrawl success stories",
|
||||
href: "/blog/category/customer-stories",
|
||||
}}
|
||||
sideLabel="Customer Stories"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: "Playground",
|
||||
href: "/playground",
|
||||
},
|
||||
{
|
||||
label: "Docs",
|
||||
href: "https://docs.firecrawl.dev",
|
||||
},
|
||||
{
|
||||
label: "Pricing",
|
||||
href: "/pricing",
|
||||
},
|
||||
{
|
||||
label: "Blog",
|
||||
href: "/blog",
|
||||
},
|
||||
{
|
||||
label: "Extract",
|
||||
href: "#",
|
||||
dropdown: (
|
||||
<HeaderDropdownContent
|
||||
navigationItems={[
|
||||
{
|
||||
label: "Extract API",
|
||||
items: [
|
||||
// { icon: <Templates />, label: 'Templates', description: 'Jumpstart your web scraping', href: '/templates' },
|
||||
{
|
||||
icon: (
|
||||
<RenderEndpointIcon
|
||||
icon={EndpointsExtract}
|
||||
alwaysHeat
|
||||
triggerOnHover
|
||||
/>
|
||||
),
|
||||
label: "Extract",
|
||||
description: "Get structured data from entire websites",
|
||||
href: "/extract",
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<div className="text-heat-100">
|
||||
<Platforms />
|
||||
</div>
|
||||
),
|
||||
label: "Playground",
|
||||
description: "Try it out in the /extract playground",
|
||||
href: "/app/extract-playground",
|
||||
},
|
||||
// { icon: <ArrowRight/>, label: 'Docs', description: 'Read the docs.', href: 'https://docs.firecrawl.dev/features/extract', target: '_blank' },
|
||||
],
|
||||
},
|
||||
]}
|
||||
sideContent={
|
||||
<div className="py-24 px-44 border-b border-border-faint relative overflow-clip">
|
||||
{/* <div className="size-40 relative mb-17"> */}
|
||||
{/* */}
|
||||
{/* </div> */}
|
||||
|
||||
<div className="text-label-large">
|
||||
Get web data with a prompt. <br />
|
||||
Collect structured data from any number of URLs or entire domains.
|
||||
</div>
|
||||
|
||||
<GithubFlame />
|
||||
</div>
|
||||
}
|
||||
sideItem={{
|
||||
icon: <ArrowRight />,
|
||||
label: "See Docs",
|
||||
description: "Read the docs.",
|
||||
href: "https://docs.firecrawl.dev/features/extract",
|
||||
}}
|
||||
sideLabel="/extract"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: "Resources",
|
||||
href: "#",
|
||||
dropdown: (
|
||||
<HeaderDropdownContent
|
||||
navigationItems={[
|
||||
{
|
||||
label: "Resources",
|
||||
items: [
|
||||
// { icon: <Templates />, label: 'Templates', description: 'Jumpstart your web scraping', href: '/templates' },
|
||||
{
|
||||
icon: <Changelog />,
|
||||
label: "Changelog",
|
||||
description: "Latest APl updates for Firecrawl",
|
||||
href: "/changelog",
|
||||
},
|
||||
{
|
||||
icon: <Api />,
|
||||
label: "API Status",
|
||||
description: "See maintenance, uptime and more",
|
||||
href: "https://firecrawl.betteruptime.dev/",
|
||||
target: "_blank",
|
||||
},
|
||||
{
|
||||
icon: <Careers />,
|
||||
label: "Careers",
|
||||
description: "Join our team, we're hiring!",
|
||||
href: "/careers",
|
||||
},
|
||||
{
|
||||
icon: <Affiliate />,
|
||||
label: "Creator & OSS Program",
|
||||
description: "Earn rewards for referring customers",
|
||||
href: "/creator-oss-program",
|
||||
},
|
||||
{
|
||||
icon: <Student />,
|
||||
label: "Student Program",
|
||||
description: "Get free credits for your projects",
|
||||
href: "/student-program",
|
||||
},
|
||||
{
|
||||
icon: <MCPIcon />,
|
||||
label: "MCP",
|
||||
description: "Connect Firecrawl to agents",
|
||||
href: "https://docs.firecrawl.dev/features/mcp",
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
sideContent={<HeaderDropdownGithub />}
|
||||
sideItem={{
|
||||
icon: <ArrowRight />,
|
||||
label: "See Github",
|
||||
description: "View the repository",
|
||||
href: "https://github.com/firecrawl/firecrawl",
|
||||
}}
|
||||
sideLabel="Open Source"
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import EndpointsScrape from "@/components/app/(home)/sections/endpoints/EndpointsScrape/EndpointsScrape";
|
||||
import { ComponentProps } from "react";
|
||||
import { useMediaQuery } from "usehooks-ts";
|
||||
|
||||
export const RenderEndpointIcon = ({
|
||||
icon: Icon,
|
||||
...props
|
||||
}: { icon: typeof EndpointsScrape } & ComponentProps<
|
||||
typeof EndpointsScrape
|
||||
>) => {
|
||||
const isMobile = useMediaQuery("(max-width: 996px)");
|
||||
|
||||
return <Icon {...props} size={isMobile ? 24 : 20} />;
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
export default function Affiliate() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M13.3332 6.6665L6.6665 13.3332M17.7082 9.99984C17.7082 14.257 14.257 17.7082 9.99984 17.7082C5.74265 17.7082 2.2915 14.257 2.2915 9.99984C2.2915 5.74265 5.74265 2.2915 9.99984 2.2915C14.257 2.2915 17.7082 5.74265 17.7082 9.99984Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
d="M7.5 6.875C7.84517 6.875 8.125 7.15483 8.125 7.5C8.125 7.84517 7.84517 8.125 7.5 8.125C7.15483 8.125 6.875 7.84517 6.875 7.5C6.875 7.15483 7.15483 6.875 7.5 6.875Z"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
d="M12.5 11.875C12.8452 11.875 13.125 12.1548 13.125 12.5C13.125 12.8452 12.8452 13.125 12.5 13.125C12.1548 13.125 11.875 12.8452 11.875 12.5C11.875 12.1548 12.1548 11.875 12.5 11.875Z"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export default function Api() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M3.125 4.79167C3.125 3.87119 3.87119 3.125 4.79167 3.125H15.2083C16.1288 3.125 16.875 3.87119 16.875 4.79167V15.2083C16.875 16.1288 16.1288 16.875 15.2083 16.875H4.79167C3.87119 16.875 3.125 16.1288 3.125 15.2083V4.79167Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="square"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
d="M3.125 10.0002H6.45833L8.33333 13.5418L11.6667 6.4585L13.5417 10.0002H16.875"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="square"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export default function ArrowRight() {
|
||||
return (
|
||||
<svg
|
||||
className="text-black-alpha-48 group-hover:text-heat-100 transition-all"
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M11.6667 4.7915L16.875 9.99982M16.875 9.99982L11.6667 15.2082M16.875 9.99982H3.125"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function Careers() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17.4998 10.625H9.99984M9.99984 10.625H2.49984M9.99984 10.625L10.0017 12.7083M6.66834 6.45833V4.375C6.66834 3.68464 7.22798 3.125 7.91834 3.125H12.085C12.7753 3.125 13.335 3.68464 13.335 4.375V6.45833M16.0415 16.875H3.95817C3.0377 16.875 2.2915 16.1288 2.2915 15.2083V8.125C2.2915 7.20452 3.0377 6.45833 3.95817 6.45833H16.0415C16.962 6.45833 17.7082 7.20452 17.7082 8.125V15.2083C17.7082 16.1288 16.962 16.875 16.0415 16.875Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function Changelog() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7.2915 2.7085H5.20817C4.2877 2.7085 3.5415 3.45469 3.5415 4.37516V15.6252C3.5415 16.5457 4.2877 17.2918 5.20817 17.2918H7.2915M7.2915 2.7085H14.7915C15.712 2.7085 16.4582 3.45469 16.4582 4.37516V15.6252C16.4582 16.5457 15.712 17.2918 14.7915 17.2918H7.2915M7.2915 2.7085V17.2918M10.6248 6.4585H13.1248M10.6248 9.79183H13.1248"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
export default function Ai() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M1.45825 7.50016C5.65385 7.50016 7.49992 5.6541 7.49992 1.4585C7.49992 5.6541 9.34598 7.50016 13.5416 7.50016C9.34598 7.50016 7.49992 9.34623 7.49992 13.5418C7.49992 9.34623 5.65385 7.50016 1.45825 7.50016Z"
|
||||
fillRule="evenodd"
|
||||
stroke="currentColor"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M10.6249 14.5835C13.3738 14.5835 14.5833 13.374 14.5833 10.6252C14.5833 13.374 15.7927 14.5835 18.5416 14.5835C15.7927 14.5835 14.5833 15.793 14.5833 18.5418C14.5833 15.793 13.3738 14.5835 10.6249 14.5835Z"
|
||||
fillRule="evenodd"
|
||||
stroke="currentColor"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export default function Lead() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10.8333 16.0417H16.25C17.1705 16.0417 17.9167 15.2955 17.9167 14.375V7.29167C17.9167 6.37119 17.1705 5.625 16.25 5.625H11.1003C10.543 5.625 10.0227 5.3465 9.71355 4.88283L9.03644 3.86717C8.72733 3.4035 8.20695 3.125 7.64969 3.125H4.16666C3.24619 3.125 2.5 3.87119 2.5 4.79167V6.875M6.45833 10.4167C6.45833 11.2221 5.80541 11.875 5 11.875C4.19458 11.875 3.54166 11.2221 3.54166 10.4167C3.54166 9.61125 4.19458 8.95833 5 8.95833C5.80541 8.95833 6.45833 9.61125 6.45833 10.4167ZM1.93082 15.8928C2.5458 14.7359 3.69002 13.9583 5 13.9583C6.30997 13.9583 7.45419 14.7359 8.06918 15.8928C8.32136 16.3672 7.92297 16.875 7.38572 16.875H2.61427C2.07702 16.875 1.67864 16.3672 1.93082 15.8928Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export default function MCPIcon() {
|
||||
return (
|
||||
<svg
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>ModelContextProtocol</title>
|
||||
<path d="M15.688 2.343a2.588 2.588 0 00-3.61 0l-9.626 9.44a.863.863 0 01-1.203 0 .823.823 0 010-1.18l9.626-9.44a4.313 4.313 0 016.016 0 4.116 4.116 0 011.204 3.54 4.3 4.3 0 013.609 1.18l.05.05a4.115 4.115 0 010 5.9l-8.706 8.537a.274.274 0 000 .393l1.788 1.754a.823.823 0 010 1.18.863.863 0 01-1.203 0l-1.788-1.753a1.92 1.92 0 010-2.754l8.706-8.538a2.47 2.47 0 000-3.54l-.05-.049a2.588 2.588 0 00-3.607-.003l-7.172 7.034-.002.002-.098.097a.863.863 0 01-1.204 0 .823.823 0 010-1.18l7.273-7.133a2.47 2.47 0 00-.003-3.537z"></path>
|
||||
<path d="M14.485 4.703a.823.823 0 000-1.18.863.863 0 00-1.204 0l-7.119 6.982a4.115 4.115 0 000 5.9 4.314 4.314 0 006.016 0l7.12-6.982a.823.823 0 000-1.18.863.863 0 00-1.204 0l-7.119 6.982a2.588 2.588 0 01-3.61 0 2.47 2.47 0 010-3.54l7.12-6.982z"></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
export default function Platforms() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.41667 7.49984C5.18655 7.49984 5 7.31329 5 7.08317C5 6.85305 5.18655 6.6665 5.41667 6.6665C5.64679 6.6665 5.83333 6.85305 5.83333 7.08317C5.83333 7.31329 5.64679 7.49984 5.41667 7.49984Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8.33333 7.49984C8.10321 7.49984 7.91667 7.31329 7.91667 7.08317C7.91667 6.85305 8.10321 6.6665 8.33333 6.6665C8.56345 6.6665 8.75 6.85305 8.75 7.08317C8.75 7.31329 8.56345 7.49984 8.33333 7.49984Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M11.25 7.49984C11.0199 7.49984 10.8333 7.31329 10.8333 7.08317C10.8333 6.85305 11.0199 6.6665 11.25 6.6665C11.4801 6.6665 11.6667 6.85305 11.6667 7.08317C11.6667 7.31329 11.4801 7.49984 11.25 7.49984Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17.7084 10.2085V5.62516C17.7084 4.70469 16.9622 3.9585 16.0417 3.9585H3.95841C3.03794 3.9585 2.29175 4.70469 2.29175 5.62516V15.2085C2.29175 16.129 3.03794 16.8752 3.95841 16.8752H10.2084M18.3334 14.295L12.5001 12.5002L14.295 18.3335L15.6411 15.6412L18.3334 14.295Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
export default function Research() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M4.8956 8.9541L2.05646 9.98744C1.40773 10.2236 1.07325 10.9409 1.30937 11.5896L1.66563 12.5684C1.90175 13.2172 2.61906 13.5517 3.26778 13.3155L6.10693 12.2822"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
d="M9.40608 6.36865L6.15568 7.55169C5.29072 7.86651 4.84474 8.82292 5.15956 9.68784L5.83647 11.5477C6.15129 12.4127 7.1077 12.8586 7.97266 12.5438L11.223 11.3608"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
d="M11.062 4.82461L15.546 3.19257C15.9785 3.03516 16.4567 3.25815 16.6142 3.69063L18.4667 8.78066C18.6242 9.21316 18.4012 9.69132 17.9687 9.84874L13.4847 11.4807C12.4035 11.8743 11.208 11.3168 10.8144 10.2357L9.81691 7.49485C9.42332 6.41365 9.98082 5.21814 11.062 4.82461Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
d="M8.95825 16.8748V12.2915"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
d="M6.45825 16.875H11.4583"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function Student() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19.375 7.50417L10 11.8833L0.625 7.50417L10 3.125L19.375 7.50417ZM19.375 7.50417V12.7175M3.95835 9.14633V12.8756C3.95835 13.4922 4.29811 14.0585 4.84186 14.3482L9.21683 16.6793C9.70642 16.9403 10.2936 16.9403 10.7832 16.6793L15.1582 14.3482C15.7019 14.0585 16.0417 13.4922 16.0417 12.8756V9.14633"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export default function Templates() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M3.95817 16.0417C3.0377 16.0417 2.2915 15.2955 2.2915 14.375V7.29167C2.2915 6.37119 3.0377 5.625 3.95817 5.625H16.0415C16.962 5.625 17.7082 6.37119 17.7082 7.29167V14.375C17.7082 15.2955 16.962 16.0417 16.0415 16.0417H3.95817Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
<path
|
||||
d="M3.9585 3.125H16.0418"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
"use client";
|
||||
|
||||
import Button from "@/components/ui/shadcn/button";
|
||||
import { useHeaderContext } from "@/components/shared/header/HeaderContext";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
export default function HeaderToggle({
|
||||
dropdownContent,
|
||||
}: {
|
||||
dropdownContent: React.ReactNode;
|
||||
}) {
|
||||
const {
|
||||
dropdownContent: headerDropdownContent,
|
||||
clearDropdown,
|
||||
setDropdownContent,
|
||||
} = useHeaderContext();
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="lg:hidden"
|
||||
variant="tertiary"
|
||||
onClick={() => {
|
||||
if (dropdownContent === headerDropdownContent) {
|
||||
clearDropdown(true);
|
||||
} else {
|
||||
setDropdownContent(dropdownContent);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
className="!size-20"
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
className={cn("transition-all origin-center", {
|
||||
"rotate-45 -translate-y-4": headerDropdownContent,
|
||||
})}
|
||||
d="M2.28906 13.9609H17.7057"
|
||||
stroke="#262626"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
style={{
|
||||
transformBox: "fill-box",
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
className={cn("transition-all origin-center", {
|
||||
"-rotate-45 translate-y-3 translate-x-[2.5px]":
|
||||
headerDropdownContent,
|
||||
})}
|
||||
d="M2.28906 6.03906H17.7057"
|
||||
stroke="#262626"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
"use client";
|
||||
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
export default function HeaderWrapper({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [shouldShrink, setShouldShrink] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
const heroContentHeight =
|
||||
document.getElementById("hero-content")?.clientHeight;
|
||||
const triggerTop = heroContentHeight ? heroContentHeight : 100;
|
||||
|
||||
const onScroll = () => {
|
||||
setShouldShrink(window.scrollY > triggerTop);
|
||||
};
|
||||
|
||||
onScroll();
|
||||
|
||||
window.addEventListener("scroll", onScroll);
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"container lg:px-56 px-16 flex justify-between transition-[padding] duration-[200ms] items-center",
|
||||
shouldShrink ? "py-20" : "py-20 lg:py-34",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
export default function Logo() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="15"
|
||||
viewBox="0 0 79 15"
|
||||
width="79"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0.599609 14.4311V0.576888H9.45474V2.59564H2.87778V6.61335H8.30575V8.57272H2.87778V14.4311H0.599609Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M11.9737 2.87272C11.2407 2.87272 10.6663 2.33835 10.6663 1.58626C10.6663 0.83418 11.2407 0.299805 11.9737 0.299805C12.7067 0.299805 13.2812 0.83418 13.2812 1.58626C13.2812 2.33835 12.7067 2.87272 11.9737 2.87272ZM10.8842 14.4311V4.29772H13.0237V14.4311H10.8842Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M20.1527 4.29772H20.6281V6.29668H19.6772C17.7755 6.29668 17.1613 7.78105 17.1613 9.3446V14.4311H15.0219V4.29772H16.9236L17.1613 5.82168C17.6764 4.97064 18.4886 4.29772 20.1527 4.29772Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M26.1788 14.5498C22.9894 14.5498 20.9886 12.4915 20.9886 9.38418C20.9886 6.2571 22.9894 4.17897 25.9807 4.17897C28.9126 4.17897 30.8738 6.03939 30.9333 9.00814C30.9333 9.26543 30.9135 9.54251 30.8738 9.8196H23.2271V9.95814C23.2865 11.68 24.3761 12.8081 26.06 12.8081C27.3674 12.8081 28.3183 12.155 28.6155 11.0269H30.755C30.3984 13.0258 28.6947 14.5498 26.1788 14.5498ZM23.3064 8.25605H28.7145C28.5362 6.75189 27.4863 5.90085 26.0005 5.90085C24.6336 5.90085 23.4648 6.81126 23.3064 8.25605Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M37.2193 14.5498C34.1487 14.5498 32.1875 12.5508 32.1875 9.38418C32.1875 6.2571 34.2081 4.17897 37.2787 4.17897C39.8936 4.17897 41.5181 5.62376 41.9341 7.9196H39.6955C39.4182 6.7321 38.5664 5.9998 37.2391 5.9998C35.5156 5.9998 34.3864 7.38522 34.3864 9.38418C34.3864 11.3633 35.5156 12.729 37.2391 12.729C38.5465 12.729 39.4182 11.9769 39.6757 10.8092H41.9341C41.5379 13.105 39.8144 14.5498 37.2193 14.5498Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M48.6034 4.29772H49.0789V6.29668H48.128C46.2262 6.29668 45.6121 7.78105 45.6121 9.3446V14.4311H43.4726V4.29772H45.3744L45.6121 5.82168C46.1272 4.97064 46.9394 4.29772 48.6034 4.29772Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M54.3679 4.17897C57.0621 4.17897 58.6073 5.46543 58.6073 7.86022V14.4311H56.7451L56.5668 12.9863C55.8735 13.8967 54.9028 14.5498 53.2981 14.5498C51.0794 14.5498 49.5936 13.4613 49.5936 11.5811C49.5936 9.50293 51.0992 8.33522 53.9519 8.33522H56.4876V7.72168C56.4876 6.59355 55.6754 5.90085 54.2688 5.90085C53.001 5.90085 52.1491 6.4946 51.9907 7.38522H49.8908C50.1087 5.40605 51.8124 4.17897 54.3679 4.17897ZM53.6547 12.8873C55.4376 12.8873 56.4678 11.8383 56.4876 10.2748V9.91855H53.833C52.5057 9.91855 51.7728 10.4133 51.7728 11.4425C51.7728 12.2936 52.4859 12.8873 53.6547 12.8873Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M62.7912 14.4311L59.4829 4.29772H61.7413L64.0591 12.0561L66.3768 4.29772H68.3381L70.5568 12.0561L72.9538 4.29772H75.1329L71.7652 14.4311H69.4672L67.3277 7.54355L65.109 14.4311H62.7912Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M76.1601 14.4311V0.576888H78.2996V14.4311H76.1601Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
// Sample of flame frames - using a subset for performance
|
||||
const flameFrames = [
|
||||
`
|
||||
▄▄▄
|
||||
▄███▄
|
||||
▄█████▄
|
||||
▄███████▄
|
||||
▄█████████▄
|
||||
▄███████████▄
|
||||
▄█████████████▄
|
||||
▄███████████████▄
|
||||
█████████████████
|
||||
███▀▀▀███▀▀▀█████
|
||||
██ ███ ███
|
||||
█ ▀ ██
|
||||
`,
|
||||
`
|
||||
▄███▄
|
||||
▄█████▄
|
||||
▄███▀███▄
|
||||
▄████▄████▄
|
||||
▄███████████▄
|
||||
▄█████▀▀██████▄
|
||||
▄██████▄▄███████▄
|
||||
█████████████████
|
||||
███▀▀█████▀▀█████
|
||||
██ ███ ███
|
||||
█ ▀ ██
|
||||
|
||||
`,
|
||||
`
|
||||
▄█████▄
|
||||
▄███████▄
|
||||
▄█████████▄
|
||||
▄███▀███▀███▄
|
||||
▄████▄███▄████▄
|
||||
▄██████████████▄
|
||||
████▀▀█████▀▀████
|
||||
███ ███ ███
|
||||
██ ▀▀ ███
|
||||
█ ██
|
||||
|
||||
|
||||
`,
|
||||
`
|
||||
▄███████▄
|
||||
▄█████████▄
|
||||
▄███████████▄
|
||||
▄█████▀▀██████▄
|
||||
▄███████▄▄██████▄
|
||||
██████████████████
|
||||
████▀▀▀████▀▀▀████
|
||||
███ ███ ███
|
||||
██ ▀▀ ██
|
||||
█ █
|
||||
|
||||
|
||||
`,
|
||||
];
|
||||
|
||||
interface HeroFlameProps {
|
||||
className?: string;
|
||||
size?: "small" | "medium" | "large";
|
||||
}
|
||||
|
||||
export function HeroFlame({ className, size = "medium" }: HeroFlameProps) {
|
||||
const [frameIndex, setFrameIndex] = useState(0);
|
||||
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
intervalRef.current = setInterval(() => {
|
||||
setFrameIndex((prev) => (prev + 1) % flameFrames.length);
|
||||
}, 85);
|
||||
|
||||
return () => {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const sizeClasses = {
|
||||
small: "text-[8px] leading-[10px]",
|
||||
medium: "text-[12px] leading-[14px]",
|
||||
large: "text-[16px] leading-[18px]",
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("flex gap-4 pointer-events-none select-none", className)}
|
||||
>
|
||||
{/* Left flame */}
|
||||
<div className="relative overflow-hidden">
|
||||
<pre
|
||||
className={cn(
|
||||
"text-heat-100 font-mono whitespace-pre",
|
||||
sizeClasses[size],
|
||||
)}
|
||||
>
|
||||
{flameFrames[frameIndex]}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
{/* Right flame (mirrored) */}
|
||||
<div className="relative overflow-hidden -scale-x-100">
|
||||
<pre
|
||||
className={cn(
|
||||
"text-heat-100 font-mono whitespace-pre",
|
||||
sizeClasses[size],
|
||||
)}
|
||||
>
|
||||
{flameFrames[frameIndex]}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
const GitHub = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12 0C5.37 0 0 5.50583 0 12.3035C0 17.7478 3.435 22.3463 8.205 23.9765C8.805 24.0842 9.03 23.715 9.03 23.3921C9.03 23.0999 9.015 22.131 9.015 21.1005C6 21.6696 5.22 20.347 4.98 19.6549C4.845 19.3012 4.26 18.2092 3.75 17.917C3.33 17.6863 2.73 17.1173 3.735 17.1019C4.68 17.0865 5.355 17.9939 5.58 18.363C6.66 20.2239 8.385 19.701 9.075 19.3781C9.18 18.5783 9.495 18.04 9.84 17.7325C7.17 17.4249 4.38 16.3637 4.38 11.6576C4.38 10.3196 4.845 9.21227 5.61 8.35102C5.49 8.04343 5.07 6.78232 5.73 5.09058C5.73 5.09058 6.735 4.76762 9.03 6.3517C9.99 6.07487 11.01 5.93645 12.03 5.93645C13.05 5.93645 14.07 6.07487 15.03 6.3517C17.325 4.75224 18.33 5.09058 18.33 5.09058C18.99 6.78232 18.57 8.04343 18.45 8.35102C19.215 9.21227 19.68 10.3042 19.68 11.6576C19.68 16.3791 16.875 17.4249 14.205 17.7325C14.64 18.1169 15.015 18.8552 15.015 20.0086C15.015 21.6542 15 22.9768 15 23.3921C15 23.715 15.225 24.0995 15.825 23.9765C18.2072 23.1519 20.2773 21.5822 21.7438 19.4882C23.2103 17.3942 23.9994 14.8814 24 12.3035C24 5.50583 18.63 0 12 0Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default GitHub;
|
||||
@@ -0,0 +1,22 @@
|
||||
const Logo = ({ ...props }) => (
|
||||
// <svg
|
||||
// width="32"
|
||||
// height="32"
|
||||
// viewBox="0 0 32 32"
|
||||
// fill="none"
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
// {...props}
|
||||
// >
|
||||
// <rect width="100%" height="100%" rx="16" fill="white" />
|
||||
// <path
|
||||
// fillRule="evenodd"
|
||||
// clipRule="evenodd"
|
||||
// d="M17.6482 10.1305L15.8785 7.02583L7.02979 22.5499H10.5278L17.6482 10.1305ZM19.8798 14.0457L18.11 17.1983L19.394 19.4511H16.8453L15.1056 22.5499H24.7272L19.8798 14.0457Z"
|
||||
// fill="black"
|
||||
// />
|
||||
// </svg>
|
||||
<span className="text-2xl" {...props}>
|
||||
🔥
|
||||
</span>
|
||||
);
|
||||
export default Logo;
|
||||
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
interface AnimatedChevronProps {
|
||||
isOpen: boolean;
|
||||
className?: string;
|
||||
size?: "sm" | "md" | "lg";
|
||||
}
|
||||
|
||||
export function AnimatedChevron({
|
||||
isOpen,
|
||||
className,
|
||||
size = "md",
|
||||
}: AnimatedChevronProps) {
|
||||
const sizeClasses = {
|
||||
sm: "h-12 w-12",
|
||||
md: "h-16 w-16",
|
||||
lg: "h-20 w-20",
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn("flex items-center justify-center", sizeClasses[size])}>
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
{isOpen ? (
|
||||
<motion.div
|
||||
key="chevron-up"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<ChevronUp
|
||||
className={cn(
|
||||
sizeClasses[size],
|
||||
"text-black-alpha-40",
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key="chevron-down"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<ChevronDown
|
||||
className={cn(
|
||||
sizeClasses[size],
|
||||
"text-black-alpha-40",
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,966 @@
|
||||
"use client";
|
||||
|
||||
import type { Transition, Variants } from "framer-motion";
|
||||
import { motion, useAnimation } from "framer-motion";
|
||||
import { useCallback, useEffect } from "react";
|
||||
|
||||
const playIconVariants: Variants = {
|
||||
normal: {
|
||||
x: 0,
|
||||
rotate: 0,
|
||||
},
|
||||
animate: {
|
||||
x: [0, -1, 2, 0],
|
||||
rotate: [0, -10, 0, 0],
|
||||
transition: {
|
||||
duration: 0.5,
|
||||
times: [0, 0.2, 0.5, 1],
|
||||
stiffness: 260,
|
||||
damping: 20,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const defaultTransition: Transition = {
|
||||
duration: 0.6,
|
||||
opacity: { duration: 0.2 },
|
||||
};
|
||||
|
||||
const pathVariants: Variants = {
|
||||
normal: {
|
||||
pathLength: 1,
|
||||
opacity: 1,
|
||||
},
|
||||
animate: {
|
||||
opacity: [0, 1],
|
||||
pathLength: [0.5, 1],
|
||||
},
|
||||
};
|
||||
|
||||
// Higher-order component for icon animation
|
||||
const withIconAnimation = (IconComponent: React.ComponentType<any>) => {
|
||||
const AnimatedIcon = ({
|
||||
isHovered = false,
|
||||
className,
|
||||
...props
|
||||
}: {
|
||||
isHovered?: boolean;
|
||||
className?: string;
|
||||
}) => {
|
||||
const controls = useAnimation();
|
||||
|
||||
useEffect(() => {
|
||||
if (isHovered) {
|
||||
controls.start("animate");
|
||||
} else {
|
||||
controls.start("normal");
|
||||
}
|
||||
}, [isHovered, controls]);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<IconComponent controls={controls} {...props} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
AnimatedIcon.displayName = `Animated${IconComponent.displayName || IconComponent.name || 'Icon'}`;
|
||||
return AnimatedIcon;
|
||||
};
|
||||
|
||||
// Higher-order component for icon animation
|
||||
const withChartIconAnimation = (IconComponent: React.ComponentType<any>) => {
|
||||
const AnimatedChartIcon = ({
|
||||
isHovered = false,
|
||||
className,
|
||||
...props
|
||||
}: {
|
||||
isHovered?: boolean;
|
||||
className?: string;
|
||||
}) => {
|
||||
const controls = useAnimation();
|
||||
|
||||
const handleHoverStart = useCallback(async () => {
|
||||
await controls.start((i) => ({
|
||||
pathLength: 0,
|
||||
opacity: 0,
|
||||
transition: { delay: i * 0.1, duration: 0.3 },
|
||||
}));
|
||||
await controls.start((i) => ({
|
||||
pathLength: 1,
|
||||
opacity: 1,
|
||||
transition: { delay: i * 0.1, duration: 0.3 },
|
||||
}));
|
||||
}, [controls]);
|
||||
|
||||
const handleHoverEnd = useCallback(() => {
|
||||
controls.start("normal");
|
||||
}, [controls]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isHovered) {
|
||||
handleHoverStart();
|
||||
} else {
|
||||
handleHoverEnd();
|
||||
}
|
||||
}, [isHovered, handleHoverStart, handleHoverEnd]);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<IconComponent
|
||||
onMouseEnter={handleHoverStart}
|
||||
onMouseLeave={handleHoverEnd}
|
||||
controls={controls}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
AnimatedChartIcon.displayName = `AnimatedChart${IconComponent.displayName || IconComponent.name || 'Icon'}`;
|
||||
return AnimatedChartIcon;
|
||||
};
|
||||
|
||||
// Base icon components
|
||||
const HomeIconBase = ({ controls }: { controls: any }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||
<motion.path
|
||||
d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"
|
||||
variants={pathVariants}
|
||||
transition={defaultTransition}
|
||||
animate={controls}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
// Example of another icon with animation
|
||||
const PlayIconBase = ({ controls }: { controls: any }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<motion.path
|
||||
d="M5 3l14 9-14 9V3z"
|
||||
variants={playIconVariants}
|
||||
transition={defaultTransition}
|
||||
animate={controls}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const SettingsGearIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<motion.svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
transition={{ type: "spring", stiffness: 50, damping: 10 }}
|
||||
variants={{
|
||||
normal: {
|
||||
rotate: 0,
|
||||
},
|
||||
animate: {
|
||||
rotate: 90,
|
||||
},
|
||||
}}
|
||||
animate={controls}
|
||||
>
|
||||
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" />
|
||||
<circle cx="12" cy="12" r="3" />
|
||||
</motion.svg>
|
||||
);
|
||||
};
|
||||
|
||||
const lineChartVariants2: Variants = {
|
||||
visible: { pathLength: 1, opacity: 1 },
|
||||
hidden: { pathLength: 0, opacity: 0 },
|
||||
};
|
||||
const ChartColumnIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<motion.path
|
||||
d="M13 17V9"
|
||||
variants={lineChartVariants2}
|
||||
transition={defaultTransition}
|
||||
animate={controls}
|
||||
initial="visible"
|
||||
custom={1}
|
||||
/>
|
||||
<motion.path
|
||||
d="M18 17V5"
|
||||
variants={lineChartVariants2}
|
||||
transition={defaultTransition}
|
||||
animate={controls}
|
||||
initial="visible"
|
||||
custom={2}
|
||||
/>
|
||||
<path d="M3 3v16a2 2 0 0 0 2 2h16" />
|
||||
<motion.path
|
||||
d="M8 17v-3"
|
||||
variants={lineChartVariants2}
|
||||
transition={defaultTransition}
|
||||
animate={controls}
|
||||
initial="visible"
|
||||
custom={0}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
// const defaultTransition: Transition = {
|
||||
// duration: 0.9,
|
||||
// ease: 'easeInOut',
|
||||
// };
|
||||
|
||||
// const pathVariants: Variants = {
|
||||
// normal: {
|
||||
// rotate: 0,
|
||||
// x: 0,
|
||||
// y: 0,
|
||||
// },
|
||||
// hover: {
|
||||
// rotate: [0, 4, 2, -3, 1, 0],
|
||||
// x: [0, 0.7, -0.3, 0.5, 0.2, 0],
|
||||
// y: [0, -0.2, 0.3, -0.2, 0.4, 0],
|
||||
// },
|
||||
// };
|
||||
|
||||
const transition = (custom: number): Transition => ({
|
||||
duration: 0.25,
|
||||
delay: custom * 0.1,
|
||||
});
|
||||
|
||||
const variants: Variants = {
|
||||
default: {
|
||||
pathLength: 1,
|
||||
opacity: 1,
|
||||
},
|
||||
normal: (custom: number) => ({
|
||||
pathLength: 1,
|
||||
opacity: 1,
|
||||
transition: transition(custom),
|
||||
}),
|
||||
animate: (custom: number) => ({
|
||||
pathLength: 0.5,
|
||||
opacity: 1,
|
||||
transition: transition(custom),
|
||||
}),
|
||||
};
|
||||
|
||||
const ActivityLogsIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<motion.rect
|
||||
variants={variants}
|
||||
initial="normal"
|
||||
animate={controls}
|
||||
custom={0}
|
||||
x="3"
|
||||
y="3"
|
||||
width="3"
|
||||
height="3"
|
||||
fill="currentColor"
|
||||
stroke="none"
|
||||
/>
|
||||
<motion.path
|
||||
variants={variants}
|
||||
initial="normal"
|
||||
animate={controls}
|
||||
custom={0}
|
||||
d="M8 4.5 L21 4.5"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
|
||||
<motion.rect
|
||||
variants={variants}
|
||||
initial="normal"
|
||||
animate={controls}
|
||||
custom={1}
|
||||
x="3"
|
||||
y="10"
|
||||
width="3"
|
||||
height="3"
|
||||
fill="currentColor"
|
||||
stroke="none"
|
||||
/>
|
||||
<motion.path
|
||||
variants={variants}
|
||||
initial="normal"
|
||||
animate={controls}
|
||||
custom={1}
|
||||
d="M8 11.5 L21 11.5"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
|
||||
<motion.rect
|
||||
variants={variants}
|
||||
initial="normal"
|
||||
animate={controls}
|
||||
custom={2}
|
||||
x="3"
|
||||
y="17"
|
||||
width="3"
|
||||
height="3"
|
||||
fill="currentColor"
|
||||
stroke="none"
|
||||
/>
|
||||
<motion.path
|
||||
variants={variants}
|
||||
initial="normal"
|
||||
animate={controls}
|
||||
custom={2}
|
||||
d="M8 18.5 L21 18.5"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const defaultTransition2: Transition = {
|
||||
type: "spring",
|
||||
stiffness: 200,
|
||||
damping: 10,
|
||||
};
|
||||
|
||||
const pathVariants2: Variants = {
|
||||
normal: {
|
||||
rotate: 0,
|
||||
},
|
||||
animate: {
|
||||
rotate: -20,
|
||||
},
|
||||
};
|
||||
|
||||
const KeyOneBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<motion.svg
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
animate={controls}
|
||||
initial="normal"
|
||||
variants={pathVariants2}
|
||||
transition={defaultTransition2}
|
||||
>
|
||||
<path d="M10.7577 11.8281L18.6066 3.97919L20.0208 5.3934L18.6066 6.80761L21.0815 9.28249L19.6673 10.6967L17.1924 8.22183L15.7782 9.63604L17.8995 11.7574L16.4853 13.1716L14.364 11.0503L12.1719 13.2423C13.4581 15.1837 13.246 17.8251 11.5355 19.5355C9.58291 21.4882 6.41709 21.4882 4.46447 19.5355C2.51184 17.5829 2.51184 14.4171 4.46447 12.4645C6.17493 10.754 8.81633 10.5419 10.7577 11.8281ZM10.1213 18.1213C11.2929 16.9497 11.2929 15.0503 10.1213 13.8787C8.94975 12.7071 7.05025 12.7071 5.87868 13.8787C4.70711 15.0503 4.70711 16.9497 5.87868 18.1213C7.05025 19.2929 8.94975 19.2929 10.1213 18.1213Z" />
|
||||
</motion.svg>
|
||||
);
|
||||
};
|
||||
|
||||
const frameVariants: Variants = {
|
||||
normal: { opacity: 1 },
|
||||
animate: { opacity: 1 },
|
||||
};
|
||||
|
||||
const lineVariants: Variants = {
|
||||
normal: { pathLength: 1, opacity: 1 },
|
||||
animate: { pathLength: 0, opacity: 0 },
|
||||
};
|
||||
|
||||
const ScanTextIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<motion.path
|
||||
d="M3 7V5a2 2 0 0 1 2-2h2"
|
||||
variants={frameVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.path
|
||||
d="M17 3h2a2 2 0 0 1 2 2v2"
|
||||
variants={frameVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.path
|
||||
d="M21 17v2a2 2 0 0 1-2 2h-2"
|
||||
variants={frameVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.path
|
||||
d="M7 21H5a2 2 0 0 1-2-2v-2"
|
||||
variants={frameVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.path
|
||||
d="M7 8h8"
|
||||
variants={lineVariants}
|
||||
initial="animate"
|
||||
animate={controls}
|
||||
custom={0}
|
||||
/>
|
||||
<motion.path
|
||||
d="M7 12h10"
|
||||
variants={lineVariants}
|
||||
initial="animate"
|
||||
animate={controls}
|
||||
custom={1}
|
||||
/>
|
||||
<motion.path
|
||||
d="M7 16h6"
|
||||
variants={lineVariants}
|
||||
initial="animate"
|
||||
animate={controls}
|
||||
custom={2}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
// Create animated versions of icons
|
||||
const HomeIcon = withIconAnimation(HomeIconBase);
|
||||
const PlayIcon = withIconAnimation(PlayIconBase);
|
||||
const SettingsGearIcon = withIconAnimation(SettingsGearIconBase);
|
||||
const ChartColumnIcon = withChartIconAnimation(ChartColumnIconBase);
|
||||
const ActivityLogsIcon = withIconAnimation(ActivityLogsIconBase);
|
||||
const ScanTextIcon = withIconAnimation(ScanTextIconBase);
|
||||
const KeyIcon = withIconAnimation(KeyOneBase);
|
||||
|
||||
// Logout icon with animation
|
||||
const LogOutIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<motion.svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
|
||||
<motion.polyline
|
||||
points="16 17 21 12 16 7"
|
||||
variants={{
|
||||
normal: { x: 0 },
|
||||
animate: { x: [0, 3, 0] },
|
||||
}}
|
||||
transition={{ duration: 0.5, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.line
|
||||
x1="21"
|
||||
y1="12"
|
||||
x2="9"
|
||||
y2="12"
|
||||
variants={{
|
||||
normal: { x1: 21, x2: 9 },
|
||||
animate: { x1: [21, 24, 21], x2: [9, 12, 9] },
|
||||
}}
|
||||
transition={{ duration: 0.5, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
</motion.svg>
|
||||
);
|
||||
};
|
||||
|
||||
// External link icon with animation
|
||||
const ExternalLinkIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
|
||||
<motion.polyline
|
||||
points="15 3 21 3 21 9"
|
||||
variants={{
|
||||
normal: { rotate: 0, scale: 1 },
|
||||
animate: { rotate: [0, -10, 0], scale: [1, 1.1, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.4, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.line
|
||||
x1="10"
|
||||
y1="14"
|
||||
x2="21"
|
||||
y2="3"
|
||||
variants={pathVariants}
|
||||
transition={defaultTransition}
|
||||
animate={controls}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
// File text icon with animation
|
||||
const FileTextIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
||||
<motion.polyline
|
||||
points="14 2 14 8 20 8"
|
||||
variants={{
|
||||
normal: { pathLength: 1, opacity: 1 },
|
||||
animate: { pathLength: [1, 0, 1], opacity: [1, 0.5, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.6, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.line
|
||||
x1="16"
|
||||
y1="13"
|
||||
x2="8"
|
||||
y2="13"
|
||||
variants={lineVariants}
|
||||
initial="animate"
|
||||
animate={controls}
|
||||
custom={0}
|
||||
/>
|
||||
<motion.line
|
||||
x1="16"
|
||||
y1="17"
|
||||
x2="8"
|
||||
y2="17"
|
||||
variants={lineVariants}
|
||||
initial="animate"
|
||||
animate={controls}
|
||||
custom={1}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
// Book open icon with animation
|
||||
const BookOpenIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<motion.path
|
||||
d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"
|
||||
variants={{
|
||||
normal: { rotate: 0 },
|
||||
animate: { rotate: [-2, 2, -2] },
|
||||
}}
|
||||
transition={{ duration: 0.6, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.path
|
||||
d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"
|
||||
variants={{
|
||||
normal: { rotate: 0 },
|
||||
animate: { rotate: [2, -2, 2] },
|
||||
}}
|
||||
transition={{ duration: 0.6, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
// Message square icon with animation
|
||||
const MessageSquareIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
||||
<motion.circle
|
||||
cx="8"
|
||||
cy="10"
|
||||
r="1"
|
||||
fill="currentColor"
|
||||
variants={{
|
||||
normal: { scale: 1, opacity: 1 },
|
||||
animate: { scale: [1, 1.5, 1], opacity: [1, 0.5, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.4, delay: 0 }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.circle
|
||||
cx="12"
|
||||
cy="10"
|
||||
r="1"
|
||||
fill="currentColor"
|
||||
variants={{
|
||||
normal: { scale: 1, opacity: 1 },
|
||||
animate: { scale: [1, 1.5, 1], opacity: [1, 0.5, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.4, delay: 0.1 }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.circle
|
||||
cx="16"
|
||||
cy="10"
|
||||
r="1"
|
||||
fill="currentColor"
|
||||
variants={{
|
||||
normal: { scale: 1, opacity: 1 },
|
||||
animate: { scale: [1, 1.5, 1], opacity: [1, 0.5, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.4, delay: 0.2 }}
|
||||
animate={controls}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const LogOutIcon = withIconAnimation(LogOutIconBase);
|
||||
const ExternalLinkIcon = withIconAnimation(ExternalLinkIconBase);
|
||||
const FileTextIcon = withIconAnimation(FileTextIconBase);
|
||||
const BookOpenIcon = withIconAnimation(BookOpenIconBase);
|
||||
const MessageSquareIcon = withIconAnimation(MessageSquareIconBase);
|
||||
|
||||
// Bell icon with animation
|
||||
const BellIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<motion.svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<motion.path
|
||||
d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"
|
||||
variants={{
|
||||
normal: { rotate: 0 },
|
||||
animate: { rotate: [-10, 10, -10, 10, 0] },
|
||||
}}
|
||||
transition={{ duration: 0.5, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
style={{ transformOrigin: "50% 20%" }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M10.3 21a1.94 1.94 0 0 0 3.4 0"
|
||||
variants={{
|
||||
normal: { scale: 1 },
|
||||
animate: { scale: [1, 1.1, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.5, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
</motion.svg>
|
||||
);
|
||||
};
|
||||
|
||||
// Gift icon with animation
|
||||
const GiftIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
{/* Gift box bottom */}
|
||||
<polyline points="20 12 20 22 4 22 4 12" />
|
||||
<line x1="12" y1="22" x2="12" y2="12" />
|
||||
|
||||
{/* Gift lid with opening animation */}
|
||||
<motion.g
|
||||
variants={{
|
||||
normal: { y: 0, rotate: 0 },
|
||||
animate: { y: -3, rotate: -8 },
|
||||
}}
|
||||
transition={{ duration: 0.4, ease: "easeOut" }}
|
||||
animate={controls}
|
||||
style={{ transformOrigin: "2px 9px" }}
|
||||
>
|
||||
<rect x="2" y="7" width="20" height="5" />
|
||||
<line x1="12" y1="7" x2="12" y2="12" />
|
||||
|
||||
{/* Left bow */}
|
||||
<motion.path
|
||||
d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"
|
||||
variants={{
|
||||
normal: { scale: 1 },
|
||||
animate: { scale: [1, 1.1, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.4, ease: "easeInOut" }}
|
||||
/>
|
||||
|
||||
{/* Right bow */}
|
||||
<motion.path
|
||||
d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"
|
||||
variants={{
|
||||
normal: { scale: 1 },
|
||||
animate: { scale: [1, 1.1, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.4, ease: "easeInOut" }}
|
||||
/>
|
||||
</motion.g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
// HelpCircle icon with animation
|
||||
const HelpCircleIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<motion.circle
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
variants={{
|
||||
normal: { rotate: 0 },
|
||||
animate: { rotate: 360 },
|
||||
}}
|
||||
transition={{ duration: 0.6, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.path
|
||||
d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"
|
||||
variants={{
|
||||
normal: { opacity: 1 },
|
||||
animate: { opacity: [1, 0.5, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.4, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.line
|
||||
x1="12"
|
||||
y1="17"
|
||||
x2="12.01"
|
||||
y2="17"
|
||||
variants={{
|
||||
normal: { scale: 1 },
|
||||
animate: { scale: [1, 1.5, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.4, ease: "easeInOut", delay: 0.2 }}
|
||||
animate={controls}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const BellIcon = withIconAnimation(BellIconBase);
|
||||
const GiftIcon = withIconAnimation(GiftIconBase);
|
||||
const HelpCircleIcon = withIconAnimation(HelpCircleIconBase);
|
||||
|
||||
// SquareArrowUp icon with animation (for Upgrade button)
|
||||
const SquareArrowUpIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" />
|
||||
<motion.path
|
||||
d="m8 12 4-4 4 4"
|
||||
variants={{
|
||||
normal: { y: 0 },
|
||||
animate: { y: [-2, 0] },
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.path
|
||||
d="M12 16V8"
|
||||
variants={{
|
||||
normal: { scaleY: 1 },
|
||||
animate: { scaleY: [0.8, 1] },
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||
animate={controls}
|
||||
style={{ transformOrigin: "50% 100%" }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const SquareArrowUpIcon = withIconAnimation(SquareArrowUpIconBase);
|
||||
|
||||
// Code icon with animation
|
||||
const CodeIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<motion.polyline
|
||||
points="16 18 22 12 16 6"
|
||||
variants={{
|
||||
normal: { x: 0 },
|
||||
animate: { x: [0, 2, 0] },
|
||||
}}
|
||||
transition={{ duration: 0.4, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
<motion.polyline
|
||||
points="8 6 2 12 8 18"
|
||||
variants={{
|
||||
normal: { x: 0 },
|
||||
animate: { x: [0, -2, 0] },
|
||||
}}
|
||||
transition={{ duration: 0.4, ease: "easeInOut" }}
|
||||
animate={controls}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const CodeIcon = withIconAnimation(CodeIconBase);
|
||||
|
||||
// TestTube icon for Extract Playground (Lucide TestTube2 icon without bubble)
|
||||
const BeakerIconBase = ({ controls }: { controls: any }) => {
|
||||
return (
|
||||
<motion.svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
variants={{
|
||||
normal: { rotate: 0 },
|
||||
animate: { rotate: [-8, 8, -8] },
|
||||
}}
|
||||
transition={{
|
||||
duration: 0.8,
|
||||
ease: "easeInOut",
|
||||
times: [0, 0.5, 1],
|
||||
}}
|
||||
animate={controls}
|
||||
>
|
||||
<path d="M21 7 6.82 21.18a2.83 2.83 0 0 1-3.99-.01v0a2.83 2.83 0 0 1 0-4L17 3" />
|
||||
<path d="m16 2 6 6" />
|
||||
</motion.svg>
|
||||
);
|
||||
};
|
||||
|
||||
const BeakerIcon = withIconAnimation(BeakerIconBase);
|
||||
|
||||
export {
|
||||
HomeIcon,
|
||||
PlayIcon,
|
||||
SettingsGearIcon,
|
||||
ChartColumnIcon,
|
||||
ActivityLogsIcon,
|
||||
KeyIcon,
|
||||
ScanTextIcon,
|
||||
LogOutIcon,
|
||||
ExternalLinkIcon,
|
||||
FileTextIcon,
|
||||
BookOpenIcon,
|
||||
MessageSquareIcon,
|
||||
BellIcon,
|
||||
GiftIcon,
|
||||
HelpCircleIcon,
|
||||
SquareArrowUpIcon,
|
||||
CodeIcon,
|
||||
BeakerIcon,
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import { cx } from "class-variance-authority";
|
||||
|
||||
export function ArrowAnimated({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<SVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
className={cx("-mr-1 ml-1.5 stroke-[1.5px]", className)}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
width="11"
|
||||
height="11"
|
||||
viewBox="0 0 10 10"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
className="opacity-0 transition group-hover:opacity-100"
|
||||
d="M0 5h7"
|
||||
/>
|
||||
<path
|
||||
className="transition group-hover:translate-x-[3px]"
|
||||
d="M1 1l4 4-4 4"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export default function Check() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M10 2.5C5.85786 2.5 2.5 5.85786 2.5 10C2.5 14.1421 5.85786 17.5 10 17.5C14.1421 17.5 17.5 14.1421 17.5 10C17.5 5.85786 14.1421 2.5 10 2.5ZM12.8305 8.59995C13.0928 8.27937 13.0455 7.80685 12.7249 7.54455C12.4043 7.28226 11.9318 7.32951 11.6695 7.65009L8.81932 11.1337L7.90533 10.2197C7.61244 9.9268 7.13756 9.9268 6.84467 10.2197C6.55178 10.5126 6.55178 10.9875 6.84467 11.2804L8.34467 12.7804C8.4945 12.9302 8.70073 13.0096 8.91236 12.9991C9.12399 12.9885 9.32129 12.8889 9.45547 12.725L12.8305 8.59995Z"
|
||||
fill="#FA5D19"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
type Direction = "left" | "right";
|
||||
|
||||
interface ChevronSlideProps extends React.SVGAttributes<SVGElement> {
|
||||
direction?: Direction;
|
||||
size?: number; // pixel size for width/height
|
||||
}
|
||||
|
||||
export function ChevronSlide({
|
||||
direction = "right",
|
||||
size = 16,
|
||||
className,
|
||||
...props
|
||||
}: ChevronSlideProps) {
|
||||
const translateClass =
|
||||
direction === "right"
|
||||
? "group-hover:translate-x-8"
|
||||
: "group-hover:-translate-x-8";
|
||||
const orientationClass = direction === "right" ? "" : "rotate-180";
|
||||
|
||||
return (
|
||||
<svg
|
||||
className={cn(
|
||||
"transition-all",
|
||||
translateClass,
|
||||
orientationClass,
|
||||
className,
|
||||
)}
|
||||
fill="none"
|
||||
height={size}
|
||||
width={size}
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M8.5 13L11.5 10L8.5 7"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default ChevronSlide;
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function CopiedIcon() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.1875 10.974L8.075 13.8959L14.8125 6.10425"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function CopyIcon() {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7.83333 7.83325V4.66659C7.83333 4.20635 8.20643 3.83325 8.66667 3.83325H15.3333C15.7936 3.83325 16.1667 4.20635 16.1667 4.66659V11.3333C16.1667 11.7935 15.7936 12.1666 15.3333 12.1666H12.1667M11.3333 7.83325H4.66667C4.20643 7.83325 3.83333 8.20635 3.83333 8.66659V15.3333C3.83333 15.7935 4.20643 16.1666 4.66667 16.1666H11.3333C11.7936 16.1666 12.1667 15.7935 12.1667 15.3333V8.66659C12.1667 8.20635 11.7936 7.83325 11.3333 7.83325Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
interface CurveProps extends React.SVGAttributes<SVGSVGElement> {
|
||||
fill?: string;
|
||||
}
|
||||
|
||||
export default function Curve({
|
||||
fill = "var(--border-faint)",
|
||||
...props
|
||||
}: CurveProps) {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="11"
|
||||
viewBox="0 0 11 11"
|
||||
width="11"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M11 1L11 11L10 11L10 7C10 3.68629 7.31371 1 4 1L-4.37114e-08 1L0 -4.80825e-07L11 4.37114e-07L11 1Z"
|
||||
fill={fill}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
"use client";
|
||||
|
||||
import type { Variants } from "motion/react";
|
||||
import { motion, useAnimation } from "motion/react";
|
||||
import type { HTMLAttributes } from "react";
|
||||
import {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
export interface FingerprintIconHandle {
|
||||
startAnimation: () => void;
|
||||
stopAnimation: () => void;
|
||||
}
|
||||
|
||||
interface FingerprintIconProps extends HTMLAttributes<HTMLDivElement> {
|
||||
size?: number;
|
||||
autoAnimate?: boolean;
|
||||
animationDelay?: number;
|
||||
}
|
||||
|
||||
const pathVariants: Variants = {
|
||||
normal: { pathLength: 1, opacity: 1 },
|
||||
animate: {
|
||||
opacity: [0, 0, 1, 1, 1],
|
||||
pathLength: [0.1, 0.3, 0.5, 0.7, 0.9, 1],
|
||||
transition: {
|
||||
opacity: { duration: 0.5 },
|
||||
pathLength: {
|
||||
duration: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const FingerprintIcon = forwardRef<FingerprintIconHandle, FingerprintIconProps>(
|
||||
(
|
||||
{
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
className,
|
||||
size = 28,
|
||||
autoAnimate = true,
|
||||
animationDelay = 0,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const controls = useAnimation();
|
||||
const isControlledRef = useRef(false);
|
||||
|
||||
useImperativeHandle(ref, () => {
|
||||
isControlledRef.current = true;
|
||||
|
||||
return {
|
||||
startAnimation: () => controls.start("animate"),
|
||||
stopAnimation: () => controls.start("normal"),
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (autoAnimate && !isControlledRef.current) {
|
||||
const timer = setTimeout(() => {
|
||||
controls.start("animate");
|
||||
}, animationDelay);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [autoAnimate, animationDelay, controls]);
|
||||
|
||||
const handleMouseEnter = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (!isControlledRef.current) {
|
||||
controls.start("animate");
|
||||
}
|
||||
onMouseEnter?.(e);
|
||||
},
|
||||
[controls, onMouseEnter],
|
||||
);
|
||||
|
||||
const handleMouseLeave = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (!isControlledRef.current) {
|
||||
controls.start("normal");
|
||||
}
|
||||
onMouseLeave?.(e);
|
||||
},
|
||||
[controls, onMouseLeave],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(className)}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
{...props}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4"
|
||||
strokeOpacity={0.4}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<motion.path
|
||||
d="M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
|
||||
<path
|
||||
d="M14 13.12c0 2.38 0 6.38-1 8.88"
|
||||
strokeOpacity={0.4}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<motion.path
|
||||
d="M14 13.12c0 2.38 0 6.38-1 8.88"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
|
||||
<path
|
||||
d="M17.29 21.02c.12-.6.43-2.3.5-3.02"
|
||||
strokeOpacity={0.4}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<motion.path
|
||||
d="M17.29 21.02c.12-.6.43-2.3.5-3.02"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
|
||||
<path
|
||||
d="M2 12a10 10 0 0 1 18-6"
|
||||
strokeOpacity={0.4}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<motion.path
|
||||
d="M2 12a10 10 0 0 1 18-6"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
|
||||
<path d="M2 16h.01" strokeOpacity={0.4} strokeWidth="2" fill="none" />
|
||||
<motion.path
|
||||
d="M2 16h.01"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
|
||||
<path
|
||||
d="M21.8 16c.2-2 .131-5.354 0-6"
|
||||
strokeOpacity={0.4}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<motion.path
|
||||
d="M21.8 16c.2-2 .131-5.354 0-6"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
|
||||
<path
|
||||
d="M5 19.5C5.5 18 6 15 6 12a6 6 0 0 1 .34-2"
|
||||
strokeOpacity={0.4}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<motion.path
|
||||
d="M5 19.5C5.5 18 6 15 6 12a6 6 0 0 1 .34-2"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
|
||||
<path
|
||||
d="M8.65 22c.21-.66.45-1.32.57-2"
|
||||
strokeOpacity={0.4}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<motion.path
|
||||
d="M8.65 22c.21-.66.45-1.32.57-2"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
|
||||
<path
|
||||
d="M9 6.8a6 6 0 0 1 9 5.2v2"
|
||||
strokeOpacity={0.4}
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<motion.path
|
||||
d="M9 6.8a6 6 0 0 1 9 5.2v2"
|
||||
variants={pathVariants}
|
||||
animate={controls}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
FingerprintIcon.displayName = "FingerprintIcon";
|
||||
|
||||
export { FingerprintIcon };
|
||||
@@ -0,0 +1,18 @@
|
||||
import * as React from "react";
|
||||
|
||||
function IconOpenai(props: React.SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<title>OpenAI</title>
|
||||
<path d="M22.282 9.821a5.985 5.985 0 00-.516-4.91 6.046 6.046 0 00-6.51-2.9A6.065 6.065 0 004.981 4.18a5.985 5.985 0 00-3.998 2.9 6.046 6.046 0 00.743 7.097 5.98 5.98 0 00.51 4.911 6.051 6.051 0 006.515 2.9A5.985 5.985 0 0013.26 24a6.056 6.056 0 005.772-4.206 5.99 5.99 0 003.997-2.9 6.056 6.056 0 00-.747-7.073zM13.26 22.43a4.476 4.476 0 01-2.876-1.04l.141-.081 4.779-2.758a.795.795 0 00.392-.681v-6.737l2.02 1.168a.071.071 0 01.038.052v5.583a4.504 4.504 0 01-4.494 4.494zM3.6 18.304a4.47 4.47 0 01-.535-3.014l.142.085 4.783 2.759a.771.771 0 00.78 0l5.843-3.369v2.332a.08.08 0 01-.033.062L9.74 19.95a4.5 4.5 0 01-6.14-1.646zM2.34 7.896a4.485 4.485 0 012.366-1.973V11.6a.766.766 0 00.388.676l5.815 3.355-2.02 1.168a.076.076 0 01-.071 0l-4.83-2.786A4.504 4.504 0 012.34 7.872zm16.597 3.855l-5.833-3.387L15.119 7.2a.076.076 0 01.071 0l4.83 2.791a4.494 4.494 0 01-.676 8.105v-5.678a.79.79 0 00-.407-.667zm2.01-3.023l-.141-.085-4.774-2.782a.776.776 0 00-.785 0L9.409 9.23V6.897a.066.066 0 01.028-.061l4.83-2.787a4.5 4.5 0 016.68 4.66zm-12.64 4.135l-2.02-1.164a.08.08 0 01-.038-.057V6.075a4.5 4.5 0 017.375-3.453l-.142.08-4.778 2.758a.795.795 0 00-.393.681zm1.097-2.365l2.602-1.5 2.607 1.5v2.999l-2.597 1.5-2.607-1.5z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default IconOpenai;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { JSXElementConstructor } from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
export const SourceIcon = ({ id }: { id: string }) => {
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="">
|
||||
{id && (
|
||||
<Image
|
||||
alt={id}
|
||||
width={36}
|
||||
height={36}
|
||||
className="h-10 w-10 aspect-square"
|
||||
src={`/icons/${id}.svg`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import React from "react";
|
||||
|
||||
const SymbolColored = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
width="50"
|
||||
height="72"
|
||||
viewBox="0 0 50 72"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M41.7154 23.1929C38.9531 24.0129 36.8707 25.8677 35.3457 27.8826C35.0182 28.3151 34.3358 27.9901 34.4658 27.4601C37.3856 15.4534 33.5283 5.47401 21.5039 0.561817C20.894 0.311833 20.259 0.859299 20.419 1.49926C25.8887 23.4604 2.88236 21.608 5.78971 46.504C5.83971 46.9314 5.35973 47.2239 5.00975 46.9739C3.9198 46.1915 2.70237 44.5591 1.86741 43.4116C1.62242 43.0742 1.09245 43.1692 0.979951 43.5716C0.314984 45.9765 0 48.2413 0 50.4912C0 59.2407 4.49727 66.9427 11.3044 71.4074C11.6944 71.6624 12.1944 71.2974 12.0619 70.8499C11.7119 69.675 11.5144 68.4351 11.4994 67.1527C11.4994 66.3652 11.5494 65.5603 11.6719 64.8103C11.9569 62.9254 12.6119 61.1306 13.7118 59.4957C17.4841 53.8335 25.0462 48.3638 23.8388 40.9368C23.7613 40.4668 24.3163 40.1569 24.6663 40.4793C29.9935 45.3465 31.0485 51.8936 30.1735 57.7658C30.0985 58.2757 30.7385 58.5482 31.061 58.1482C31.8759 57.1283 32.8709 56.2334 33.9533 55.5609C34.2233 55.3934 34.5833 55.5209 34.6858 55.8209C35.2882 57.5733 36.1832 59.2182 37.0281 60.8631C38.0381 62.8404 38.5756 65.0978 38.4906 67.4877C38.4481 68.6501 38.2556 69.775 37.9331 70.8449C37.7956 71.2974 38.2906 71.6749 38.6881 71.4149C45.5002 66.9502 50 59.2482 50 50.4937C50 47.4514 49.4675 44.4691 48.4601 41.6743C46.3477 35.8121 40.988 31.4099 42.3429 23.7704C42.4079 23.4054 42.0704 23.0879 41.7154 23.1929Z"
|
||||
fill="#FA5D19"
|
||||
style={{ fill: "#FA5D19", fillOpacity: 1 }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default SymbolColored;
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
|
||||
const SymbolWhite = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="50"
|
||||
height="72"
|
||||
viewBox="0 0 50 72"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M41.7154 23.1929C38.9531 24.0129 36.8707 25.8677 35.3457 27.8826C35.0182 28.3151 34.3358 27.9901 34.4658 27.4601C37.3856 15.4534 33.5283 5.47401 21.5039 0.561817C20.894 0.311833 20.259 0.859299 20.419 1.49926C25.8887 23.4604 2.88236 21.608 5.78971 46.504C5.83971 46.9314 5.35973 47.2239 5.00975 46.9739C3.9198 46.1915 2.70237 44.5591 1.86741 43.4116C1.62242 43.0742 1.09245 43.1692 0.979951 43.5716C0.314984 45.9765 0 48.2413 0 50.4912C0 59.2407 4.49727 66.9427 11.3044 71.4074C11.6944 71.6624 12.1944 71.2974 12.0619 70.8499C11.7119 69.675 11.5144 68.4351 11.4994 67.1527C11.4994 66.3652 11.5494 65.5603 11.6719 64.8103C11.9569 62.9254 12.6119 61.1306 13.7118 59.4957C17.4841 53.8335 25.0462 48.3638 23.8388 40.9368C23.7613 40.4668 24.3163 40.1569 24.6663 40.4793C29.9935 45.3465 31.0485 51.8936 30.1735 57.7658C30.0985 58.2757 30.7385 58.5482 31.061 58.1482C31.8759 57.1283 32.8709 56.2334 33.9533 55.5609C34.2233 55.3934 34.5833 55.5209 34.6858 55.8209C35.2882 57.5733 36.1832 59.2182 37.0281 60.8631C38.0381 62.8404 38.5756 65.0978 38.4906 67.4877C38.4481 68.6501 38.2556 69.775 37.9331 70.8449C37.7956 71.2974 38.2906 71.6749 38.6881 71.4149C45.5002 66.9502 50 59.2482 50 50.4937C50 47.4514 49.4675 44.4691 48.4601 41.6743C46.3477 35.8121 40.988 31.4099 42.3429 23.7704C42.4079 23.4054 42.0704 23.0879 41.7154 23.1929Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default SymbolWhite;
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { SVGProps } from "react";
|
||||
|
||||
export const TremorPlaceholder = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg className={props.className} fill="none" viewBox="0 0 92 92" {...props}>
|
||||
<g clipPath="url(#clip0_10096_2462)">
|
||||
<mask
|
||||
id="mask0_10096_2462"
|
||||
width={92}
|
||||
height={92}
|
||||
x={0}
|
||||
y={0}
|
||||
maskUnits="userSpaceOnUse"
|
||||
style={{
|
||||
maskType: "luminance",
|
||||
}}
|
||||
>
|
||||
<path fill="white" d="M92 0H0V92H92V0Z" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_10096_2462)">
|
||||
<path
|
||||
fill="#DEDEDE"
|
||||
d="M1.09521 20.809L19.7581 3.28516H72.2419L90.9047 20.809H1.09521Z"
|
||||
/>
|
||||
<path fill="#C9C9C9" d="M2 20H89V88.5H2V20Z" />
|
||||
<path
|
||||
stroke="#8C8C8C"
|
||||
strokeWidth={3.28571}
|
||||
d="M17.8761 2.97375L3.49687 17.8023C2.30794 19.0283 1.64307 20.6691 1.64307 22.377V85.5C1.64307 87.7091 3.43392 89.5 5.64306 89.5H86.3574C88.5665 89.5 90.3574 87.7091 90.3574 85.5V22.8208C90.3574 20.8283 89.5817 18.9141 88.1945 17.4837L74.1244 2.97375C73.2992 2.12284 72.1646 1.64258 70.9793 1.64258H21.0211C19.8358 1.64258 18.7012 2.12284 17.8761 2.97375Z"
|
||||
/>
|
||||
<path
|
||||
stroke="#8C8C8C"
|
||||
strokeWidth={3.28571}
|
||||
d="M2.19043 19.7129H90.3571"
|
||||
/>
|
||||
<path
|
||||
fill="#7D7D7D"
|
||||
fillOpacity={0.8}
|
||||
d="M37.7855 3.28516H54.214L56.9521 19.7137V34.7564C56.9521 36.7315 55.3509 38.3328 53.3757 38.3328H38.6238C36.6486 38.3328 35.0474 36.7315 35.0474 34.7564V19.7137L37.7855 3.28516Z"
|
||||
/>
|
||||
<path
|
||||
fill="white"
|
||||
d="M48.2744 63.3867H14.2329C12.9363 63.3867 11.8853 64.3853 11.8853 65.617V77.8837C11.8853 79.1155 12.9363 80.114 14.2329 80.114H48.2744C49.571 80.114 50.6221 79.1155 50.6221 77.8837V65.617C50.6221 64.3853 49.571 63.3867 48.2744 63.3867Z"
|
||||
/>
|
||||
<path
|
||||
stroke="black"
|
||||
strokeOpacity={0.07}
|
||||
strokeWidth={1.09524}
|
||||
d="M48.1495 62.9473H14.3583C12.7495 62.9473 11.4453 64.179 11.4453 65.6985V77.8037C11.4453 79.3232 12.7495 80.5549 14.3583 80.5549H48.1495C49.7583 80.5549 51.0625 79.3232 51.0625 77.8037V65.6985C51.0625 64.179 49.7583 62.9473 48.1495 62.9473Z"
|
||||
/>
|
||||
<path
|
||||
fill="#0F172A"
|
||||
d="M17.7102 75.4604C16.7747 75.4604 15.9759 74.9874 15.9759 73.7891V71.382H15.1034V70.1627H16.0284V68.7647L17.4474 68.2392V70.1627H18.5932V71.382H17.4474V73.4422C17.4474 73.9047 17.6787 74.136 18.1727 74.136C18.3304 74.136 18.4775 74.1045 18.5932 74.0729V75.3448C18.4565 75.3868 18.0781 75.4604 17.7102 75.4604ZM19.5597 75.3027V70.1627H21.0103V70.909C21.2625 70.3414 21.7355 69.9946 22.3872 69.9946C22.4923 69.9946 22.7026 70.0156 22.7656 70.0261V71.5187C22.5975 71.4766 22.4293 71.4661 22.2296 71.4661C21.6725 71.4661 21.1574 71.834 21.0313 72.3281V75.3027H19.5597ZM25.8567 75.4604C24.3746 75.4604 23.1553 74.4723 23.1553 72.6959C23.1553 71.0772 24.322 69.9946 25.7936 69.9946C27.4229 69.9946 28.3478 71.1298 28.3478 72.717C28.3478 72.8431 28.3373 73.0638 28.3268 73.1479H24.6899C24.7215 73.8522 25.3732 74.2411 26.0143 74.2411C26.7081 74.2411 27.2967 74.0519 27.9694 73.6104V74.8823C27.4964 75.1871 26.8868 75.4604 25.8567 75.4604ZM24.7215 72.1599H26.8658C26.8342 71.6764 26.4979 71.2139 25.7936 71.2139C25.1524 71.2139 24.753 71.6974 24.7215 72.1599ZM35.2192 69.9946C36.1862 69.9946 37.0586 70.6568 37.0586 71.8761V75.3027H35.587V72.244C35.587 71.6869 35.2822 71.34 34.7882 71.34C34.4203 71.34 34.126 71.5502 33.9158 71.8445V71.8761V75.3027H32.4442V72.244C32.4442 71.6869 32.1499 71.34 31.6558 71.34C31.2669 71.34 30.9726 71.5607 30.7624 71.8761V75.3027H29.2908V70.1627H30.7414V70.5727C31.0252 70.2468 31.4561 69.9946 32.1078 69.9946C32.707 69.9946 33.2641 70.2468 33.5899 70.7303C33.8527 70.4255 34.3677 69.9946 35.2192 69.9946ZM40.6916 75.4604C39.0309 75.4604 37.8957 74.2621 37.8957 72.717C37.8957 71.1823 39.0309 69.9946 40.6916 69.9946C42.3524 69.9946 43.4981 71.1823 43.4981 72.717C43.4981 74.2621 42.3524 75.4604 40.6916 75.4604ZM40.6916 74.0729C41.4064 74.0729 41.974 73.5684 41.974 72.717C41.974 71.8866 41.4064 71.3715 40.6916 71.3715C39.9874 71.3715 39.4198 71.8866 39.4198 72.717C39.4198 73.5684 39.9874 74.0729 40.6916 74.0729ZM44.4418 75.3027V70.1627H45.8923V70.909C46.1446 70.3414 46.6176 69.9946 47.2693 69.9946C47.3744 69.9946 47.5846 70.0156 47.6477 70.0261V71.5187C47.4795 71.4766 47.3113 71.4661 47.1116 71.4661C46.5545 71.4661 46.0395 71.834 45.9133 72.3281V75.3027H44.4418Z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_10096_2462">
|
||||
<rect width={92} height={92} fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,57 @@
|
||||
import React from "react";
|
||||
|
||||
const WordmarkColored = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="172"
|
||||
height="40"
|
||||
viewBox="0 0 172 40"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M23.3606 12.8281C21.8137 13.2873 20.6476 14.3261 19.7936 15.4544C19.6102 15.6966 19.228 15.5146 19.3008 15.2178C20.936 8.49401 18.7759 2.90556 12.0422 0.154735C11.7006 0.0147436 11.345 0.321324 11.4346 0.679702C14.4977 12.9779 1.61412 11.9406 3.24224 25.8823C3.27024 26.1217 3.00145 26.2855 2.80546 26.1455C2.19509 25.7073 1.51332 24.7932 1.04575 24.1506C0.908555 23.9616 0.611769 24.0148 0.548773 24.2402C0.176391 25.5869 0 26.8553 0 28.1152C0 33.0149 2.51847 37.328 6.33048 39.8283C6.54887 39.9711 6.82886 39.7667 6.75466 39.5161C6.55867 38.8581 6.44808 38.1638 6.43968 37.4456C6.43968 37.0046 6.46768 36.5539 6.53627 36.1339C6.69587 35.0784 7.06265 34.0732 7.67862 33.1577C9.79111 29.9869 14.0259 26.9239 13.3497 22.7647C13.3063 22.5015 13.6171 22.328 13.8131 22.5085C16.7964 25.2342 17.3871 28.9005 16.8972 32.1889C16.8552 32.4745 17.2135 32.6271 17.3941 32.4031C17.8505 31.832 18.4077 31.3308 19.0138 30.9542C19.165 30.8604 19.3666 30.9318 19.424 31.0998C19.7614 32.0811 20.2626 33.0023 20.7358 33.9234C21.3013 35.0308 21.6023 36.2949 21.5547 37.6332C21.5309 38.2842 21.4231 38.9141 21.2425 39.5133C21.1655 39.7667 21.4427 39.9781 21.6653 39.8325C25.4801 37.3322 28 33.0191 28 28.1166C28 26.4129 27.7018 24.7428 27.1376 23.1777C25.9547 19.8949 22.9533 17.4297 23.712 13.1515C23.7484 12.9471 23.5594 12.7693 23.3606 12.8281Z"
|
||||
fill="#FA5D19"
|
||||
/>
|
||||
<path
|
||||
d="M41 34.0521V10.9618H55.7586V14.3264H44.7969V21.0226H53.8436V24.2882H44.7969V34.0521H41Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M59.9569 14.7882C58.7352 14.7882 57.7777 13.8976 57.7777 12.6441C57.7777 11.3906 58.7352 10.5 59.9569 10.5C61.1785 10.5 62.136 11.3906 62.136 12.6441C62.136 13.8976 61.1785 14.7882 59.9569 14.7882ZM58.1409 34.0521V17.1632H61.7068V34.0521H58.1409Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M73.5885 17.1632H74.3809V20.4948H72.796C69.6264 20.4948 68.6029 22.9687 68.6029 25.5747V34.0521H65.0371V17.1632H68.2067L68.6029 19.7031C69.4613 18.2847 70.815 17.1632 73.5885 17.1632Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M83.632 34.25C78.3163 34.25 74.9816 30.8194 74.9816 25.6406C74.9816 20.4288 78.3163 16.9653 83.3019 16.9653C88.1884 16.9653 91.457 20.066 91.5561 25.0139C91.5561 25.4427 91.5231 25.9045 91.457 26.3663H78.7125V26.5972C78.8116 29.467 80.6275 31.3472 83.4339 31.3472C85.613 31.3472 87.1979 30.2587 87.6931 28.3785H91.2589C90.6646 31.7101 87.8252 34.25 83.632 34.25ZM78.8446 23.7604H87.8582C87.561 21.2535 85.8112 19.8351 83.3349 19.8351C81.0567 19.8351 79.1087 21.3524 78.8446 23.7604Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M102.033 34.25C96.9151 34.25 93.6465 30.9184 93.6465 25.6406C93.6465 20.4288 97.0142 16.9653 102.132 16.9653C106.49 16.9653 109.197 19.3733 109.891 23.1997H106.16C105.698 21.2205 104.278 20 102.066 20C99.1933 20 97.3113 22.309 97.3113 25.6406C97.3113 28.9392 99.1933 31.2153 102.066 31.2153C104.245 31.2153 105.698 29.9618 106.127 28.0156H109.891C109.23 31.842 106.358 34.25 102.033 34.25Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M121.006 17.1632H121.799V20.4948H120.214C117.044 20.4948 116.021 22.9687 116.021 25.5747V34.0521H112.455V17.1632H115.625L116.021 19.7031C116.879 18.2847 118.233 17.1632 121.006 17.1632Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M130.614 16.9653C135.104 16.9653 137.679 19.1094 137.679 23.1007V34.0521H134.576L134.279 31.6441C133.123 33.1615 131.505 34.25 128.831 34.25C125.133 34.25 122.657 32.4358 122.657 29.3021C122.657 25.8385 125.166 23.8924 129.92 23.8924H134.147V22.8698C134.147 20.9896 132.793 19.8351 130.449 19.8351C128.336 19.8351 126.916 20.8247 126.652 22.309H123.152C123.515 19.0104 126.355 16.9653 130.614 16.9653ZM129.425 31.4792C132.397 31.4792 134.114 29.7309 134.147 27.125V26.5312H129.722C127.51 26.5312 126.289 27.3559 126.289 29.0712C126.289 30.4896 127.477 31.4792 129.425 31.4792Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M144.653 34.0521L139.139 17.1632H142.903L146.766 30.0937L150.629 17.1632H153.897L157.595 30.0937L161.59 17.1632H165.222L159.609 34.0521H155.779L152.214 22.5729L148.516 34.0521H144.653Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
<path
|
||||
d="M166.934 34.0521V10.9618H170.5V34.0521H166.934Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default WordmarkColored;
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
|
||||
const WordmarkWhite = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="172"
|
||||
height="40"
|
||||
viewBox="0 0 172 40"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M23.3606 12.8281C21.8137 13.2873 20.6476 14.3261 19.7936 15.4544C19.6102 15.6966 19.228 15.5146 19.3008 15.2178C20.936 8.49401 18.7759 2.90556 12.0422 0.154735C11.7006 0.0147436 11.345 0.321324 11.4346 0.679702C14.4977 12.9779 1.61412 11.9406 3.24224 25.8823C3.27024 26.1217 3.00145 26.2855 2.80546 26.1455C2.19509 25.7073 1.51332 24.7932 1.04575 24.1506C0.908555 23.9616 0.611769 24.0148 0.548773 24.2402C0.176391 25.5869 0 26.8553 0 28.1152C0 33.0149 2.51847 37.328 6.33048 39.8283C6.54887 39.9711 6.82886 39.7667 6.75466 39.5161C6.55867 38.8581 6.44808 38.1638 6.43968 37.4456C6.43968 37.0046 6.46768 36.5539 6.53627 36.1339C6.69587 35.0784 7.06265 34.0732 7.67862 33.1577C9.79111 29.9869 14.0259 26.9239 13.3497 22.7647C13.3063 22.5015 13.6171 22.328 13.8131 22.5085C16.7964 25.2342 17.3871 28.9005 16.8972 32.1889C16.8552 32.4745 17.2135 32.6271 17.3941 32.4031C17.8505 31.832 18.4077 31.3308 19.0138 30.9542C19.165 30.8604 19.3666 30.9318 19.424 31.0998C19.7614 32.0811 20.2626 33.0023 20.7358 33.9234C21.3013 35.0308 21.6023 36.2949 21.5547 37.6332C21.5309 38.2842 21.4231 38.9141 21.2425 39.5133C21.1655 39.7667 21.4427 39.9781 21.6653 39.8325C25.4801 37.3322 28 33.0191 28 28.1166C28 26.4129 27.7018 24.7428 27.1376 23.1777C25.9547 19.8949 22.9533 17.4297 23.712 13.1515C23.7484 12.9471 23.5594 12.7693 23.3606 12.8281Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M41 34.0521V10.9618H55.7586V14.3264H44.7969V21.0226H53.8436V24.2882H44.7969V34.0521H41Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M59.9569 14.7882C58.7352 14.7882 57.7777 13.8976 57.7777 12.6441C57.7777 11.3906 58.7352 10.5 59.9569 10.5C61.1785 10.5 62.136 11.3906 62.136 12.6441C62.136 13.8976 61.1785 14.7882 59.9569 14.7882ZM58.1409 34.0521V17.1632H61.7068V34.0521H58.1409Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M73.5885 17.1632H74.3809V20.4948H72.796C69.6264 20.4948 68.6029 22.9687 68.6029 25.5747V34.0521H65.0371V17.1632H68.2067L68.6029 19.7031C69.4613 18.2847 70.815 17.1632 73.5885 17.1632Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M83.632 34.25C78.3163 34.25 74.9816 30.8194 74.9816 25.6406C74.9816 20.4288 78.3163 16.9653 83.3019 16.9653C88.1884 16.9653 91.457 20.066 91.5561 25.0139C91.5561 25.4427 91.5231 25.9045 91.457 26.3663H78.7125V26.5972C78.8116 29.467 80.6275 31.3472 83.4339 31.3472C85.613 31.3472 87.1979 30.2587 87.6931 28.3785H91.2589C90.6646 31.7101 87.8252 34.25 83.632 34.25ZM78.8446 23.7604H87.8582C87.561 21.2535 85.8112 19.8351 83.3349 19.8351C81.0567 19.8351 79.1087 21.3524 78.8446 23.7604Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M102.033 34.25C96.9151 34.25 93.6465 30.9184 93.6465 25.6406C93.6465 20.4288 97.0142 16.9653 102.132 16.9653C106.49 16.9653 109.197 19.3733 109.891 23.1997H106.16C105.698 21.2205 104.278 20 102.066 20C99.1933 20 97.3113 22.309 97.3113 25.6406C97.3113 28.9392 99.1933 31.2153 102.066 31.2153C104.245 31.2153 105.698 29.9618 106.127 28.0156H109.891C109.23 31.842 106.358 34.25 102.033 34.25Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M121.006 17.1632H121.799V20.4948H120.214C117.044 20.4948 116.021 22.9687 116.021 25.5747V34.0521H112.455V17.1632H115.625L116.021 19.7031C116.879 18.2847 118.233 17.1632 121.006 17.1632Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M130.614 16.9653C135.104 16.9653 137.679 19.1094 137.679 23.1007V34.0521H134.576L134.279 31.6441C133.123 33.1615 131.505 34.25 128.831 34.25C125.133 34.25 122.657 32.4358 122.657 29.3021C122.657 25.8385 125.166 23.8924 129.92 23.8924H134.147V22.8698C134.147 20.9896 132.793 19.8351 130.449 19.8351C128.336 19.8351 126.916 20.8247 126.652 22.309H123.152C123.515 19.0104 126.355 16.9653 130.614 16.9653ZM129.425 31.4792C132.397 31.4792 134.114 29.7309 134.147 27.125V26.5312H129.722C127.51 26.5312 126.289 27.3559 126.289 29.0712C126.289 30.4896 127.477 31.4792 129.425 31.4792Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M144.653 34.0521L139.139 17.1632H142.903L146.766 30.0937L150.629 17.1632H153.897L157.595 30.0937L161.59 17.1632H165.222L159.609 34.0521H155.779L152.214 22.5729L148.516 34.0521H144.653Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path d="M166.934 34.0521V10.9618H170.5V34.0521H166.934Z" fill="white" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default WordmarkWhite;
|
||||
@@ -0,0 +1,56 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import { ComponentProps } from "react";
|
||||
|
||||
import compressorConfig from "@/public/compressor.json";
|
||||
|
||||
interface Props extends ComponentProps<"img"> {
|
||||
src: string;
|
||||
alt: string;
|
||||
raw?: boolean;
|
||||
}
|
||||
|
||||
const BASE_SRC = "/assets/";
|
||||
const RAW_SRC = "/assets-original/";
|
||||
|
||||
export default function Image({ src, raw, ...attrs }: Props) {
|
||||
if (raw) {
|
||||
return (
|
||||
<img
|
||||
{...attrs}
|
||||
alt={attrs.alt}
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
src={RAW_SRC + src + ".png"}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<picture>
|
||||
{compressorConfig.configs
|
||||
.sort((a, b) => {
|
||||
if (a.extension === "avif" && b.extension !== "avif") return -1;
|
||||
if (b.extension === "avif" && a.extension !== "avif") return 1;
|
||||
|
||||
return a.scale - b.scale;
|
||||
})
|
||||
.map((c) => {
|
||||
return (
|
||||
<source
|
||||
key={`${c.extension}_q${c.quality}@${c.scale}x`}
|
||||
srcSet={`${BASE_SRC}${src}_q${c.quality}@${c.scale}x.${c.extension}`}
|
||||
type={`image/${c.extension}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
<img
|
||||
{...attrs}
|
||||
alt={attrs.alt}
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
src={`${BASE_SRC}${src}.png`}
|
||||
/>
|
||||
</picture>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import compressorConfig from "@/public/compressor.json";
|
||||
|
||||
const avifConfig = compressorConfig.configs.find(
|
||||
(c) => c.extension === "avif",
|
||||
)!;
|
||||
const webpConfig = compressorConfig.configs.find(
|
||||
(c) => c.extension === "webp",
|
||||
)!;
|
||||
|
||||
export async function getImageSrc(src: string) {
|
||||
const BASE_SRC = "/assets/";
|
||||
|
||||
if (await supportsEncode()) {
|
||||
return `${BASE_SRC}${src}_q${avifConfig.quality}@${avifConfig.scale}x.avif`;
|
||||
}
|
||||
|
||||
return `${BASE_SRC}${src}_q${webpConfig.quality}@${webpConfig.scale}x.webp`;
|
||||
}
|
||||
|
||||
let promise: Promise<boolean> | null = null;
|
||||
|
||||
async function supportsEncode() {
|
||||
if (promise) return promise;
|
||||
|
||||
const avifData =
|
||||
"data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUEAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABYAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgSAAAAAAABNjb2xybmNseAACAAIABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAAB5tZGF0EgAKBzgADlAgIGkyCR/wAABAAACvcA==";
|
||||
|
||||
promise = fetch(avifData)
|
||||
.then((r) => r.blob())
|
||||
.then((b) => createImageBitmap(b))
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
|
||||
return promise;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
"use client";
|
||||
|
||||
import { motion, MotionProps, TargetAndTransition } from "motion/react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
type AnimatedHeight = {
|
||||
children: React.ReactNode;
|
||||
animate?: TargetAndTransition;
|
||||
initial?: TargetAndTransition;
|
||||
exit?: TargetAndTransition;
|
||||
className?: string;
|
||||
transition?: MotionProps["transition"];
|
||||
};
|
||||
|
||||
export default function AnimatedHeight({ children, ...attrs }: AnimatedHeight) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [height, setHeight] = useState<number | "auto">("auto");
|
||||
|
||||
useEffect(() => {
|
||||
const child = containerRef.current?.children[0] as Element;
|
||||
|
||||
const updateHeight = () => {
|
||||
if (!child) return;
|
||||
|
||||
setHeight(child.clientHeight);
|
||||
};
|
||||
|
||||
updateHeight();
|
||||
|
||||
const resizeObserver = new ResizeObserver(updateHeight);
|
||||
|
||||
resizeObserver.observe(child);
|
||||
|
||||
return () => resizeObserver.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
{...attrs}
|
||||
animate={{
|
||||
height,
|
||||
...attrs.animate,
|
||||
}}
|
||||
className={cn(attrs.className)}
|
||||
initial={{
|
||||
height,
|
||||
...attrs.initial,
|
||||
}}
|
||||
ref={containerRef}
|
||||
>
|
||||
<div className="h-max">{children}</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
"use client";
|
||||
|
||||
import { motion, TargetAndTransition, Transition } from "motion/react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
type AnimatedWidthProps = {
|
||||
children: React.ReactNode;
|
||||
animate?: TargetAndTransition;
|
||||
initial?: TargetAndTransition;
|
||||
transition?: Transition;
|
||||
};
|
||||
|
||||
export default function AnimatedWidth({
|
||||
children,
|
||||
...attrs
|
||||
}: AnimatedWidthProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [width, setWidth] = useState<number | "auto">("auto");
|
||||
|
||||
useEffect(() => {
|
||||
const child = containerRef.current?.children[0] as Element;
|
||||
|
||||
const updateWidth = () => {
|
||||
if (!child) return;
|
||||
|
||||
setWidth(child.clientWidth);
|
||||
};
|
||||
|
||||
updateWidth();
|
||||
|
||||
const resizeObserver = new ResizeObserver(updateWidth);
|
||||
|
||||
resizeObserver.observe(child);
|
||||
|
||||
return () => resizeObserver.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
{...attrs}
|
||||
animate={{
|
||||
width,
|
||||
...attrs.animate,
|
||||
}}
|
||||
className="overflow-hidden"
|
||||
initial={{
|
||||
width,
|
||||
...attrs.initial,
|
||||
}}
|
||||
ref={containerRef}
|
||||
>
|
||||
<div className="w-max whitespace-nowrap">{children}</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
|
||||
import CurvyRect from "./curvy-rect";
|
||||
|
||||
export function CurvyRectDivider() {
|
||||
return (
|
||||
<div className="relative mx-1 my-1">
|
||||
<div className="relative h-px bg-zinc-200 border-x border-zinc-200">
|
||||
<CurvyRect
|
||||
className="absolute -top-[0.5px] -left-[1px] w-[calc(100%+2px)]"
|
||||
top
|
||||
/>
|
||||
<CurvyRect
|
||||
className="absolute -bottom-[0.5px] -left-[1px] w-[calc(100%+2px)]"
|
||||
bottom
|
||||
/>
|
||||
<CurvyRect
|
||||
className="absolute -left-[0.5px] -top-[1px] h-[calc(100%+2px)]"
|
||||
left
|
||||
/>
|
||||
<CurvyRect
|
||||
className="absolute -right-[0.5px] -top-[1px] h-[calc(100%+2px)]"
|
||||
right
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
import Curve from "@/components/shared/icons/curve";
|
||||
|
||||
interface CurvyRectProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
allSides?: boolean;
|
||||
|
||||
x?: boolean;
|
||||
y?: boolean;
|
||||
|
||||
left?: boolean;
|
||||
right?: boolean;
|
||||
top?: boolean;
|
||||
bottom?: boolean;
|
||||
|
||||
topLeft?: boolean;
|
||||
topRight?: boolean;
|
||||
bottomLeft?: boolean;
|
||||
bottomRight?: boolean;
|
||||
}
|
||||
|
||||
export default function CurvyRect({
|
||||
className,
|
||||
allSides,
|
||||
x,
|
||||
y,
|
||||
left,
|
||||
right,
|
||||
top,
|
||||
bottom,
|
||||
topLeft,
|
||||
topRight,
|
||||
bottomLeft,
|
||||
bottomRight,
|
||||
...props
|
||||
}: CurvyRectProps) {
|
||||
const hasTopLeft = topLeft || top || left || x || allSides;
|
||||
const hasTopRight = topRight || top || right || x || allSides;
|
||||
const hasBottomLeft = bottomLeft || bottom || left || y || allSides;
|
||||
const hasBottomRight = bottomRight || bottom || right || y || allSides;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
className,
|
||||
"pointer-events-none contain-[layout,paint] curvy-rect",
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{hasTopLeft && <Curve className="-rotate-90 absolute top-0 left-0" />}
|
||||
{hasTopRight && <Curve className="absolute top-0 right-0" />}
|
||||
{hasBottomLeft && (
|
||||
<Curve className="rotate-180 absolute bottom-0 left-0" />
|
||||
)}
|
||||
{hasBottomRight && (
|
||||
<Curve className="rotate-90 absolute bottom-0 right-0" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const Connector = ({
|
||||
className,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="21"
|
||||
viewBox="0 0 22 21"
|
||||
width="22"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
className={cn(
|
||||
"pointer-events-none contain-[layout,paint] absolute",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<path
|
||||
d="M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z"
|
||||
fill="#EDEDED"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConnectorToRight = ({
|
||||
className,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="21"
|
||||
viewBox="0 0 11 21"
|
||||
width="11"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
className={cn(
|
||||
"pointer-events-none contain-[layout,paint] absolute",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<path
|
||||
d="M1 4C1 7.31371 3.68629 10 7 10H11V11H7C3.68629 11 1 13.6863 1 17V21H0V0H1V4Z"
|
||||
fill="#EDEDED"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConnectorToLeft = ({
|
||||
className,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="21"
|
||||
viewBox="0 0 11 21"
|
||||
width="11"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
className={cn(
|
||||
"pointer-events-none contain-[layout,paint] absolute",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<path
|
||||
d="M11 21H10V17C10 13.6863 7.31371 11 4 11H0V10H4C7.31371 10 10 7.31371 10 4V0H11V21Z"
|
||||
fill="#EDEDED"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConnectorToTop = ({
|
||||
className,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="11"
|
||||
viewBox="0 0 21 11"
|
||||
width="21"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
className={cn(
|
||||
"pointer-events-none contain-[layout,paint] absolute",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<path
|
||||
d="M11 4C11 7.31371 13.6863 10 17 10H21V11H0V10H4C7.31371 10 10 7.31371 10 4V0H11V4Z"
|
||||
fill="#EDEDED"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConnectorToBottom = ({
|
||||
className,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height="11"
|
||||
viewBox="0 0 21 11"
|
||||
width="21"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
className={cn(
|
||||
"pointer-events-none contain-[layout,paint] absolute",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<path
|
||||
d="M11 7C11 3.68629 13.6863 1 17 1H21V0H0V1H4C7.31371 1 10 3.68629 10 7V11H11V7Z"
|
||||
fill="#EDEDED"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
import { useState, useEffect } from "react";
|
||||
import ScrambleText from "@/components/ui/motion/scramble-text";
|
||||
|
||||
export const Shimmer = ({
|
||||
className,
|
||||
text = "Loading...",
|
||||
}: {
|
||||
className?: string;
|
||||
text?: string;
|
||||
}) => {
|
||||
const [isInView, setIsInView] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsInView(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={cn("w-full", className)}>
|
||||
{text && (
|
||||
<div className="mb-4 text-label-large text-black-alpha-56">
|
||||
<ScrambleText
|
||||
text={text}
|
||||
delay={0}
|
||||
duration={1.2}
|
||||
isInView={isInView}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-3">
|
||||
<div className="h-4 rounded-8 bg-gradient-to-r from-black-alpha-4 via-black-alpha-8 to-black-alpha-4 animate-shimmer mb-2 w-3/4">
|
||||
<span className="sr-only">{text}</span>
|
||||
</div>
|
||||
<div className="h-4 rounded-8 bg-gradient-to-r from-black-alpha-4 via-black-alpha-8 to-black-alpha-4 animate-shimmer animation-delay-150 mb-2 w-1/2"></div>
|
||||
<div className="h-4 rounded-8 bg-gradient-to-r from-black-alpha-4 via-black-alpha-8 to-black-alpha-4 animate-shimmer animation-delay-300 mb-2 w-full"></div>
|
||||
<div className="h-4 rounded-8 bg-gradient-to-r from-black-alpha-4 via-black-alpha-8 to-black-alpha-4 animate-shimmer animation-delay-450 mb-2 w-1/2"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ShimmerSingle = ({
|
||||
className,
|
||||
text,
|
||||
}: {
|
||||
className?: string;
|
||||
text?: string;
|
||||
}) => {
|
||||
const [isInView, setIsInView] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsInView(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={cn("w-full", className)}>
|
||||
{text && (
|
||||
<div className="mb-2 text-label-small text-black-alpha-56">
|
||||
<ScrambleText
|
||||
text={text}
|
||||
delay={0}
|
||||
duration={1}
|
||||
isInView={isInView}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="h-4 rounded-8 bg-gradient-to-r from-black-alpha-4 via-black-alpha-8 to-black-alpha-4 animate-shimmer w-full"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Chart shimmer with fire glow effect
|
||||
export const ChartShimmer = ({
|
||||
className,
|
||||
text = "Loading chart data...",
|
||||
}: {
|
||||
className?: string;
|
||||
text?: string;
|
||||
}) => {
|
||||
const [isInView, setIsInView] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsInView(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={cn("w-full h-full relative overflow-hidden", className)}>
|
||||
{/* Subtle fire glow background */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-heat-4/10 via-transparent to-heat-4/10 animate-pulse" />
|
||||
|
||||
{/* Loading text */}
|
||||
{text && (
|
||||
<div className="absolute top-4 left-4 text-label-small text-black-alpha-56 z-10">
|
||||
<ScrambleText
|
||||
text={text}
|
||||
delay={0}
|
||||
duration={0.8}
|
||||
isInView={isInView}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Chart bars */}
|
||||
<div className="absolute bottom-0 left-0 right-0 flex items-end justify-between px-4 pb-4 gap-2">
|
||||
{Array.from({ length: 8 }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex-1 bg-gradient-to-t from-black-alpha-8 to-transparent rounded-t-4 animate-shimmer"
|
||||
style={{
|
||||
height: `${Math.random() * 60 + 20}%`,
|
||||
animationDelay: `${i * 100}ms`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import ScrambleText from "@/components/ui/motion/scramble-text";
|
||||
|
||||
export function UsageLoadingText({ text = "Loading..." }: { text?: string }) {
|
||||
const [isInView, setIsInView] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsInView(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="text-xs text-zinc-500">
|
||||
<ScrambleText text={text} delay={0} duration={1} isInView={isInView} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Utility to lock/unlock the document body based on a set of keys.
|
||||
* Each key can "lock" the body (e.g., prevent scrolling), and the lock is only released when all keys are removed.
|
||||
*
|
||||
* @param {string} key - Unique identifier for the lock (e.g., component name or id)
|
||||
* @param {'lock'|'unlock'} action - Whether to lock or unlock
|
||||
* @param {(locked: boolean) => void} [onLockChange] - Optional callback when lock state changes
|
||||
*/
|
||||
const activeLocks = new Set<string>();
|
||||
|
||||
export function lockBody(
|
||||
key: string,
|
||||
action: boolean,
|
||||
onLockChange?: (locked: boolean) => void,
|
||||
) {
|
||||
if (action) {
|
||||
activeLocks.add(key);
|
||||
} else {
|
||||
activeLocks.delete(key);
|
||||
}
|
||||
|
||||
const shouldLock = activeLocks.size > 0;
|
||||
document.body.classList.toggle("overflow-hidden", shouldLock);
|
||||
if (onLockChange) onLockChange(shouldLock);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user