Skip to content

Commit 5bfd87f

Browse files
authored
Merge pull request #392 from carmelcity/preview
added a friendlier home page
2 parents d780281 + 439a38f commit 5bfd87f

25 files changed

+2862
-298
lines changed

components.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": false,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.cjs",
8+
"css": "styles/globals.css",
9+
"baseColor": "neutral",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "~/components",
15+
"utils": "~/lib/utils",
16+
"ui": "~/components/ui",
17+
"lib": "~/lib",
18+
"hooks": "~/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { cn } from "~/lib/utils";
2+
import { ComponentPropsWithoutRef } from "react";
3+
4+
export interface AnimatedGradientTextProps
5+
extends ComponentPropsWithoutRef<"div"> {
6+
speed?: number;
7+
colorFrom?: string;
8+
colorTo?: string;
9+
}
10+
11+
export function AnimatedGradientText({
12+
children,
13+
className,
14+
speed = 1,
15+
colorFrom = "#ffaa40",
16+
colorTo = "#9c40ff",
17+
...props
18+
}: AnimatedGradientTextProps) {
19+
return (
20+
<span
21+
style={
22+
{
23+
"--bg-size": `${speed * 300}%`,
24+
"--color-from": colorFrom,
25+
"--color-to": colorTo,
26+
} as React.CSSProperties
27+
}
28+
className={cn(
29+
`inline animate-gradient bg-gradient-to-r from-[var(--color-from)] via-[var(--color-to)] to-[var(--color-from)] bg-[length:var(--bg-size)_100%] bg-clip-text text-transparent`,
30+
className,
31+
)}
32+
{...props}
33+
>
34+
{children}
35+
</span>
36+
);
37+
}

components/magicui/box-reveal.tsx

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"use client";
2+
3+
import { motion, useAnimation, useInView } from "motion/react";
4+
import { useEffect, useRef } from "react";
5+
6+
interface BoxRevealProps {
7+
children: JSX.Element;
8+
width?: "fit-content" | "100%";
9+
boxColor?: string;
10+
duration?: number;
11+
}
12+
13+
export const BoxReveal = ({
14+
children,
15+
width = "fit-content",
16+
boxColor = "#5046e6",
17+
duration,
18+
}: BoxRevealProps) => {
19+
const mainControls = useAnimation();
20+
const slideControls = useAnimation();
21+
22+
const ref = useRef(null);
23+
const isInView = useInView(ref, { once: true });
24+
25+
useEffect(() => {
26+
if (isInView) {
27+
slideControls.start("visible");
28+
mainControls.start("visible");
29+
} else {
30+
slideControls.start("hidden");
31+
mainControls.start("hidden");
32+
}
33+
}, [isInView, mainControls, slideControls]);
34+
35+
return (
36+
<div ref={ref} style={{ position: "relative", width, overflow: "hidden" }}>
37+
<motion.div
38+
variants={{
39+
hidden: { opacity: 0, y: 75 },
40+
visible: { opacity: 1, y: 0 },
41+
}}
42+
initial="hidden"
43+
animate={mainControls}
44+
transition={{ duration: duration ? duration : 0.5, delay: 0.25 }}
45+
>
46+
{children}
47+
</motion.div>
48+
49+
<motion.div
50+
variants={{
51+
hidden: { left: 0 },
52+
visible: { left: "100%" },
53+
}}
54+
initial="hidden"
55+
animate={slideControls}
56+
transition={{ duration: duration ? duration : 0.5, ease: "easeIn" }}
57+
style={{
58+
position: "absolute",
59+
top: 4,
60+
bottom: 4,
61+
left: 0,
62+
right: 0,
63+
zIndex: 20,
64+
background: boxColor,
65+
}}
66+
/>
67+
</div>
68+
);
69+
};

