From 7d1587696e5fe951ad9f4caae0d8b31244f18fc4 Mon Sep 17 00:00:00 2001 From: marcolivierbouch Date: Fri, 29 Nov 2024 08:45:54 -0500 Subject: [PATCH] feat: add everything you need section --- README.md | 22 ++-- .../configuration-api/app/api/domain/route.ts | 5 +- .../components/custom-domain-config.tsx | 6 +- websites/customdomainready/app/layout.tsx | 25 ++-- websites/customdomainready/app/page.tsx | 101 ++++++++++------ websites/customdomainready/app/providers.tsx | 8 +- .../customdomainready/components/Footer.tsx | 7 +- .../customdomainready/components/UserFlow.tsx | 6 +- .../components/dynamic-background.tsx | 108 +++++++++--------- .../components/features-grid.tsx | 55 +++++++++ .../components/key-benefits.tsx | 27 +++-- .../components/providers.tsx | 7 +- .../components/testimonials.tsx | 41 ++++--- .../components/ui/avatar.tsx | 76 ++++++------ websites/customdomainready/tailwind.config.js | 69 ++++++----- 15 files changed, 331 insertions(+), 232 deletions(-) create mode 100644 websites/customdomainready/components/features-grid.tsx diff --git a/README.md b/README.md index 0ca75e0..7204785 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -``` -$$$$$$\ $$\ $$$$$$$\ $$\ $$$$$$$\ $$\ -$$ __$$\ $$ | $$ __$$\ \__| $$ __$$\ $$ | -$$ / \__|$$\ $$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\$$$$\ $$ | $$ | $$$$$$\ $$$$$$\ $$$$$$\$$$$\ $$\ $$$$$$$\ $$ | $$ | $$$$$$\ $$$$$$\ $$$$$$$ |$$\ $$\ +``` +$$$$$$\ $$\ $$$$$$$\ $$\ $$$$$$$\ $$\ +$$ __$$\ $$ | $$ __$$\ \__| $$ __$$\ $$ | +$$ / \__|$$\ $$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\$$$$\ $$ | $$ | $$$$$$\ $$$$$$\ $$$$$$\$$$$\ $$\ $$$$$$$\ $$ | $$ | $$$$$$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$ | $$ | $$ |$$ _____|\_$$ _| $$ __$$\ $$ _$$ _$$\ $$ | $$ |$$ __$$\ \____$$\ $$ _$$ _$$\ $$ |$$ __$$\ $$$$$$$ |$$ __$$\ \____$$\ $$ __$$ |$$ | $$ | $$ | $$ | $$ |\$$$$$$\ $$ | $$ / $$ |$$ / $$ / $$ | $$ | $$ |$$ / $$ | $$$$$$$ |$$ / $$ / $$ |$$ |$$ | $$ | $$ __$$< $$$$$$$$ | $$$$$$$ |$$ / $$ |$$ | $$ | $$ | $$\ $$ | $$ | \____$$\ $$ |$$\ $$ | $$ |$$ | $$ | $$ | $$ | $$ |$$ | $$ |$$ __$$ |$$ | $$ | $$ |$$ |$$ | $$ | $$ | $$ |$$ ____|$$ __$$ |$$ | $$ |$$ | $$ | @@ -9,7 +9,7 @@ $$ | $$\ $$ | $$ | \____$$\ $$ |$$\ $$ | $$ |$$ | $$ | $$ | $$ | $$ | \______/ \______/ \_______/ \____/ \______/ \__| \__| \__| \_______/ \______/ \_______|\__| \__| \__|\__|\__| \__| \__| \__| \_______| \_______| \_______| \____$$ | $$\ $$ | \$$$$$$ | - \______/ + \______/ ``` # Custom Domain Ready @@ -24,15 +24,15 @@ For this tutorial you'll need a [Vercel](https://vercel.com/) account. 1. Create a new storage [Edge Config](https://vercel.com/docs/storage/edge-config). 2. Create a new vercel project and import configuration-api. -![image](https://github.com/user-attachments/assets/a32e8dcc-3f23-4890-b887-4a94d8bbbc93) + ![image](https://github.com/user-attachments/assets/a32e8dcc-3f23-4890-b887-4a94d8bbbc93) -4. Create a new project and import custom-domain-proxy. -![image](https://github.com/user-attachments/assets/f7d07dd7-009e-49a3-a3ec-5a6726e422ae) +3. Create a new project and import custom-domain-proxy. + ![image](https://github.com/user-attachments/assets/f7d07dd7-009e-49a3-a3ec-5a6726e422ae) -5. Connect the storage to the project custom-domain-proxy. -![image](https://github.com/user-attachments/assets/afd55de4-6e2e-412e-898f-a8c8ea05503f) +4. Connect the storage to the project custom-domain-proxy. + ![image](https://github.com/user-attachments/assets/afd55de4-6e2e-412e-898f-a8c8ea05503f) -7. Add the required env vars for the configuration-api +5. Add the required env vars for the configuration-api ```bash VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID= # You can find the edge config id when you click on the storage diff --git a/apps/configuration-api/app/api/domain/route.ts b/apps/configuration-api/app/api/domain/route.ts index 3b1260e..7ba5534 100644 --- a/apps/configuration-api/app/api/domain/route.ts +++ b/apps/configuration-api/app/api/domain/route.ts @@ -1,7 +1,4 @@ -import { - addDomainToVercel, - getDomains, -} from '@customdomainready/sdk'; +import { addDomainToVercel, getDomains } from '@customdomainready/sdk'; import { NextResponse } from 'next/server'; import * as z from 'zod'; diff --git a/apps/configuration-api/components/custom-domain-config.tsx b/apps/configuration-api/components/custom-domain-config.tsx index ff8e678..9ed3159 100644 --- a/apps/configuration-api/components/custom-domain-config.tsx +++ b/apps/configuration-api/components/custom-domain-config.tsx @@ -62,8 +62,8 @@ export default function CustomDomainConfig() { throw new Error('Failed to add domain'); } - const response = await domainResponse.json() - alert(JSON.stringify(response)) + const response = await domainResponse.json(); + alert(JSON.stringify(response)); } const aliasResponse = await fetch('/api/assign', { @@ -77,7 +77,7 @@ export default function CustomDomainConfig() { destination: newConfig.destinationPath, }), }); - + if (!aliasResponse.ok) { throw new Error('Failed to create alias'); } diff --git a/websites/customdomainready/app/layout.tsx b/websites/customdomainready/app/layout.tsx index 27ce5a3..78b160e 100644 --- a/websites/customdomainready/app/layout.tsx +++ b/websites/customdomainready/app/layout.tsx @@ -1,13 +1,15 @@ -import { Providers } from './providers' -import './globals.css' -import { Metadata } from 'next' +import { Providers } from './providers'; +import './globals.css'; +import { Metadata } from 'next'; export const metadata: Metadata = { title: 'Custom Domain Ready', - description: 'Ship custom domain support for your SaaS in less than a day for free', + description: + 'Ship custom domain support for your SaaS in less than a day for free', openGraph: { title: 'Custom Domain Ready', - description: 'Ship custom domain support for your SaaS in less than a day for free', + description: + 'Ship custom domain support for your SaaS in less than a day for free', url: 'https://customdomainready.com', siteName: 'Custom Domain Ready', //images: [ @@ -24,17 +26,22 @@ export const metadata: Metadata = { twitter: { card: 'summary_large_image', title: 'Custom Domain Ready', - description: 'Ship custom domain support for your SaaS in less than a day for free', + description: + 'Ship custom domain support for your SaaS in less than a day for free', //images: ['https://yourdomain.com/og-image.png'], }, -} +}; -export default function RootLayout({ children }: { children: React.ReactNode }) { +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { return ( {children} - ) + ); } diff --git a/websites/customdomainready/app/page.tsx b/websites/customdomainready/app/page.tsx index f76e894..d552e54 100644 --- a/websites/customdomainready/app/page.tsx +++ b/websites/customdomainready/app/page.tsx @@ -1,60 +1,81 @@ -'use client' +'use client'; -import { useState, useEffect } from 'react' -import { useTheme } from 'next-themes' -import { Github, Moon, Sun } from 'lucide-react' -import DynamicBackground from '@/components/dynamic-background' -import { Button } from '@/components/ui/button' -import { Footer } from '@/components/Footer' -import { UserFlow } from '@/components/UserFlow' -import { KeyBenefits } from '@/components/key-benefits' -import { Testimonials } from '@/components/testimonials' -import Link from 'next/link' +import { useState, useEffect } from 'react'; +import { useTheme } from 'next-themes'; +import { Github, Moon, Sun } from 'lucide-react'; +import DynamicBackground from '@/components/dynamic-background'; +import { Button } from '@/components/ui/button'; +import { Footer } from '@/components/Footer'; +import { UserFlow } from '@/components/UserFlow'; +import { KeyBenefits } from '@/components/key-benefits'; +import { Testimonials } from '@/components/testimonials'; +import Link from 'next/link'; +import FeaturesGrid from '@/components/features-grid'; export default function Home() { - const [mounted, setMounted] = useState(false) - const [scrolled, setScrolled] = useState(false) - const { theme, setTheme } = useTheme() + const [mounted, setMounted] = useState(false); + const [scrolled, setScrolled] = useState(false); + const { theme, setTheme } = useTheme(); useEffect(() => { - setMounted(true) + setMounted(true); const handleScroll = () => { - setScrolled(window.scrollY > 20) - } + setScrolled(window.scrollY > 20); + }; - window.addEventListener('scroll', handleScroll) - return () => window.removeEventListener('scroll', handleScroll) - }, []) + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll); + }, []); if (!mounted) { - return null + return null; } return (
-
+
-

