diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 152259f0..386a0ac4 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -13,7 +13,7 @@ jobs: - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: - node-version: 18.18.0 + node-version: 24.4.0 cache: "pnpm" - run: pnpm install --frozen-lockfile - run: pnpm biome ci diff --git a/apps/docs/app/docs/[[...slug]]/page.tsx b/apps/docs/app/docs/[[...slug]]/page.tsx index 8df18d5c..3e5a1dd7 100644 --- a/apps/docs/app/docs/[[...slug]]/page.tsx +++ b/apps/docs/app/docs/[[...slug]]/page.tsx @@ -1,5 +1,5 @@ import { CopyMarkdownButton } from "@/components/copy-markdown-button"; -import { getPageImage, getLLMText, source } from "@/lib/source"; +import { getLLMText, getPageImage, source } from "@/lib/source"; import { getMDXComponents } from "@/mdx-components"; import { DocsBody, diff --git a/apps/docs/app/llms.txt/route.ts b/apps/docs/app/llms.txt/route.ts index 2d649904..c47825ea 100644 --- a/apps/docs/app/llms.txt/route.ts +++ b/apps/docs/app/llms.txt/route.ts @@ -6,9 +6,7 @@ const baseUrl = "https://docs.dokploy.com"; export function GET() { const pages = source.getPages(); - const docsPages = pages.filter( - (page) => !page.url.startsWith("/docs/api/"), - ); + const docsPages = pages.filter((page) => !page.url.startsWith("/docs/api/")); const lines = [ "# Dokploy Documentation", diff --git a/apps/docs/content/docs/core/dns-providers/meta.json b/apps/docs/content/docs/core/dns-providers/meta.json index b7d79c59..6518e581 100644 --- a/apps/docs/content/docs/core/dns-providers/meta.json +++ b/apps/docs/content/docs/core/dns-providers/meta.json @@ -1,7 +1,4 @@ { "title": "DNS Providers", - "pages": [ - "cloudflare", - "route53" - ] + "pages": ["cloudflare", "route53"] } diff --git a/apps/docs/content/docs/core/secrets-providers/meta.json b/apps/docs/content/docs/core/secrets-providers/meta.json index 47eb50d0..543e0904 100644 --- a/apps/docs/content/docs/core/secrets-providers/meta.json +++ b/apps/docs/content/docs/core/secrets-providers/meta.json @@ -1,11 +1,4 @@ { "title": "Secrets Providers", - "pages": [ - "hashicorp", - "infisical", - "aws", - "doppler", - "azure", - "scaleway" - ] + "pages": ["hashicorp", "infisical", "aws", "doppler", "azure", "scaleway"] } diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs index 0fc90ee9..b8638fac 100644 --- a/apps/docs/next.config.mjs +++ b/apps/docs/next.config.mjs @@ -7,7 +7,9 @@ const config = { reactStrictMode: true, output: "standalone", outputFileTracingIncludes: { - "/**": ["../../node_modules/.pnpm/@swc+helpers@*/node_modules/@swc/helpers/**"], + "/**": [ + "../../node_modules/.pnpm/@swc+helpers@*/node_modules/@swc/helpers/**", + ], }, images: { remotePatterns: [ diff --git a/apps/docs/scripts/fix-api-paths.mjs b/apps/docs/scripts/fix-api-paths.mjs index 06819028..aa928e56 100644 --- a/apps/docs/scripts/fix-api-paths.mjs +++ b/apps/docs/scripts/fix-api-paths.mjs @@ -3,7 +3,7 @@ * Converts slash notation (/tag/operation) to dot notation (/tag.operation) * so they match our OpenAPI schema paths and display the real API path. */ -import { readdirSync, readFileSync, writeFileSync } from "node:fs"; +import { readFileSync, readdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; const API_DOCS_DIR = join(process.cwd(), "content", "docs", "api"); @@ -17,7 +17,7 @@ for (const name of readdirSync(API_DOCS_DIR)) { const newContent = content.replace(/"path":"(\/[^"]+)"/g, (_, path) => { // Convert /tag/operation or /tag/op/subop to /tag.operation or /tag.op.subop to match schema if (path.includes("/") && !path.includes(".")) { - const dotPath = "/" + path.slice(1).replace(/\//g, "."); + const dotPath = `/${path.slice(1).replace(/\//g, ".")}`; totalFixed++; return `"path":"${dotPath}"`; } diff --git a/apps/docs/scripts/fix-openapi.mjs b/apps/docs/scripts/fix-openapi.mjs index a1ba17ca..b23a93fe 100644 --- a/apps/docs/scripts/fix-openapi.mjs +++ b/apps/docs/scripts/fix-openapi.mjs @@ -1,5 +1,5 @@ -import { readFileSync, writeFileSync } from "fs"; -import { join } from "path"; +import { readFileSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; const openapiPath = join(process.cwd(), "public", "openapi.json"); @@ -10,7 +10,10 @@ try { let unwrapped = false; // If the spec is nested (e.g. result.data.json from a migrated/source API), use the inner spec - if (openapi.result?.data?.json && typeof openapi.result.data.json === "object") { + if ( + openapi.result?.data?.json && + typeof openapi.result.data.json === "object" + ) { openapi = openapi.result.data.json; unwrapped = true; console.log("✓ Unwrapped nested OpenAPI spec (result.data.json)"); @@ -28,8 +31,8 @@ try { } // Remove old Authorization scheme - if (openapi.components.securitySchemes["Authorization"]) { - delete openapi.components.securitySchemes["Authorization"]; + if (openapi.components.securitySchemes.Authorization) { + openapi.components.securitySchemes.Authorization = undefined; securityFixed = true; } @@ -45,7 +48,7 @@ try { // Replace global security from Authorization to x-api-key if (openapi.security) { - openapi.security = openapi.security.filter((sec) => !sec["Authorization"]); + openapi.security = openapi.security.filter((sec) => !sec.Authorization); } else { openapi.security = []; } @@ -59,10 +62,10 @@ try { // Replace Authorization with x-api-key in all operation security for (const [path, pathItem] of Object.entries(openapi.paths || {})) { for (const [method, operation] of Object.entries(pathItem)) { - if (operation && operation.security) { + if (operation?.security) { // Replace Authorization with x-api-key operation.security = operation.security.map((sec) => { - if (sec["Authorization"] !== undefined) { + if (sec.Authorization !== undefined) { securityFixed = true; return { "x-api-key": [] }; } @@ -77,7 +80,7 @@ try { for (const [method, operation] of Object.entries(pathItem)) { if (operation.responses) { for (const [status, response] of Object.entries(operation.responses)) { - if (response.content && response.content["application/json"]) { + if (response.content?.["application/json"]) { const content = response.content["application/json"]; // Check if schema is completely empty or missing if (Object.keys(content).length === 0 || !content.schema) { @@ -105,7 +108,7 @@ try { let removed = 0; for (const pathKey of Object.keys(openapi.paths || {})) { if (pathKey.includes("/") && !pathKey.includes(".")) { - const dotKey = "/" + pathKey.slice(1).replace(/\//g, "."); + const dotKey = `/${pathKey.slice(1).replace(/\//g, ".")}`; if (openapi.paths[dotKey]) { delete openapi.paths[pathKey]; removed++; @@ -114,7 +117,9 @@ try { } if (removed > 0) { writeFileSync(openapiPath, JSON.stringify(openapi, null, 2)); - console.log(`✓ Removed ${removed} slash path alias(es), keeping dot paths only`); + console.log( + `✓ Removed ${removed} slash path alias(es), keeping dot paths only`, + ); } if (!(unwrapped || fixed > 0 || securityFixed) && removed === 0) { diff --git a/apps/website/app/api/docker-stats/route.ts b/apps/website/app/api/docker-stats/route.ts index 84efd9ec..11b60ee5 100644 --- a/apps/website/app/api/docker-stats/route.ts +++ b/apps/website/app/api/docker-stats/route.ts @@ -9,8 +9,7 @@ export async function GET() { { pull_count: cachedPulls.count }, { headers: { - "Cache-Control": - "public, s-maxage=1800, stale-while-revalidate=3600", + "Cache-Control": "public, s-maxage=1800, stale-while-revalidate=3600", }, }, ); @@ -45,8 +44,7 @@ export async function GET() { { pull_count: pullCount }, { headers: { - "Cache-Control": - "public, s-maxage=1800, stale-while-revalidate=3600", + "Cache-Control": "public, s-maxage=1800, stale-while-revalidate=3600", }, }, ); diff --git a/apps/website/app/api/github-contributors/route.ts b/apps/website/app/api/github-contributors/route.ts index c515ef06..e57c3c1e 100644 --- a/apps/website/app/api/github-contributors/route.ts +++ b/apps/website/app/api/github-contributors/route.ts @@ -12,8 +12,7 @@ export async function GET() { { contributors_count: cachedContributors.count }, { headers: { - "Cache-Control": - "public, s-maxage=1800, stale-while-revalidate=3600", + "Cache-Control": "public, s-maxage=1800, stale-while-revalidate=3600", }, }, ); @@ -43,9 +42,7 @@ export async function GET() { if (linkHeader) { // Parse last page number from Link header: <...?page=N>; rel="last" - const lastMatch = linkHeader.match( - /[&?]page=(\d+)[^>]*>;\s*rel="last"/, - ); + const lastMatch = linkHeader.match(/[&?]page=(\d+)[^>]*>;\s*rel="last"/); if (lastMatch) { count = Number.parseInt(lastMatch[1], 10); } @@ -60,8 +57,7 @@ export async function GET() { { contributors_count: count }, { headers: { - "Cache-Control": - "public, s-maxage=1800, stale-while-revalidate=3600", + "Cache-Control": "public, s-maxage=1800, stale-while-revalidate=3600", }, }, ); diff --git a/apps/website/app/api/og/route.ts b/apps/website/app/api/og/route.ts index bcf44d0a..2dde104c 100644 --- a/apps/website/app/api/og/route.ts +++ b/apps/website/app/api/og/route.ts @@ -22,7 +22,7 @@ export async function GET(request: NextRequest) { label: "Dokploy - Open Source Templates", }); - return new Response(ogImage, { + return new Response(new Uint8Array(ogImage), { headers: { "Content-Type": "image/png", "Cache-Control": "public, max-age=86400, stale-while-revalidate", @@ -65,7 +65,7 @@ export async function GET(request: NextRequest) { readingTime: post.reading_time, }); - return new Response(ogImage, { + return new Response(new Uint8Array(ogImage), { headers: { "Content-Type": "image/png", "Cache-Control": "public, max-age=31536000, immutable", diff --git a/apps/website/app/blog/[slug]/components/shared.ts b/apps/website/app/blog/[slug]/components/shared.ts index d30727f6..8400997e 100644 --- a/apps/website/app/blog/[slug]/components/shared.ts +++ b/apps/website/app/blog/[slug]/components/shared.ts @@ -10,9 +10,9 @@ export async function highlight(code: string, lang: BundledLanguage) { lang, theme: "houston", }); - return toJsxRuntime(out, { - Fragment: react.Fragment, - jsx: jsxRuntime.jsx, - jsxs: jsxRuntime.jsxs + return toJsxRuntime(out, { + Fragment: react.Fragment, + jsx: jsxRuntime.jsx, + jsxs: jsxRuntime.jsxs, }) as JSX.Element; } diff --git a/apps/website/app/blog/[slug]/page.tsx b/apps/website/app/blog/[slug]/page.tsx index a6366e18..2b1773a7 100644 --- a/apps/website/app/blog/[slug]/page.tsx +++ b/apps/website/app/blog/[slug]/page.tsx @@ -90,21 +90,20 @@ export default async function BlogPostPage({ params }: Props) { const scripts = doc.querySelectorAll( 'script[type="application/ld+json"], script', ); - scripts.forEach((script) => script.remove()); + for (const script of scripts) script.remove(); const unwantedElements = doc.querySelectorAll("style, meta, link"); - unwantedElements.forEach((el) => el.remove()); + for (const el of unwantedElements) el.remove(); return doc.body.innerHTML; - } else { - return html - .replace( - /]*type="application\/ld\+json"[^>]*>[\s\S]*?<\/script>/gi, - "", - ) - .replace(/]*>[\s\S]*?<\/script>/gi, "") - .replace(/]*>[\s\S]*?<\/style>/gi, "") - .replace(/]*>/gi, "") - .replace(/]*>/gi, ""); } + return html + .replace( + /]*type="application\/ld\+json"[^>]*>[\s\S]*?<\/script>/gi, + "", + ) + .replace(/]*>[\s\S]*?<\/script>/gi, "") + .replace(/]*>[\s\S]*?<\/style>/gi, "") + .replace(/]*>/gi, "") + .replace(/]*>/gi, ""); }; const turndownService = new TurndownService({ @@ -189,7 +188,7 @@ export default async function BlogPostPage({ params }: Props) { ), img: ({ node, src, alt }) => ( @@ -199,9 +198,9 @@ export default async function BlogPostPage({ params }: Props) { children, inline, }: { - className: string; - children: React.ReactNode; - inline: boolean; + className?: string; + children?: React.ReactNode; + inline?: boolean; }) => { if (inline || !className || !/language-(\w+)/.test(className)) { return ( diff --git a/apps/website/app/comparison/page.tsx b/apps/website/app/comparison/page.tsx index 1b23efe5..3eab3e24 100644 --- a/apps/website/app/comparison/page.tsx +++ b/apps/website/app/comparison/page.tsx @@ -1,16 +1,16 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; +import { Container } from "@/components/Container"; import { Testimonials } from "@/components/Testimonials"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; -import { ArrowRight, GitBranch, Activity, Users, Gauge } from "lucide-react"; -import Link from "next/link"; +import { Activity, ArrowRight, Gauge, GitBranch, Users } from "lucide-react"; import type { Metadata } from "next"; +import Link from "next/link"; export const metadata: Metadata = { title: "Dokploy Vs. and PaaS Comparison Pages | Dokploy", description: - "How does Dokploy compare to other application deployment, database management, and PaaS solutions? Learn on our \"Dokploy vs.\" alternative comparison pages.", + 'How does Dokploy compare to other application deployment, database management, and PaaS solutions? Learn on our "Dokploy vs." alternative comparison pages.', }; const competitors = [ diff --git a/apps/website/app/contact/page.tsx b/apps/website/app/contact/page.tsx index f821b43d..d4939d30 100644 --- a/apps/website/app/contact/page.tsx +++ b/apps/website/app/contact/page.tsx @@ -1,7 +1,7 @@ "use client"; -import { Container } from "@/components/Container"; import { ContactForm } from "@/components/ContactForm"; +import { Container } from "@/components/Container"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { cn } from "@/lib/utils"; import { useState } from "react"; diff --git a/apps/website/app/deploy-ai/page.tsx b/apps/website/app/deploy-ai/page.tsx index cf90b119..328958da 100644 --- a/apps/website/app/deploy-ai/page.tsx +++ b/apps/website/app/deploy-ai/page.tsx @@ -2,20 +2,20 @@ import { Container } from "@/components/Container"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; import { + Activity, Bot, Boxes, - Activity, - Users, + FlaskConical, + KeyRound, MousePointerClick, Network, - KeyRound, - ShieldCheck, - FlaskConical, Rocket, + ShieldCheck, Sparkles, + Users, } from "lucide-react"; -import Link from "next/link"; import type { Metadata } from "next"; +import Link from "next/link"; export const metadata: Metadata = { title: "Deploy AI Apps Securely with Dokploy", @@ -133,7 +133,11 @@ export default function DeployAIPage() { className="rounded-full bg-[#5965F2] hover:bg-[#4A55E0]" asChild > - + Contact Us diff --git a/apps/website/app/dokploy-vs-caprover/page.tsx b/apps/website/app/dokploy-vs-caprover/page.tsx index 38a61577..edbdf4cd 100644 --- a/apps/website/app/dokploy-vs-caprover/page.tsx +++ b/apps/website/app/dokploy-vs-caprover/page.tsx @@ -1,13 +1,13 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; +import { Container } from "@/components/Container"; import { Testimonials } from "@/components/Testimonials"; import { ComparisonStats } from "@/components/comparison-stats"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; -import { Check, X, Zap, Bell, Users, LayoutDashboard } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Bell, Check, LayoutDashboard, Users, X, Zap } from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; -import { Button } from "@/components/ui/button"; export const metadata: Metadata = { title: "Dokploy vs. CapRover Comparison | Dokploy", @@ -26,35 +26,101 @@ interface FeatureRow { const featureComparisonRows: FeatureRow[] = [ // Setup & Installation - { feature: "One-command installation", dokploy: true, caprover: true, section: "Setup & Installation" }, - { feature: "Installation feedback and progress logs", dokploy: true, caprover: false }, - { feature: "Works with firewall and Tailscale out of the box", dokploy: true, caprover: false }, - { feature: "Lightweight CPU usage while idle", dokploy: true, caprover: false }, - { feature: "Built with Next.js / TypeScript", dokploy: true, caprover: false }, + { + feature: "One-command installation", + dokploy: true, + caprover: true, + section: "Setup & Installation", + }, + { + feature: "Installation feedback and progress logs", + dokploy: true, + caprover: false, + }, + { + feature: "Works with firewall and Tailscale out of the box", + dokploy: true, + caprover: false, + }, + { + feature: "Lightweight CPU usage while idle", + dokploy: true, + caprover: false, + }, + { + feature: "Built with Next.js / TypeScript", + dokploy: true, + caprover: false, + }, // Deployment - { feature: "Deploy from GitHub, GitLab, Bitbucket", dokploy: true, caprover: "limited", section: "Deployment" }, + { + feature: "Deploy from GitHub, GitLab, Bitbucket", + dokploy: true, + caprover: "limited", + section: "Deployment", + }, { feature: "Auto-deploy on git push", dokploy: true, caprover: true }, { feature: "Docker Compose support", dokploy: true, caprover: "limited" }, - { feature: "Deploy from custom Docker images", dokploy: true, caprover: true }, + { + feature: "Deploy from custom Docker images", + dokploy: true, + caprover: true, + }, { feature: "Nixpacks and Buildpack support", dokploy: true, caprover: false }, - { feature: "Preview deployments (review apps)", dokploy: true, caprover: false }, + { + feature: "Preview deployments (review apps)", + dokploy: true, + caprover: false, + }, { feature: "One-click app templates", dokploy: true, caprover: true }, // Networking & Domains - { feature: "Built-in reverse proxy (Dokploy: Traefik, CapRover: Nginx)", dokploy: true, caprover: true, section: "Networking & Domains" }, + { + feature: "Built-in reverse proxy (Dokploy: Traefik, CapRover: Nginx)", + dokploy: true, + caprover: true, + section: "Networking & Domains", + }, { feature: "Automatic SSL via Let's Encrypt", dokploy: true, caprover: true }, { feature: "Custom domain management", dokploy: true, caprover: true }, // Infrastructure - { feature: "Multi-server deployment", dokploy: true, caprover: "limited", section: "Infrastructure" }, + { + feature: "Multi-server deployment", + dokploy: true, + caprover: "limited", + section: "Infrastructure", + }, { feature: "Docker Swarm clustering", dokploy: true, caprover: true }, - { feature: "Scheduled database backups (S3)", dokploy: true, caprover: false }, - { feature: "Back up arbitrary Docker volumes", dokploy: true, caprover: false }, + { + feature: "Scheduled database backups (S3)", + dokploy: true, + caprover: false, + }, + { + feature: "Back up arbitrary Docker volumes", + dokploy: true, + caprover: false, + }, // Monitoring & Alerts - { feature: "Real-time monitoring (CPU, RAM, disk)", dokploy: true, caprover: false, section: "Monitoring & Alerts" }, + { + feature: "Real-time monitoring (CPU, RAM, disk)", + dokploy: true, + caprover: false, + section: "Monitoring & Alerts", + }, { feature: "Metrics enabled by default", dokploy: true, caprover: false }, { feature: "Automated alerts from metrics", dokploy: true, caprover: false }, // Teams & Access - { feature: "Teams and multi-user support", dokploy: true, caprover: false, section: "Teams & Access" }, - { feature: "Role-based access control (RBAC)", dokploy: true, caprover: false }, + { + feature: "Teams and multi-user support", + dokploy: true, + caprover: false, + section: "Teams & Access", + }, + { + feature: "Role-based access control (RBAC)", + dokploy: true, + caprover: false, + }, { feature: "Projects grouping", dokploy: true, caprover: false }, { feature: "API and CLI access", dokploy: true, caprover: true }, { feature: "AI-assisted deployments", dokploy: true, caprover: false }, @@ -111,19 +177,23 @@ const integrationRows = [ }, { category: "Build and deployment systems", - dokploy: "Docker, Docker Compose, Nixpacks, Heroku Buildpacks, Paketo Buildpacks, Railpack", + dokploy: + "Docker, Docker Compose, Nixpacks, Heroku Buildpacks, Paketo Buildpacks, Railpack", caprover: "Docker, Captain Definition file", }, { category: "Notifications and communication", - dokploy: "Slack, Telegram, Discord, Lark, Email (SMTP), Resend, Gotify, Ntfy, Pushover, Webhook", + dokploy: + "Slack, Telegram, Discord, Lark, Email (SMTP), Resend, Gotify, Ntfy, Pushover, Webhook", caprover: "None built-in", }, ]; function FeatureCell({ value }: { value: FeatureValue }) { - if (value === true) return ; - if (value === "limited") return Limited; + if (value === true) + return ; + if (value === "limited") + return Limited; return ; } @@ -166,8 +236,8 @@ export default function DokployVsCapRoverPage() {

CapRover

For solo developers who want a simple, Heroku-like PaaS with - one-click apps and a straightforward captain dashboard - that's easy to get started with—choose CapRover. + one-click apps and a straightforward captain dashboard that's + easy to get started with—choose CapRover.

@@ -203,15 +273,22 @@ export default function DokployVsCapRoverPage() { Feature - Dokploy - CapRover + + Dokploy + + + CapRover + {featureComparisonRows.map((row) => ( <> {row.section && ( - + {item.title} -

{item.description}

+

+ {item.description} +

@@ -300,17 +379,18 @@ export default function DokployVsCapRoverPage() { - + - + {integrationRows.map((row) => ( - + - - + + @@ -234,7 +277,9 @@ export default function DokployVsCoolifyPage() {

{item.title}

-

{item.description}

+

+ {item.description} +

{index === 0 ? ( @@ -320,17 +365,16 @@ export default function DokployVsCoolifyPage() {
Category + Category + DokployCapRover + CapRover +
{row.category} {row.dokploy} diff --git a/apps/website/app/dokploy-vs-coolify/page.tsx b/apps/website/app/dokploy-vs-coolify/page.tsx index 9632f238..33bf0135 100644 --- a/apps/website/app/dokploy-vs-coolify/page.tsx +++ b/apps/website/app/dokploy-vs-coolify/page.tsx @@ -1,13 +1,22 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; +import { Container } from "@/components/Container"; import { Testimonials } from "@/components/Testimonials"; import { ComparisonStats } from "@/components/comparison-stats"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; -import { Check, X, Zap, Cpu, Plug, LayoutDashboard, Bell, Bot } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { + Bell, + Bot, + Check, + Cpu, + LayoutDashboard, + Plug, + X, + Zap, +} from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; -import { Button } from "@/components/ui/button"; export const metadata: Metadata = { title: "Dokploy Vs. Coolify Comparison", @@ -17,9 +26,21 @@ export const metadata: Metadata = { const featureComparisonRows = [ { feature: "One-command installation", dokploy: true, coolify: true }, - { feature: "Installation feedback and progress logs", dokploy: true, coolify: true }, - { feature: "Works with firewall and Tailscale out of the box", dokploy: true, coolify: false }, - { feature: "Lightweight CPU usage while idle", dokploy: true, coolify: false }, + { + feature: "Installation feedback and progress logs", + dokploy: true, + coolify: true, + }, + { + feature: "Works with firewall and Tailscale out of the box", + dokploy: true, + coolify: false, + }, + { + feature: "Lightweight CPU usage while idle", + dokploy: true, + coolify: false, + }, { feature: "Low memory usage", dokploy: true, coolify: true }, { feature: "Teams and organizations support", dokploy: true, coolify: true }, { feature: "Projects grouping", dokploy: true, coolify: true }, @@ -27,16 +48,32 @@ const featureComparisonRows = [ { feature: "Built with Next.js / TypeScript", dokploy: true, coolify: false }, { feature: "AI-assisted deployments", dokploy: true, coolify: false }, { feature: "Deploy from custom Docker images", dokploy: true, coolify: true }, - { feature: "Database deployment (Postgres, MySQL, Redis, etc.)", dokploy: true, coolify: true }, + { + feature: "Database deployment (Postgres, MySQL, Redis, etc.)", + dokploy: true, + coolify: true, + }, { feature: "Scheduled database backups (S3)", dokploy: true, coolify: true }, - { feature: "Back up arbitrary Docker volumes, not just databases", dokploy: true, coolify: false }, - { feature: "Preview deployments (review apps)", dokploy: true, coolify: true }, + { + feature: "Back up arbitrary Docker volumes, not just databases", + dokploy: true, + coolify: false, + }, + { + feature: "Preview deployments (review apps)", + dokploy: true, + coolify: true, + }, { feature: "API and CLI tools for automation", dokploy: true, coolify: true }, { feature: "Multi-server deployment", dokploy: true, coolify: true }, { feature: "Docker Swarm clustering", dokploy: true, coolify: "limited" }, { feature: "Cron jobs inside containers", dokploy: true, coolify: true }, { feature: "Cron jobs on your host machine", dokploy: true, coolify: false }, - { feature: "Monitoring metrics (CPU, RAM, Disk)", dokploy: true, coolify: "limited" }, + { + feature: "Monitoring metrics (CPU, RAM, Disk)", + dokploy: true, + coolify: "limited", + }, { feature: "Metrics enabled by default", dokploy: true, coolify: false }, { feature: "Automated alerts from metrics", dokploy: true, coolify: false }, ]; @@ -88,12 +125,14 @@ const integrationRows = [ }, { category: "Build and deployment systems", - dokploy: "Docker, Docker Compose, Nixpacks, Heroku Buildpacks, Paketo Buildpacks, Railpack", + dokploy: + "Docker, Docker Compose, Nixpacks, Heroku Buildpacks, Paketo Buildpacks, Railpack", coolify: "Docker, Docker Compose, Nixpacks", }, { category: "Notifications and communication", - dokploy: "Slack, Telegram, Discord, Lark, Email (SMTP), Resend, Gotify, Ntfy, Pushover, Webhook", + dokploy: + "Slack, Telegram, Discord, Lark, Email (SMTP), Resend, Gotify, Ntfy, Pushover, Webhook", coolify: "Slack, Discord, Telegram, Email (SMTP), Pushover, Resend, Teams", }, ]; @@ -175,8 +214,12 @@ export default function DokployVsCoolifyPage() {
FeatureDokployCoolify + Dokploy + + Coolify +
- + {integrationRows.map((row) => ( - + - + @@ -234,7 +277,10 @@ export default function DokployVsDokkuPage() { {featureComparisonRows.map((row) => ( <> {row.section && ( - +
Category + Category + Dokploy Coolify
{row.category} {row.dokploy} diff --git a/apps/website/app/dokploy-vs-dokku/page.tsx b/apps/website/app/dokploy-vs-dokku/page.tsx index bc4f92a0..d0b1af97 100644 --- a/apps/website/app/dokploy-vs-dokku/page.tsx +++ b/apps/website/app/dokploy-vs-dokku/page.tsx @@ -1,13 +1,13 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; +import { Container } from "@/components/Container"; import { Testimonials } from "@/components/Testimonials"; import { ComparisonStats } from "@/components/comparison-stats"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; -import { Check, X, Zap, Globe, Bell, Users, Shield } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Bell, Check, Globe, Shield, Users, X, Zap } from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; -import { Button } from "@/components/ui/button"; export const metadata: Metadata = { title: "Dokploy vs. Dokku Comparison | Dokploy | Dokploy", @@ -26,12 +26,26 @@ interface FeatureRow { const featureComparisonRows: FeatureRow[] = [ // Setup & Installation - { feature: "One-command installation", dokploy: true, dokku: true, section: "Setup & Installation" }, + { + feature: "One-command installation", + dokploy: true, + dokku: true, + section: "Setup & Installation", + }, { feature: "Web-based UI dashboard", dokploy: true, dokku: false }, - { feature: "Works with firewall and Tailscale out of the box", dokploy: true, dokku: false }, + { + feature: "Works with firewall and Tailscale out of the box", + dokploy: true, + dokku: false, + }, { feature: "Lightweight CPU usage while idle", dokploy: true, dokku: true }, // Deployment - { feature: "Deploy from GitHub, GitLab, Bitbucket", dokploy: true, dokku: "limited", section: "Deployment" }, + { + feature: "Deploy from GitHub, GitLab, Bitbucket", + dokploy: true, + dokku: "limited", + section: "Deployment", + }, { feature: "Auto-deploy on git push", dokploy: true, dokku: true }, { feature: "Docker Compose support", dokploy: true, dokku: "limited" }, { feature: "Deploy from custom Docker images", dokploy: true, dokku: true }, @@ -39,20 +53,44 @@ const featureComparisonRows: FeatureRow[] = [ { feature: "Preview deployments (review apps)", dokploy: true, dokku: false }, { feature: "One-click app templates", dokploy: true, dokku: false }, // Networking & Domains - { feature: "Built-in reverse proxy", dokploy: true, dokku: true, section: "Networking & Domains" }, + { + feature: "Built-in reverse proxy", + dokploy: true, + dokku: true, + section: "Networking & Domains", + }, { feature: "Automatic SSL via Let's Encrypt", dokploy: true, dokku: true }, { feature: "Custom domain management via UI", dokploy: true, dokku: false }, // Data & Backups - { feature: "Database deployment (Postgres, MySQL, Redis, etc.)", dokploy: true, dokku: true, section: "Data & Backups" }, - { feature: "Scheduled database backups (S3)", dokploy: true, dokku: "limited" }, + { + feature: "Database deployment (Postgres, MySQL, Redis, etc.)", + dokploy: true, + dokku: true, + section: "Data & Backups", + }, + { + feature: "Scheduled database backups (S3)", + dokploy: true, + dokku: "limited", + }, { feature: "Back up arbitrary Docker volumes", dokploy: true, dokku: false }, // Monitoring & Alerts - { feature: "Real-time monitoring (CPU, RAM, disk)", dokploy: true, dokku: false, section: "Monitoring & Alerts" }, + { + feature: "Real-time monitoring (CPU, RAM, disk)", + dokploy: true, + dokku: false, + section: "Monitoring & Alerts", + }, { feature: "Metrics enabled by default", dokploy: true, dokku: false }, { feature: "Automated alerts from metrics", dokploy: true, dokku: false }, { feature: "Application log viewer in UI", dokploy: true, dokku: false }, // Teams & Access - { feature: "Teams and multi-user support", dokploy: true, dokku: false, section: "Teams & Access" }, + { + feature: "Teams and multi-user support", + dokploy: true, + dokku: false, + section: "Teams & Access", + }, { feature: "Role-based access control (RBAC)", dokploy: true, dokku: false }, { feature: "Projects grouping", dokploy: true, dokku: false }, { feature: "Multi-server deployment", dokploy: true, dokku: false }, @@ -121,19 +159,23 @@ const integrationRows = [ }, { category: "Build and deployment systems", - dokploy: "Docker, Docker Compose, Nixpacks, Heroku Buildpacks, Paketo Buildpacks, Railpack", + dokploy: + "Docker, Docker Compose, Nixpacks, Heroku Buildpacks, Paketo Buildpacks, Railpack", dokku: "Docker, Heroku Buildpacks (via plugins)", }, { category: "Notifications and communication", - dokploy: "Slack, Telegram, Discord, Lark, Email (SMTP), Resend, Gotify, Ntfy, Pushover, Webhook", + dokploy: + "Slack, Telegram, Discord, Lark, Email (SMTP), Resend, Gotify, Ntfy, Pushover, Webhook", dokku: "None built-in", }, ]; function FeatureCell({ value }: { value: FeatureValue }) { - if (value === true) return ; - if (value === "limited") return Limited; + if (value === true) + return ; + if (value === "limited") + return Limited; return ; } @@ -176,10 +218,9 @@ export default function DokployVsDokkuPage() {

Dokku

For experienced developers who prefer a CLI-driven, - Heroku-like PaaS that's minimal and scriptable, with a - plugin ecosystem for extending functionality—choose Dokku. - Trade-offs include fewer enterprise features and - integrations. + Heroku-like PaaS that's minimal and scriptable, with a plugin + ecosystem for extending functionality—choose Dokku. Trade-offs + include fewer enterprise features and integrations.

@@ -190,8 +231,8 @@ export default function DokployVsDokkuPage() {

Choose Dokploy if you want complete control over your - infrastructure with a simpler way to manage apps, databases, - and multiple servers. + infrastructure with a simpler way to manage apps, databases, and + multiple servers.

@@ -226,7 +267,9 @@ export default function DokployVsDokkuPage() {
FeatureDokploy + Dokploy + Dokku
{item.title} -

{item.description}

+

+ {item.description} +

@@ -315,8 +363,7 @@ export default function DokployVsDokkuPage() {

When it comes to a Dokploy vs. Dokku comparison, you want the - self-hosted PaaS that syncs with the tools in your - workflow. + self-hosted PaaS that syncs with the tools in your workflow.

@@ -324,17 +371,16 @@ export default function DokployVsDokkuPage() { - + {integrationRows.map((row) => ( - + - - + + {featureComparisonRows.map((row) => ( <> {row.section && ( - +
Category + Category + Dokploy Dokku
{row.category} {row.dokploy} diff --git a/apps/website/app/dokploy-vs-portainer/page.tsx b/apps/website/app/dokploy-vs-portainer/page.tsx index b33635d5..55bf1ee6 100644 --- a/apps/website/app/dokploy-vs-portainer/page.tsx +++ b/apps/website/app/dokploy-vs-portainer/page.tsx @@ -1,13 +1,13 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; +import { Container } from "@/components/Container"; import { Testimonials } from "@/components/Testimonials"; import { ComparisonStats } from "@/components/comparison-stats"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; -import { Check, X, Zap, Globe, Bell, Users } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Bell, Check, Globe, Users, X, Zap } from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; -import { Button } from "@/components/ui/button"; export const metadata: Metadata = { title: "Dokploy vs. Portainer Comparison | Dokploy", @@ -26,39 +26,113 @@ interface FeatureRow { const featureComparisonRows: FeatureRow[] = [ // Setup & Installation - { feature: "One-command installation", dokploy: true, portainer: true, section: "Setup & Installation" }, - { feature: "Installation feedback and progress logs", dokploy: true, portainer: false }, - { feature: "Works with firewall and Tailscale out of the box", dokploy: true, portainer: false }, - { feature: "Lightweight CPU usage while idle", dokploy: true, portainer: true }, + { + feature: "One-command installation", + dokploy: true, + portainer: true, + section: "Setup & Installation", + }, + { + feature: "Installation feedback and progress logs", + dokploy: true, + portainer: false, + }, + { + feature: "Works with firewall and Tailscale out of the box", + dokploy: true, + portainer: false, + }, + { + feature: "Lightweight CPU usage while idle", + dokploy: true, + portainer: true, + }, // Deployment - { feature: "Deploy web apps from git repos (GitHub, GitLab, Bitbucket)", dokploy: true, portainer: "limited", section: "Deployment" }, + { + feature: "Deploy web apps from git repos (GitHub, GitLab, Bitbucket)", + dokploy: true, + portainer: "limited", + section: "Deployment", + }, { feature: "Auto-deploy on git push", dokploy: true, portainer: "limited" }, { feature: "Docker Compose support", dokploy: true, portainer: true }, - { feature: "Deploy from custom Docker images", dokploy: true, portainer: true }, - { feature: "Nixpacks and Heroku Buildpack support", dokploy: true, portainer: false }, - { feature: "Preview deployments (review apps)", dokploy: true, portainer: false }, - { feature: "One-click open source templates", dokploy: true, portainer: true }, + { + feature: "Deploy from custom Docker images", + dokploy: true, + portainer: true, + }, + { + feature: "Nixpacks and Heroku Buildpack support", + dokploy: true, + portainer: false, + }, + { + feature: "Preview deployments (review apps)", + dokploy: true, + portainer: false, + }, + { + feature: "One-click open source templates", + dokploy: true, + portainer: true, + }, // Networking & Domains - { feature: "Built-in reverse proxy (Traefik)", dokploy: true, portainer: false, section: "Networking & Domains" }, - { feature: "Automatic SSL / encrypt cert via Let's Encrypt", dokploy: true, portainer: false }, + { + feature: "Built-in reverse proxy (Traefik)", + dokploy: true, + portainer: false, + section: "Networking & Domains", + }, + { + feature: "Automatic SSL / encrypt cert via Let's Encrypt", + dokploy: true, + portainer: false, + }, { feature: "Custom domain management", dokploy: true, portainer: false }, // Infrastructure - { feature: "Multi-server support", dokploy: true, portainer: true, section: "Infrastructure" }, + { + feature: "Multi-server support", + dokploy: true, + portainer: true, + section: "Infrastructure", + }, { feature: "Docker Swarm clustering", dokploy: true, portainer: true }, { feature: "Kubernetes support", dokploy: false, portainer: true }, // Configuration & Services - { feature: "Real-time monitoring (CPU, RAM, disk)", dokploy: true, portainer: "limited", section: "Configuration & Services" }, + { + feature: "Real-time monitoring (CPU, RAM, disk)", + dokploy: true, + portainer: "limited", + section: "Configuration & Services", + }, { feature: "Metrics enabled by default", dokploy: true, portainer: false }, { feature: "Automated alerts from metrics", dokploy: true, portainer: false }, - { feature: "Application and container log viewer", dokploy: true, portainer: true }, + { + feature: "Application and container log viewer", + dokploy: true, + portainer: true, + }, // Teams & Access - { feature: "Teams and multi-user support", dokploy: true, portainer: true, section: "Teams & Access" }, - { feature: "Role-based access control (RBAC)", dokploy: true, portainer: true }, + { + feature: "Teams and multi-user support", + dokploy: true, + portainer: true, + section: "Teams & Access", + }, + { + feature: "Role-based access control (RBAC)", + dokploy: true, + portainer: true, + }, { feature: "Projects grouping", dokploy: true, portainer: false }, { feature: "API and CLI access", dokploy: true, portainer: true }, { feature: "AI-assisted deployments", dokploy: true, portainer: false }, { feature: "Free community edition", dokploy: true, portainer: true }, - { feature: "Full-featured without a paid plan", dokploy: true, portainer: false }, + { + feature: "Full-featured without a paid plan", + dokploy: true, + portainer: false, + }, ]; const whyChooseItems = [ @@ -112,19 +186,23 @@ const integrationRows = [ }, { category: "Build and deployment systems", - dokploy: "Docker, Docker Compose, Nixpacks, Heroku Buildpacks, Paketo Buildpacks, Railpack", + dokploy: + "Docker, Docker Compose, Nixpacks, Heroku Buildpacks, Paketo Buildpacks, Railpack", portainer: "Docker, Docker Compose", }, { category: "Notifications and communication", - dokploy: "Slack, Telegram, Discord, Lark, Email (SMTP), Resend, Gotify, Ntfy, Pushover, Webhook", + dokploy: + "Slack, Telegram, Discord, Lark, Email (SMTP), Resend, Gotify, Ntfy, Pushover, Webhook", portainer: "Slack, Microsoft Teams, Email (SMTP), Webhook", }, ]; function FeatureCell({ value }: { value: FeatureValue }) { - if (value === true) return ; - if (value === "limited") return Limited; + if (value === true) + return ; + if (value === "limited") + return Limited; return ; } @@ -149,16 +227,18 @@ export default function DokployVsPortainerPage() {

Both tools help you manage containers on your own server. But they - solve very different problems—here's what that means for your setup. + solve very different problems—here's what that means for your + setup.

Dokploy

- For scaling teams that want to self-host web apps and databases - with a polished UI, automated deployments from git repos, - multi-server support, a built-in reverse proxy, and SSL. + For scaling teams that want to self-host web apps and + databases with a polished UI, automated deployments from git + repos, multi-server support, a built-in reverse proxy, and + SSL.

@@ -203,15 +283,22 @@ export default function DokployVsPortainerPage() {
FeatureDokployPortainer + Dokploy + + Portainer +
{item.title} -

{item.description}

+

+ {item.description} +

@@ -291,7 +380,11 @@ export default function DokployVsPortainerPage() { Deploy AI tools in a secure environment

- Create sandboxes with Dokploy that combine multitenancy, SSO, audit logs, and IP allowlisting in a single setup. Every deployment is logged, access is tied to your identity provider, workspaces are kept separate, and non-technical users can go from code to a running app without an engineer involved. + Create sandboxes with Dokploy that combine multitenancy, SSO, + audit logs, and IP allowlisting in a single setup. Every + deployment is logged, access is tied to your identity provider, + workspaces are kept separate, and non-technical users can go from + code to a running app without an engineer involved.

@@ -325,17 +418,18 @@ export default function DokployVsPortainerPage() { - + - + {integrationRows.map((row) => ( - + - - + + @@ -268,7 +320,9 @@ export default function DokployVsRenderPage() {

{item.title}

-

{item.description}

+

+ {item.description} +

{index === 0 ? ( @@ -337,10 +391,11 @@ export default function DokployVsRenderPage() { Pricing comparison: platform fees vs. per-service compute

- Dokploy Cloud charges per server, not per service, so your platform - cost stays flat as your app count grows. Render charges a workspace - plan fee plus a separate compute for every service instance, with - managed databases, storage, and bandwidth each billed on top. + Dokploy Cloud charges per server, not per service, so your + platform cost stays flat as your app count grows. Render charges a + workspace plan fee plus a separate compute for every service + instance, with managed databases, storage, and bandwidth each + billed on top.

@@ -386,7 +441,9 @@ export default function DokployVsRenderPage() {
Category + Category + DokployPortainer + Portainer +
{row.category} {row.dokploy} @@ -362,9 +456,9 @@ export default function DokployVsPortainerPage() { Whether you're a startup founder deploying your first web app on a cheap VPS or a growing team managing multiple services across servers, Dokploy's flexible, polished platform makes self-hosting - accessible to everyone—from beginners and non-technical users who've - never touched a bash script to engineers who want full control over - their config, containers, and workflow. + accessible to everyone—from beginners and non-technical users + who've never touched a bash script to engineers who want full + control over their config, containers, and workflow.

diff --git a/apps/website/app/dokploy-vs-render/page.tsx b/apps/website/app/dokploy-vs-render/page.tsx index b8b5795a..ab7b7359 100644 --- a/apps/website/app/dokploy-vs-render/page.tsx +++ b/apps/website/app/dokploy-vs-render/page.tsx @@ -1,21 +1,21 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; +import { Container } from "@/components/Container"; import { Testimonials } from "@/components/Testimonials"; import { ComparisonStats } from "@/components/comparison-stats"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; +import { Button } from "@/components/ui/button"; import { - Check, - X, + Archive, + Bot, Building2, + Check, Container as ContainerIcon, - Archive, Gauge, - Bot, + X, } from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; -import { Button } from "@/components/ui/button"; export const metadata: Metadata = { title: "Dokploy Vs. Render: Self-Hosted Vs. Managed PaaS", @@ -24,25 +24,49 @@ export const metadata: Metadata = { }; const featureComparisonRows = [ - { feature: "Self-hostable on your own VPS or server", dokploy: true, render: false }, - { feature: "Run on any cloud provider via SSH", dokploy: true, render: false }, + { + feature: "Self-hostable on your own VPS or server", + dokploy: true, + render: false, + }, + { + feature: "Run on any cloud provider via SSH", + dokploy: true, + render: false, + }, { feature: "Docker Compose support", dokploy: true, render: false }, { feature: "Docker Stack support", dokploy: true, render: false }, - { feature: "Dockerfile and prebuilt image deploys", dokploy: true, render: true }, + { + feature: "Dockerfile and prebuilt image deploys", + dokploy: true, + render: true, + }, { feature: "Nixpacks build support", dokploy: true, render: false }, { feature: "Heroku Buildpacks support", dokploy: true, render: true }, { feature: "Paketo Buildpacks support", dokploy: true, render: false }, { feature: "Railpack build support", dokploy: true, render: false }, { feature: "Custom build servers", dokploy: true, render: false }, - { feature: "Named Docker volume backups to S3", dokploy: true, render: false }, - { feature: "Scheduled database backups to S3 (built-in)", dokploy: true, render: false }, + { + feature: "Named Docker volume backups to S3", + dokploy: true, + render: false, + }, + { + feature: "Scheduled database backups to S3 (built-in)", + dokploy: true, + render: false, + }, { feature: "Preview deployments", dokploy: true, render: true }, { feature: "Multi-server deployment", dokploy: true, render: false }, { feature: "Docker Swarm clustering", dokploy: true, render: false }, { feature: "One-command installation", dokploy: true, render: false }, { feature: "Scheduled jobs (cron)", dokploy: true, render: true }, { feature: "Background workers", dokploy: true, render: true }, - { feature: "Built-in monitoring metrics (CPU, RAM, Disk)", dokploy: true, render: false }, + { + feature: "Built-in monitoring metrics (CPU, RAM, Disk)", + dokploy: true, + render: false, + }, { feature: "Automated metric alerts", dokploy: true, render: false }, { feature: "Metrics enabled by default", dokploy: true, render: false }, { feature: "AI-assisted deployments", dokploy: true, render: false }, @@ -51,8 +75,16 @@ const featureComparisonRows = [ { feature: "Fine-grained RBAC", dokploy: true, render: false }, { feature: "SSO / SAML", dokploy: true, render: true }, { feature: "Audit logs", dokploy: true, render: true }, - { feature: "Predictable per-server platform pricing", dokploy: true, render: false }, - { feature: "Persistent disk shared across services", dokploy: true, render: false }, + { + feature: "Predictable per-server platform pricing", + dokploy: true, + render: false, + }, + { + feature: "Persistent disk shared across services", + dokploy: true, + render: false, + }, ]; const whyChooseItems = [ @@ -89,7 +121,11 @@ const whyChooseItems = [ ]; const pricingRows = [ - { label: "Pricing model", dokploy: "Per server", render: "Workspace plan + per-service compute" }, + { + label: "Pricing model", + dokploy: "Per server", + render: "Workspace plan + per-service compute", + }, { label: "Entry price", dokploy: "Free (open source, self-hosted)", @@ -100,14 +136,26 @@ const pricingRows = [ dokploy: "$15/month (Startup, 3 servers)", render: "$25/month workspace + compute per service", }, - { label: "Apps per server or plan", dokploy: "Unlimited", render: "No service cap on paid plans" }, - { label: "Databases", dokploy: "Unlimited per server", render: "Billed separately per instance" }, + { + label: "Apps per server or plan", + dokploy: "Unlimited", + render: "No service cap on paid plans", + }, + { + label: "Databases", + dokploy: "Unlimited per server", + render: "Billed separately per instance", + }, { label: "Bandwidth", dokploy: "Included (your server's allowance)", render: "25 GB included on Pro; metered above that", }, - { label: "Infrastructure", dokploy: "Your own servers (any provider)", render: "Render-managed only" }, + { + label: "Infrastructure", + dokploy: "Your own servers (any provider)", + render: "Render-managed only", + }, ]; const integrationRows = [ @@ -211,8 +259,12 @@ export default function DokployVsRenderPage() {
FeatureDokployRender + Dokploy + + Render +
- + diff --git a/apps/website/app/dokploy-vs-vercel/page.tsx b/apps/website/app/dokploy-vs-vercel/page.tsx index 79e6bd15..a8f10d57 100644 --- a/apps/website/app/dokploy-vs-vercel/page.tsx +++ b/apps/website/app/dokploy-vs-vercel/page.tsx @@ -1,21 +1,21 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; +import { Container } from "@/components/Container"; import { Testimonials } from "@/components/Testimonials"; import { ComparisonStats } from "@/components/comparison-stats"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; +import { Button } from "@/components/ui/button"; import { + Bot, Check, - X, Container as ContainerLucide, - Settings, - HardDrive, Gauge, - Bot, + HardDrive, + Settings, + X, } from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; -import { Button } from "@/components/ui/button"; export const metadata: Metadata = { title: "Dokploy vs. Vercel: Docker-Native vs. Serverless", @@ -24,16 +24,48 @@ export const metadata: Metadata = { }; const featureComparisonRows = [ - { feature: "Self-hostable on your own VPS or server", dokploy: true, vercel: false }, - { feature: "Run on any cloud provider via SSH", dokploy: true, vercel: false }, - { feature: "Deploy Docker images and containers", dokploy: true, vercel: false }, + { + feature: "Self-hostable on your own VPS or server", + dokploy: true, + vercel: false, + }, + { + feature: "Run on any cloud provider via SSH", + dokploy: true, + vercel: false, + }, + { + feature: "Deploy Docker images and containers", + dokploy: true, + vercel: false, + }, { feature: "Docker Compose support", dokploy: true, vercel: false }, { feature: "Docker Stack support", dokploy: true, vercel: false }, - { feature: "Persistent filesystem (Docker volumes)", dokploy: true, vercel: false }, - { feature: "Persistent disk shared across services", dokploy: true, vercel: false }, - { feature: "Named Docker volume backups to S3", dokploy: true, vercel: false }, - { feature: "One-click scheduled database backups to S3", dokploy: true, vercel: false }, - { feature: "Long-running processes and background workers", dokploy: true, vercel: false }, + { + feature: "Persistent filesystem (Docker volumes)", + dokploy: true, + vercel: false, + }, + { + feature: "Persistent disk shared across services", + dokploy: true, + vercel: false, + }, + { + feature: "Named Docker volume backups to S3", + dokploy: true, + vercel: false, + }, + { + feature: "One-click scheduled database backups to S3", + dokploy: true, + vercel: false, + }, + { + feature: "Long-running processes and background workers", + dokploy: true, + vercel: false, + }, { feature: "WebSocket connections without function duration limits", dokploy: true, @@ -48,7 +80,11 @@ const featureComparisonRows = [ { feature: "Docker Swarm clustering", dokploy: true, vercel: false }, { feature: "One-command installation", dokploy: true, vercel: false }, { feature: "Scheduled jobs (cron)", dokploy: true, vercel: true }, - { feature: "Built-in monitoring metrics (CPU, RAM, Disk)", dokploy: true, vercel: false }, + { + feature: "Built-in monitoring metrics (CPU, RAM, Disk)", + dokploy: true, + vercel: false, + }, { feature: "Automated metric alerts built in", dokploy: true, vercel: true }, { feature: "AI-assisted deployments", dokploy: true, vercel: true }, { feature: "MCP server support", dokploy: true, vercel: true }, @@ -56,7 +92,11 @@ const featureComparisonRows = [ { feature: "Fine-grained RBAC", dokploy: true, vercel: false }, { feature: "SSO / SAML", dokploy: true, vercel: true }, { feature: "Audit logs", dokploy: true, vercel: true }, - { feature: "Predictable per-server platform pricing", dokploy: true, vercel: false }, + { + feature: "Predictable per-server platform pricing", + dokploy: true, + vercel: false, + }, { feature: "No per-seat billing", dokploy: true, vercel: false }, ]; @@ -94,7 +134,11 @@ const whyChooseItems = [ ]; const pricingRows = [ - { label: "Pricing model", dokploy: "Per server", vercel: "Per seat + metered usage" }, + { + label: "Pricing model", + dokploy: "Per server", + vercel: "Per seat + metered usage", + }, { label: "Entry price", dokploy: "Free (open source, self-hosted)", @@ -106,13 +150,21 @@ const pricingRows = [ vercel: "$20/month per deploying seat", }, { label: "Apps per plan", dokploy: "Unlimited", vercel: "Unlimited on Pro" }, - { label: "Databases", dokploy: "Unlimited per server", vercel: "Not included – third-party add-ons" }, + { + label: "Databases", + dokploy: "Unlimited per server", + vercel: "Not included – third-party add-ons", + }, { label: "Bandwidth", dokploy: "Included (your server's allowance)", vercel: "1 TB included on Pro; metered above that", }, - { label: "Infrastructure", dokploy: "Your own servers (any provider)", vercel: "Vercel-managed only" }, + { + label: "Infrastructure", + dokploy: "Your own servers (any provider)", + vercel: "Vercel-managed only", + }, ]; const integrationRows = [ @@ -164,9 +216,9 @@ export default function DokployVsVercelPage() {

Dokploy

Dokploy is built for full-stack, Docker-native deployment on - infrastructure you own. Choose Vercel if your app is - primarily frontend or serverless and you want a managed - platform optimized for that model. + infrastructure you own. Choose Vercel if your app is primarily + frontend or serverless and you want a managed platform + optimized for that model.

@@ -216,8 +268,12 @@ export default function DokployVsVercelPage() {
- - + + @@ -273,7 +329,9 @@ export default function DokployVsVercelPage() {

{item.title}

-

{item.description}

+

+ {item.description} +

{index === 0 ? ( @@ -393,7 +451,9 @@ export default function DokployVsVercelPage() {
Category + Category + Dokploy Render
FeatureDokployVercel + Dokploy + + Vercel +
- + diff --git a/apps/website/app/features/application-deployment-platform/page.tsx b/apps/website/app/features/application-deployment-platform/page.tsx index 6c42eec3..c4f24ca7 100644 --- a/apps/website/app/features/application-deployment-platform/page.tsx +++ b/apps/website/app/features/application-deployment-platform/page.tsx @@ -1,37 +1,37 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; -import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; +import { Container } from "@/components/Container"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion"; +import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; import { + Bot, + Clock, + Cloud, + CloudCog, Code2, - Layers, - Wrench, - GitBranch, - Webhook, Eye, + FileCode, FolderInput, - Server, - Cloud, + GitBranch, + Layers, + LayoutDashboard, LayoutTemplate, - Workflow, - FileCode, RotateCcw, - LayoutDashboard, - CloudCog, - Clock, - Users, - Bot, + Server, Shield, + Users, + Webhook, + Workflow, + Wrench, } from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; export const metadata: Metadata = { title: "Application & Software Deployment Platform", @@ -247,7 +247,11 @@ export default function ApplicationDeploymentPlatformPage() { className="rounded-full bg-[#5965F2] hover:bg-[#4A55E0]" asChild > - + Contact Us @@ -295,7 +299,9 @@ export default function ApplicationDeploymentPlatformPage() { Deploy the apps your teams are already building with AI

- AI coding tools are changing how applications get written. Dokploy handles the deployment side, from AI-generated code to a live URL, powered by your existing workflows. + AI coding tools are changing how applications get written. Dokploy + handles the deployment side, from AI-generated code to a live URL, + powered by your existing workflows.

@@ -315,9 +321,12 @@ export default function ApplicationDeploymentPlatformPage() { ))}
-

Need a governed environment for AI tools?

+

+ Need a governed environment for AI tools? +

- See how Dokploy handles sandboxed deploys, non-technical users, and enterprise security for AI-built apps. + See how Dokploy handles sandboxed deploys, non-technical users, + and enterprise security for AI-built apps.

@@ -435,9 +444,9 @@ export default function ApplicationDeploymentPlatformPage() { Hundreds of templates to get started

- Deploy popular open-source apps in one click with Dokploy Templates, - a ready-to-run library of pre-configured apps you can deploy fast, - without rebuilding the same stack from scratch. + Deploy popular open-source apps in one click with Dokploy + Templates, a ready-to-run library of pre-configured apps you can + deploy fast, without rebuilding the same stack from scratch.

diff --git a/apps/website/app/features/application-management-software/page.tsx b/apps/website/app/features/application-management-software/page.tsx index 9d0dc8bc..0fe2583e 100644 --- a/apps/website/app/features/application-management-software/page.tsx +++ b/apps/website/app/features/application-management-software/page.tsx @@ -1,32 +1,32 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; -import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; +import { Container } from "@/components/Container"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion"; +import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; import { Activity, - FileText, - RotateCcw, + CheckCircle2, Clock, - Eye, - Settings2, - Server, Cloud, Cpu, - Network, - Terminal, + Eye, + FileText, HardDrive, Lock, - CheckCircle2, + Network, + RotateCcw, + Server, + Settings2, + Terminal, } from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; export const metadata: Metadata = { title: "Application Management Software and Solutions", @@ -198,7 +198,11 @@ export default function ApplicationManagementSoftwarePage() { className="rounded-full bg-[#5965F2] hover:bg-[#4A55E0]" asChild > - + Contact Us @@ -412,7 +416,9 @@ export default function ApplicationManagementSoftwarePage() { Deploy AI in a controlled environment

- Use Dokploy to create sandbox environments separated from production infrastructure, where technical and non-technical employees can launch AI-coded apps safely. + Use Dokploy to create sandbox environments separated from + production infrastructure, where technical and non-technical + employees can launch AI-coded apps safely.

@@ -444,7 +450,9 @@ export default function ApplicationManagementSoftwarePage() { {step.number}

{step.title}

-

{step.description}

+

+ {step.description} +

))} diff --git a/apps/website/app/features/audit-logs/page.tsx b/apps/website/app/features/audit-logs/page.tsx index 35b84c4c..ad77d465 100644 --- a/apps/website/app/features/audit-logs/page.tsx +++ b/apps/website/app/features/audit-logs/page.tsx @@ -2,17 +2,17 @@ import { Container } from "@/components/Container"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; import { - ScrollText, + AlertCircle, Building2, - Search, FileCheck, - AlertCircle, - Shield, KeyRound, Paintbrush, + ScrollText, + Search, + Shield, } from "lucide-react"; -import Link from "next/link"; import type { Metadata } from "next"; +import Link from "next/link"; export const metadata: Metadata = { title: "Audit Logs for Enterprise Compliance", diff --git a/apps/website/app/features/container-server-monitoring/page.tsx b/apps/website/app/features/container-server-monitoring/page.tsx index 2f33082c..a7d49c1d 100644 --- a/apps/website/app/features/container-server-monitoring/page.tsx +++ b/apps/website/app/features/container-server-monitoring/page.tsx @@ -2,19 +2,19 @@ import { Container } from "@/components/Container"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; import { + Bell, Cpu, - MemoryStick, + Database, HardDrive, + LayoutDashboard, + MemoryStick, Network, - Bell, - Settings, Server, + Settings, Shield, - Database, - LayoutDashboard, } from "lucide-react"; -import Link from "next/link"; import type { Metadata } from "next"; +import Link from "next/link"; export const metadata: Metadata = { title: "Server & Container Monitoring | Network, CPU, Memory Monitoring Tool", @@ -65,8 +65,7 @@ const alertFeatures = [ { icon: Settings, title: "Easy alert management", - description: - "Disable alerts by just setting your limits to zero.", + description: "Disable alerts by just setting your limits to zero.", }, ]; @@ -359,7 +358,9 @@ export default function ContainerServerMonitoringPage() {

{faq.question}

-

{faq.answer}

+

+ {faq.answer} +

))} @@ -374,8 +375,8 @@ export default function ContainerServerMonitoringPage() { Container and Server monitoring tool

- Take advantage of Dokploy's comprehensive container and server - monitoring software alongside the rest of the platform. + Take advantage of Dokploy's comprehensive container and + server monitoring software alongside the rest of the platform.

diff --git a/apps/website/app/features/database-management-tool/page.tsx b/apps/website/app/features/database-management-tool/page.tsx index 56549ac1..b5a44709 100644 --- a/apps/website/app/features/database-management-tool/page.tsx +++ b/apps/website/app/features/database-management-tool/page.tsx @@ -1,34 +1,34 @@ -import { Container } from "@/components/Container"; import { CallToAction } from "@/components/CallToAction"; -import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; +import { Container } from "@/components/Container"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion"; +import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; import { - Database, Activity, - Shield, + AlertTriangle, Archive, - FileText, - RotateCcw, - Link2, Container as ContainerIcon, - Terminal, - HardDrive, Cpu, + Database, + FileText, + HardDrive, + KeyRound, Keyboard, - AlertTriangle, + Link2, Lock, - KeyRound, + RotateCcw, + Shield, ShieldCheck, + Terminal, } from "lucide-react"; +import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; -import type { Metadata } from "next"; export const metadata: Metadata = { title: "Database Management Tool & Deployment Software", @@ -213,7 +213,11 @@ export default function DatabaseManagementToolPage() { className="rounded-full bg-[#5965F2] hover:bg-[#4A55E0]" asChild > - + Contact Us @@ -357,9 +361,8 @@ export default function DatabaseManagementToolPage() {

Your database data is stored on your own server. Dokploy creates - Docker containers on your infrastructure, so you have full - control over your data—no third parties, no external - dependencies. + Docker containers on your infrastructure, so you have full control + over your data—no third parties, no external dependencies.

diff --git a/apps/website/app/features/role-based-access-control/page.tsx b/apps/website/app/features/role-based-access-control/page.tsx index 4110d904..46352e08 100644 --- a/apps/website/app/features/role-based-access-control/page.tsx +++ b/apps/website/app/features/role-based-access-control/page.tsx @@ -2,17 +2,17 @@ import { Container } from "@/components/Container"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; import { - Shield, - Users, FolderLock, - SlidersHorizontal, - UserPlus, KeyRound, - ScrollText, Paintbrush, + ScrollText, + Shield, + SlidersHorizontal, + UserPlus, + Users, } from "lucide-react"; -import Link from "next/link"; import type { Metadata } from "next"; +import Link from "next/link"; export const metadata: Metadata = { title: "Role-Based Access Control for Teams", @@ -186,8 +186,8 @@ export default function RoleBasedAccessControlPage() { Ready to take your business to the next level?

- Talk to us about fine-grained RBAC and the rest of - Dokploy's higher-tier feature set. + Talk to us about fine-grained RBAC and the rest of Dokploy's + higher-tier feature set.

))}
diff --git a/apps/website/app/features/white-labeling/page.tsx b/apps/website/app/features/white-labeling/page.tsx index 3ee4c84a..29f8e7ae 100644 --- a/apps/website/app/features/white-labeling/page.tsx +++ b/apps/website/app/features/white-labeling/page.tsx @@ -2,17 +2,17 @@ import { Container } from "@/components/Container"; import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Button } from "@/components/ui/button"; import { - Paintbrush, - Type, - Palette, + KeyRound, Link2, MonitorCheck, - Shield, - KeyRound, + Paintbrush, + Palette, ScrollText, + Shield, + Type, } from "lucide-react"; -import Link from "next/link"; import type { Metadata } from "next"; +import Link from "next/link"; export const metadata: Metadata = { title: "White Label Deployment Platform", diff --git a/apps/website/app/industries/higher-education/page.tsx b/apps/website/app/industries/higher-education/page.tsx index 2027770e..231785ed 100644 --- a/apps/website/app/industries/higher-education/page.tsx +++ b/apps/website/app/industries/higher-education/page.tsx @@ -139,7 +139,8 @@ const data: IndustryPageData = { }, { area: "Git workflows", - support: "GitHub, GitLab, Bitbucket, Gitea, and webhook-based auto deploys", + support: + "GitHub, GitLab, Bitbucket, Gitea, and webhook-based auto deploys", }, { area: "Access control", @@ -178,7 +179,8 @@ const data: IndustryPageData = { "Yes. Dokploy supports multiple deployment methods, including Git-based apps, Dockerfiles, and Docker Compose. It also supports common databases used in coursework, including PostgreSQL, MySQL, MongoDB, Redis, and MariaDB.", }, { - question: "Can universities connect Dokploy to existing identity systems?", + question: + "Can universities connect Dokploy to existing identity systems?", answer: "Dokploy Enterprise includes single sign-on options through providers such as Auth0, Keycloak, and other OIDC/SAML providers. That makes it easier to fit Dokploy into existing institutional access workflows.", }, diff --git a/apps/website/app/jobs/page.tsx b/apps/website/app/jobs/page.tsx index 710c006c..185a0640 100644 --- a/apps/website/app/jobs/page.tsx +++ b/apps/website/app/jobs/page.tsx @@ -1,10 +1,10 @@ import { Container } from "@/components/Container"; +import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; -import { MapPin, ArrowRight } from "lucide-react"; -import Link from "next/link"; +import { ArrowRight, MapPin } from "lucide-react"; import type { Metadata } from "next"; +import Link from "next/link"; export const metadata: Metadata = { title: "Dokploy Jobs & Open Positions", @@ -41,8 +41,9 @@ export default function JobsPage() {

We're a small, focused team building tools that developers - actually love. If you care about open source, developer experience, - and shipping things that matter — you'll fit right in. + actually love. If you care about open source, developer + experience, and shipping things that matter — you'll fit + right in.

@@ -353,7 +357,9 @@ export default function SelfHostedPaasPage() {

@@ -427,9 +433,9 @@ export default function SelfHostedPaasPage() { Should you choose Cloud or Self-Hosted?

- Both are great options. Every key feature available in - Self-Hosted is also available in Cloud, and vice versa. The choice - comes down to how much you want to manage yourself. + Both are great options. Every key feature available in Self-Hosted + is also available in Cloud, and vice versa. The choice comes down + to how much you want to manage yourself.

diff --git a/apps/website/app/templates/[id]/page.tsx b/apps/website/app/templates/[id]/page.tsx index 165ee3e8..63b8dff4 100644 --- a/apps/website/app/templates/[id]/page.tsx +++ b/apps/website/app/templates/[id]/page.tsx @@ -46,7 +46,9 @@ export async function generateMetadata({ params }: Props): Promise { } const title = template.seoTitle ?? `Deploy ${template.name} on Dokploy`; - const description = template.seoDescription ?? `${template.description} Deploy ${template.name} on your own server with one click using Dokploy's open source template.`; + const description = + template.seoDescription ?? + `${template.description} Deploy ${template.name} on your own server with one click using Dokploy's open source template.`; const url = `https://dokploy.com/templates/${template.id}`; const ogUrl = new URL( diff --git a/apps/website/app/terms-of-service/page.tsx b/apps/website/app/terms-of-service/page.tsx index d82da67f..45b31add 100644 --- a/apps/website/app/terms-of-service/page.tsx +++ b/apps/website/app/terms-of-service/page.tsx @@ -9,9 +9,7 @@ export const metadata: Metadata = { export default function TermsOfServicePage() { return (
-

- Terms of Service -

+

Terms of Service

Dokploy.com · Last Updated: January 2026

@@ -41,9 +39,7 @@ export default function TermsOfServicePage() {
-

- Section 1 – Definitions -

+

Section 1 – Definitions

  • "Authorized Users" means individuals @@ -103,8 +99,8 @@ export default function TermsOfServicePage() { accessible via the internet. We are responsible for infrastructure maintenance, security updates, and platform availability in accordance with our Service Level Agreement (Section 7). The services provided - are permitted to be used by businesses and individuals over the age - of 18 years. + are permitted to be used by businesses and individuals over the age of + 18 years.

    2.2 On-Premise Software

    @@ -141,9 +137,9 @@ export default function TermsOfServicePage() {

    You are responsible for maintaining the confidentiality of your account credentials and for all activities that occur under your - account. You must immediately notify us of any unauthorized use of your - account or any other breach of security. We are not liable for any - loss arising from unauthorized use of your account. + account. You must immediately notify us of any unauthorized use of + your account or any other breach of security. We are not liable for + any loss arising from unauthorized use of your account.

    3.3 Account Information

    @@ -155,7 +151,9 @@ export default function TermsOfServicePage() {

-

Section 4 – License Grant

+

+ Section 4 – License Grant +

4.1 Cloud Services License

Subject to these Terms and payment of applicable fees, we grant you a @@ -168,9 +166,9 @@ export default function TermsOfServicePage() { Subject to these Terms and payment of applicable fees, we grant you a limited, non-exclusive, non-transferable, non-sublicensable license to install and use the On-Premise Software on your own infrastructure - during the Subscription Term. This license is limited to the number - of instances, nodes, or users specified in your subscription plan. - The On-Premise Software may be used solely for Customer's internal + during the Subscription Term. This license is limited to the number of + instances, nodes, or users specified in your subscription plan. The + On-Premise Software may be used solely for Customer's internal business purposes and may not be used to provide services to third parties, operate as a managed service, or otherwise make the On-Premise Software available to any third party without our prior @@ -178,9 +176,8 @@ export default function TermsOfServicePage() {

4.3 Documentation License

- We grant you a limited, non-exclusive license to use the - Documentation solely in connection with your authorized use of the - Services. + We grant you a limited, non-exclusive license to use the Documentation + solely in connection with your authorized use of the Services.

4.4 Restrictions

@@ -235,7 +232,9 @@ export default function TermsOfServicePage() { the date and time of the violation and any identifying information regarding the violator including e-mail or IP address, if available.

-

5.2 Hosting-Specific Prohibitions

+

+ 5.2 Hosting-Specific Prohibitions +

The following activities are strictly prohibited on our platform:

  • @@ -247,14 +246,16 @@ export default function TermsOfServicePage() { botnets, or any malicious software;
  • - (c) Hosting content that exploits minors in any way, including - child sexual abuse material (CSAM); + (c) Hosting content that exploits minors in any way, including child + sexual abuse material (CSAM);
  • (d) Operating open proxies, anonymizers, or services designed to obscure network traffic origins;
  • -
  • (e) Launching or facilitating denial-of-service (DoS/DDoS) attacks;
  • +
  • + (e) Launching or facilitating denial-of-service (DoS/DDoS) attacks; +
  • (f) Sending spam, unsolicited bulk messages, or phishing communications; @@ -264,8 +265,8 @@ export default function TermsOfServicePage() { quotas, or usage restrictions;
  • - (h) Hosting content or applications that violate export control - laws or sanctions. + (h) Hosting content or applications that violate export control laws + or sanctions.

5.3 Resource Usage

@@ -281,8 +282,8 @@ export default function TermsOfServicePage() { may lead to suspension or termination of your account and legal action. We reserve the right to take any other remedial action including reporting illegal activities to appropriate law enforcement - authorities. You may be required to pay for the costs of - investigation and remedial action related to AUP violations. + authorities. You may be required to pay for the costs of investigation + and remedial action related to AUP violations.

@@ -348,8 +349,8 @@ export default function TermsOfServicePage() { Maintenance; (b) outages caused by factors outside our reasonable control, including force majeure events, internet service provider failures, or third-party service outages; (c) outages resulting from - Customer actions or inactions, including misconfiguration; (d) - outages during beta or preview features. + Customer actions or inactions, including misconfiguration; (d) outages + during beta or preview features.

7.3 Service Credits

@@ -403,7 +404,9 @@ export default function TermsOfServicePage() {

-

Section 9 – Customer Data

+

+ Section 9 – Customer Data +

9.1 Ownership

You retain all rights, title, and interest in and to your Customer @@ -421,7 +424,9 @@ export default function TermsOfServicePage() { troubleshooting. Any such processing will be performed in accordance with the DPA incorporated herein.

-

9.3 Data Security (Cloud Services)

+

+ 9.3 Data Security (Cloud Services) +

We implement industry-standard security measures to protect Customer Data in our Cloud Services, including encryption in transit and at @@ -437,7 +442,9 @@ export default function TermsOfServicePage() { .

-

9.4 Data Security (On-Premise Software)

+

+ 9.4 Data Security (On-Premise Software) +

For On-Premise Software, Customer is solely responsible for implementing appropriate security measures, including encryption, @@ -464,8 +471,8 @@ export default function TermsOfServicePage() { "DPA") attached hereto as Appendix I and is incorporated by reference. The DPA applies only to the extent that the Services involve the processing of Personal Data on behalf of the customer. In - the event of a conflict between these terms and the DPA, the DPA - shall prevail solely with respect to the Processing of Personal Data. + the event of a conflict between these terms and the DPA, the DPA shall + prevail solely with respect to the Processing of Personal Data.

@@ -530,10 +537,9 @@ export default function TermsOfServicePage() {

11.1 Definition

"Confidential Information" means any non-public information - disclosed by one party to the other that is designated as - confidential or that a reasonable person would understand to be - confidential, including pricing, business plans, technical data, and - Customer Data. + disclosed by one party to the other that is designated as confidential + or that a reasonable person would understand to be confidential, + including pricing, business plans, technical data, and Customer Data.

11.2 Obligations

@@ -565,9 +571,9 @@ export default function TermsOfServicePage() {

Confidentiality obligations do not apply to information that: (a) is or becomes publicly available without breach; (b) was known prior to - disclosure; (c) is received from a third party without - confidentiality restrictions; or (d) is independently developed - without use of Confidential Information. + disclosure; (c) is received from a third party without confidentiality + restrictions; or (d) is independently developed without use of + Confidential Information.

@@ -578,10 +584,10 @@ export default function TermsOfServicePage() {

The Services may integrate with or rely upon third-party services, including container registries, cloud providers, and external APIs. - Your use of third-party services is subject to their respective - terms and conditions. We are not responsible for the availability, - accuracy, or content of third-party services, and we make no - warranties regarding them. + Your use of third-party services is subject to their respective terms + and conditions. We are not responsible for the availability, accuracy, + or content of third-party services, and we make no warranties + regarding them.

@@ -594,23 +600,25 @@ export default function TermsOfServicePage() { These Terms commence upon your first use of the Services and continue until terminated. Subscription Terms automatically renew for successive periods of the same duration unless either party provides - written notice of non-renewal at least thirty [30] days before the - end of the current term. + written notice of non-renewal at least thirty [30] days before the end + of the current term.

-

13.2 Termination for Convenience

+

+ 13.2 Termination for Convenience +

You may terminate your subscription at any time and without cause by providing thirty (30) days written notice. If you terminate for convenience under this Section, you will remain liable for the full - balance of fees due for the remainder of the Term of the Agreement. - No refunds are provided for unused portions of prepaid fees except as + balance of fees due for the remainder of the Term of the Agreement. No + refunds are provided for unused portions of prepaid fees except as expressly stated in Section 6.5.

13.3 Termination for Cause

Either party may terminate this Agreement for the other's - material breach by written notice specifying, in detail, the nature - of the breach. The breaching party will have thirty (30) days from the + material breach by written notice specifying, in detail, the nature of + the breach. The breaching party will have thirty (30) days from the date the party receives notice of the breach to cure the breach. If the breaching party fails to cure the breach within thirty (30) days, the other party may terminate at the expiration of the cure period. @@ -635,8 +643,8 @@ export default function TermsOfServicePage() { control; (c) you may export Customer Data for thirty [30] days as provided in Section 9.6; (d) each party must return or destroy the other party's Confidential Information. Sections that by their - nature should survive termination shall survive, including Sections - 9, 10, 11, 14, 15, and 16. + nature should survive termination shall survive, including Sections 9, + 10, 11, 14, 15, and 16.

@@ -663,15 +671,14 @@ export default function TermsOfServicePage() { error-free, or completely secure. Without limiting the generality of the foregoing, we have no obligation to indemnify, defend, or hold harmless Customer, including without limitation against claims related - to product liability or infringement of intellectual property - rights, unless this Agreement specifically provides for such an - indemnity. + to product liability or infringement of intellectual property rights, + unless this Agreement specifically provides for such an indemnity.

14.3 Beta Features

- Beta, preview, or experimental features are provided "as - is" without any warranty. We may modify or discontinue beta - features at any time without notice. + Beta, preview, or experimental features are provided "as is" + without any warranty. We may modify or discontinue beta features at + any time without notice.

@@ -736,17 +743,17 @@ export default function TermsOfServicePage() {

17.1 Governing Law

- These Terms shall be governed by and construed in accordance with - the laws of the State of Delaware, United States, without regard to - its conflict of law principles. + These Terms shall be governed by and construed in accordance with the + laws of the State of Delaware, United States, without regard to its + conflict of law principles.

17.2 Dispute Resolution

- [OPTION 1 - ARBITRATION: Any dispute arising from these Terms shall - be resolved by binding arbitration administered by AAA in accordance - with its Commercial Arbitration Rules. The arbitration shall be - conducted in the State of Delaware. The arbitrator's decision - shall be final and binding.] + [OPTION 1 - ARBITRATION: Any dispute arising from these Terms shall be + resolved by binding arbitration administered by AAA in accordance with + its Commercial Arbitration Rules. The arbitration shall be conducted + in the State of Delaware. The arbitrator's decision shall be + final and binding.]

17.3 Waiver of Jury Trial

@@ -764,8 +771,8 @@ export default function TermsOfServicePage() { will provide at least thirty [30] days' notice via email or through the Services. Your continued use of the Services after the effective date of changes constitutes acceptance of the updated Terms. - If you do not agree to the changes, you may terminate your subscription - before the changes take effect. + If you do not agree to the changes, you may terminate your + subscription before the changes take effect.

@@ -778,8 +785,8 @@ export default function TermsOfServicePage() { This Agreement is the parties' entire agreement regarding its subject matter and supersedes any prior or contemporaneous agreements regarding its subject matter. In this Agreement, headings are for - convenience only and "including" and similar terms are to - be construed without limitation. Excluding Orders, terms in business + convenience only and "including" and similar terms are to be + construed without limitation. Excluding Orders, terms in business forms, purchase orders or quotes used by either party will not amend or modify this Agreement; any such documents are for administrative purposes only. This Agreement may be executed in counterparts @@ -803,22 +810,25 @@ export default function TermsOfServicePage() { Neither party may assign this Agreement without the prior consent of the other party, except that either party may assign this Agreement, with notice to the other party, in connection with the assigning - party's merger, reorganization, acquisition or other transfer - of all or substantially all of its assets or voting securities. Any + party's merger, reorganization, acquisition or other transfer of + all or substantially all of its assets or voting securities. Any non-permitted assignment is void. This Agreement will bind and inure to the benefit of each party's permitted successors and assigns.

20.5 Notices

- A. Except as set out in this Agreement, notices, requests and approvals - under this Agreement must be in writing to the addresses on the Cover - Page and will be deemed given: (1) upon receipt if by personal - delivery, (2) upon receipt if by certified or registered U.S. mail - (return receipt requested), (3) one day after dispatch if by a - commercial overnight delivery or (4) upon delivery if by email. - Either party may update its address with notice to the other. + A. Except as set out in this Agreement, notices, requests and + approvals under this Agreement must be in writing to the addresses on + the Cover Page and will be deemed given: (1) upon receipt if by + personal delivery, (2) upon receipt if by certified or registered U.S. + mail (return receipt requested), (3) one day after dispatch if by a + commercial overnight delivery or (4) upon delivery if by email. Either + party may update its address with notice to the other. +

+

+ B. Provider may also send operational notices through the Cloud + Service.

-

B. Provider may also send operational notices through the Cloud Service.

20.6 Force Majeure

Neither party is liable for a delay or failure to perform this @@ -846,8 +856,7 @@ export default function TermsOfServicePage() { at:

Dokploy Technologies, Inc.

-

2912 Steiner St Unit 4 - San Francisco, CA 94123

+

2912 Steiner St Unit 4 San Francisco, CA 94123

Email:{" "} "Audit Report" is defined in Section 9.2 below.

  • "Controller" means the natural or legal person, public - authority, agency or other body which, alone or jointly with - others, determines the purposes and means of Processing of - Personal Data. + authority, agency or other body which, alone or jointly with others, + determines the purposes and means of Processing of Personal Data. +
  • +
  • + "Customer Instructions" is defined in Section 3.1 below.
  • -
  • "Customer Instructions" is defined in Section 3.1 below.
  • "Customer Personal Data" means Personal Data in Customer Data (as defined in the Agreement). @@ -900,9 +910,9 @@ export default function TermsOfServicePage() { Privacy Act, as amended by the California Privacy Rights Act, and any binding regulations promulgated thereunder ("CCPA"), (ii) the General Data Protection Regulation (Regulation (EU) - 2016/679) ("EU GDPR" or "GDPR"), (iii) the - Swiss Federal Act on Data Protection ("FADP"), (iv) the EU - GDPR as it forms part of the law of England and Wales by virtue of + 2016/679) ("EU GDPR" or "GDPR"), (iii) the Swiss + Federal Act on Data Protection ("FADP"), (iv) the EU GDPR + as it forms part of the law of England and Wales by virtue of section 3 of the European Union (Withdrawal) Act 2018 (the "UK GDPR") and (v) the UK Data Protection Act 2018; in each case, as updated, amended or replaced from time to time. @@ -916,26 +926,25 @@ export default function TermsOfServicePage() {
  • "DPA Setup Page" means a separate document executed by - Customer and Provider which causes this DPA to become an - Attachment to their Agreement. + Customer and Provider which causes this DPA to become an Attachment + to their Agreement.
  • "EEA" means European Economic Area.
  • "Key Terms" means Agreement, DPA Effective Date and - Subprocessor List as specified by the parties on the DPA Setup - Page. + Subprocessor List as specified by the parties on the DPA Setup Page.
  • "Personal Data" means information about an identified or identifiable natural person or which otherwise constitutes "personal data", "personal information", - "personally identifiable information" or similar terms - as defined in Data Protection Laws. + "personally identifiable information" or similar terms as + defined in Data Protection Laws.
  • "Processing" and inflections thereof refer to any - operation or set of operations that is performed on Personal Data - or on sets of Personal Data, whether or not by automated means. + operation or set of operations that is performed on Personal Data or + on sets of Personal Data, whether or not by automated means.
  • "Processor" means a natural or legal person, public @@ -944,13 +953,13 @@ export default function TermsOfServicePage() {
  • "Restricted Transfer" means: (i) where EU GDPR applies, a - transfer of Customer Personal Data from the EEA to a country - outside the EEA that is not subject to an adequacy determination, - (ii) where UK GDPR applies, a transfer of Customer Personal Data - from the United Kingdom to any other country that is not subject to - an adequacy determination or (iii) where FADP applies, a transfer - of Customer Personal Data from Switzerland to any other country - that is not subject to an adequacy determination. + transfer of Customer Personal Data from the EEA to a country outside + the EEA that is not subject to an adequacy determination, (ii) where + UK GDPR applies, a transfer of Customer Personal Data from the + United Kingdom to any other country that is not subject to an + adequacy determination or (iii) where FADP applies, a transfer of + Customer Personal Data from Switzerland to any other country that is + not subject to an adequacy determination.
  • "Schedules" means one or more schedules incorporated by @@ -977,10 +986,11 @@ export default function TermsOfServicePage() {

    The full DPA continues with sections on Scope and Duration, Processing - of Personal Data, Confidentiality, Compliance with Laws, Subprocessors, - Security, Data Subject Requests, Data Return or Deletion, Audits, and - Cross-Border Transfers/Region-Specific Terms. For the complete - legal text of the Data Processing Addendum, please contact{" "} + of Personal Data, Confidentiality, Compliance with Laws, + Subprocessors, Security, Data Subject Requests, Data Return or + Deletion, Audits, and Cross-Border Transfers/Region-Specific Terms. + For the complete legal text of the Data Processing Addendum, please + contact{" "} = new Set(require("free-email-domains")); interface ContactFormData { - inquiryType: "" | "support" | "sales"; + inquiryType: "" | "support" | "sales" | "other"; deploymentType: "" | "cloud" | "self-hosted"; teamSize: string; serverCount: string; @@ -27,7 +27,7 @@ interface ContactFormData { } interface ContactFormProps { - defaultInquiryType?: "" | "support" | "sales"; + defaultInquiryType?: "" | "support" | "sales" | "other"; onSuccess?: () => void; onCancel?: () => void; showCancelButton?: boolean; @@ -79,8 +79,7 @@ export function ContactForm({ formData.inquiryType === "sales" && FREE_EMAIL_DOMAINS.has(formData.email.split("@")[1]?.toLowerCase()) ) { - newErrors.email = - "Please use your work email address to contact sales"; + newErrors.email = "Please use your work email address to contact sales"; } if (formData.inquiryType === "sales" && !formData.teamSize) { newErrors.teamSize = "Please select your team size"; @@ -195,39 +194,36 @@ export function ContactForm({ ); } - return ( -
    - {!hideInquiryType && ( -

    - )} + return ( + + {!hideInquiryType && ( +
    + + + {errors.inquiryType && ( +

    {errors.inquiryType}

    + )} +
    + )} {formData.inquiryType === "support" && (
    @@ -256,9 +252,7 @@ export function ContactForm({ {errors.deploymentType && ( -

    - {errors.deploymentType} -

    +

    {errors.deploymentType}

    )} {formData.deploymentType === "self-hosted" && ( @@ -345,9 +339,7 @@ export function ContactForm({ {errors.programInterest && ( -

    - {errors.programInterest} -

    +

    {errors.programInterest}

    )}
    @@ -231,7 +229,11 @@ export function PartnerForm() {

    {errors.message}

    )}
    - diff --git a/apps/website/components/SecondaryFeatures.tsx b/apps/website/components/SecondaryFeatures.tsx index 1f86b933..56b4cb6b 100644 --- a/apps/website/components/SecondaryFeatures.tsx +++ b/apps/website/components/SecondaryFeatures.tsx @@ -6,7 +6,7 @@ import { motion } from "framer-motion"; import { Layers, Terminal, Users } from "lucide-react"; import { Container } from "./Container"; interface Feature { - name: string; + name: React.ReactNode; summary: string; description: string; image: string; diff --git a/apps/website/components/comparison-stats.tsx b/apps/website/components/comparison-stats.tsx index 57e5a6f2..95599a31 100644 --- a/apps/website/components/comparison-stats.tsx +++ b/apps/website/components/comparison-stats.tsx @@ -1,9 +1,9 @@ "use client"; -import { useEffect, useState } from "react"; import { Container } from "@/components/Container"; -import NumberTicker from "@/components/ui/number-ticker"; import { Grid } from "@/components/stats"; +import NumberTicker from "@/components/ui/number-ticker"; +import { useEffect, useState } from "react"; const statsValues = { githubStars: 26000, @@ -17,9 +17,7 @@ export function ComparisonStats() { const [dockerDownloads, setDockerDownloads] = useState( statsValues.dockerDownloads, ); - const [contributors, setContributors] = useState( - statsValues.contributors, - ); + const [contributors, setContributors] = useState(statsValues.contributors); useEffect(() => { const fetchStats = async () => { diff --git a/apps/website/components/navigation.tsx b/apps/website/components/navigation.tsx index fbade8bd..d4e1d2a4 100644 --- a/apps/website/components/navigation.tsx +++ b/apps/website/components/navigation.tsx @@ -1,4 +1,4 @@ -const navigation = [ +export const navigation = [ { name: "home", href: "/" }, { name: "features", href: "/features" }, { name: "pricing", href: "/pricing" }, diff --git a/apps/website/components/pricing-legacy.tsx b/apps/website/components/pricing-legacy.tsx index 9469c0a2..855a43ff 100644 --- a/apps/website/components/pricing-legacy.tsx +++ b/apps/website/components/pricing-legacy.tsx @@ -14,10 +14,10 @@ import { import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState } from "react"; -import { Container } from "./Container"; import { ContactFormModal } from "./ContactFormModal"; -import { Badge } from "./ui/badge"; +import { Container } from "./Container"; import AnimatedGradientText from "./ui/animated-gradient-text"; +import { Badge } from "./ui/badge"; import { Button, buttonVariants } from "./ui/button"; import HeroVideoDialog from "./ui/hero-video-dialog"; import { NumberInput } from "./ui/input"; @@ -151,225 +151,228 @@ export function PricingLegacy() { : "lg:py-8", )} > -
    -

    - Free -

    - | -

    - Open Source -

    -
    - -

    - Dokploy Open Source -

    -

    - Install and manage Dokploy UI on your own server. -

    - -
      - {[ - "Complete Flexibility: Install Dokploy UI on your own infrastructure", - "Self-hosted Infrastructure", - "Community Support", - "Access to Core Features", - "Access to All Updates", - "Unlimited Servers", - ].map((feature) => ( -
    • - - {feature} -
    • - ))} -
    • - - - Remote Servers Monitoring - -
    • -
    -
    -
    - - Unlimited Servers - - - Start deploying{" "} - - -
    -
    - -
    - {isAnnual && ( -
    - Recommended 🚀 -
    - )} - - {isAnnual ? (

    - $ {calculatePrice(serverQuantity, isAnnual).toFixed(2)}{" "} - USD + Free

    |

    - ${" "} - {(calculatePrice(serverQuantity, isAnnual) / 12).toFixed( - 2, - )}{" "} - / Month USD + Open Source

    - ) : ( -

    - $ {calculatePrice(serverQuantity, isAnnual).toFixed(2)} USD + +

    + Dokploy Open Source +

    +

    + Install and manage Dokploy UI on your own server.

    - )} -

    - Dokploy Plan -

    -

    + {[ + "Complete Flexibility: Install Dokploy UI on your own infrastructure", + "Self-hosted Infrastructure", + "Community Support", + "Access to Core Features", + "Access to All Updates", + "Unlimited Servers", + ].map((feature) => ( +

  • + + {feature} +
  • + ))} +
  • + + + Remote Servers Monitoring + +
  • + +
    +
    + + Unlimited Servers + + + Start deploying{" "} + + +
    +
    +
    +
    - We manage the Dokploy UI infrastructure, we take care of it - for you. -

    + {isAnnual && ( +
    + Recommended 🚀 +
    + )} -
      +

      + $ {calculatePrice(serverQuantity, isAnnual).toFixed(2)}{" "} + USD +

      + | +

      + ${" "} + {( + calculatePrice(serverQuantity, isAnnual) / 12 + ).toFixed(2)}{" "} + / Month USD +

      +
  • + ) : ( +

    + $ {calculatePrice(serverQuantity, isAnnual).toFixed(2)}{" "} + USD +

    )} - > - {[ - "Managed Hosting: No need to manage your own servers", - "Unlimited Deployments", - "Unlimited Databases", - "Unlimited Applications", - "Unlimited Users", - "Remote Servers Monitoring", - "Priority Support", - ].map((feature, index) => ( -
  • - - {feature} -
  • - ))} - -
    -
    - - No. of {serverQuantity} Servers (You bring the servers) - - - - setOpenVideo(true)}> - - - -
    - setOpenVideo(false)} - className="flex size-4 cursor-pointer self-end text-muted-foreground transition-colors hover:text-primary" - /> -
    -

    - We recommend you to watch the video to understand - the benefits of Dokploy Cloud -

    +

    + Dokploy Plan +

    +

    + We manage the Dokploy UI infrastructure, we take care of it + for you. +

    - -
    -
    -
    -
    +
      + {[ + "Managed Hosting: No need to manage your own servers", + "Unlimited Deployments", + "Unlimited Databases", + "Unlimited Applications", + "Unlimited Users", + "Remote Servers Monitoring", + "Priority Support", + ].map((feature, index) => ( +
    • + + {feature} +
    • + ))} +
    +
    +
    + + No. of {serverQuantity} Servers (You bring the servers) + + + + setOpenVideo(true)}> + + + +
    + setOpenVideo(false)} + className="flex size-4 cursor-pointer self-end text-muted-foreground transition-colors hover:text-primary" + /> +
    +

    + We recommend you to watch the video to understand + the benefits of Dokploy Cloud +

    -
    -
    - setServerQuantity(serverQuantity - 1); - }} - > - - - { - setServerQuantity(e.target.value as unknown as number); - }} - /> +
    + -
    -
    -
    - - Subscribe - + + + { + setServerQuantity( + e.target.value as unknown as number, + ); + }} + /> + + +
    +
    +
    + + Subscribe + +
    -
    - +

    - Custom solutions and dedicated support for your organization. + Custom solutions and dedicated support for your + organization.

      diff --git a/apps/website/components/pricing/PricingFeatureTable.tsx b/apps/website/components/pricing/PricingFeatureTable.tsx index 0c8e4665..c64fce28 100644 --- a/apps/website/components/pricing/PricingFeatureTable.tsx +++ b/apps/website/components/pricing/PricingFeatureTable.tsx @@ -1,8 +1,8 @@ "use client"; -import React from "react"; import { Check } from "lucide-react"; -import { pricingFeatures, type FeatureValue } from "./pricing-data"; +import React from "react"; +import { type FeatureValue, pricingFeatures } from "./pricing-data"; function FeatureCell({ value }: { value: FeatureValue }) { if (value === true) { diff --git a/apps/website/components/pricing/pricing-data.ts b/apps/website/components/pricing/pricing-data.ts index 223de797..ae51652d 100644 --- a/apps/website/components/pricing/pricing-data.ts +++ b/apps/website/components/pricing/pricing-data.ts @@ -10,91 +10,553 @@ export interface FeatureRow { export const pricingFeatures: FeatureRow[] = [ // Application and Compose Deployment - { category: "Application and Compose Deployment", feature: "Application Deployment", hobby: true, startup: true, enterprise: true }, - { category: "Application and Compose Deployment", feature: "Multiple Build Types", hobby: true, startup: true, enterprise: true }, - { category: "Application and Compose Deployment", feature: "Docker Compose Support (Stack & Compose)", hobby: true, startup: true, enterprise: true }, - { category: "Application and Compose Deployment", feature: "Git Integration", hobby: true, startup: true, enterprise: true }, - { category: "Application and Compose Deployment", feature: "Docker Registry Support", hobby: true, startup: true, enterprise: true }, - { category: "Application and Compose Deployment", feature: "Auto Deploy via Webhooks", hobby: true, startup: true, enterprise: true }, - { category: "Application and Compose Deployment", feature: "Preview Deployments", hobby: true, startup: true, enterprise: true }, - { category: "Application and Compose Deployment", feature: "One-Click Templates", hobby: true, startup: true, enterprise: true }, - { category: "Application and Compose Deployment", feature: "Watch Paths", hobby: true, startup: true, enterprise: true }, + { + category: "Application and Compose Deployment", + feature: "Application Deployment", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Application and Compose Deployment", + feature: "Multiple Build Types", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Application and Compose Deployment", + feature: "Docker Compose Support (Stack & Compose)", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Application and Compose Deployment", + feature: "Git Integration", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Application and Compose Deployment", + feature: "Docker Registry Support", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Application and Compose Deployment", + feature: "Auto Deploy via Webhooks", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Application and Compose Deployment", + feature: "Preview Deployments", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Application and Compose Deployment", + feature: "One-Click Templates", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Application and Compose Deployment", + feature: "Watch Paths", + hobby: true, + startup: true, + enterprise: true, + }, // Database Management - { category: "Database Management", feature: "Supported Databases", hobby: true, startup: true, enterprise: true }, - { category: "Database Management", feature: "Database Management", hobby: true, startup: true, enterprise: true }, - { category: "Database Management", feature: "Terminal Access", hobby: true, startup: true, enterprise: true }, - { category: "Database Management", feature: "Database Backups", hobby: "1 backup per database", startup: "Unlimited Backups", enterprise: "Unlimited Backups" }, - { category: "Database Management", feature: "Backup Logs", hobby: true, startup: true, enterprise: true }, - { category: "Database Management", feature: "Custom Docker Images", hobby: true, startup: true, enterprise: true }, - { category: "Database Management", feature: "Resource Limits", hobby: true, startup: true, enterprise: true }, + { + category: "Database Management", + feature: "Supported Databases", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Database Management", + feature: "Database Management", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Database Management", + feature: "Terminal Access", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Database Management", + feature: "Database Backups", + hobby: "1 backup per database", + startup: "Unlimited Backups", + enterprise: "Unlimited Backups", + }, + { + category: "Database Management", + feature: "Backup Logs", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Database Management", + feature: "Custom Docker Images", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Database Management", + feature: "Resource Limits", + hobby: true, + startup: true, + enterprise: true, + }, // Infrastructure and Scaling - { category: "Infrastructure and Scaling", feature: "Multi-Server Support", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Docker Swarm Clusters", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Build Server Support", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Traefik Integration", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Custom Domain Management", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Auto SSL/TLS", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Zero Downtime Deployments", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Registry-based Rollbacks", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Resource Limits", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Volume Management", hobby: true, startup: true, enterprise: true }, - { category: "Infrastructure and Scaling", feature: "Volume Backups", hobby: "1 backup per volume", startup: "Unlimited Backups", enterprise: "Unlimited Backups" }, + { + category: "Infrastructure and Scaling", + feature: "Multi-Server Support", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Docker Swarm Clusters", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Build Server Support", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Traefik Integration", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Custom Domain Management", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Auto SSL/TLS", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Zero Downtime Deployments", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Registry-based Rollbacks", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Resource Limits", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Volume Management", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Infrastructure and Scaling", + feature: "Volume Backups", + hobby: "1 backup per volume", + startup: "Unlimited Backups", + enterprise: "Unlimited Backups", + }, // Monitoring and Logging - { category: "Monitoring and Logging", feature: "Real-time Monitoring", hobby: true, startup: true, enterprise: true }, - { category: "Monitoring and Logging", feature: "Application Logs", hobby: true, startup: true, enterprise: true }, - { category: "Monitoring and Logging", feature: "Deployment Logs", hobby: true, startup: true, enterprise: true }, - { category: "Monitoring and Logging", feature: "Deployment History", hobby: true, startup: true, enterprise: true }, - { category: "Monitoring and Logging", feature: "Queue Management", hobby: true, startup: true, enterprise: true }, + { + category: "Monitoring and Logging", + feature: "Real-time Monitoring", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Monitoring and Logging", + feature: "Application Logs", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Monitoring and Logging", + feature: "Deployment Logs", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Monitoring and Logging", + feature: "Deployment History", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Monitoring and Logging", + feature: "Queue Management", + hobby: true, + startup: true, + enterprise: true, + }, // Automation and Scheduling - { category: "Automation and Scheduling", feature: "Scheduled Jobs", hobby: "1 job per server or container", startup: "Unlimited Jobs", enterprise: "Unlimited Jobs" }, - { category: "Automation and Scheduling", feature: "Docker Cleanup Jobs", hobby: true, startup: true, enterprise: true }, - { category: "Automation and Scheduling", feature: "Custom Scripts", hobby: true, startup: true, enterprise: true }, - { category: "Automation and Scheduling", feature: "CI/CD Integration", hobby: true, startup: true, enterprise: true }, - { category: "Automation and Scheduling", feature: "Run Commands", hobby: true, startup: true, enterprise: true }, + { + category: "Automation and Scheduling", + feature: "Scheduled Jobs", + hobby: "1 job per server or container", + startup: "Unlimited Jobs", + enterprise: "Unlimited Jobs", + }, + { + category: "Automation and Scheduling", + feature: "Docker Cleanup Jobs", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Automation and Scheduling", + feature: "Custom Scripts", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Automation and Scheduling", + feature: "CI/CD Integration", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Automation and Scheduling", + feature: "Run Commands", + hobby: true, + startup: true, + enterprise: true, + }, // Notifications and Alerts - { category: "Notifications and Alerts", feature: "Slack Notifications", hobby: true, startup: true, enterprise: true }, - { category: "Notifications and Alerts", feature: "Discord Notifications", hobby: true, startup: true, enterprise: true }, - { category: "Notifications and Alerts", feature: "Telegram Notifications", hobby: true, startup: true, enterprise: true }, - { category: "Notifications and Alerts", feature: "Email Notifications", hobby: true, startup: true, enterprise: true }, - { category: "Notifications and Alerts", feature: "Webhook Notifications", hobby: true, startup: true, enterprise: true }, - { category: "Notifications and Alerts", feature: "Lark Notifications", hobby: true, startup: true, enterprise: true }, - { category: "Notifications and Alerts", feature: "Gotify Integration", hobby: true, startup: true, enterprise: true }, - { category: "Notifications and Alerts", feature: "Ntfy Integration", hobby: true, startup: true, enterprise: true }, - { category: "Notifications and Alerts", feature: "Event Triggers", hobby: true, startup: true, enterprise: true }, + { + category: "Notifications and Alerts", + feature: "Slack Notifications", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Notifications and Alerts", + feature: "Discord Notifications", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Notifications and Alerts", + feature: "Telegram Notifications", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Notifications and Alerts", + feature: "Email Notifications", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Notifications and Alerts", + feature: "Webhook Notifications", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Notifications and Alerts", + feature: "Lark Notifications", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Notifications and Alerts", + feature: "Gotify Integration", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Notifications and Alerts", + feature: "Ntfy Integration", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Notifications and Alerts", + feature: "Event Triggers", + hobby: true, + startup: true, + enterprise: true, + }, // Security - { category: "Security", feature: "Two-Factor Authentication", hobby: true, startup: true, enterprise: true }, - { category: "Security", feature: "API Key Authentication", hobby: true, startup: true, enterprise: true }, - { category: "Security", feature: "SSH Key Management", hobby: true, startup: true, enterprise: true }, - { category: "Security", feature: "Certificate Management", hobby: true, startup: true, enterprise: true }, - { category: "Security", feature: "Security Audits", hobby: true, startup: true, enterprise: true }, - { category: "Security", feature: "UFW Firewall Guidance", hobby: true, startup: true, enterprise: true }, + { + category: "Security", + feature: "Two-Factor Authentication", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Security", + feature: "API Key Authentication", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Security", + feature: "SSH Key Management", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Security", + feature: "Certificate Management", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Security", + feature: "Security Audits", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Security", + feature: "UFW Firewall Guidance", + hobby: true, + startup: true, + enterprise: true, + }, // User and Organization Management - { category: "User and Organization Management", feature: "User Management", hobby: "1 user", startup: "Unlimited", enterprise: "Unlimited" }, - { category: "User and Organization Management", feature: "Organizations", hobby: "1 Organizations", startup: "3 Organizations", enterprise: "10+ Organizations" }, - { category: "User and Organization Management", feature: "Projects", hobby: true, startup: true, enterprise: true }, - { category: "User and Organization Management", feature: "Environment", hobby: "2 Environments", startup: "Unlimited", enterprise: "Unlimited" }, - { category: "User and Organization Management", feature: "Role-based Permissions", hobby: "NA", startup: "Admin, Developer", enterprise: "Admin, Developer" }, - { category: "User and Organization Management", feature: "Social Login", hobby: "Google, Github, Gitlab", startup: "Google, Github, Gitlab", enterprise: "SSO (Okta, Azure, and more)" }, + { + category: "User and Organization Management", + feature: "User Management", + hobby: "1 user", + startup: "Unlimited", + enterprise: "Unlimited", + }, + { + category: "User and Organization Management", + feature: "Organizations", + hobby: "1 Organizations", + startup: "3 Organizations", + enterprise: "10+ Organizations", + }, + { + category: "User and Organization Management", + feature: "Projects", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "User and Organization Management", + feature: "Environment", + hobby: "2 Environments", + startup: "Unlimited", + enterprise: "Unlimited", + }, + { + category: "User and Organization Management", + feature: "Role-based Permissions", + hobby: "NA", + startup: "Admin, Developer", + enterprise: "Admin, Developer", + }, + { + category: "User and Organization Management", + feature: "Social Login", + hobby: "Google, Github, Gitlab", + startup: "Google, Github, Gitlab", + enterprise: "SSO (Okta, Azure, and more)", + }, // Developer Tools - { category: "Developer Tools", feature: "REST API", hobby: true, startup: true, enterprise: true }, - { category: "Developer Tools", feature: "CLI Tool", hobby: true, startup: true, enterprise: true }, - { category: "Developer Tools", feature: "Environment Variables", hobby: true, startup: true, enterprise: true }, - { category: "Developer Tools", feature: "Container Terminal", hobby: true, startup: true, enterprise: true }, - { category: "Developer Tools", feature: "Keyboard Shortcuts", hobby: true, startup: true, enterprise: true }, - { category: "Developer Tools", feature: "Swagger Documentation", hobby: true, startup: true, enterprise: true }, + { + category: "Developer Tools", + feature: "REST API", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Developer Tools", + feature: "CLI Tool", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Developer Tools", + feature: "Environment Variables", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Developer Tools", + feature: "Container Terminal", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Developer Tools", + feature: "Keyboard Shortcuts", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Developer Tools", + feature: "Swagger Documentation", + hobby: true, + startup: true, + enterprise: true, + }, // Advanced Configuration - { category: "Advanced Configuration", feature: "Swarm Settings", hobby: true, startup: true, enterprise: true }, - { category: "Advanced Configuration", feature: "Health Checks", hobby: true, startup: true, enterprise: true }, - { category: "Advanced Configuration", feature: "Network Configuration", hobby: true, startup: true, enterprise: true }, - { category: "Advanced Configuration", feature: "Container Labels", hobby: true, startup: true, enterprise: true }, - { category: "Advanced Configuration", feature: "Traefik File Editor", hobby: true, startup: true, enterprise: true }, - { category: "Advanced Configuration", feature: "Port Configuration", hobby: true, startup: true, enterprise: true }, - { category: "Advanced Configuration", feature: "Security Headers", hobby: true, startup: true, enterprise: true }, - { category: "Advanced Configuration", feature: "Redirects", hobby: true, startup: true, enterprise: true }, + { + category: "Advanced Configuration", + feature: "Swarm Settings", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Advanced Configuration", + feature: "Health Checks", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Advanced Configuration", + feature: "Network Configuration", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Advanced Configuration", + feature: "Container Labels", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Advanced Configuration", + feature: "Traefik File Editor", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Advanced Configuration", + feature: "Port Configuration", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Advanced Configuration", + feature: "Security Headers", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Advanced Configuration", + feature: "Redirects", + hobby: true, + startup: true, + enterprise: true, + }, // Support and Services - { category: "Support and Services", feature: "Community Support", hobby: true, startup: true, enterprise: true }, - { category: "Support and Services", feature: "Email and Chat Support", hobby: false, startup: true, enterprise: true }, - { category: "Support and Services", feature: "Phone & Video Support", hobby: false, startup: false, enterprise: true }, - { category: "Support and Services", feature: "SLA", hobby: "Online T&C's", startup: "Online T&C's", enterprise: true }, - { category: "Support and Services", feature: "MSA", hobby: "Online T&C's", startup: "Online T&C's", enterprise: true }, + { + category: "Support and Services", + feature: "Community Support", + hobby: true, + startup: true, + enterprise: true, + }, + { + category: "Support and Services", + feature: "Email and Chat Support", + hobby: false, + startup: true, + enterprise: true, + }, + { + category: "Support and Services", + feature: "Phone & Video Support", + hobby: false, + startup: false, + enterprise: true, + }, + { + category: "Support and Services", + feature: "SLA", + hobby: "Online T&C's", + startup: "Online T&C's", + enterprise: true, + }, + { + category: "Support and Services", + feature: "MSA", + hobby: "Online T&C's", + startup: "Online T&C's", + enterprise: true, + }, ]; diff --git a/apps/website/components/stats.tsx b/apps/website/components/stats.tsx index 23e62a88..5a41bf0d 100644 --- a/apps/website/components/stats.tsx +++ b/apps/website/components/stats.tsx @@ -17,9 +17,7 @@ export function StatsSection() { const [dockerDownloads, setDockerDownloads] = useState( defaultStats.dockerDownloads, ); - const [contributors, setContributors] = useState( - defaultStats.contributors, - ); + const [contributors, setContributors] = useState(defaultStats.contributors); useEffect(() => { const fetchStats = async () => { diff --git a/apps/website/components/ui/navigation-menu.tsx b/apps/website/components/ui/navigation-menu.tsx index cc2d9163..303ebbb9 100644 --- a/apps/website/components/ui/navigation-menu.tsx +++ b/apps/website/components/ui/navigation-menu.tsx @@ -1,137 +1,137 @@ -import * as React from "react" -import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu" -import { cva } from "class-variance-authority" -import { ChevronDown } from "lucide-react" +import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"; +import { cva } from "class-variance-authority"; +import { ChevronDown } from "lucide-react"; +import * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const NavigationMenu = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - {children} - -)) -NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName + + {children} + +)); +NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName; const NavigationMenuList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName + +)); +NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName; const NavigationMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -NavigationMenuItem.displayName = NavigationMenuPrimitive.Item.displayName + +)); +NavigationMenuItem.displayName = NavigationMenuPrimitive.Item.displayName; const navigationMenuTriggerStyle = cva( - "group inline-flex h-8 w-max items-center justify-center rounded-md bg-transparent px-3.5 py-1.5 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:bg-accent/50 data-[state=open]:hover:bg-accent data-[state=open]:focus:bg-accent" -) + "group inline-flex h-8 w-max items-center justify-center rounded-md bg-transparent px-3.5 py-1.5 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:bg-accent/50 data-[state=open]:hover:bg-accent data-[state=open]:focus:bg-accent", +); const NavigationMenuTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - {children}{" "} - -)) -NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName + + {children}{" "} + +)); +NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName; const NavigationMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName + +)); +NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName; -const NavigationMenuLink = NavigationMenuPrimitive.Link +const NavigationMenuLink = NavigationMenuPrimitive.Link; const NavigationMenuViewport = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( -
      - -
      -)) +
      + +
      +)); NavigationMenuViewport.displayName = - NavigationMenuPrimitive.Viewport.displayName + NavigationMenuPrimitive.Viewport.displayName; const NavigationMenuIndicator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -
      - -)) + +
      + +)); NavigationMenuIndicator.displayName = - NavigationMenuPrimitive.Indicator.displayName + NavigationMenuPrimitive.Indicator.displayName; export { - navigationMenuTriggerStyle, - NavigationMenu, - NavigationMenuList, - NavigationMenuItem, - NavigationMenuContent, - NavigationMenuTrigger, - NavigationMenuLink, - NavigationMenuIndicator, - NavigationMenuViewport, -} + navigationMenuTriggerStyle, + NavigationMenu, + NavigationMenuList, + NavigationMenuItem, + NavigationMenuContent, + NavigationMenuTrigger, + NavigationMenuLink, + NavigationMenuIndicator, + NavigationMenuViewport, +}; diff --git a/apps/website/components/ui/ripple.tsx b/apps/website/components/ui/ripple.tsx index 6e52e09c..94fd540f 100644 --- a/apps/website/components/ui/ripple.tsx +++ b/apps/website/components/ui/ripple.tsx @@ -97,7 +97,7 @@ const Ripple = React.memo(function Ripple({ link: "https://cloudblast.io/?ref=dokploy", type: "supporting", }, - + { name: "Synexa", image: @@ -119,7 +119,7 @@ const Ripple = React.memo(function Ripple({ }, ]; - const communitySponsors = []; + const communitySponsors: { name: string; image: string; link: string }[] = []; return (
      { } } -export async function getTags() { +export async function getTags(): Promise<{ slug: string; name: string }[]> { try { const result = await api.tags.browse(); - return result; + return result as { slug: string; name: string }[]; } catch (error) { console.error("Error fetching tags:", error); return []; } } -export async function getPostsByTag(tag: string) { +export async function getPostsByTag(tag: string): Promise { try { const result = await api.posts.browse({ limit: "all", filter: `tag:${tag}`, include: ["tags", "authors"], }); - return result; + return result as Post[]; } catch (error) { console.error(`Error fetching posts with tag ${tag}:`, error); return []; diff --git a/apps/website/lib/hooks/use-debounce.ts b/apps/website/lib/hooks/use-debounce.ts index a0f1c0cf..84751705 100644 --- a/apps/website/lib/hooks/use-debounce.ts +++ b/apps/website/lib/hooks/use-debounce.ts @@ -4,7 +4,7 @@ export function useDebounce any>( callback: T, delay: number, ): T { - const timeoutRef = useRef(); + const timeoutRef = useRef(undefined); useEffect(() => { return () => { diff --git a/apps/website/lib/slack.ts b/apps/website/lib/slack.ts index c706ec23..2619dc0b 100644 --- a/apps/website/lib/slack.ts +++ b/apps/website/lib/slack.ts @@ -31,9 +31,7 @@ interface SlackBlock { /** * Format contact form data as a Slack message with blocks */ -function formatContactDataForSlack( - contactData: ContactFormData, -): SlackMessage { +function formatContactDataForSlack(contactData: ContactFormData): SlackMessage { // Get emoji and label based on inquiry type let inquiryTypeEmoji: string; let inquiryTypeLabel: string; @@ -153,9 +151,7 @@ export async function notifySlack( const webhookUrl = process.env.SLACK_WEBHOOK_URL; if (!webhookUrl) { - console.warn( - "Slack webhook URL is not configured (SLACK_WEBHOOK_URL)", - ); + console.warn("Slack webhook URL is not configured (SLACK_WEBHOOK_URL)"); return false; } diff --git a/apps/website/package.json b/apps/website/package.json index 67d0fcfd..65f75119 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -35,7 +35,7 @@ "axios": "^1.20.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", - "framer-motion": "^11.3.19", + "framer-motion": "^11.18.2", "free-email-domains": "^1.2.26", "hast-util-to-jsx-runtime": "^2.3.5", "lucide-react": "0.364.0", diff --git a/apps/website/tsconfig.json b/apps/website/tsconfig.json index ad63ce60..4263b3c5 100644 --- a/apps/website/tsconfig.json +++ b/apps/website/tsconfig.json @@ -1,42 +1,34 @@ { - "compilerOptions": { - "target": "es6", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": [ - "./*" - ] - } - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts" - ], - "exclude": [ - "node_modules" - ] + "compilerOptions": { + "target": "es6", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] } diff --git a/biome.json b/biome.json index a6fa0857..d2c602d2 100644 --- a/biome.json +++ b/biome.json @@ -7,7 +7,8 @@ ".next/**", "drizzle/**", ".docker", - "dist" + "dist", + "apps/docs/public/openapi.json" ] }, "organizeImports": { diff --git a/package.json b/package.json index d27755a8..e3765856 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,7 @@ { "name": "website", "private": true, - "workspaces": [ - "apps/*", - "packages/*" - ], + "workspaces": ["apps/*", "packages/*"], "scripts": { "docs:dev": "pnpm --filter=docs run dev", "docs:build": "pnpm --filter=docs run build", @@ -37,9 +34,7 @@ ] }, "commitlint": { - "extends": [ - "@commitlint/config-conventional" - ] + "extends": ["@commitlint/config-conventional"] }, "resolutions": { "@babel/core@<7.29.6": "^7.29.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1e037e1..29e28928 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -199,8 +199,8 @@ importers: specifier: ^2.1.0 version: 2.1.1 framer-motion: - specifier: ^11.3.19 - version: 11.3.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + specifier: ^11.18.2 + version: 11.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) free-email-domains: specifier: ^1.2.26 version: 1.2.26 @@ -2846,12 +2846,12 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@11.3.19: - resolution: {integrity: sha512-+luuQdx4AsamyMcvzW7jUAJYIKvQs1KE7oHvKkW3eNzmo0S+3PSDWjBuQkuIP9WyneGnKGMLUSuHs8OP7jKpQg==} + framer-motion@11.18.2: + resolution: {integrity: sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==} peerDependencies: '@emotion/is-prop-valid': '*' - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@emotion/is-prop-valid': optional: true @@ -2994,7 +2994,7 @@ packages: git-raw-commits@4.0.0: resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} engines: {node: '>=16'} - deprecated: Deprecated and no longer maintained. Use @conventional-changelog/git-client instead. + deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead. hasBin: true github-slugger@2.0.0: @@ -3601,6 +3601,12 @@ packages: mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + motion-dom@11.18.1: + resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==} + + motion-utils@11.18.1: + resolution: {integrity: sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==} + ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -6951,9 +6957,11 @@ snapshots: fraction.js@4.3.7: {} - framer-motion@11.3.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + framer-motion@11.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - tslib: 2.6.3 + motion-dom: 11.18.1 + motion-utils: 11.18.1 + tslib: 2.8.1 optionalDependencies: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) @@ -8024,6 +8032,12 @@ snapshots: mitt@3.0.1: {} + motion-dom@11.18.1: + dependencies: + motion-utils: 11.18.1 + + motion-utils@11.18.1: {} + ms@2.1.2: {} ms@2.1.3: {}
    Category + Category + Dokploy Vercel