components/ui/3d-marquee.tsx

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
"use client";
2+
3+
import { motion } from "motion/react";
4+
import { cn } from "~/lib/utils";
5+
export const ThreeDMarquee = ({
6+
images,
7+
className,
8+
}: {
9+
images: string[];
10+
className?: string;
11+
}) => {
12+
// Split the images array into 4 equal parts
13+
const chunkSize = Math.ceil(images.length / 4);
14+
const chunks = Array.from({ length: 4 }, (_, colIndex) => {
15+
const start = colIndex * chunkSize;
16+
return images.slice(start, start + chunkSize);
17+
});
18+
return (
19+
<div
20+
className={cn(
21+
"mx-auto block h-[600px] overflow-hidden rounded-2xl max-sm:h-100",
22+
className,
23+
)}
24+
>
25+
<div className="flex size-full items-center justify-center">
26+
<div className="size-[1720px] shrink-0 scale-50 sm:scale-75 lg:scale-100">
27+
<div
28+
style={{
29+
transform: "rotateX(55deg) rotateY(0deg) rotateZ(-45deg)",
30+
}}
31+
className="relative top-96 right-[50%] grid size-full origin-top-left grid-cols-4 gap-8 transform-3d"
32+
>
33+
{chunks.map((subarray, colIndex) => (
34+
<motion.div
35+
animate={{ y: colIndex % 2 === 0 ? 100 : -100 }}
36+
transition={{
37+
duration: colIndex % 2 === 0 ? 10 : 15,
38+
repeat: Infinity,
39+
repeatType: "reverse",
40+
}}
41+
key={colIndex + "marquee"}
42+
className="flex flex-col items-start gap-8"
43+
>
44+
<GridLineVertical className="-left-4" offset="80px" />
45+
{subarray.map((image, imageIndex) => (
46+
<div className="relative" key={imageIndex + image}>
47+
<GridLineHorizontal className="-top-4" offset="20px" />
48+
<motion.img
49+
whileHover={{
50+
y: -10,
51+
}}
52+
transition={{
53+
duration: 0.3,
54+
ease: "easeInOut",
55+
}}
56+
key={imageIndex + image}
57+
src={image}
58+
alt={`Image ${imageIndex + 1}`}
59+
className="aspect-[970/700] rounded-lg object-cover ring ring-gray-950/5 hover:shadow-2xl"
60+
width={970}
61+
height={700}
62+
/>
63+
</div>
64+
))}
65+
</motion.div>
66+
))}
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
);
72+
};
73+
74+
const GridLineHorizontal = ({
75+
className,
76+
offset,
77+
}: {
78+
className?: string;
79+
offset?: string;
80+
}) => {
81+
return (
82+
<div
83+
style={
84+
{
85+
"--background": "#ffffff",
86+
"--color": "rgba(0, 0, 0, 0.2)",
87+
"--height": "1px",
88+
"--width": "5px",
89+
"--fade-stop": "90%",
90+
"--offset": offset || "200px", //-100px if you want to keep the line inside
91+
"--color-dark": "rgba(255, 255, 255, 0.2)",
92+
maskComposite: "exclude",
93+
} as React.CSSProperties
94+
}
95+
className={cn(
96+
"absolute left-[calc(var(--offset)/2*-1)] h-[var(--height)] w-[calc(100%+var(--offset))]",
97+
"bg-[linear-gradient(to_right,var(--color),var(--color)_50%,transparent_0,transparent)]",
98+
"[background-size:var(--width)_var(--height)]",
99+
"[mask:linear-gradient(to_left,var(--background)_var(--fade-stop),transparent),_linear-gradient(to_right,var(--background)_var(--fade-stop),transparent),_linear-gradient(black,black)]",
100+
"[mask-composite:exclude]",
101+
"z-30",
102+
"dark:bg-[linear-gradient(to_right,var(--color-dark),var(--color-dark)_50%,transparent_0,transparent)]",
103+
className,
104+
)}
105+
></div>
106+
);
107+
};
108+
109+
const GridLineVertical = ({
110+
className,
111+
offset,
112+
}: {
113+
className?: string;
114+
offset?: string;
115+
}) => {
116+
return (
117+
<div
118+
style={
119+
{
120+
"--background": "#ffffff",
121+
"--color": "rgba(0, 0, 0, 0.2)",
122+
"--height": "5px",
123+
"--width": "1px",
124+
"--fade-stop": "90%",
125+
"--offset": offset || "150px", //-100px if you want to keep the line inside
126+
"--color-dark": "rgba(255, 255, 255, 0.2)",
127+
maskComposite: "exclude",
128+
} as React.CSSProperties
129+
}
130+
className={cn(
131+
"absolute top-[calc(var(--offset)/2*-1)] h-[calc(100%+var(--offset))] w-[var(--width)]",
132+
"bg-[linear-gradient(to_bottom,var(--color),var(--color)_50%,transparent_0,transparent)]",
133+
"[background-size:var(--width)_var(--height)]",
134+
"[mask:linear-gradient(to_top,var(--background)_var(--fade-stop),transparent),_linear-gradient(to_bottom,var(--background)_var(--fade-stop),transparent),_linear-gradient(black,black)]",
135+
"[mask-composite:exclude]",
136+
"z-30",
137+
"dark:bg-[linear-gradient(to_bottom,var(--color-dark),var(--color-dark)_50%,transparent_0,transparent)]",
138+
className,
139+
)}
140+
></div>
141+
);
142+
};

0 commit comments

Comments
 (0)