├── .gitignore ├── README.md ├── components.json ├── components ├── Authors.tsx ├── BlogIndex.tsx ├── CloudFunctionsDemo.tsx ├── Download.tsx ├── DownloadButton.tsx ├── Footer.tsx ├── Intercom.tsx ├── IntroducingCelest.tsx ├── Logo.tsx ├── Pricing.tsx ├── WelcomeBanner.tsx ├── _app.tsx ├── _error.jsx ├── calendar.tsx ├── compliance.tsx ├── discord.tsx ├── icons.tsx ├── landing │ ├── Content.tsx │ ├── EmailForm.tsx │ ├── Feature.tsx │ ├── Hero.tsx │ ├── Newsletter.tsx │ └── YCLogo.tsx └── ui │ ├── accordion.tsx │ ├── button.tsx │ ├── card.tsx │ ├── carousel.tsx │ ├── chart.tsx │ ├── hover-card.tsx │ ├── table.tsx │ └── tooltip.tsx ├── next-env.d.ts ├── next-sitemap.config.js ├── next.config.mjs ├── package.json ├── pages ├── 404.mdx ├── _app.mdx ├── _error.mdx ├── _meta.json ├── api │ └── og.tsx ├── blog.mdx ├── blog │ ├── fluttering-in-the-sky.mdx │ ├── how-we-want-to-backend.mdx │ └── local-iterations-release.mdx ├── compliance.mdx ├── discord.mdx ├── docs │ ├── _meta.json │ ├── auth.mdx │ ├── auth │ │ ├── _meta.json │ │ ├── celest-auth.mdx │ │ ├── firebase-auth.mdx │ │ ├── supabase-auth.mdx │ │ └── using-the-auth-client.mdx │ ├── cli-commands-reference.mdx │ ├── data.mdx │ ├── download.mdx │ ├── folder-structure.mdx │ ├── functions.mdx │ ├── functions │ │ ├── _meta.json │ │ ├── authorizing-functions.mdx │ │ ├── creating-functions.mdx │ │ ├── customizing-serialization.mdx │ │ ├── data-types.mdx │ │ ├── env-variables.mdx │ │ ├── exceptions.mdx │ │ ├── http.mdx │ │ ├── http │ │ │ ├── _meta.json │ │ │ ├── conventions.mdx │ │ │ └── customization.mdx │ │ ├── img │ │ │ ├── file-middleware.png │ │ │ ├── function.png │ │ │ └── individual-middleware.png │ │ ├── logging.mdx │ │ ├── packages.mdx │ │ └── testing.mdx │ ├── get-started.mdx │ ├── index.mdx │ └── self-hosting.mdx └── index.mdx ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── fonts │ ├── BerkeleyMono-Regular.ttf │ ├── BerkeleyMono-Regular.woff2 │ ├── Poppins.woff2 │ └── Poppins │ │ ├── OFL.txt │ │ ├── Poppins-Black.ttf │ │ ├── Poppins-BlackItalic.ttf │ │ ├── Poppins-Bold.ttf │ │ ├── Poppins-BoldItalic.ttf │ │ ├── Poppins-ExtraBold.ttf │ │ ├── Poppins-ExtraBoldItalic.ttf │ │ ├── Poppins-ExtraLight.ttf │ │ ├── Poppins-ExtraLightItalic.ttf │ │ ├── Poppins-Italic.ttf │ │ ├── Poppins-Light.ttf │ │ ├── Poppins-LightItalic.ttf │ │ ├── Poppins-Medium.ttf │ │ ├── Poppins-MediumItalic.ttf │ │ ├── Poppins-Regular.ttf │ │ ├── Poppins-SemiBold.ttf │ │ ├── Poppins-SemiBoldItalic.ttf │ │ ├── Poppins-Thin.ttf │ │ └── Poppins-ThinItalic.ttf ├── img │ ├── annotate-all-the-things.jpeg │ ├── celest-deploy.png │ ├── celest-start-ts.png │ ├── celest-start.png │ ├── cloud-functions-demo-avc1.mp4 │ ├── cloud-functions-demo-hevc.mp4 │ ├── cloud-functions-demo.jpg │ ├── cloud-functions-demo.vtt │ ├── cloud-functions-demo.webm │ ├── coming-soon.svg │ ├── deploy.gif │ ├── dillon.png │ ├── dillon.webp │ ├── discord.png │ ├── fluttering-in-the-sky.webp │ ├── introducing-celest.jpg │ ├── introducing-celest.mp4 │ ├── introducing-celest.vtt │ ├── introducing-celest.webm │ ├── logo-full.png │ ├── logo-small.png │ ├── logo-small.webp │ ├── logo-white.png │ ├── logo-xsmall.png │ ├── logo-xsmall.webp │ ├── logo.png │ ├── logo.webp │ ├── open-graph.png │ ├── pricing.png │ ├── pricing.webp │ ├── x.png │ ├── x.webp │ └── youtube.svg ├── robots.txt ├── sitemap-0.xml └── sitemap.xml ├── sentry.client.config.ts ├── src ├── analytics.ts ├── instrumentation.ts ├── navigator.d.ts └── utils.ts ├── styles.css ├── styles └── global.css ├── tailwind.config.js ├── theme.config.tsx └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | .next 2 | node_modules 3 | .DS_Store 4 | 5 | # Sentry Config File 6 | .env.sentry-build-plugin 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | The code for [celest.dev](https://www.celest.dev), home of Celest, the Flutter cloud platform. 4 | 5 | ## Development 6 | 7 | This website is built using [Nextra](https://nextra.site/) and deployed to Vercel. To contribute, you will need to install [pnpm](https://pnpm.io/). 8 | 9 | ### Setup 10 | 11 | Start by cloning the repository and installing its dependencies. 12 | 13 | ```console 14 | $ git clone https://github.com/celest-dev/website 15 | $ cd website 16 | $ pnpm install 17 | ``` 18 | 19 | ### Local Development 20 | 21 | To start a local development server, run `pnpm dev`. Most changes will be reflected live without having to restart the server. 22 | 23 | ### Build 24 | 25 | To build the website for production, run `pnpm build`. This command generates static content into the `build` directory. 26 | 27 | To view the production build locally, run `pnpm start`. 28 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "styles.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components/", 15 | "utils": "@/src/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /components/Authors.tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from "next/router"; 2 | import { MdxFile } from "nextra"; 3 | import { getPagesUnderRoute } from "nextra/context"; 4 | 5 | export default function Authors({ children, by = "by" }) { 6 | const currentRoute = useRouter().route; 7 | const page = getPagesUnderRoute("/blog").find( 8 | (page) => page.route === currentRoute 9 | ) as MdxFile; 10 | const { frontMatter } = page; 11 | return ( 12 |
13 | {frontMatter.date} {"|"} 14 | {children && ( 15 | <> 16 | {by} {children} 17 | 18 | )} 19 |
20 | ); 21 | } 22 | 23 | export function Author({ name, link }) { 24 | return ( 25 | 26 | 32 | {name} 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /components/BlogIndex.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import { MdxFile, Page } from "nextra"; 3 | import { getPagesUnderRoute } from "nextra/context"; 4 | 5 | const pageIsMdx = (page: Page): page is MdxFile => page.kind === "MdxPage"; 6 | 7 | export default function BlogIndex() { 8 | const blogs = getPagesUnderRoute("/blog") 9 | .filter(pageIsMdx) 10 | .sort((a, b) => { 11 | const { 12 | frontMatter: { date: aDateStr, order: aOrder = 0 }, 13 | } = a; 14 | const { 15 | frontMatter: { date: bDateStr, order: bOrder = 0 }, 16 | } = b; 17 | if (aDateStr === bDateStr) return bOrder - aOrder; 18 | const aDate = new Date(aDateStr); 19 | const bDate = new Date(bDateStr); 20 | return bDate.getDate() - aDate.getDate(); 21 | }); 22 | return blogs.map((page) => { 23 | const { frontMatter, route, name } = page; 24 | return ( 25 |
26 |

27 | 32 | {frontMatter?.title || name} 33 | 34 |

35 |

36 | {frontMatter?.description}{" "} 37 | 38 | 42 | Read more → 43 | 44 | 45 |

46 | {frontMatter?.date ? ( 47 |

48 | {frontMatter.date} 49 |

50 | ) : null} 51 |
52 | ); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /components/CloudFunctionsDemo.tsx: -------------------------------------------------------------------------------- 1 | import { usePostHog } from "posthog-js/react"; 2 | import { onVideoPlay, onVideoError } from "../src/analytics"; 3 | import React from "react"; 4 | 5 | export function CloudFunctionsDemo(props?: React.ComponentProps<"div">) { 6 | const posthog = usePostHog(); 7 | return ( 8 |
9 | 51 |
52 | ); 53 | } 54 | 55 | function CloudFunctionsDemoYouTube() { 56 | return ( 57 | 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /components/Download.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { FaLinux, FaWindows, FaApple } from "react-icons/fa"; 3 | import { IconBaseProps, IconType } from "react-icons"; 4 | import { usePostHog } from "posthog-js/react"; 5 | import { recordEvent } from "../src/analytics"; 6 | import { Card, Link } from "nextra-theme-docs"; 7 | import type { PostHog } from "posthog-js"; 8 | import clsx from "clsx"; 9 | 10 | type DownloadState = { 11 | os: OperatingSystem; 12 | architecture: Architecture; 13 | downloadLink?: string; 14 | }; 15 | 16 | type OperatingSystem = "Windows" | "Apple" | "Linux" | "Unknown"; 17 | type Architecture = "Intel" | "ARM" | "Unknown"; 18 | 19 | const osDisplay = (os: OperatingSystem, architecture: Architecture) => { 20 | switch (os) { 21 | case "Windows": 22 | return architecture === "Intel" ? "Windows (x64)" : "Windows (ARM)"; 23 | case "Apple": 24 | return architecture === "Intel" ? "macOS (Intel)" : "macOS (Silicon)"; 25 | case "Linux": 26 | return architecture === "Intel" ? "Linux (x64)" : "Linux (ARM)"; 27 | } 28 | }; 29 | 30 | export function useDetectSystem() { 31 | const [detectedSystem, setDetectedSystem] = useState({ 32 | os: "Unknown", 33 | architecture: "Unknown", 34 | }); 35 | 36 | useEffect(() => { 37 | // Detect operating system 38 | let os: OperatingSystem = "Unknown"; 39 | const userAgent = ( 40 | navigator.userAgentData?.platform ?? navigator.platform 41 | ).toLowerCase(); 42 | if (userAgent.includes("win")) { 43 | os = "Windows"; 44 | } else if (userAgent.includes("mac")) { 45 | os = "Apple"; 46 | } else if (userAgent.includes("linux") && !userAgent.includes("android")) { 47 | os = "Linux"; 48 | } 49 | 50 | // Detect architecture 51 | let architecture: Architecture = "Unknown"; 52 | if (!navigator.userAgentData) { 53 | setDetectedSystem({ 54 | os, 55 | architecture, 56 | downloadLink: getDownloadLink(os, architecture), 57 | }); 58 | return; 59 | } 60 | navigator.userAgentData 61 | .getHighEntropyValues(["architecture"]) 62 | .then((result) => { 63 | switch (result.architecture) { 64 | case "x86": 65 | case "x86_64": 66 | architecture = "Intel"; 67 | break; 68 | case "arm": 69 | case "arm64": 70 | architecture = "ARM"; 71 | break; 72 | } 73 | }) 74 | .catch(() => {}) 75 | .finally(() => { 76 | setDetectedSystem({ 77 | os, 78 | architecture, 79 | downloadLink: getDownloadLink(os, architecture), 80 | }); 81 | }); 82 | }, []); 83 | 84 | return detectedSystem; 85 | } 86 | 87 | export function DownloadButton() { 88 | const system = useDetectSystem(); 89 | return ; 90 | } 91 | 92 | function renderIcon(os: OperatingSystem) { 93 | let Icon: IconType; 94 | switch (os) { 95 | case "Windows": 96 | Icon = FaWindows; 97 | break; 98 | case "Apple": 99 | Icon = FaApple; 100 | break; 101 | case "Linux": 102 | Icon = FaLinux; 103 | break; 104 | default: 105 | return; 106 | } 107 | const IconElement = (props: IconBaseProps) => { 108 | const icon = Icon(props); 109 | return <>{icon}; 110 | }; 111 | return IconElement; 112 | } 113 | 114 | // Component for detected OS Card 115 | function OSCard(props: DownloadState) { 116 | const { os, architecture, downloadLink } = props; 117 | let Icon = renderIcon(os); 118 | 119 | const posthog = usePostHog(); 120 | recordEvent(posthog, "detected_operating_system", { 121 | downloadCLIAutoDetectOperatingSystem: true, 122 | downloadCLIOperatingSystemArchitecture: architecture, 123 | downloadCLIOperatingSystemName: os, 124 | }); 125 | return ( 126 |
127 | 137 | 138 |
139 |

Download for

140 |

141 | {getDisplayString(os, architecture)} 142 |

143 |
144 |
145 |
146 | ); 147 | } 148 | 149 | function DownloadCard( 150 | props: { 151 | os: OperatingSystem; 152 | architectures: Architecture[]; 153 | detected: DownloadState; 154 | } & React.ComponentProps<"div"> 155 | ) { 156 | const { os, architectures, detected } = props; 157 | 158 | let Icon = renderIcon(os); 159 | 160 | const posthog = usePostHog(); 161 | const isDetected = (architecture: Architecture) => 162 | os === detected.os && architecture === detected.architecture; 163 | const title = (architecture: Architecture) => { 164 | let title = getDisplayString(os, architecture); 165 | if (isDetected(architecture)) { 166 | title += " ⭐️"; 167 | } 168 | return title; 169 | }; 170 | 171 | return ( 172 |
173 | 174 |

{os}

175 |
176 | {architectures.map((architecture) => ( 177 |
194 | } 197 | href={getDownloadLink(os, architecture)} 198 | > 199 | {title(architecture)} 200 | 201 |
202 | ))} 203 |
204 | ); 205 | } 206 | 207 | export function Download(props?: React.ComponentProps<"section">) { 208 | const detected = useDetectSystem(); 209 | return ( 210 |
211 |
212 | 218 | 224 | 230 |
231 | {detected.os !== "Unknown" && detected.architecture !== "Unknown" && ( 232 |

⭐️ Recommended for you

233 | )} 234 |
235 | ); 236 | } 237 | 238 | function getDownloadLink( 239 | os: OperatingSystem, 240 | architecture: Architecture 241 | ): string { 242 | if (os === "Apple" && architecture === "Intel") { 243 | return "https://releases.celest.dev/macos_x64/latest/celest-latest-macos_x64.pkg"; 244 | } else if (os === "Apple" && architecture === "ARM") { 245 | return "https://releases.celest.dev/macos_arm64/latest/celest-latest-macos_arm64.pkg"; 246 | } else if (os === "Linux") { 247 | switch (architecture) { 248 | case "Intel": 249 | return "https://releases.celest.dev/linux_x64/latest/celest-latest-linux_x64.deb"; 250 | case "ARM": 251 | return "https://releases.celest.dev/linux_arm64/latest/celest-latest-linux_arm64.deb"; 252 | } 253 | } else if (os === "Windows" && architecture === "Intel") { 254 | return "https://releases.celest.dev/windows_x64/latest/celest-latest-windows_x64.appx"; 255 | } 256 | } 257 | 258 | function getDisplayString( 259 | os: OperatingSystem, 260 | architecture: Architecture 261 | ): string { 262 | switch (os) { 263 | case "Windows": 264 | return architecture === "Intel" ? "Windows x64" : "Windows ARM"; 265 | case "Apple": 266 | return architecture === "Intel" ? "Apple Intel" : "Apple Silicon"; 267 | case "Linux": 268 | return architecture === "Intel" ? "Linux x64" : "Linux ARM"; 269 | } 270 | } 271 | 272 | // Event handler for download link click used for recording analytics 273 | function handleDownloadLinkEventTrigger( 274 | posthog: PostHog, 275 | autoDetectOperatingSystemValue: boolean, 276 | architecture: Architecture, 277 | operatingSystem: OperatingSystem 278 | ) { 279 | return function (_: React.MouseEvent) { 280 | recordEvent(posthog, "click_download_cli", { 281 | downloadCLIAutoDetectOperatingSystem: autoDetectOperatingSystemValue, 282 | downloadCLIOperatingSystemArchitecture: architecture, 283 | downloadCLIOperatingSystemName: operatingSystem, 284 | }); 285 | }; 286 | } 287 | -------------------------------------------------------------------------------- /components/DownloadButton.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { Button } from "./ui/button"; 3 | import { Check, Copy } from "lucide-react"; 4 | import { clsx } from "clsx"; 5 | 6 | export default function DownloadButton(props: { className?: string }) { 7 | const [copied, setCopied] = useState(false); 8 | 9 | const copyToClipboard = () => { 10 | navigator.clipboard.writeText("dart pub global activate celest_cli"); 11 | setCopied(true); 12 | setTimeout(() => setCopied(false), 2000); 13 | }; 14 | 15 | 16 | return ( 17 |
18 | $ dart pub global activate celest_cli 19 | 31 |
32 | ); 33 | } -------------------------------------------------------------------------------- /components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | export default function Footer() { 4 | // return ( 5 | // <> 6 | //
© {new Date().getFullYear()} Teo, Inc. (Celest)
7 | //
8 | // Privacy Policy 9 | // 10 | // Terms of Service 11 | // 12 | // Compliance 13 | // 14 | // ); 15 | return <>; 16 | } 17 | -------------------------------------------------------------------------------- /components/Intercom.tsx: -------------------------------------------------------------------------------- 1 | export function loadIntercom() { 2 | const sdk = import("@intercom/messenger-js-sdk"); 3 | const loader = () => sdk.then(Intercom => Intercom.default({ 4 | app_id: "gxzf8bwj", 5 | })); 6 | if (window && window.requestIdleCallback) { 7 | requestIdleCallback(loader); 8 | } else { 9 | setTimeout(loader, 2000); 10 | } 11 | } -------------------------------------------------------------------------------- /components/IntroducingCelest.tsx: -------------------------------------------------------------------------------- 1 | import { usePostHog } from "posthog-js/react"; 2 | import { onVideoPlay, onVideoError } from "../src/analytics"; 3 | 4 | export function IntroducingCelest() { 5 | const posthog = usePostHog(); 6 | return ( 7 |
8 | 42 |
43 | ); 44 | } 45 | 46 | function IntroducingCelestYouTube() { 47 | return ( 48 | 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /components/Logo.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Logo() { 4 | return ( 5 |
6 | Celest Logo 7 |

Celest

8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /components/Pricing.tsx: -------------------------------------------------------------------------------- 1 | import { FaBuilding, FaRocket, FaUserAstronaut } from "react-icons/fa"; 2 | import { 3 | Card, 4 | CardContent, 5 | CardDescription, 6 | CardFooter, 7 | CardHeader, 8 | CardTitle, 9 | } from "./ui/card"; 10 | 11 | import { IconType } from "react-icons"; 12 | import { Button } from "./ui/button"; 13 | import { Check, XIcon } from "lucide-react"; 14 | import Link from "next/link"; 15 | import { PostHog, usePostHog } from "posthog-js/react"; 16 | import clsx from "clsx"; 17 | import { 18 | Accordion, 19 | AccordionContent, 20 | AccordionItem, 21 | AccordionTrigger, 22 | } from "./ui/accordion"; 23 | import { 24 | Table, 25 | TableBody, 26 | TableCaption, 27 | TableCell, 28 | TableHead, 29 | TableHeader, 30 | TableRow, 31 | } from "./ui/table"; 32 | 33 | type PricingFeature = { 34 | type: "pro" | "con"; 35 | description: string; 36 | pupm?: boolean; 37 | }; 38 | 39 | interface PricingTier extends React.ComponentProps { 40 | name: string; 41 | description: string; 42 | Icon: IconType; 43 | features: PricingFeature[]; 44 | price?: number | string; 45 | Action: React.FC<{ posthog: PostHog }>; 46 | } 47 | 48 | export function PricingTier({ 49 | name, 50 | description, 51 | Icon, 52 | features, 53 | price, 54 | Action, 55 | ...props 56 | }: PricingTier) { 57 | const posthog = usePostHog(); 58 | return ( 59 | 60 | 61 | 62 | <>{Icon({ className: "my-4" })} 63 | {name} 64 | 65 |
69 | {typeof price === "number" ? `$${price} / month` : price} 70 |
71 | {description} 72 |
73 | 74 |
    75 | {features.map((feature) => ( 76 |
  • 77 | {feature.type === "pro" && ( 78 | 79 | )} 80 | {feature.type === "con" && ( 81 | 82 | )} 83 | {feature.description} 84 | {feature.pupm && ( 85 |
    91 | per project per month 92 |
    93 | )} 94 |
  • 95 | ))} 96 |
97 |
98 | 99 |
100 | 101 |
102 |
103 |
104 | ); 105 | } 106 | 107 | PricingTier.Community = () => ( 108 | ( 124 | 125 | 136 | 137 | )} 138 | /> 139 | ); 140 | 141 | PricingTier.Pro = () => ( 142 | ( 158 | 159 | 170 | 171 | )} 172 | /> 173 | ); 174 | 175 | PricingTier.Teams = () => ( 176 | ( 189 | 190 | 202 | 203 | )} 204 | /> 205 | ); 206 | 207 | export function PricingFaq() { 208 | const posthog = usePostHog(); 209 | return ( 210 | { 214 | posthog.capture("faq_expand", { value: value }); 215 | }} 216 | > 217 | 218 | Free vs. Premium projects 219 | 220 |

221 | The Pro tier includes 3 premium projects and unlimited free 222 | projects. Free projects have limited resources and cold starts, but 223 | cost you nothing to run. 224 |

225 |
226 |

227 | Every premium project comes with an included amount of usage. If 228 | your project scales beyond these limits, you pay for any additional 229 | resources as you go. 230 |

231 |
232 |
233 | 234 | Free Usage 235 | 236 | 237 | Usage Limits (per free project) 238 | 239 | 240 | 241 | Functions 242 | Auth 243 | 244 | 245 | 246 | 247 | Included 248 | 50,000 invocations 249 | 1,000 monthly active users (MAUs) 250 | 251 | 252 | Additional 253 | $1 / 10,000 invocations 254 | $0.01 / MAU 255 | 256 | 257 |
258 |
259 |
260 | 261 | Premium Usage 262 | 263 | 264 | Usage Limits (per premium project) 265 | 266 | 267 | 268 | Projects 269 | Functions 270 | Auth 271 | 272 | 273 | 274 | 275 | Included 276 | 277 | 3 premium 278 |
279 | ∞ free 280 |
281 | 500,000 invocations 282 | 10,000 monthly active users (MAUs) 283 |
284 | 285 | Additional 286 | 287 | $10 / premium 288 |
289 | $0 / free 290 |
291 | $1 / 10,000 invocations 292 | $0.01 / MAU 293 |
294 |
295 |
296 |
297 |
298 |
299 | ); 300 | } 301 | 302 | export default function PricingTable() { 303 | return ( 304 |
305 | 306 | 307 | 308 |
309 | ); 310 | } 311 | -------------------------------------------------------------------------------- /components/WelcomeBanner.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import { useSearchParams } from "next/navigation"; 3 | import { Callout } from "nextra-theme-docs"; 4 | import { usePostHog } from "posthog-js/react"; 5 | 6 | export default function WelcomeBanner() { 7 | const searchParams = useSearchParams(); 8 | if (searchParams.has("subscribed")) { 9 | return ( 10 |
11 | 12 | Welcome to Celest Cloud! 🎉 13 |
14 | Your subscription is now active and you're ready to deploy your first project! 🚀 15 |
16 |
17 | ); 18 | } else if (searchParams.has("error")) { 19 | const error = searchParams.get("error"); 20 | const postHog = usePostHog(); 21 | postHog.captureException(new Error(error)); 22 | 23 | return ( 24 |
25 | 26 | We encountered an error with your subscription to Celest Cloud. 27 |
28 | Please contact{" "} 29 | 30 | support@celest.dev 31 | {" "} 32 | or visit us on{" "} 33 | 34 | Discord 35 | {" "} 36 | so we can resolve this issue. 37 |
38 |
39 | ); 40 | } 41 | 42 | return null; 43 | } 44 | -------------------------------------------------------------------------------- /components/_app.tsx: -------------------------------------------------------------------------------- 1 | import { PostHogProvider } from "posthog-js/react"; 2 | import { SpeedInsights } from "@vercel/speed-insights/next"; 3 | import { useEffect } from "react"; 4 | import localFont from "next/font/local"; 5 | import { loadIntercom } from "./Intercom"; 6 | import { useRouter } from "next/router"; 7 | 8 | const poppins = localFont({ 9 | preload: true, 10 | src: "../public/fonts/Poppins.woff2", 11 | display: "swap", 12 | variable: "--font-poppins", 13 | }); 14 | 15 | const berkeleyMono = localFont({ 16 | preload: true, 17 | src: "../public/fonts/BerkeleyMono-Regular.woff2", 18 | display: "swap", 19 | variable: "--font-berkeley-mono", 20 | weight: "400", 21 | fallback: ["monospace"], 22 | }); 23 | 24 | // FA 25 | import { config } from '@fortawesome/fontawesome-svg-core' 26 | import '@fortawesome/fontawesome-svg-core/styles.css' 27 | config.autoAddCss = false 28 | 29 | export default function App({ Component, pageProps }) { 30 | return ( 31 | 37 |
38 | 39 | 40 |
41 |
42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /components/_error.jsx: -------------------------------------------------------------------------------- 1 | import * as Sentry from "@sentry/nextjs"; 2 | import Error from "next/error"; 3 | 4 | const CustomErrorComponent = (props) => { 5 | return ; 6 | }; 7 | 8 | CustomErrorComponent.getInitialProps = async (contextData) => { 9 | // In case this is running in a serverless function, await this in order to give Sentry 10 | // time to send the error before the lambda exits 11 | await Sentry.captureUnderscoreErrorException(contextData); 12 | 13 | // This will contain the status code of the response 14 | return Error.getInitialProps(contextData); 15 | }; 16 | 17 | export default CustomErrorComponent; 18 | -------------------------------------------------------------------------------- /components/calendar.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import Cal, { getCalApi } from "@calcom/embed-react"; 3 | 4 | export function useFloatingCalendar() { 5 | useEffect(() => { 6 | (async function () { 7 | const cal = await getCalApi(); 8 | cal("floatingButton", { 9 | calLink: "celest-dev/meet-website", 10 | buttonText: "Book a demo", 11 | config: { 12 | layout: "month_view", 13 | }, 14 | }); 15 | cal("ui", { 16 | theme: "dark", 17 | layout: "month_view", 18 | }); 19 | })(); 20 | }, []); 21 | } 22 | 23 | export default function Calendar() { 24 | useEffect(() => { 25 | (async function () { 26 | const cal = await getCalApi({}); 27 | cal("ui", { 28 | styles: { branding: { brandColor: "#000000" } }, 29 | hideEventTypeDetails: false, 30 | layout: "month_view", 31 | }); 32 | })(); 33 | }, []); 34 | return ( 35 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /components/compliance.tsx: -------------------------------------------------------------------------------- 1 | /// Redirect to https://app.getdelve.com/celest 2 | export default function Compliance() { 3 | return ( 4 | <> 5 |