Skip to content

Commit 30daf28

Browse files
Restore mistakenly deleted gradient-preview components from upstream and fix Twitter card issues
1 parent cbf4d75 commit 30daf28

3 files changed

Lines changed: 380 additions & 0 deletions

File tree

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import React, { useRef, useEffect } from "react";
2+
3+
export const PastelGradientCanvas = ({
4+
rounded,
5+
width,
6+
height,
7+
}: {
8+
rounded: boolean;
9+
width?: number;
10+
height?: number;
11+
}) => {
12+
const canvasRef = useRef<HTMLCanvasElement | null>(null);
13+
14+
useEffect(() => {
15+
if (!canvasRef.current) return;
16+
const canvas = canvasRef.current;
17+
const ctx = canvas.getContext("2d");
18+
let animationFrameId: number;
19+
20+
const resizeCanvas = () => {
21+
canvas.width = window.innerWidth;
22+
canvas.height = window.innerHeight;
23+
};
24+
25+
resizeCanvas();
26+
window.addEventListener("resize", resizeCanvas);
27+
28+
let time = 0;
29+
const animate = () => {
30+
time += 0.005; // Slow increment for ambient motion
31+
const w = canvas.width;
32+
const h = canvas.height;
33+
34+
if (!ctx) {
35+
animationFrameId = requestAnimationFrame(animate);
36+
return;
37+
}
38+
39+
ctx.clearRect(0, 0, w, h);
40+
41+
// Base fill for a light pastel foundation
42+
ctx.fillStyle = "#F8F8FF"; // GhostWhite
43+
ctx.fillRect(0, 0, w, h);
44+
45+
// Left side: Pink blob
46+
let cx1 = w * 0.2 + Math.sin(time) * 50;
47+
let cy1 = h / 2 + Math.cos(time) * 50;
48+
const grad1 = ctx.createRadialGradient(cx1, cy1, 0, cx1, cy1, w / 2);
49+
grad1.addColorStop(0, "rgba(255, 182, 193, 0.8)");
50+
grad1.addColorStop(1, "rgba(255, 182, 193, 0)");
51+
ctx.fillStyle = grad1;
52+
ctx.fillRect(0, 0, w, h);
53+
54+
// Left side: Peach blob
55+
let cx2 = w * 0.3 + Math.cos(time * 1.2) * 60;
56+
let cy2 = h / 2 + Math.sin(time * 1.2) * 60;
57+
const grad2 = ctx.createRadialGradient(cx2, cy2, 0, cx2, cy2, w / 1.5);
58+
grad2.addColorStop(0, "rgba(255, 229, 180, 0.7)");
59+
grad2.addColorStop(1, "rgba(255, 229, 180, 0)");
60+
ctx.fillStyle = grad2;
61+
ctx.fillRect(0, 0, w, h);
62+
63+
// Left side: Magenta blob
64+
let cx3 = w * 0.1 + Math.sin(time * 0.8) * 40;
65+
let cy3 = h / 2 + Math.cos(time * 0.8) * 40;
66+
const grad3 = ctx.createRadialGradient(cx3, cy3, 0, cx3, cy3, w / 2.5);
67+
grad3.addColorStop(0, "rgba(255, 119, 168, 0.6)");
68+
grad3.addColorStop(1, "rgba(255, 119, 168, 0)");
69+
ctx.fillStyle = grad3;
70+
ctx.fillRect(0, 0, w, h);
71+
72+
// Center: Yellow blob
73+
let cx4 = w / 2 + Math.sin(time * 1.1) * 30;
74+
let cy4 = h / 2 + Math.cos(time * 1.1) * 30;
75+
const grad4 = ctx.createRadialGradient(cx4, cy4, 0, cx4, cy4, w / 3);
76+
grad4.addColorStop(0, "rgba(255, 255, 153, 0.8)");
77+
grad4.addColorStop(1, "rgba(255, 255, 153, 0)");
78+
ctx.fillStyle = grad4;
79+
ctx.fillRect(0, 0, w, h);
80+
81+
// Right side: Lavender blob
82+
let cx5 = w * 0.7 + Math.cos(time * 0.9) * 50;
83+
let cy5 = h / 2 + Math.sin(time * 0.9) * 50;
84+
const grad5 = ctx.createRadialGradient(cx5, cy5, 0, cx5, cy5, w / 2);
85+
grad5.addColorStop(0, "rgba(195, 177, 225, 0.7)");
86+
grad5.addColorStop(1, "rgba(195, 177, 225, 0)");
87+
ctx.fillStyle = grad5;
88+
ctx.fillRect(0, 0, w, h);
89+
90+
// Right side: Light blue blob
91+
let cx6 = w * 0.8 + Math.sin(time * 1.3) * 40;
92+
let cy6 = h / 2 + Math.cos(time * 1.3) * 40;
93+
const grad6 = ctx.createRadialGradient(cx6, cy6, 0, cx6, cy6, w / 1.8);
94+
grad6.addColorStop(0, "rgba(167, 199, 231, 0.6)");
95+
grad6.addColorStop(1, "rgba(167, 199, 231, 0)");
96+
ctx.fillStyle = grad6;
97+
ctx.fillRect(0, 0, w, h);
98+
99+
animationFrameId = requestAnimationFrame(animate);
100+
};
101+
102+
animate();
103+
104+
return () => {
105+
window.removeEventListener("resize", resizeCanvas);
106+
cancelAnimationFrame(animationFrameId);
107+
};
108+
}, []);
109+
110+
return (
111+
<canvas
112+
ref={canvasRef}
113+
style={{
114+
width: width ? width + "px" : "100%",
115+
height: height ? height + "px" : "100%",
116+
borderRadius: rounded ? "15px" : "0",
117+
}}
118+
/>
119+
);
120+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.download-card {
2+
/* color: rgb(0, 0, 0) !important;
3+
background-color: rgb(255, 255, 255) !important; */
4+
min-height: 200px;
5+
}
6+
7+
:root {
8+
--text-primary: #0d0d0d;
9+
}
10+
11+
.roboto-flex {
12+
font-family: var(--font-roboto-flex), sans-serif;
13+
}
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
"use client";
2+
3+
import React from "react";
4+
import { CardContainer } from "../layouts/card-container";
5+
import "./gradient-preview.style.css";
6+
import { PastelGradientCanvas } from "./PastelGradientCanvas";
7+
8+
interface GradientPreviewProps {
9+
className?: string;
10+
styles?: React.CSSProperties;
11+
pageName?: string;
12+
logoUrl?: string;
13+
logoUrlLabel?: string;
14+
scale?: number;
15+
16+
rounded?: boolean;
17+
title?: string;
18+
text: string;
19+
gradientWidth?: number;
20+
gradientHeight?: number;
21+
gradientType?: string;
22+
blurAmount?: number;
23+
customImage: string;
24+
}
25+
26+
export const GradientPreview: React.FC<GradientPreviewProps> = ({
27+
title = "",
28+
text,
29+
className = "",
30+
styles = {},
31+
pageName,
32+
logoUrl = "",
33+
logoUrlLabel = "",
34+
rounded = false,
35+
scale = 1,
36+
gradientWidth,
37+
gradientHeight,
38+
gradientType = "default",
39+
blurAmount = 0,
40+
customImage,
41+
}) => {
42+
return (
43+
<CardContainer
44+
className={className}
45+
styles={styles}
46+
pageName={pageName}
47+
logoUrl={logoUrl}
48+
logoUrlLabel={logoUrlLabel}
49+
lightMode={true}
50+
scale={scale}
51+
>
52+
<div
53+
style={{
54+
position: "relative",
55+
}}
56+
>
57+
{title && (
58+
<div
59+
className="roboto-flex mb-4 text-center font-bold"
60+
style={{
61+
fontSize: "1.8rem",
62+
color: "#000",
63+
}}
64+
>
65+
{title}
66+
</div>
67+
)}
68+
{gradientType === "default" && (
69+
<div
70+
style={{
71+
display: "flex",
72+
justifyContent: "center",
73+
alignItems: "center",
74+
width: "100%",
75+
height: gradientHeight ? gradientHeight : 200,
76+
marginBottom: "16px",
77+
filter: `blur(${blurAmount}px)`,
78+
}}
79+
>
80+
<PastelGradientCanvas
81+
width={gradientWidth}
82+
height={gradientHeight}
83+
rounded={rounded}
84+
/>
85+
</div>
86+
)}
87+
88+
{gradientType === "nano" && (
89+
<div
90+
style={{
91+
display: "flex",
92+
justifyContent: "center",
93+
alignItems: "center",
94+
width: "100%",
95+
height: gradientHeight ? gradientHeight : 200,
96+
marginBottom: "16px",
97+
}}
98+
>
99+
<img
100+
style={{
101+
objectFit: "cover",
102+
width: gradientWidth ? gradientWidth + "px" : "100%",
103+
height: gradientHeight ? gradientHeight + "px" : "100%",
104+
borderRadius: rounded ? "15px" : "0",
105+
filter: `blur(${blurAmount}px)`,
106+
}}
107+
src="/gpt-5-nano-1.jpg"
108+
width={100}
109+
height={100}
110+
alt="Background"
111+
/>
112+
</div>
113+
)}
114+
115+
{gradientType === "mini" && (
116+
<div
117+
style={{
118+
display: "flex",
119+
justifyContent: "center",
120+
alignItems: "center",
121+
width: "100%",
122+
height: gradientHeight ? gradientHeight : 200,
123+
marginBottom: "16px",
124+
}}
125+
>
126+
<img
127+
style={{
128+
objectFit: "cover",
129+
width: gradientWidth ? gradientWidth + "px" : "100%",
130+
height: gradientHeight ? gradientHeight + "px" : "100%",
131+
borderRadius: rounded ? "15px" : "0",
132+
filter: `blur(${blurAmount}px)`,
133+
}}
134+
src="/gpt-5-mini.jpg"
135+
width={100}
136+
height={100}
137+
alt="Background"
138+
/>
139+
</div>
140+
)}
141+
142+
{gradientType === "pink" && (
143+
<div
144+
style={{
145+
display: "flex",
146+
justifyContent: "center",
147+
alignItems: "center",
148+
width: "100%",
149+
height: gradientHeight ? gradientHeight : 200,
150+
marginBottom: "16px",
151+
}}
152+
>
153+
<img
154+
style={{
155+
objectFit: "cover",
156+
width: gradientWidth ? gradientWidth + "px" : "100%",
157+
height: gradientHeight ? gradientHeight + "px" : "100%",
158+
borderRadius: rounded ? "15px" : "0",
159+
filter: `blur(${blurAmount}px)`,
160+
}}
161+
src="/gpt-5.jpg"
162+
width={100}
163+
height={100}
164+
alt="Background"
165+
/>
166+
</div>
167+
)}
168+
169+
{gradientType === "conic" && (
170+
<div
171+
style={{
172+
display: "absolute",
173+
inset: 0,
174+
justifyContent: "center",
175+
alignItems: "center",
176+
width: "100%",
177+
height: gradientHeight ? gradientHeight : 200,
178+
marginBottom: "16px",
179+
}}
180+
>
181+
<img
182+
style={{
183+
objectFit: "cover",
184+
// mouse event none
185+
pointerEvents: "none",
186+
display: "inline-block",
187+
width: gradientWidth ? gradientWidth + "px" : "100%",
188+
height: gradientHeight ? gradientHeight + "px" : "100%",
189+
borderRadius: rounded ? "15px" : "0",
190+
filter: `blur(${blurAmount}px)`,
191+
}}
192+
src="/640.webp"
193+
alt="Background"
194+
/>
195+
</div>
196+
)}
197+
198+
199+
{gradientType === "custom" && (
200+
<div
201+
style={{
202+
display: "flex",
203+
justifyContent: "center",
204+
alignItems: "center",
205+
width: "100%",
206+
height: gradientHeight ? gradientHeight : 200,
207+
marginBottom: "16px",
208+
}}
209+
>
210+
<img
211+
style={{
212+
objectFit: "cover",
213+
width: gradientWidth ? gradientWidth + "px" : "100%",
214+
height: gradientHeight ? gradientHeight + "px" : "100%",
215+
borderRadius: rounded ? "15px" : "0",
216+
filter: `blur(${blurAmount}px)`,
217+
}}
218+
src={customImage}
219+
width={100}
220+
height={100}
221+
alt="Background"
222+
/>
223+
</div>
224+
)}
225+
226+
<div
227+
style={{
228+
width: "100%",
229+
height: "100%",
230+
}}
231+
>
232+
{text && (
233+
<div
234+
className="roboto-flex text-center"
235+
style={{
236+
color: "#000",
237+
fontSize: "1.2rem",
238+
}}
239+
>
240+
{text}
241+
</div>
242+
)}
243+
</div>
244+
</div>
245+
</CardContainer>
246+
);
247+
};

0 commit comments

Comments
 (0)