first commit

This commit is contained in:
R-Bharathraj
2026-07-15 17:13:09 +05:30
parent a314b87153
commit 3cb2613195
59 changed files with 7428 additions and 101 deletions

228
src/components/story/ui.tsx Normal file
View File

@@ -0,0 +1,228 @@
"use client";
import { ReactNode } from "react";
import Image from "next/image";
import { motion, Variants } from "framer-motion";
import { C } from "./palette";
export { C };
const viewport = { once: true, amount: 0.25 } as const;
/* stagger container variants */
export const stagger: Variants = {
hidden: {},
show: { transition: { staggerChildren: 0.09, delayChildren: 0.05 } },
};
export const riseItem: Variants = {
hidden: { opacity: 0, y: 30, scale: 0.96 },
show: {
opacity: 1,
y: 0,
scale: 1,
transition: { type: "spring", stiffness: 130, damping: 16 },
},
};
/* ------- Section ------- */
type SectionProps = {
id: string;
children: ReactNode;
variant?: "cream" | "deep" | "night" | "plain";
className?: string;
};
export function Section({ id, children, variant = "deep", className = "" }: SectionProps) {
const bg =
variant === "cream"
? "bg-cream text-[#0a0a0a]"
: variant === "night"
? "bg-night text-white"
: variant === "plain"
? "bg-[#120a1f] text-white"
: "bg-deep text-white";
return (
<section
id={id}
className={`relative flex min-h-screen w-full flex-col justify-center overflow-hidden px-6 py-20 sm:px-10 lg:px-20 ${bg} ${className}`}
>
<div className="mx-auto w-full max-w-6xl">{children}</div>
</section>
);
}
/* ------- Reveal (fade/slide up on scroll) ------- */
export function Reveal({
children,
className = "",
delay = 0,
y = 26,
}: {
children: ReactNode;
className?: string;
delay?: number;
y?: number;
}) {
return (
<motion.div
className={className}
initial={{ opacity: 0, y }}
whileInView={{ opacity: 1, y: 0 }}
viewport={viewport}
transition={{ type: "spring", stiffness: 120, damping: 18, delay }}
>
{children}
</motion.div>
);
}
/* ------- Group (stagger children that use riseItem) ------- */
export function Group({
children,
className = "",
}: {
children: ReactNode;
className?: string;
}) {
return (
<motion.div
className={className}
variants={stagger}
initial="hidden"
whileInView="show"
viewport={{ once: true, amount: 0.15 }}
>
{children}
</motion.div>
);
}
/* ------- Pill ------- */
export function Pill({
children,
bg = C.pink,
text = "#fff",
}: {
children: ReactNode;
bg?: string;
text?: string;
}) {
return (
<motion.span
className="nb-sm inline-flex items-center gap-2 rounded-full px-4 py-1.5 text-xs font-extrabold uppercase tracking-wide sm:text-sm"
style={{ background: bg, color: text }}
initial={{ opacity: 0, scale: 0.8, y: 12 }}
whileInView={{ opacity: 1, scale: 1, y: 0 }}
viewport={viewport}
transition={{ type: "spring", stiffness: 320, damping: 15 }}
>
{children}
</motion.span>
);
}
/* ------- Card (scroll-reveal + neobrutalist hover) ------- */
export function Card({
children,
bg = "#fff",
text = "#0a0a0a",
className = "",
rounded = "rounded-2xl",
delay = 0,
group = false,
}: {
children: ReactNode;
bg?: string;
text?: string;
className?: string;
rounded?: string;
delay?: number;
/** set true when rendered inside a <Group> so stagger drives the entrance */
group?: boolean;
}) {
const entrance = group
? { variants: riseItem }
: {
initial: { opacity: 0, y: 30, scale: 0.96 },
whileInView: { opacity: 1, y: 0, scale: 1 },
viewport,
transition: { type: "spring" as const, stiffness: 130, damping: 16, delay },
};
return (
<motion.div
className={`nb ${rounded} ${className}`}
style={{ background: bg, color: text }}
{...entrance}
whileHover={{
y: -6,
x: -3,
boxShadow: "11px 13px 0 0 #0a0a0a",
transition: { type: "spring", stiffness: 400, damping: 15 },
}}
>
{children}
</motion.div>
);
}
/* ------- Chip ------- */
export function Chip({
children,
bg = C.lime,
text = "#0a0a0a",
delay = 0,
}: {
children: ReactNode;
bg?: string;
text?: string;
delay?: number;
}) {
return (
<motion.span
className="nb-sm inline-flex items-center gap-1.5 rounded-xl px-3 py-2 text-sm font-extrabold sm:px-4"
style={{ background: bg, color: text }}
initial={{ opacity: 0, scale: 0.85, y: 10 }}
whileInView={{ opacity: 1, scale: 1, y: 0 }}
viewport={viewport}
transition={{ type: "spring", stiffness: 300, damping: 16, delay }}
whileHover={{ scale: 1.06, rotate: -1.5 }}
>
{children}
</motion.span>
);
}
/* ------- Heading (self-animating) ------- */
export function Heading({
children,
className = "",
}: {
children: ReactNode;
className?: string;
}) {
return (
<motion.h2
className={`font-sora text-4xl font-extrabold leading-[0.95] tracking-tight sm:text-5xl lg:text-6xl ${className}`}
initial={{ opacity: 0, y: 28 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={viewport}
transition={{ type: "spring", stiffness: 120, damping: 18 }}
>
{children}
</motion.h2>
);
}
/* LytsUp wordmark */
export function Logo({ className = "" }: { className?: string }) {
return (
<Image
src="/images/lytsup_app.png"
alt="LytsUp"
width={2048}
height={554}
priority
className={`h-10 w-auto sm:h-12 ${className}`}
/>
);
}