mirror of
https://github.com/Dokploy/website
synced 2025-06-26 18:16:01 +00:00
feat: add canvas-confetti for celebratory animations and implement LicenseSuccess page
This commit is contained in:
111
apps/website/app/[locale]/license/success/page.tsx
Normal file
111
apps/website/app/[locale]/license/success/page.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
"use client";
|
||||
import { Container } from "@/components/Container";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import confetti from "canvas-confetti";
|
||||
import { CheckCircle2, Copy, Terminal } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function LicenseSuccess() {
|
||||
const [copied, setCopied] = useState(false);
|
||||
// Generate a realistic-looking API key
|
||||
const apiKey = `dk_live_${Array.from(
|
||||
crypto.getRandomValues(new Uint8Array(24)),
|
||||
)
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("")}`;
|
||||
|
||||
useEffect(() => {
|
||||
// Launch confetti when the page loads
|
||||
confetti({
|
||||
particleCount: 150,
|
||||
spread: 100,
|
||||
origin: { y: 0.6 },
|
||||
});
|
||||
}, []);
|
||||
|
||||
const copyToClipboard = () => {
|
||||
navigator.clipboard.writeText(apiKey);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative min-h-screen bg-gradient-to-b from-black via-zinc-900 to-black">
|
||||
<div className="absolute inset-0 bg-[url('/grid.svg')] bg-center [mask-image:linear-gradient(180deg,white,rgba(255,255,255,0))]" />
|
||||
|
||||
<Container className="relative pt-24 pb-28">
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
<div className="flex justify-center mb-8">
|
||||
<div className="rounded-full bg-green-500/10 p-4">
|
||||
<CheckCircle2 className="h-16 w-16 text-green-500" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 className="text-5xl font-bold tracking-tight text-white sm:text-6xl mb-6">
|
||||
Thank you for your purchase!
|
||||
</h1>
|
||||
|
||||
<p className="text-xl leading-8 text-zinc-400 mb-12">
|
||||
Your Dokploy license has been successfully activated. Here's your
|
||||
API key to get started.
|
||||
</p>
|
||||
|
||||
<div className="bg-black/50 backdrop-blur-sm border border-zinc-800 rounded-xl p-8 mb-12">
|
||||
<div className="flex flex-col items-center space-y-6">
|
||||
<Terminal className="h-10 w-10 text-zinc-500" />
|
||||
<div className="space-y-4 w-full">
|
||||
<div className="flex items-center justify-between space-x-4 bg-black/50 rounded-lg p-4 border border-zinc-800">
|
||||
<code className="text-green-500 text-lg font-mono">
|
||||
{apiKey}
|
||||
</code>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={copyToClipboard}
|
||||
className="transition-all duration-200 hover:bg-green-500/10 hover:text-green-500"
|
||||
>
|
||||
{copied ? (
|
||||
<CheckCircle2 className="h-5 w-5" />
|
||||
) : (
|
||||
<Copy className="h-5 w-5" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="text-left space-y-3">
|
||||
<p className="text-zinc-400 text-sm">
|
||||
To start using your license, add this API key to your
|
||||
configuration file:
|
||||
</p>
|
||||
<pre className="bg-black/50 rounded-lg p-4 overflow-x-auto border border-zinc-800">
|
||||
<code className="text-sm font-mono text-zinc-300">
|
||||
{`# .env
|
||||
DOKPLOY_LICENSE_KEY=${apiKey}`}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row justify-center gap-4">
|
||||
<Link href="https://docs.dokploy.com/docs/core/installation">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full sm:w-auto hover:bg-zinc-800"
|
||||
>
|
||||
View Documentation
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="https://discord.gg/dokploy">
|
||||
<Button className="w-full sm:w-auto bg-gradient-to-r from-indigo-500 to-purple-500 hover:from-indigo-600 hover:to-purple-600">
|
||||
Join our Discord
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -167,8 +167,6 @@ export function Pricing() {
|
||||
|
||||
const { sessionId } = await response.json();
|
||||
|
||||
console.log(sessionId);
|
||||
|
||||
// Redirect to Stripe checkout
|
||||
const { error } = await stripe.redirectToCheckout({
|
||||
sessionId,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"@types/turndown": "^5.0.5",
|
||||
"autoprefixer": "^10.4.12",
|
||||
"axios": "^1.8.1",
|
||||
"canvas-confetti": "^1.9.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"framer-motion": "^11.3.19",
|
||||
@@ -62,6 +63,7 @@
|
||||
"@babel/parser": "^7.26.9",
|
||||
"@babel/plugin-syntax-typescript": "^7.25.9",
|
||||
"@biomejs/biome": "1.7.0",
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"@types/react": "18.3.5",
|
||||
"@types/react-dom": "18.3.0",
|
||||
"prettier-plugin-tailwindcss": "^0.5.14"
|
||||
|
||||
8
apps/website/public/grid.svg
Normal file
8
apps/website/public/grid.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
|
||||
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="url(#grid)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 340 B |
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -145,6 +145,9 @@ importers:
|
||||
axios:
|
||||
specifier: ^1.8.1
|
||||
version: 1.8.1
|
||||
canvas-confetti:
|
||||
specifier: ^1.9.3
|
||||
version: 1.9.3
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
@@ -236,6 +239,9 @@ importers:
|
||||
'@biomejs/biome':
|
||||
specifier: 1.7.0
|
||||
version: 1.7.0
|
||||
'@types/canvas-confetti':
|
||||
specifier: ^1.9.0
|
||||
version: 1.9.0
|
||||
'@types/react':
|
||||
specifier: 18.3.5
|
||||
version: 18.3.5
|
||||
@@ -1693,6 +1699,9 @@ packages:
|
||||
'@types/acorn@4.0.6':
|
||||
resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==}
|
||||
|
||||
'@types/canvas-confetti@1.9.0':
|
||||
resolution: {integrity: sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==}
|
||||
|
||||
'@types/conventional-commits-parser@5.0.0':
|
||||
resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==}
|
||||
|
||||
@@ -1900,6 +1909,9 @@ packages:
|
||||
caniuse-lite@1.0.30001679:
|
||||
resolution: {integrity: sha512-j2YqID/YwpLnKzCmBOS4tlZdWprXm3ZmQLBH9ZBXFOhoxLA46fwyBvx6toCBWBmnuwUY/qB3kEU6gFx8qgCroA==}
|
||||
|
||||
canvas-confetti@1.9.3:
|
||||
resolution: {integrity: sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==}
|
||||
|
||||
ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
|
||||
@@ -5440,6 +5452,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.5
|
||||
|
||||
'@types/canvas-confetti@1.9.0': {}
|
||||
|
||||
'@types/conventional-commits-parser@5.0.0':
|
||||
dependencies:
|
||||
'@types/node': 20.17.16
|
||||
@@ -5641,6 +5655,8 @@ snapshots:
|
||||
|
||||
caniuse-lite@1.0.30001679: {}
|
||||
|
||||
canvas-confetti@1.9.3: {}
|
||||
|
||||
ccount@2.0.1: {}
|
||||
|
||||
chalk@2.4.2:
|
||||
|
||||
Reference in New Issue
Block a user