Custom Domain Ready

+

+ Custom Domain Ready +

- +
- +

- Ship custom domain support
in less than a day + Ship custom domain support +
+ + in less than a day +

Totally free — Host your custom domain solution in your Vercel account

- - + +
- + + - +
- ) + ); } - diff --git a/websites/customdomainready/app/providers.tsx b/websites/customdomainready/app/providers.tsx index be4e037..a704551 100644 --- a/websites/customdomainready/app/providers.tsx +++ b/websites/customdomainready/app/providers.tsx @@ -1,9 +1,7 @@ +'use client'; -'use client' - -import { ThemeProvider } from 'next-themes' +import { ThemeProvider } from 'next-themes'; export function Providers({ children }: { children: React.ReactNode }) { - return {children} + return {children}; } - diff --git a/websites/customdomainready/components/Footer.tsx b/websites/customdomainready/components/Footer.tsx index d9a9a8d..86c7ef1 100644 --- a/websites/customdomainready/components/Footer.tsx +++ b/websites/customdomainready/components/Footer.tsx @@ -11,11 +11,7 @@ export function Footer() { © 2024 CustomDomainReady. All rights reserved.

-
{index < steps.length - 1 && ( - + )} ))} @@ -90,4 +93,3 @@ export function UserFlow() { ); } - diff --git a/websites/customdomainready/components/dynamic-background.tsx b/websites/customdomainready/components/dynamic-background.tsx index 61ebaa5..4936e20 100644 --- a/websites/customdomainready/components/dynamic-background.tsx +++ b/websites/customdomainready/components/dynamic-background.tsx @@ -1,88 +1,90 @@ -'use client' +'use client'; -import { useEffect, useRef } from 'react' -import { useTheme } from 'next-themes' +import { useEffect, useRef } from 'react'; +import { useTheme } from 'next-themes'; interface Particle { - x: number - y: number - dx: number - dy: number - size: number + x: number; + y: number; + dx: number; + dy: number; + size: number; } export default function DynamicBackground() { - const canvasRef = useRef(null) - const particles = useRef([]) - const { theme } = useTheme() + const canvasRef = useRef(null); + const particles = useRef([]); + const { theme } = useTheme(); useEffect(() => { - const canvas = canvasRef.current - if (!canvas) return + const canvas = canvasRef.current; + if (!canvas) return; - const ctx = canvas.getContext('2d') - if (!ctx) return + const ctx = canvas.getContext('2d'); + if (!ctx) return; const setCanvasSize = () => { - canvas.width = window.innerWidth - canvas.height = window.innerHeight - } + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + }; const initParticles = () => { - particles.current = [] - const numberOfParticles = Math.floor((canvas.width * canvas.height) / 50000) // Reduced particle density - + particles.current = []; + const numberOfParticles = Math.floor( + (canvas.width * canvas.height) / 50000, + ); // Reduced particle density + for (let i = 0; i < numberOfParticles; i++) { particles.current.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, dx: (Math.random() - 0.5) * 0.1, // Slower movement dy: (Math.random() - 0.5) * 0.1, // Slower movement - size: Math.random() * 2 + 1 - }) + size: Math.random() * 2 + 1, + }); } - } + }; const animate = () => { - if (!ctx || !canvas) return + if (!ctx || !canvas) return; - ctx.clearRect(0, 0, canvas.width, canvas.height) - - particles.current.forEach((particle) => { - particle.x += particle.dx - particle.y += particle.dy + ctx.clearRect(0, 0, canvas.width, canvas.height); - if (particle.x < 0) particle.x = canvas.width - if (particle.x > canvas.width) particle.x = 0 - if (particle.y < 0) particle.y = canvas.height - if (particle.y > canvas.height) particle.y = 0 + particles.current.forEach(particle => { + particle.x += particle.dx; + particle.y += particle.dy; - // Particle drawing - ctx.beginPath() - ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2) - ctx.fillStyle = theme === 'dark' ? 'rgba(255, 255, 255, 0.5)' : 'rgba(0, 0, 0, 0.5)' - ctx.fill() + if (particle.x < 0) particle.x = canvas.width; + if (particle.x > canvas.width) particle.x = 0; + if (particle.y < 0) particle.y = canvas.height; + if (particle.y > canvas.height) particle.y = 0; - }) + // Particle drawing + ctx.beginPath(); + ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2); + ctx.fillStyle = + theme === 'dark' ? 'rgba(255, 255, 255, 0.5)' : 'rgba(0, 0, 0, 0.5)'; + ctx.fill(); + }); - requestAnimationFrame(animate) - } + requestAnimationFrame(animate); + }; const handleResize = () => { - setCanvasSize() - initParticles() - } + setCanvasSize(); + initParticles(); + }; - setCanvasSize() - initParticles() - animate() + setCanvasSize(); + initParticles(); + animate(); - window.addEventListener('resize', handleResize) + window.addEventListener('resize', handleResize); return () => { - window.removeEventListener('resize', handleResize) - } - }, [theme]) + window.removeEventListener('resize', handleResize); + }; + }, [theme]); return (