diff --git a/src/app/components/SupporterMessage.tsx b/src/app/components/SupporterMessage.tsx index 678b1bdd..7706e190 100644 --- a/src/app/components/SupporterMessage.tsx +++ b/src/app/components/SupporterMessage.tsx @@ -5,29 +5,41 @@ import confetti from "canvas-confetti"; export default function SupporterMessage({ tier }: { tier: string }) { return ( -
-
+ { // Get the bounding box of the element const rect = ( e.target as HTMLElement ).getBoundingClientRect(); - // Calculate the origin based on the top center of the box + // Trigger confetti centered on the word "Pangolin" confetti({ particleCount: 100, spread: 70, origin: { - x: (rect.left + rect.width / 2) / window.innerWidth, // Horizontal center of the box - y: rect.top / window.innerHeight // Top of the box - } + x: (rect.left + rect.width / 2) / window.innerWidth, + y: rect.top / window.innerHeight + }, + colors: ["#FFA500", "#FF4500", "#FFD700"] }); }} > -

- Thank you for supporting Pangolin as a {tier}! -

+ Pangolin +
+ {/* SVG Star */} + + + + {/* Popover */} +
+ Thank you for supporting Pangolin as a {tier}!
); diff --git a/src/app/globals.css b/src/app/globals.css index cb32e061..db1d8feb 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -2,65 +2,63 @@ @tailwind components; @tailwind utilities; - @layer base { - :root { - --background: 0 0% 100%; - --foreground: 20 0.0% 10.0%; - --card: 0 0% 100%; - --card-foreground: 20 0.0% 10.0%; - --popover: 0 0% 100%; - --popover-foreground: 20 0.0% 10.0%; - --primary: 24.6 95% 53.1%; - --primary-foreground: 60 9.1% 97.8%; - --secondary: 60 4.8% 95.9%; - --secondary-foreground: 24 9.8% 10%; - --muted: 60 4.8% 85.0%; - --muted-foreground: 25 5.3% 44.7%; - --accent: 60 4.8% 90%; - --accent-foreground: 24 9.8% 10%; - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 60 9.1% 97.8%; - --border: 20 5.9% 80%; - --input: 20 5.9% 75%; - --ring: 24.6 95% 53.1%; - --radius: 0.75rem; - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; - } + :root { + --background: 0 0% 100%; + --foreground: 20 0% 10%; + --card: 0 0% 100%; + --card-foreground: 20 0% 10%; + --popover: 0 0% 100%; + --popover-foreground: 20 0% 10%; + --primary: 24.6 95% 53.1%; + --primary-foreground: 60 9.1% 97.8%; + --secondary: 60 4.8% 95.9%; + --secondary-foreground: 24 9.8% 10%; + --muted: 60 4.8% 85%; + --muted-foreground: 25 5.3% 44.7%; + --accent: 60 4.8% 90%; + --accent-foreground: 24 9.8% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 60 9.1% 97.8%; + --border: 20 5.9% 80%; + --input: 20 5.9% 75%; + --ring: 24.6 95% 53.1%; + --radius: 0.75rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } - .dark { - --background: 20 0.0% 10.0%; - --foreground: 60 9.1% 97.8%; - --card: 20 0.0% 10.0%; - --card-foreground: 60 9.1% 97.8%; - --popover: 20 0.0% 10.0%; - --popover-foreground: 60 9.1% 97.8%; - --primary: 20.5 90.2% 48.2%; - --primary-foreground: 60 9.1% 97.8%; - --secondary: 12 6.5% 15.0%; - --secondary-foreground: 60 9.1% 97.8%; - --muted: 12 6.5% 25.0%; - --muted-foreground: 24 5.4% 63.9%; - --accent: 12 2.5% 15.0%; - --accent-foreground: 60 9.1% 97.8%; - --destructive: 0 72.2% 50.6%; - --destructive-foreground: 60 9.1% 97.8%; - --border: 12 6.5% 30.0%; - --input: 12 6.5% 35.0%; - --ring: 20.5 90.2% 48.2%; - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; - } + .dark { + --background: 20 0% 10%; + --foreground: 60 9.1% 97.8%; + --card: 20 0% 10%; + --card-foreground: 60 9.1% 97.8%; + --popover: 20 0% 10%; + --popover-foreground: 60 9.1% 97.8%; + --primary: 20.5 90.2% 48.2%; + --primary-foreground: 60 9.1% 97.8%; + --secondary: 12 6.5% 15%; + --secondary-foreground: 60 9.1% 97.8%; + --muted: 12 6.5% 25%; + --muted-foreground: 24 5.4% 63.9%; + --accent: 12 2.5% 15%; + --accent-foreground: 60 9.1% 97.8%; + --destructive: 0 72.2% 50.6%; + --destructive-foreground: 60 9.1% 97.8%; + --border: 12 6.5% 30%; + --input: 12 6.5% 35%; + --ring: 20.5 90.2% 48.2%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } } - @layer base { * { @apply border-border; @@ -70,4 +68,3 @@ @apply bg-background text-foreground; } } - diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8d472673..9a6f7cb9 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -62,9 +62,15 @@ export default async function RootLayout({ {/* Footer */} diff --git a/src/components/SupporterStatus.tsx b/src/components/SupporterStatus.tsx index b7b45c40..a08fdf77 100644 --- a/src/components/SupporterStatus.tsx +++ b/src/components/SupporterStatus.tsx @@ -47,6 +47,7 @@ import { CardTitle } from "./ui/card"; import { Check, ExternalLink } from "lucide-react"; +import confetti from "canvas-confetti"; const formSchema = z.object({ githubUsername: z @@ -100,6 +101,7 @@ export default function SupporterStatus() { return; } + // Trigger the toast toast({ variant: "default", title: "Valid Key", @@ -107,6 +109,50 @@ export default function SupporterStatus() { "Your supporter key has been validated. Thank you for your support!" }); + // Fireworks-style confetti + const duration = 5 * 1000; // 5 seconds + const animationEnd = Date.now() + duration; + const defaults = { + startVelocity: 30, + spread: 360, + ticks: 60, + zIndex: 0, + colors: ["#FFA500", "#FF4500", "#FFD700"] // Orange hues + }; + + function randomInRange(min: number, max: number) { + return Math.random() * (max - min) + min; + } + + const interval = setInterval(() => { + const timeLeft = animationEnd - Date.now(); + + if (timeLeft <= 0) { + clearInterval(interval); + return; + } + + const particleCount = 50 * (timeLeft / duration); + + // Launch confetti from two random horizontal positions + confetti({ + ...defaults, + particleCount, + origin: { + x: randomInRange(0.1, 0.3), + y: Math.random() - 0.2 + } + }); + confetti({ + ...defaults, + particleCount, + origin: { + x: randomInRange(0.7, 0.9), + y: Math.random() - 0.2 + } + }); + }, 250); + setPurchaseOptionsOpen(false); setKeyOpen(false); @@ -177,7 +223,9 @@ export default function SupporterStatus() {

-

Please select the option that best suits you.

+

+ Please select the option that best suits you. +

diff --git a/tailwind.config.ts b/tailwind.config.ts index 1978d23a..67762da1 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -5,59 +5,59 @@ const config: Config = { content: [ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", "./src/components/**/*.{js,ts,jsx,tsx,mdx}", - "./src/app/**/*.{js,ts,jsx,tsx,mdx}", + "./src/app/**/*.{js,ts,jsx,tsx,mdx}" ], theme: { extend: { colors: { - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", card: { - DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))' + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))" }, popover: { - DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))' + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))" }, primary: { - DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))' + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))" }, secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))' + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))" }, muted: { - DEFAULT: 'hsl(var(--muted))', - foreground: 'hsl(var(--muted-foreground))' + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))" }, accent: { - DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))' + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))" }, destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))' + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))" }, - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", chart: { - '1': 'hsl(var(--chart-1))', - '2': 'hsl(var(--chart-2))', - '3': 'hsl(var(--chart-3))', - '4': 'hsl(var(--chart-4))', - '5': 'hsl(var(--chart-5))' + "1": "hsl(var(--chart-1))", + "2": "hsl(var(--chart-2))", + "3": "hsl(var(--chart-3))", + "4": "hsl(var(--chart-4))", + "5": "hsl(var(--chart-5))" } }, borderRadius: { - lg: 'var(--radius)', - md: 'calc(var(--radius) - 2px)', - sm: 'calc(var(--radius) - 4px)' + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)" } } }, - plugins: [require("tailwindcss-animate")], + plugins: [require("tailwindcss-animate")] }; export default config;