mirror of
https://github.com/Dokploy/website.git
synced 2026-06-15 20:25:25 +02:00
Merge branch 'main' into patch-1
This commit is contained in:
@@ -167,7 +167,7 @@ install_dokploy() {
|
||||
--restart always \
|
||||
-v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
|
||||
-v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
-p 80:80/tcp \
|
||||
-p 443:443/tcp \
|
||||
-p 443:443/udp \
|
||||
@@ -183,7 +183,7 @@ install_dokploy() {
|
||||
# --network dokploy-network \
|
||||
# --mount type=bind,source=/etc/dokploy/traefik/traefik.yml,target=/etc/traefik/traefik.yml \
|
||||
# --mount type=bind,source=/etc/dokploy/traefik/dynamic,target=/etc/dokploy/traefik/dynamic \
|
||||
# --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
|
||||
# --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,readonly \
|
||||
# --publish mode=host,published=443,target=443 \
|
||||
# --publish mode=host,published=80,target=80 \
|
||||
# --publish mode=host,published=443,target=443,protocol=udp \
|
||||
|
||||
@@ -472,7 +472,7 @@ docker run -d \
|
||||
--restart always \
|
||||
-v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
|
||||
-v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
-p 80:80/tcp \
|
||||
-p 443:443/tcp \
|
||||
-p 443:443/udp \
|
||||
@@ -486,15 +486,14 @@ docker service rm dokploy-traefik
|
||||
# Create a new dokploy-traefik service
|
||||
docker service create \
|
||||
--name dokploy-traefik \
|
||||
--constraint 'node.role == manager' \
|
||||
--replicas 1 \
|
||||
--constraint 'node.role==manager' \
|
||||
--network dokploy-network \
|
||||
--publish published=80,target=80,mode=host \
|
||||
--publish published=443,target=443,mode=host \
|
||||
--mount type=bind,source=/etc/dokploy/traefik/traefik.yml,target=/etc/traefik/traefik.yml \
|
||||
--mount type=bind,source=/etc/dokploy/traefik/dynamic,target=/etc/dokploy/traefik/dynamic \
|
||||
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
|
||||
--label traefik.enable=true \
|
||||
--publish mode=host,published=443,target=443 \
|
||||
--publish mode=host,published=80,target=80 \
|
||||
--publish mode=host,published=443,target=443,protocol=udp \
|
||||
traefik:v3.6.1
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
export default function CatchAll() {
|
||||
notFound();
|
||||
}
|
||||
77
apps/website/app/api/github-stars/route.ts
Normal file
77
apps/website/app/api/github-stars/route.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// Cache the result for 5 minutes to avoid rate limiting
|
||||
let cachedStars: { count: number; timestamp: number } | null = null;
|
||||
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes in milliseconds
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const owner = searchParams.get("owner");
|
||||
const repo = searchParams.get("repo");
|
||||
|
||||
if (!owner || !repo) {
|
||||
return NextResponse.json(
|
||||
{ error: "Owner and repo parameters are required" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
// Check if we have a valid cached result
|
||||
if (
|
||||
cachedStars &&
|
||||
Date.now() - cachedStars.timestamp < CACHE_DURATION
|
||||
) {
|
||||
return NextResponse.json(
|
||||
{ stargazers_count: cachedStars.count },
|
||||
{
|
||||
headers: {
|
||||
"Cache-Control": "public, s-maxage=300, stale-while-revalidate=600",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://api.github.com/repos/${owner}/${repo}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
"User-Agent": "Dokploy-Website",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to fetch repository data" },
|
||||
{ status: response.status },
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const starCount = data.stargazers_count;
|
||||
|
||||
// Cache the result
|
||||
cachedStars = {
|
||||
count: starCount,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
return NextResponse.json(
|
||||
{ stargazers_count: starCount },
|
||||
{
|
||||
headers: {
|
||||
"Cache-Control": "public, s-maxage=300, stale-while-revalidate=600",
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error fetching GitHub stars:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ export async function GET(request: NextRequest) {
|
||||
return new Response("Post not found", { status: 404 });
|
||||
}
|
||||
|
||||
console.log("Found post:", post.title);
|
||||
|
||||
const formattedDate = new Date(post.published_at).toLocaleDateString(
|
||||
"en-US",
|
||||
@@ -44,8 +43,6 @@ export async function GET(request: NextRequest) {
|
||||
readingTime: post.reading_time,
|
||||
});
|
||||
|
||||
console.log("Successfully generated OG image");
|
||||
|
||||
return new Response(ogImage, {
|
||||
headers: {
|
||||
"Content-Type": "image/png",
|
||||
|
||||
@@ -17,7 +17,6 @@ import { CodeBlock } from "./components/CodeBlock";
|
||||
import { H1, H2, H3 } from "./components/Headings";
|
||||
import { TableOfContents } from "./components/TableOfContents";
|
||||
import { ZoomableImage } from "./components/ZoomableImage";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
|
||||
type Props = {
|
||||
params: { slug: string };
|
||||
@@ -72,7 +71,6 @@ export async function generateMetadata(
|
||||
|
||||
export default async function BlogPostPage({ params }: Props) {
|
||||
const { slug } = await params;
|
||||
const t = useTranslations("blog");
|
||||
const post = await getPost(slug);
|
||||
const allPosts = await getPosts();
|
||||
|
||||
@@ -233,7 +231,7 @@ export default async function BlogPostPage({ params }: Props) {
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
{t("backToBlog")}
|
||||
Back to Blog
|
||||
</Link>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_250px] gap-8">
|
||||
@@ -313,7 +311,7 @@ export default async function BlogPostPage({ params }: Props) {
|
||||
|
||||
{post.tags && post.tags.length > 0 && (
|
||||
<div className="mt-12 pt-6 border-t border-border">
|
||||
<h2 className="text-xl font-semibold mb-4">{t("tags")}</h2>
|
||||
<h2 className="text-xl font-semibold mb-4">Tags</h2>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{post.tags.map((tag) => (
|
||||
<Link
|
||||
@@ -338,7 +336,7 @@ export default async function BlogPostPage({ params }: Props) {
|
||||
|
||||
{relatedPosts.length > 0 && (
|
||||
<div className="mt-12">
|
||||
<h2 className="text-2xl font-bold mb-6">{t("relatedPosts")}</h2>
|
||||
<h2 className="text-2xl font-bold mb-6">Related Posts</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{relatedPosts.map((relatedPost) => {
|
||||
const relatedPostDate = new Date(
|
||||
|
||||
@@ -5,7 +5,6 @@ import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { BlogPostCard } from "./components/BlogPostCard";
|
||||
import { SearchAndFilter } from "./components/SearchAndFilter";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
|
||||
interface Tag {
|
||||
id: string;
|
||||
@@ -14,7 +13,7 @@ interface Tag {
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Blog | Dokploy",
|
||||
title: "Blog",
|
||||
description: "Latest news, updates, and articles from Dokploy",
|
||||
};
|
||||
|
||||
@@ -24,7 +23,6 @@ export default async function BlogPage({
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
}) {
|
||||
const searchParams2 = await searchParams;
|
||||
const t = useTranslations("blog");
|
||||
const posts = await getPosts();
|
||||
const tags = (await getTags()) as Tag[];
|
||||
const search =
|
||||
@@ -61,21 +59,21 @@ export default async function BlogPage({
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<SearchAndFilter
|
||||
tags={tags}
|
||||
initialSearch={search}
|
||||
initialTag={selectedTag}
|
||||
searchPlaceholder={t("searchPlaceholder")}
|
||||
allTagsText={t("allTags")}
|
||||
/>
|
||||
<SearchAndFilter
|
||||
tags={tags}
|
||||
initialSearch={search}
|
||||
initialTag={selectedTag}
|
||||
searchPlaceholder="Search posts..."
|
||||
allTagsText="All Tags"
|
||||
/>
|
||||
|
||||
{filteredPosts.length === 0 ? (
|
||||
<div className="text-center py-12 min-h-[20vh] flex items-center justify-center">
|
||||
<p className="text-xl text-muted-foreground">
|
||||
{search || selectedTag ? t("noResults") : t("noPosts")}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
{filteredPosts.length === 0 ? (
|
||||
<div className="text-center py-12 min-h-[20vh] flex items-center justify-center">
|
||||
<p className="text-xl text-muted-foreground">
|
||||
{search || selectedTag ? "No posts found matching your criteria" : "No posts available"}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-8">
|
||||
{filteredPosts.map((post: Post) => (
|
||||
<BlogPostCard key={post.id} post={post} />
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { Metadata } from "next";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
|
||||
type Props = {
|
||||
params: { tag: string };
|
||||
@@ -12,11 +11,21 @@ type Props = {
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { tag } = await params;
|
||||
const t = useTranslations("blog");
|
||||
const posts = await getPostsByTag(tag);
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return {
|
||||
title: "Tag Not Found",
|
||||
description: "The requested tag could not be found",
|
||||
};
|
||||
}
|
||||
|
||||
const tagName =
|
||||
posts[0].tags?.find((t: { slug: string }) => t.slug === tag)?.name || tag;
|
||||
|
||||
return {
|
||||
title: `${t("tagTitle", { tag })}`,
|
||||
description: t("tagDescription", { tag }),
|
||||
title: `${tagName} Posts`,
|
||||
description: `Browse all posts tagged with ${tagName}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +36,6 @@ export async function generateStaticParams() {
|
||||
|
||||
export default async function TagPage({ params }: Props) {
|
||||
const { tag } = await params;
|
||||
const t = useTranslations("blog");
|
||||
const posts = await getPostsByTag(tag);
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
@@ -55,16 +63,16 @@ export default async function TagPage({ params }: Props) {
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
{t("backToBlog")}
|
||||
Back to Blog
|
||||
</Link>
|
||||
|
||||
<div className="mb-8">
|
||||
<h1 className="text-3xl font-bold mb-2">
|
||||
{t("postsTaggedWith")}{" "}
|
||||
Posts tagged with{" "}
|
||||
<span className="text-primary-600">"{tagName}"</span>
|
||||
</h1>
|
||||
<p className="text-gray-600 dark:text-gray-400">
|
||||
{t("foundPosts", { count: posts.length })}
|
||||
{posts.length} {posts.length === 1 ? 'post' : 'posts'} found
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
13
apps/website/app/contact/layout.tsx
Normal file
13
apps/website/app/contact/layout.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { Metadata } from "next";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Contact Us",
|
||||
description:
|
||||
"Get in touch with our team. We're here to help with any questions about Dokploy.",
|
||||
};
|
||||
|
||||
export default function ContactLayout({ children }: { children: ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
@@ -12,27 +12,30 @@ type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
// export const metadata: Metadata = {
|
||||
// metadataBase: new URL("https://dokploy.com"),
|
||||
// title: "Dokploy - Deploy your applications with ease",
|
||||
// description: "Deploy your applications with ease using Dokploy",
|
||||
// icons: {
|
||||
// icon: "icon.svg",
|
||||
// apple: "apple-touch-icon.png",
|
||||
// },
|
||||
// openGraph: {
|
||||
// title: "Dokploy - Deploy your applications with ease",
|
||||
// description: "Deploy your applications with ease using Dokploy",
|
||||
// images: "favicon.ico",
|
||||
// type: "website",
|
||||
// },
|
||||
// twitter: {
|
||||
// card: "summary_large_image",
|
||||
// title: "Dokploy - Deploy your applications with ease",
|
||||
// description: "Deploy your applications with ease using Dokploy",
|
||||
// images: ["/og.png"],
|
||||
// },
|
||||
// };
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL("https://dokploy.com"),
|
||||
title: {
|
||||
default: "Dokploy - Deploy your applications with ease",
|
||||
template: "%s | Dokploy",
|
||||
},
|
||||
description: "Deploy your applications with ease using Dokploy",
|
||||
icons: {
|
||||
icon: "icon.svg",
|
||||
apple: "apple-touch-icon.png",
|
||||
},
|
||||
openGraph: {
|
||||
title: "Dokploy - Deploy your applications with ease",
|
||||
description: "Deploy your applications with ease using Dokploy",
|
||||
images: "/og.png",
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Dokploy - Deploy your applications with ease",
|
||||
description: "Deploy your applications with ease using Dokploy",
|
||||
images: ["/og.png"],
|
||||
},
|
||||
};
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
display: "swap",
|
||||
|
||||
@@ -7,6 +7,14 @@ import { Pricing } from "@/components/pricing";
|
||||
import { SecondaryFeaturesSections } from "@/components/secondary-features";
|
||||
import { Sponsors } from "@/components/sponsors";
|
||||
import { StatsSection } from "@/components/stats";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
absolute: "Dokploy - Deploy your applications with ease",
|
||||
},
|
||||
description: "Open-source self-hostable Platform as a Service (PaaS) that simplifies the deployment and management of applications and databases",
|
||||
};
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
export default function Home() {
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Privacy Policy",
|
||||
description:
|
||||
"Learn about how Dokploy collects, uses, and safeguards your personal information when you use our website and services.",
|
||||
};
|
||||
|
||||
export default function PrivacyPage() {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 w-full max-w-4xl mx-auto">
|
||||
<div className="flex flex-col gap-4 w-full max-w-4xl mx-auto py-12 px-4">
|
||||
<h1 className="text-3xl font-bold text-center mb-6">Privacy</h1>
|
||||
|
||||
<section className="flex flex-col gap-2">
|
||||
@@ -97,7 +105,7 @@ export default function Home() {
|
||||
please contact us at:
|
||||
</p>
|
||||
<p className="mb-4">
|
||||
Email:
|
||||
Email:{" "}
|
||||
<a
|
||||
href="mailto:support@dokploy.com"
|
||||
className="text-blue-500 hover:underline"
|
||||
@@ -109,3 +117,4 @@ export default function Home() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
export default function Home() {
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Terms and Conditions",
|
||||
description:
|
||||
"Read the terms and conditions for using Dokploy's website and services.",
|
||||
};
|
||||
|
||||
export default function TermsPage() {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 w-full max-w-4xl mx-auto">
|
||||
<div className="flex flex-col gap-4 w-full max-w-4xl mx-auto py-12 px-4">
|
||||
<h1 className="text-3xl font-bold text-center mb-6">
|
||||
Terms and Conditions
|
||||
</h1>
|
||||
@@ -8,7 +16,7 @@ export default function Home() {
|
||||
<section className="flex flex-col gap-2">
|
||||
<p>
|
||||
Welcome to Dokploy! These Terms and Conditions outline the rules and
|
||||
regulations for the use of Dokploy’s website and services.
|
||||
regulations for the use of Dokploy's website and services.
|
||||
</p>
|
||||
<p>
|
||||
By accessing or using our services, you agree to be bound by the
|
||||
@@ -180,7 +188,7 @@ export default function Home() {
|
||||
These Terms & Conditions are governed by applicable laws based on the
|
||||
user's location. Any disputes arising under these terms will be
|
||||
resolved in accordance with the legal jurisdiction relevant to the
|
||||
user’s location, unless otherwise required by applicable law.
|
||||
user's location, unless otherwise required by applicable law.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
@@ -191,7 +199,7 @@ export default function Home() {
|
||||
reach us at:
|
||||
</p>
|
||||
<p className="mb-4">
|
||||
Email:
|
||||
Email:{" "}
|
||||
<a
|
||||
href="mailto:support@dokploy.com"
|
||||
className="text-blue-500 hover:underline"
|
||||
@@ -203,3 +211,4 @@ export default function Home() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { Container } from "@/components/Container";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
import Link from "next/link";
|
||||
import { Button } from "./ui/button";
|
||||
|
||||
export function CallToAction() {
|
||||
const t = useTranslations("HomePage");
|
||||
return (
|
||||
<section
|
||||
id="get-started-today"
|
||||
@@ -32,22 +30,22 @@ export function CallToAction() {
|
||||
<Container className="relative z-30">
|
||||
<div className="mx-auto max-w-lg text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
{t("callToAction.title")}
|
||||
Unlock Your Deployment Potential with Dokploy Cloud
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-muted-foreground">
|
||||
{t("callToAction.des")}
|
||||
Say goodbye to infrastructure hassles—Dokploy Cloud handles it all. Effortlessly deploy, manage Docker containers, and secure your traffic with Traefik. Focus on building, we'll handle the rest.
|
||||
</p>
|
||||
|
||||
<Button className="mt-10 rounded-full" asChild>
|
||||
<Link
|
||||
href={"https://app.dokploy.com/register"}
|
||||
aria-label="Dokploy on GitHub"
|
||||
target="_blank"
|
||||
className="flex flex-row items-center gap-2"
|
||||
>
|
||||
{t("callToAction.button")}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button className="mt-10 rounded-full" asChild>
|
||||
<Link
|
||||
href={"https://app.dokploy.com/register"}
|
||||
aria-label="Dokploy on GitHub"
|
||||
target="_blank"
|
||||
className="flex flex-row items-center gap-2"
|
||||
>
|
||||
Create an account
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
@@ -4,82 +4,80 @@ import {
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
import { Container } from "./Container";
|
||||
|
||||
const faqs = [
|
||||
{
|
||||
question: "faq.q1",
|
||||
answer: "faq.a1",
|
||||
question: "What is Dokploy?",
|
||||
answer: "Dokploy is a stable, easy-to-use deployment solution designed to simplify the application management process. Think of Dokploy as a free alternative self-hostable solution to platforms like Heroku, Vercel, and Netlify.",
|
||||
},
|
||||
{
|
||||
question: "faq.q11",
|
||||
answer: "faq.a11",
|
||||
question: "How does Dokploy's Open Source plan work?",
|
||||
answer: "You can host Dokploy UI on your own infrastructure and you will be responsible for the maintenance and updates.",
|
||||
},
|
||||
{
|
||||
question: "faq.q12",
|
||||
answer: "faq.a12",
|
||||
question: "Do I need to provide my own server for the managed plan?",
|
||||
answer: "Yes, in the managed plan, you provide your own server (e.g., Hetzner, Hostinger, AWS, etc.) VPS, and we manage the Dokploy UI infrastructure for you.",
|
||||
},
|
||||
{
|
||||
question: "faq.q13",
|
||||
answer: "faq.a13",
|
||||
question: "What happens if I need more than one server?",
|
||||
answer: "The first server costs $4.50/month, if you buy more than one it will be $3.50/month per server.",
|
||||
},
|
||||
{
|
||||
question: "faq.q14",
|
||||
answer: "faq.a14",
|
||||
question: "Is there a limit on the number of deployments?",
|
||||
answer: "No, there is no limit on the number of deployments in any of the plans.",
|
||||
},
|
||||
{
|
||||
question: "faq.q15",
|
||||
answer: "faq.a15",
|
||||
question: "What happens if I exceed my purchased server limit?",
|
||||
answer: "The most recently added servers will be deactivated. You won't be able to create services on inactive servers until they are reactivated.",
|
||||
},
|
||||
{
|
||||
question: "faq.q17",
|
||||
answer: "faq.a17",
|
||||
question: "What kind of support do you offer?",
|
||||
answer: "We offer community support for the open source version and priority support for paid plans (via Discord or Email at support@dokploy.com).",
|
||||
},
|
||||
{
|
||||
question: "faq.q18",
|
||||
answer: "faq.a18",
|
||||
question: "What's the catch on the Paid Plan?",
|
||||
answer: "Nothing, once you link your server (VPS) to your account, you can deploy unlimited applications, databases, and users, and you get unlimited updates, deployments, backups, and more.",
|
||||
},
|
||||
{
|
||||
question: "faq.q2",
|
||||
answer: "faq.a2",
|
||||
question: "Why Choose Dokploy?",
|
||||
answer: "Dokploy offers simplicity, flexibility, and speed in application deployment and management.",
|
||||
},
|
||||
{
|
||||
question: "faq.q4",
|
||||
answer: "faq.a4",
|
||||
question: "Is it open source?",
|
||||
answer: "Yes, Dokploy is open source and free to use.",
|
||||
},
|
||||
{
|
||||
question: "faq.q5",
|
||||
answer: "faq.a5",
|
||||
question: "What types of languages can I deploy with Dokploy?",
|
||||
answer: "Dokploy does not restrict programming languages. You are free to choose your preferred language and framework.",
|
||||
},
|
||||
{
|
||||
question: "faq.q6",
|
||||
answer: "faq.a6",
|
||||
question: "How do I request a feature or report a bug?",
|
||||
answer: "To request a feature or report a bug, please create an issue on our GitHub repository or ask in our Discord channel.",
|
||||
},
|
||||
{
|
||||
question: "faq.q7",
|
||||
answer: "faq.a7",
|
||||
question: "Do you track the usage of Dokploy?",
|
||||
answer: "No, we don't track any usage data.",
|
||||
},
|
||||
{
|
||||
question: "faq.q8",
|
||||
answer: "faq.a8",
|
||||
question: "Are there any user forums or communities where I can interact with other users?",
|
||||
answer: "Yes, we have active GitHub discussions and Discord where you can share ideas, ask for help, and connect with other users.",
|
||||
},
|
||||
{
|
||||
question: "faq.q16",
|
||||
answer: "faq.a16",
|
||||
question: "Do you offer a refunds?",
|
||||
answer: "We do not offer refunds. However, you can cancel your subscription at any time. Feel free to try our open-source version for free before making a purchase.",
|
||||
},
|
||||
{
|
||||
question: "faq.q9",
|
||||
answer: "faq.a9",
|
||||
question: "What types of applications can I deploy with Dokploy?",
|
||||
answer: "You can deploy any application that can be Dockerized, with no limits. Dokploy supports builds from Git repositories, Dockerfiles, Nixpacks, and Buildpacks like Heroku and Paketo.",
|
||||
},
|
||||
{
|
||||
question: "faq.q10",
|
||||
answer: "faq.a10",
|
||||
question: "How does Dokploy handle database management?",
|
||||
answer: "Dokploy supports multiple database systems including Postgres, MySQL, MariaDB, MongoDB, and Redis, providing tools for easy deployment and management and backups directly from the dashboard.",
|
||||
},
|
||||
];
|
||||
|
||||
export function Faqs() {
|
||||
const t = useTranslations("HomePage");
|
||||
return (
|
||||
<section
|
||||
id="faqs"
|
||||
@@ -92,10 +90,10 @@ export function Faqs() {
|
||||
id="faq-title"
|
||||
className="font-display text-3xl tracking-tight text-primary sm:text-4xl text-center"
|
||||
>
|
||||
{t("faq.title")}
|
||||
Frequently asked questions
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-muted-foreground text-center">
|
||||
{t("faq.des")}
|
||||
If you can't find what you're looking for, please submit an issue through our GitHub repository or ask questions on our Discord.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -104,12 +102,12 @@ export function Faqs() {
|
||||
collapsible
|
||||
className="w-full max-w-3xl mx-auto"
|
||||
>
|
||||
{faqs.map((column, columnIndex) => (
|
||||
{faqs.map((faq, columnIndex) => (
|
||||
<AccordionItem value={`${columnIndex}`} key={columnIndex}>
|
||||
<AccordionTrigger className="text-left">
|
||||
{t(column.question)}
|
||||
{faq.question}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>{t(column.answer)}</AccordionContent>
|
||||
<AccordionContent>{faq.answer}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type GithubStarsProps = {
|
||||
@@ -10,17 +11,73 @@ type GithubStarsProps = {
|
||||
count?: string;
|
||||
};
|
||||
|
||||
// Function to format star count (e.g., 26400 -> "26.4k")
|
||||
function formatStarCount(count: number): string {
|
||||
if (count >= 1000000) {
|
||||
return `${(count / 1000000).toFixed(1)}M`;
|
||||
}
|
||||
if (count >= 1000) {
|
||||
return `${(count / 1000).toFixed(1)}k`;
|
||||
}
|
||||
return count.toString();
|
||||
}
|
||||
|
||||
// Extract owner and repo from GitHub URL
|
||||
function extractRepoInfo(url: string): { owner: string; repo: string } | null {
|
||||
try {
|
||||
const match = url.match(/github\.com\/([^\/]+)\/([^\/]+)/);
|
||||
if (match) {
|
||||
return { owner: match[1], repo: match[2].replace(/\.git$/, "") };
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error extracting repo info:", error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function GithubStars({
|
||||
className,
|
||||
repoUrl = "https://github.com/dokploy/dokploy",
|
||||
label = "GitHub Stars",
|
||||
count = "26.4k",
|
||||
count: defaultCount = "26.4k",
|
||||
}: GithubStarsProps) {
|
||||
const [starCount, setStarCount] = useState<string>(defaultCount);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchStarCount = async () => {
|
||||
const repoInfo = extractRepoInfo(repoUrl);
|
||||
if (!repoInfo) {
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/github-stars?owner=${encodeURIComponent(repoInfo.owner)}&repo=${encodeURIComponent(repoInfo.repo)}`,
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const formattedCount = formatStarCount(data.stargazers_count);
|
||||
setStarCount(formattedCount);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching GitHub stars:", error);
|
||||
// Keep default count on error
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchStarCount();
|
||||
}, [repoUrl]);
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={repoUrl}
|
||||
target="_blank"
|
||||
aria-label={`${label}: ${count}`}
|
||||
aria-label={`${label}: ${starCount}`}
|
||||
className={cn(
|
||||
"group relative inline-flex items-center gap-2 rounded-full px-3 py-1",
|
||||
"shadow-[0_0_0_2px_#000_inset,0_2px_8px_rgba(0,0,0,0.35)]",
|
||||
@@ -109,7 +166,9 @@ export function GithubStars({
|
||||
{/* copy */}
|
||||
<span className="flex items-baseline gap-1 pr-0.5">
|
||||
<span className="text-xs font-semibold">Stars</span>
|
||||
<span className="text-sm font-extrabold tracking-tight">{count}</span>
|
||||
<span className="text-sm font-extrabold tracking-tight">
|
||||
{isLoading ? "..." : starCount}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{/* subtle ring on hover */}
|
||||
|
||||
@@ -154,7 +154,7 @@ function MobileNavigation() {
|
||||
|
||||
export function Header() {
|
||||
return (
|
||||
<header className="bg-background py-10">
|
||||
<header className="sticky top-0 z-50 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b border-border/40 py-5">
|
||||
<Container>
|
||||
<nav className="relative z-50 flex justify-between">
|
||||
<div className="flex items-center md:gap-x-12">
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { motion } from "framer-motion";
|
||||
import { Check, ChevronRight, Copy } from "lucide-react";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
import AnimatedGradientText from "./ui/animated-gradient-text";
|
||||
@@ -43,7 +42,6 @@ import HeroVideoDialog from "./ui/hero-video-dialog";
|
||||
// };
|
||||
|
||||
export function Hero() {
|
||||
const t = useTranslations("HomePage");
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -57,7 +55,7 @@ export function Hero() {
|
||||
<div className=" bottom-0 flex w-full items-center justify-center overflow-hidden rounded-lg bg-background md:shadow-xl">
|
||||
<div className="relative px-4">
|
||||
<div className="text-center">
|
||||
<motion.a
|
||||
{/* <motion.a
|
||||
href="#pricing"
|
||||
className="relative z-10 mb-4 inline-block"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
@@ -72,41 +70,41 @@ export function Hero() {
|
||||
"inline animate-gradient bg-gradient-to-r from-[#ffaa40] via-[#9c40ff] to-[#ffaa40] bg-[length:var(--bg-size)_100%] bg-clip-text text-transparent",
|
||||
)}
|
||||
>
|
||||
{t("hero.cloud")}
|
||||
Introducing Dokploy Cloud
|
||||
</span>
|
||||
<ChevronRight className="ml-1 size-3 transition-transform duration-300 ease-in-out group-hover:translate-x-0.5" />
|
||||
</AnimatedGradientText>
|
||||
</div>
|
||||
</motion.a>
|
||||
</motion.a> */}
|
||||
|
||||
<motion.h1
|
||||
className="mx-auto max-w-4xl font-display text-5xl font-medium tracking-tight text-muted-foreground sm:text-7xl"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
<motion.h1
|
||||
className="mx-auto max-w-4xl font-display text-5xl font-medium tracking-tight text-muted-foreground sm:text-7xl"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
Simplify{" "}
|
||||
<span className="relative whitespace-nowrap text-primary">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 418 42"
|
||||
className="absolute left-0 top-2/3 h-[0.58em] w-full fill-primary"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
{t("hero.deploy")}{" "}
|
||||
<span className="relative whitespace-nowrap text-primary">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 418 42"
|
||||
className="absolute left-0 top-2/3 h-[0.58em] w-full fill-primary"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<path d="M203.371.916c-26.013-2.078-76.686 1.963-124.73 9.946L67.3 12.749C35.421 18.062 18.2 21.766 6.004 25.934 1.244 27.561.828 27.778.874 28.61c.07 1.214.828 1.121 9.595-1.176 9.072-2.377 17.15-3.92 39.246-7.496C123.565 7.986 157.869 4.492 195.942 5.046c7.461.108 19.25 1.696 19.17 2.582-.107 1.183-7.874 4.31-25.75 10.366-21.992 7.45-35.43 12.534-36.701 13.884-2.173 2.308-.202 4.407 4.442 4.734 2.654.187 3.263.157 15.593-.78 35.401-2.686 57.944-3.488 88.365-3.143 46.327.526 75.721 2.23 130.788 7.584 19.787 1.924 20.814 1.98 24.557 1.332l.066-.011c1.201-.203 1.53-1.825.399-2.335-2.911-1.31-4.893-1.604-22.048-3.261-57.509-5.556-87.871-7.36-132.059-7.842-23.239-.254-33.617-.116-50.627.674-11.629.54-42.371 2.494-46.696 2.967-2.359.259 8.133-3.625 26.504-9.81 23.239-7.825 27.934-10.149 28.304-14.005.417-4.348-3.529-6-16.878-7.066Z" />
|
||||
</svg>
|
||||
<span className="relative"> {t("hero.anywhere")}</span>
|
||||
</span>{" "}
|
||||
{t("hero.with")}
|
||||
</motion.h1>
|
||||
<motion.p
|
||||
className="mx-auto mt-6 max-w-2xl text-lg tracking-tight text-muted-foreground"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3, delay: 0.2 }}
|
||||
>
|
||||
{t("hero.des")}
|
||||
</motion.p>
|
||||
<path d="M203.371.916c-26.013-2.078-76.686 1.963-124.73 9.946L67.3 12.749C35.421 18.062 18.2 21.766 6.004 25.934 1.244 27.561.828 27.778.874 28.61c.07 1.214.828 1.121 9.595-1.176 9.072-2.377 17.15-3.92 39.246-7.496C123.565 7.986 157.869 4.492 195.942 5.046c7.461.108 19.25 1.696 19.17 2.582-.107 1.183-7.874 4.31-25.75 10.366-21.992 7.45-35.43 12.534-36.701 13.884-2.173 2.308-.202 4.407 4.442 4.734 2.654.187 3.263.157 15.593-.78 35.401-2.686 57.944-3.488 88.365-3.143 46.327.526 75.721 2.23 130.788 7.584 19.787 1.924 20.814 1.98 24.557 1.332l.066-.011c1.201-.203 1.53-1.825.399-2.335-2.911-1.31-4.893-1.604-22.048-3.261-57.509-5.556-87.871-7.36-132.059-7.842-23.239-.254-33.617-.116-50.627.674-11.629.54-42.371 2.494-46.696 2.967-2.359.259 8.133-3.625 26.504-9.81 23.239-7.825 27.934-10.149 28.304-14.005.417-4.348-3.529-6-16.878-7.066Z" />
|
||||
</svg>
|
||||
<span className="relative">Application and Database</span>
|
||||
</span>{" "}
|
||||
Deployments
|
||||
</motion.h1>
|
||||
<motion.p
|
||||
className="mx-auto mt-6 max-w-2xl text-lg tracking-tight text-muted-foreground"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3, delay: 0.2 }}
|
||||
>
|
||||
Manage containerized deployments across multiple servers with ease thanks to our all-in-one platform for developers.
|
||||
</motion.p>
|
||||
<motion.div
|
||||
className="flex flex-col items-center justify-center space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
@@ -168,7 +166,7 @@ export function Hero() {
|
||||
>
|
||||
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z" />
|
||||
</svg>
|
||||
{t("navigation.discord")}
|
||||
Discord
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -4,10 +4,9 @@ import { cn } from "@/lib/utils";
|
||||
import { Tab } from "@headlessui/react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Layers, Terminal, Users } from "lucide-react";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
import { Container } from "./Container";
|
||||
interface Feature {
|
||||
name: React.ReactNode;
|
||||
name: string;
|
||||
summary: string;
|
||||
description: string;
|
||||
image: string;
|
||||
@@ -16,9 +15,9 @@ interface Feature {
|
||||
|
||||
const features: Array<Feature> = [
|
||||
{
|
||||
name: "secondaryFeatures.templates",
|
||||
summary: "secondaryFeatures.templatesSummary",
|
||||
description: "secondaryFeatures.templatesDes",
|
||||
name: "Open Source Templates",
|
||||
summary: "One click to deploy open source templates.",
|
||||
description: "Deploy open source templates with one click, powered by Docker Compose, (Plausible, Calcom, Pocketbase, etc.)",
|
||||
image: "/secondary/templates.png",
|
||||
icon: function ReportingIcon() {
|
||||
return (
|
||||
@@ -29,9 +28,9 @@ const features: Array<Feature> = [
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secondaryFeatures.traefik",
|
||||
summary: "secondaryFeatures.traefikSummary",
|
||||
description: "secondaryFeatures.traefikDes",
|
||||
name: "Real-Time Traefik Configuration",
|
||||
summary: "Modify Traefik settings on-the-fly via a graphical interface or API.",
|
||||
description: "Users can adjust Traefik's configuration, including middleware, forwarding rules, and SSL certificates through an intuitive interface or API. This feature enables seamless traffic routing and security adjustments without the need to restart services",
|
||||
image: "/secondary/traefik.png",
|
||||
icon: function ReportingIcon() {
|
||||
return (
|
||||
@@ -215,9 +214,9 @@ const features: Array<Feature> = [
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secondaryFeatures.users",
|
||||
summary: "secondaryFeatures.usersSummary",
|
||||
description: "secondaryFeatures.usersDes",
|
||||
name: "User Permission Management",
|
||||
summary: "Detailed control over user permissions for accessing and managing projects and services.",
|
||||
description: "Allows administrators to define specific roles and permissions for each user, including the ability to create, modify, or delete applications and databases. This feature ensures secure and efficient management of large and diverse teams.",
|
||||
image: "/secondary/users.png",
|
||||
icon: function InventoryIcon() {
|
||||
return (
|
||||
@@ -228,9 +227,9 @@ const features: Array<Feature> = [
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secondaryFeatures.terminal",
|
||||
summary: "secondaryFeatures.terminalSummary",
|
||||
description: "secondaryFeatures.terminalDes",
|
||||
name: "Terminal Access",
|
||||
summary: "Direct access to each container's and server terminal for advanced management.",
|
||||
description: "Provides an interface to access the command line of any active container, allowing developers to execute commands, manage services, and troubleshoot directly from the dashboard",
|
||||
image: "/secondary/terminal.png",
|
||||
icon: function ContactsIcon() {
|
||||
return (
|
||||
@@ -251,7 +250,6 @@ function Feature({
|
||||
feature: Feature;
|
||||
isActive: boolean;
|
||||
}) {
|
||||
const t = useTranslations("HomePage");
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -289,10 +287,10 @@ function Feature({
|
||||
{feature.name}
|
||||
</h3>
|
||||
<p className="mt-2 font-display text-xl text-foreground">
|
||||
{t(feature.summary)}
|
||||
{feature.summary}
|
||||
</p>
|
||||
<p className="mt-4 text-sm text-muted-foreground">
|
||||
{t(feature.description)}
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@@ -322,7 +320,6 @@ function FeaturesMobile() {
|
||||
}
|
||||
|
||||
function FeaturesDesktop() {
|
||||
const t = useTranslations("HomePage");
|
||||
return (
|
||||
<Tab.Group as="div" className="hidden lg:mt-20 lg:block">
|
||||
{({ selectedIndex }) => (
|
||||
@@ -336,7 +333,7 @@ function FeaturesDesktop() {
|
||||
name: (
|
||||
<Tab className="ui-not-focus-visible:outline-none">
|
||||
<span className="absolute inset-0" />
|
||||
{t(feature.name)}
|
||||
{feature.name}
|
||||
</Tab>
|
||||
),
|
||||
}}
|
||||
@@ -380,7 +377,6 @@ function FeaturesDesktop() {
|
||||
}
|
||||
|
||||
export function SecondaryFeatures() {
|
||||
const t = useTranslations("HomePage");
|
||||
return (
|
||||
<section
|
||||
id="secondary-features"
|
||||
@@ -390,10 +386,10 @@ export function SecondaryFeatures() {
|
||||
<Container className="max-w-[95rem]">
|
||||
<div className="mx-auto max-w-2xl md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-primary sm:text-4xl">
|
||||
{t("secondaryFeatures.title")}
|
||||
Advanced Management Tools
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-muted-foreground">
|
||||
{t("secondaryFeatures.des")}
|
||||
Elevate your infrastructure with tools that offer precise control, detailed monitoring, and enhanced security, ensuring seamless management and robust performance.
|
||||
</p>
|
||||
</div>
|
||||
<FeaturesMobile />
|
||||
|
||||
@@ -60,7 +60,7 @@ export function FirstFeaturesSection() {
|
||||
{
|
||||
title: "Open Source Templates",
|
||||
description:
|
||||
"Get started quickly with pre-configured templates for popular tools like Supabase, Cal.com, and Pocketbase.",
|
||||
"Get started quickly with pre-configured templates for popular tools like Supabase, Cal.com, and PocketBase.",
|
||||
icon: <IconTemplate />,
|
||||
},
|
||||
{
|
||||
@@ -76,7 +76,7 @@ export function FirstFeaturesSection() {
|
||||
icon: <IconActivity />,
|
||||
},
|
||||
{
|
||||
title: "Built for developers",
|
||||
title: "Built for Developers",
|
||||
description:
|
||||
"Designed specifically for engineers and developers seeking control and flexibility.",
|
||||
icon: <IconTerminal2 />,
|
||||
@@ -91,7 +91,7 @@ export function FirstFeaturesSection() {
|
||||
return (
|
||||
<div className="flex flex-col justify-center items-center mt-20 px-4">
|
||||
<h2 className="font-display text-3xl tracking-tight text-primary sm:text-4xl text-center">
|
||||
Powerful Deployment, Tailored for You
|
||||
Powerful Deployment Tailored to You
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-muted-foreground text-center">
|
||||
Unlock seamless multi-server deployments, advanced user control, and
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
X,
|
||||
XCircleIcon,
|
||||
} from "lucide-react";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
@@ -85,7 +84,6 @@ export const calculatePrice = (count: number, isAnnual = false) => {
|
||||
|
||||
export function Pricing() {
|
||||
const router = useRouter();
|
||||
const t = useTranslations("Pricing");
|
||||
const [isAnnual, setIsAnnual] = useState(false);
|
||||
const [serverQuantity, setServerQuantity] = useState(1);
|
||||
const featured = true;
|
||||
@@ -119,12 +117,12 @@ export function Pricing() {
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
<span className="relative whitespace-nowrap">
|
||||
<SwirlyDoodle className="absolute left-0 top-1/2 h-[1em] w-full fill-muted-foreground" />
|
||||
<span className="relative">{t("swirlyDoodleTitle")}</span>
|
||||
<span className="relative">Simple Affordable</span>
|
||||
</span>{" "}
|
||||
{t("restTitle")}
|
||||
Pricing.
|
||||
</h2>
|
||||
<p className="mt-4 text-lg text-muted-foreground">
|
||||
{t("description")}
|
||||
Deploy Smarter and Scale Faster, Without Breaking the Bank
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -137,10 +135,10 @@ export function Pricing() {
|
||||
>
|
||||
<TabsList>
|
||||
<TabsTrigger value="monthly">
|
||||
{t("billingCycle.monthly")}
|
||||
Monthly
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="annual">
|
||||
{t("billingCycle.annual")}
|
||||
Annual
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
@@ -153,69 +151,70 @@ export function Pricing() {
|
||||
: "lg:py-8",
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<p className=" text-2xl font-semibold tracking-tight text-primary ">
|
||||
{t("plan.free.title")}
|
||||
</p>
|
||||
|
|
||||
<p className=" text-base font-semibold tracking-tight text-muted-foreground">
|
||||
{t("plan.free.subTitle")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3 className="mt-5 text-lg font-medium text-white">
|
||||
{t("plan.free.section.title")}
|
||||
</h3>
|
||||
<p
|
||||
className={clsx(
|
||||
"text-sm",
|
||||
featured ? "text-white" : "text-slate-400",
|
||||
)}
|
||||
>
|
||||
{t("plan.free.section.description")}
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<p className=" text-2xl font-semibold tracking-tight text-primary ">
|
||||
Free
|
||||
</p>
|
||||
|
|
||||
<p className=" text-base font-semibold tracking-tight text-muted-foreground">
|
||||
Open Source
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul
|
||||
role="list"
|
||||
className={clsx(
|
||||
" mt-4 flex flex-col gap-y-2 text-sm",
|
||||
featured ? "text-white" : "text-slate-200",
|
||||
)}
|
||||
>
|
||||
{[
|
||||
t("plan.free.features.f1"),
|
||||
t("plan.free.features.f2"),
|
||||
t("plan.free.features.f3"),
|
||||
t("plan.free.features.f4"),
|
||||
t("plan.free.features.f5"),
|
||||
].map((feature) => (
|
||||
<li key={feature} className="flex text-muted-foreground">
|
||||
<CheckIcon />
|
||||
<span className="ml-2">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
<li className="flex text-muted-foreground">
|
||||
<XCircleIcon className="size-5 self-center text-destructive" />
|
||||
<span className="ml-3 text-destructive">
|
||||
Remote Servers Monitoring
|
||||
</span>
|
||||
<h3 className="mt-5 text-lg font-medium text-white">
|
||||
Dokploy Open Source
|
||||
</h3>
|
||||
<p
|
||||
className={clsx(
|
||||
"text-sm",
|
||||
featured ? "text-white" : "text-slate-400",
|
||||
)}
|
||||
>
|
||||
Install and manage Dokploy UI on your own server.
|
||||
</p>
|
||||
|
||||
<ul
|
||||
role="list"
|
||||
className={clsx(
|
||||
" mt-4 flex flex-col gap-y-2 text-sm",
|
||||
featured ? "text-white" : "text-slate-200",
|
||||
)}
|
||||
>
|
||||
{[
|
||||
"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) => (
|
||||
<li key={feature} className="flex text-muted-foreground">
|
||||
<CheckIcon />
|
||||
<span className="ml-2">{feature}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t("plan.free.features.f9")}
|
||||
</span>
|
||||
<Link
|
||||
href="https://docs.dokploy.com/docs/core/installation#docker"
|
||||
target="_blank"
|
||||
className="flex items-start text-sm text-primary"
|
||||
>
|
||||
{t("plan.free.go")}{" "}
|
||||
<ArrowRight className="ml-2 size-4 self-center" />
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
<li className="flex text-muted-foreground">
|
||||
<XCircleIcon className="size-5 self-center text-destructive" />
|
||||
<span className="ml-3 text-destructive">
|
||||
Remote Servers Monitoring
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Unlimited Servers
|
||||
</span>
|
||||
<Link
|
||||
href="https://docs.dokploy.com/docs/core/installation#docker"
|
||||
target="_blank"
|
||||
className="flex items-start text-sm text-primary"
|
||||
>
|
||||
Start deploying{" "}
|
||||
<ArrowRight className="ml-2 size-4 self-center" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
className={clsx(
|
||||
@@ -224,12 +223,12 @@ export function Pricing() {
|
||||
? "order-first border bg-black py-8 lg:order-none"
|
||||
: "lg:py-8",
|
||||
)}
|
||||
>
|
||||
{isAnnual && (
|
||||
<div className="mb-4 flex flex-row items-center gap-2">
|
||||
<Badge>{t("plan.cloud.title")} 🚀</Badge>
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
{isAnnual && (
|
||||
<div className="mb-4 flex flex-row items-center gap-2">
|
||||
<Badge>Recommended 🚀</Badge>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isAnnual ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
@@ -251,50 +250,48 @@ export function Pricing() {
|
||||
$ {calculatePrice(serverQuantity, isAnnual).toFixed(2)} USD
|
||||
</p>
|
||||
)}
|
||||
<h3 className="mt-5 text-lg font-medium text-white">
|
||||
{t("plan.cloud.section.title")}
|
||||
</h3>
|
||||
<p
|
||||
className={clsx(
|
||||
"text-sm",
|
||||
featured ? "text-white" : "text-slate-400",
|
||||
)}
|
||||
>
|
||||
{t("plan.cloud.section.description")}
|
||||
</p>
|
||||
<h3 className="mt-5 text-lg font-medium text-white">
|
||||
Dokploy Plan
|
||||
</h3>
|
||||
<p
|
||||
className={clsx(
|
||||
"text-sm",
|
||||
featured ? "text-white" : "text-slate-400",
|
||||
)}
|
||||
>
|
||||
We manage the Dokploy UI infrastructure, we take care of it for you.
|
||||
</p>
|
||||
|
||||
<ul
|
||||
role="list"
|
||||
className={clsx(
|
||||
" mt-4 flex flex-col gap-y-2 text-sm",
|
||||
featured ? "text-white" : "text-slate-200",
|
||||
)}
|
||||
>
|
||||
{[
|
||||
t("plan.cloud.features.f1"),
|
||||
t("plan.cloud.features.f2"),
|
||||
t("plan.cloud.features.f3"),
|
||||
t("plan.cloud.features.f4"),
|
||||
t("plan.cloud.features.f5"),
|
||||
t("plan.cloud.features.f6"),
|
||||
t("plan.cloud.features.f7"),
|
||||
].map((feature, index) => (
|
||||
<li
|
||||
key={`${feature}-${index}`}
|
||||
className="flex text-muted-foreground"
|
||||
>
|
||||
<CheckIcon />
|
||||
<span className="ml-2">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t("plan.cloud.servers", {
|
||||
serverQuantity,
|
||||
})}
|
||||
</span>
|
||||
<ul
|
||||
role="list"
|
||||
className={clsx(
|
||||
" mt-4 flex flex-col gap-y-2 text-sm",
|
||||
featured ? "text-white" : "text-slate-200",
|
||||
)}
|
||||
>
|
||||
{[
|
||||
"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) => (
|
||||
<li
|
||||
key={`${feature}-${index}`}
|
||||
className="flex text-muted-foreground"
|
||||
>
|
||||
<CheckIcon />
|
||||
<span className="ml-2">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
No. of {serverQuantity} Servers (You bring the servers)
|
||||
</span>
|
||||
<TooltipProvider>
|
||||
<Tooltip open={openVideo}>
|
||||
<TooltipTrigger onClick={() => setOpenVideo(true)}>
|
||||
@@ -308,7 +305,7 @@ export function Pricing() {
|
||||
/>
|
||||
</div>
|
||||
<p className="text-primary mb-2 text-left">
|
||||
We Recommend to watch the video to understand the
|
||||
We recommend you to watch the video to understand the
|
||||
benefits of Dokploy Cloud
|
||||
</p>
|
||||
|
||||
@@ -366,7 +363,7 @@ export function Pricing() {
|
||||
className: "w-full",
|
||||
})}
|
||||
>
|
||||
{t("plan.cloud.go")}
|
||||
Subscribe
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,53 +5,51 @@ import { AnimatePresence, motion } from "framer-motion";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
|
||||
const features = [
|
||||
{
|
||||
title: "primaryFeatures.applications",
|
||||
description: "primaryFeatures.applicationsDes",
|
||||
title: "Applications & Databases",
|
||||
description: "Centralize control of your applications and databases for enhanced security and efficiency, simplifying access and management across your infrastructure.",
|
||||
image: "/dashboard.png",
|
||||
},
|
||||
{
|
||||
title: "primaryFeatures.compose",
|
||||
description: "primaryFeatures.composeDes",
|
||||
title: "Docker Compose",
|
||||
description: "Native Docker Compose support so you can manage complex applications and services with ease.",
|
||||
image: "/compose.png",
|
||||
},
|
||||
{
|
||||
title: "primaryFeatures.multiserver",
|
||||
description: "primaryFeatures.multiserverDes",
|
||||
title: "Multiserver",
|
||||
description: "Deploy applications to multiple servers without the extra effort.",
|
||||
image: "/remote.png",
|
||||
},
|
||||
{
|
||||
title: "primaryFeatures.logs",
|
||||
description: "primaryFeatures.logsDes",
|
||||
title: "Logs",
|
||||
description: "Monitor and manage your applications' logs with ease, ensuring efficient troubleshooting and optimal performance.",
|
||||
image: "/logs.png",
|
||||
},
|
||||
{
|
||||
title: "primaryFeatures.monitoring",
|
||||
description: "primaryFeatures.monitoringDes",
|
||||
title: "Monitoring",
|
||||
description: "Monitor your systems' performance and health in real time, ensuring continuous and uninterrupted operation.",
|
||||
image: "/primary/monitoring.png",
|
||||
},
|
||||
{
|
||||
title: "primaryFeatures.backups",
|
||||
description: "primaryFeatures.backupsDes",
|
||||
title: "Backups",
|
||||
description: "Implement automatic and secure backup solutions to protect your critical data and restore it quickly when necessary.",
|
||||
image: "/backups.png",
|
||||
},
|
||||
{
|
||||
title: "primaryFeatures.traefik",
|
||||
description: "primaryFeatures.traefikDes",
|
||||
title: "Traefik",
|
||||
description: "Manage Traefik via File Editor to configure your own domain names, certificates, and more.",
|
||||
image: "/traefik.png",
|
||||
},
|
||||
{
|
||||
title: "primaryFeatures.templates",
|
||||
description: "primaryFeatures.templatesDes",
|
||||
title: "Templates",
|
||||
description: "Deploy open source templates with one click.",
|
||||
image: "/templates.png",
|
||||
},
|
||||
];
|
||||
|
||||
export function SecondaryFeaturesSections() {
|
||||
const t = useTranslations("HomePage");
|
||||
const [tabOrientation, setTabOrientation] = useState<
|
||||
"horizontal" | "vertical"
|
||||
>("horizontal");
|
||||
@@ -84,23 +82,13 @@ export function SecondaryFeaturesSections() {
|
||||
aria-label="Features for running your books"
|
||||
className="relative overflow-hidden bg-black pb-28 pt-20 sm:py-32"
|
||||
>
|
||||
{/* <div class="absolute inset-0 h-full w-full bg-background bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:24px_24px]" /> */}
|
||||
|
||||
{/* <Image
|
||||
className="absolute left-1/2 top-1/2 max-w-none translate-x-[-44%] translate-y-[-42%]"
|
||||
src={backgroundImage}
|
||||
alt=""
|
||||
width={2245}
|
||||
height={1636}
|
||||
unoptimized
|
||||
/> */}
|
||||
<div className="mx-auto max-w-7xl max-lg:px-4 relative">
|
||||
<div className="max-w-2xl md:mx-auto md:text-center xl:max-w-none">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl md:text-5xl">
|
||||
{t("primaryFeatures.title")}
|
||||
Comprehensive Control of Your Digital Ecosystem
|
||||
</h2>
|
||||
<p className="mt-6 text-lg tracking-tight text-muted-foreground">
|
||||
{t("primaryFeatures.des")}
|
||||
Simplify your project and data management, ensure robust monitoring, and secure your backups—all without the fuss over minute details.
|
||||
</p>
|
||||
</div>
|
||||
<Tab.Group
|
||||
@@ -148,7 +136,7 @@ export function SecondaryFeaturesSections() {
|
||||
)}
|
||||
>
|
||||
<span className="absolute inset-0 rounded-full" />
|
||||
{t(feature.title)}
|
||||
{feature.title}
|
||||
</Tab>
|
||||
</h3>
|
||||
<p
|
||||
@@ -156,7 +144,7 @@ export function SecondaryFeaturesSections() {
|
||||
"mt-2 hidden text-sm text-muted-foreground ",
|
||||
)}
|
||||
>
|
||||
{t(feature.description)}
|
||||
{feature.description}
|
||||
</p>
|
||||
</motion.div>
|
||||
))}
|
||||
@@ -168,7 +156,7 @@ export function SecondaryFeaturesSections() {
|
||||
<div className="relative sm:px-6 ">
|
||||
<div className="absolute -inset-x-4 bottom-[-4.25rem] top-[-6.5rem] bg-card/60 ring-1 ring-inset ring-white/10 sm:inset-x-0 sm:rounded-t-xl" />
|
||||
<p className="relative mx-auto max-w-2xl text-base text-white sm:text-center mb-10">
|
||||
{t(feature.description)}
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
import { PlusCircleIcon } from "lucide-react";
|
||||
import { useTranslations } from "@/lib/intl";
|
||||
import Link from "next/link";
|
||||
import { buttonVariants } from "./ui/button";
|
||||
import Ripple from "./ui/ripple";
|
||||
@@ -12,15 +11,14 @@ import {
|
||||
} from "./ui/tooltip";
|
||||
|
||||
export const Sponsors = () => {
|
||||
const t = useTranslations("HomePage");
|
||||
return (
|
||||
<div className="mt-20 flex flex-col justify-center gap-y-10 w-full ">
|
||||
<div className="flex flex-col justify-start gap-4 px-4">
|
||||
<h3 className="mx-auto max-w-2xl font-display text-3xl font-medium tracking-tight text-primary sm:text-5xl text-center">
|
||||
{t("hero.sponsors.title")}
|
||||
Sponsors
|
||||
</h3>
|
||||
<p className="mx-auto max-w-2xl text-lg tracking-tight text-muted-foreground text-center">
|
||||
{t("hero.sponsors.description")}
|
||||
Dokploy is an open source project that is maintained by a community of volunteers. We would like to thank our sponsors for their support and contributions to the project, which help us to continue to develop and improve Dokploy.
|
||||
</p>
|
||||
</div>
|
||||
<div className="relative flex h-[700px] w-full flex-col items-center justify-center overflow-hidden bg-background md:shadow-xl">
|
||||
|
||||
@@ -1,24 +1,48 @@
|
||||
"use client";
|
||||
|
||||
import { HandCoins, Users } from "lucide-react";
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useId } from "react";
|
||||
import NumberTicker from "./ui/number-ticker";
|
||||
|
||||
const statsValues = {
|
||||
githubStars: 26000,
|
||||
dockerDownloads: 3500000,
|
||||
dockerDownloads: 4000000,
|
||||
contributors: 200,
|
||||
sponsors: 50,
|
||||
};
|
||||
|
||||
export function StatsSection() {
|
||||
const [githubStars, setGithubStars] = useState(statsValues.githubStars);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchGitHubStars = async () => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
"/api/github-stars?owner=dokploy&repo=dokploy",
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setGithubStars(data.stargazers_count);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching GitHub stars:", error);
|
||||
// Keep default value on error
|
||||
}
|
||||
};
|
||||
|
||||
fetchGitHubStars();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="py-20 lg:py-40 flex flex-col gap-10 px-4 ">
|
||||
<div className="mx-auto max-w-2xl md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight sm:text-4xl text-center">
|
||||
Stats You Didn’t Ask For (But Secretly Love to See)
|
||||
Stats You Didn't Ask For (But Secretly Love to See)
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-muted-foreground text-center">
|
||||
Just a few numbers to show we’re not *completely* making this up.
|
||||
Just a few numbers to show we're not *completely* making this up.
|
||||
Turns out, Dokploy has actually helped a few people—who knew?
|
||||
</p>
|
||||
</div>
|
||||
@@ -35,9 +59,13 @@ export function StatsSection() {
|
||||
{feature.icon}
|
||||
</p>
|
||||
<p className="text-neutral-400 mt-4 text-base font-normal relative z-20">
|
||||
{feature.description}
|
||||
{typeof feature.description === "function"
|
||||
? feature.description(githubStars)
|
||||
: feature.description}
|
||||
</p>
|
||||
{feature.component}
|
||||
{typeof feature.component === "function"
|
||||
? feature.component(githubStars)
|
||||
: feature.component}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -48,15 +76,16 @@ export function StatsSection() {
|
||||
const grid = [
|
||||
{
|
||||
title: "GitHub Stars",
|
||||
description: `With over ${(statsValues.githubStars / 1000).toFixed(1)}k stars on GitHub, Dokploy is trusted by developers worldwide. Explore our repositories and join our community!`,
|
||||
description: (stars: number) =>
|
||||
`With over ${(stars / 1000).toFixed(1)}k stars on GitHub, Dokploy is trusted by developers worldwide. Explore our repositories and join our community!`,
|
||||
icon: (
|
||||
<svg aria-hidden="true" className="h-6 w-6 fill-white">
|
||||
<path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2Z" />
|
||||
</svg>
|
||||
),
|
||||
component: (
|
||||
component: (stars: number) => (
|
||||
<p className="whitespace-pre-wrap text-2xl !font-semibold tracking-tighter mt-4">
|
||||
<NumberTicker value={statsValues.githubStars} />+
|
||||
<NumberTicker value={stars} />+
|
||||
</p>
|
||||
),
|
||||
},
|
||||
@@ -83,7 +112,7 @@ const grid = [
|
||||
},
|
||||
{
|
||||
title: "Community Contributors",
|
||||
description: `Thanks to a growing base of over ${statsValues.contributors} contributors, Dokploy continues to thrive with valuable contributions from developers around the world.`,
|
||||
description: `Thanks to our growing base of over ${statsValues.contributors} contributors, Dokploy continues to thrive, with valuable contributions from developers around the world.`,
|
||||
icon: <Users className="h-6 w-6 stroke-white" />,
|
||||
component: (
|
||||
<p className="whitespace-pre-wrap text-2xl !font-semibold tracking-tighter mt-4">
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import en from "../locales/en.json";
|
||||
|
||||
type Messages = typeof en;
|
||||
|
||||
function getByPath(obj: any, path: string): any {
|
||||
return path
|
||||
.split(".")
|
||||
.reduce((acc, key) => (acc ? acc[key] : undefined), obj);
|
||||
}
|
||||
|
||||
export function useTranslations(namespace?: keyof Messages | string) {
|
||||
return (key: string, params?: Record<string, any>) => {
|
||||
const fullKey = namespace ? `${namespace}.${key}` : key;
|
||||
let value = getByPath(en as any, fullKey);
|
||||
if (typeof value === "string" && params) {
|
||||
for (const [k, v] of Object.entries(params)) {
|
||||
value = value.replaceAll(`{${k}}`, String(v));
|
||||
}
|
||||
}
|
||||
return value ?? fullKey;
|
||||
};
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
{
|
||||
"HomePage": {
|
||||
"navigation": {
|
||||
"features": "Features",
|
||||
"faqs": "FAQ",
|
||||
"docs": "Docs",
|
||||
"pricing": "Pricing",
|
||||
"support": "Support",
|
||||
"dashboard": "Sign In",
|
||||
"discord": "Discord",
|
||||
"i18nButtonPlaceholder": "Language",
|
||||
"i18nFr": "Français",
|
||||
"i18nEn": "English",
|
||||
"i18nEs": "Español",
|
||||
"i18nZh-Hans": "简体中文",
|
||||
"blog": "Blog",
|
||||
"home": "Home",
|
||||
"login": "Login",
|
||||
"register": "Register",
|
||||
"contact": "Contact"
|
||||
},
|
||||
"hero": {
|
||||
"cloud": "Introducing Dokploy Cloud",
|
||||
"deploy": "Deploy",
|
||||
"anywhere": "Anywhere",
|
||||
"with": "with Total Freedom and Ease.",
|
||||
"des": "Streamline your operations with our all-in-one platform — perfect for managing projects, data, and system health with simplicity and efficiency.",
|
||||
"featuredIn": "Featured in",
|
||||
"sponsors": {
|
||||
"title": "Sponsors",
|
||||
"description": "Dokploy is an open source project that is maintained by a community of volunteers. We would like to thank our sponsors for their support and contributions to the project, which help us to continue to develop and improve Dokploy.",
|
||||
"level": {
|
||||
"hero": "Hero Sponsors",
|
||||
"premium": "Premium Supporters",
|
||||
"supporting": "Supporting Members",
|
||||
"community": "Community Backers",
|
||||
"organizations": "Organizations",
|
||||
"individuals": "Individuals"
|
||||
}
|
||||
}
|
||||
},
|
||||
"primaryFeatures": {
|
||||
"title": "Comprehensive Control for Your Digital Ecosystem",
|
||||
"des": "Simplify your project and data management, ensure robust monitoring, and secure your backups—all without the fuss over minute details.",
|
||||
"projects": "Projects",
|
||||
"templates": "Templates",
|
||||
"templatesDes": "One click to deploy open source templates.",
|
||||
"logs": "Logs",
|
||||
"logsDes": "Monitor and manage your applications' logs with ease, ensuring efficient troubleshooting and optimal performance.",
|
||||
"projectsDes": "Manage and organize all your projects in one place, keeping detailed track of progress and resource allocation.",
|
||||
"applications": "Applications & Databases",
|
||||
"applicationsDes": "Centralize control over your applications and databases for enhanced security and efficiency, simplifying access and management across your infrastructure.",
|
||||
"compose": "Docker Compose",
|
||||
"composeDes": "Native Docker Compose support for manage complex applications and services with ease.",
|
||||
"multiserver": "Multiserver",
|
||||
"multiserverDes": "Deploy applications to multiple servers without effort.",
|
||||
"monitoring": "Monitoring",
|
||||
"monitoringDes": "Monitor your systems' performance and health in real time, ensuring continuous and uninterrupted operation.",
|
||||
"backups": "Backups",
|
||||
"backupsDes": "Implement automatic and secure backup solutions to protect your critical data and restore it quickly when necessary.",
|
||||
"traefik": "Traefik",
|
||||
"traefikDes": "Manage traefik via File Editor to configure your own domain names, certificates, and more."
|
||||
},
|
||||
"secondaryFeatures": {
|
||||
"title": "Advanced Management Tools",
|
||||
"des": "Elevate your infrastructure with tools that offer precise control, detailed monitoring, and enhanced security, ensuring seamless management and robust performance.",
|
||||
"templates": "Open Source Templates",
|
||||
"templatesSummary": "One click to deploy open source templates.",
|
||||
"templatesDes": "Deploy open source templates with one click, powered by Docker Compose, (Plausible, Calcom, Pocketbase, etc.)",
|
||||
"traefik": "Real-Time Traefik Configuration",
|
||||
"traefikSummary": "Modify Traefik settings on-the-fly via a graphical interface or API.",
|
||||
"traefikDes": "Users can adjust Traefik's configuration, including middleware, forwarding rules, and SSL certificates through an intuitive interface or API. This feature enables seamless traffic routing and security adjustments without the need to restart services",
|
||||
"users": "User Permission Management",
|
||||
"usersSummary": "Detailed control over user permissions for accessing and managing projects and services.",
|
||||
"usersDes": "Allows administrators to define specific roles and permissions for each user, including the ability to create, modify, or delete applications and databases. This feature ensures secure and efficient management of large and diverse teams.",
|
||||
"terminal": "Terminal Access",
|
||||
"terminalSummary": "Direct access to each container's and server terminal for advanced management.",
|
||||
"terminalDes": "Provides an interface to access the command line of any active container, allowing developers to execute commands, manage services, and troubleshoot directly from the dashboard"
|
||||
},
|
||||
"callToAction": {
|
||||
"title": "Unlock Your Deployment Potential with Dokploy Cloud",
|
||||
"des": "Say goodbye to infrastructure hassles—Dokploy Cloud handles it all. Effortlessly deploy, manage Docker containers, and secure your traffic with Traefik. Focus on building, we'll handle the rest.",
|
||||
"button": "Get Started Now"
|
||||
},
|
||||
"faq": {
|
||||
"title": "Frequently asked questions",
|
||||
"des": "If you can't find what you're looking for, please submit an issue through our GitHub repository or ask questions on our Discord.",
|
||||
"q1": "What is Dokploy?",
|
||||
"a1": "Dokploy is a stable, easy-to-use deployment solution designed to simplify the application management process. Think of Dokploy as a free alternative self-hostable solution to platforms like Heroku, Vercel, and Netlify.",
|
||||
"q2": "Why Choose Dokploy?",
|
||||
"a2": "Dokploy offers simplicity, flexibility, and speed in application deployment and management.",
|
||||
"q4": "Is it open source?",
|
||||
"a4": "Yes, Dokploy is open source and free to use.",
|
||||
"q5": "What types of languages can I deploy with Dokploy?",
|
||||
"a5": "Dokploy does not restrict programming languages. You are free to choose your preferred language and framework.",
|
||||
"q6": "How do I request a feature or report a bug?",
|
||||
"a6": "To request a feature or report a bug, please create an issue on our GitHub repository or ask in our Discord channel.",
|
||||
"q7": "Do you track the usage of Dokploy?",
|
||||
"a7": "No, we don't track any usage data.",
|
||||
"q8": "Are there any user forums or communities where I can interact with other users?",
|
||||
"a8": "Yes, we have active GitHub discussions and Discord where you can share ideas, ask for help, and connect with other users.",
|
||||
"q9": "What types of applications can I deploy with Dokploy?",
|
||||
"a9": "You can deploy any application that can be Dockerized, with no limits. Dokploy supports builds from Git repositories, Dockerfiles, Nixpacks, and Buildpacks like Heroku and Paketo.",
|
||||
"q10": "How does Dokploy handle database management?",
|
||||
"a10": "Dokploy supports multiple database systems including Postgres, MySQL, MariaDB, MongoDB, and Redis, providing tools for easy deployment and management and backups directly from the dashboard.",
|
||||
"q11": "How does Dokploy's Open Source plan work?",
|
||||
"a11": "You can host Dokploy UI on your own infrastructure and you will be responsible for the maintenance and updates.",
|
||||
"q12": "Do I need to provide my own server for the managed plan?",
|
||||
"a12": "Yes, in the managed plan, you provide your own server e.g. (Hetzner, Hostinger, AWS, ETC.) VPS, and we manage the Dokploy UI infrastructure for you.",
|
||||
"q13": "What happens if I need more than one server?",
|
||||
"a13": "The first server costs $4.50/month, if you buy more than one it will be $3.50/month per server.",
|
||||
"q14": "Is there a limit on the number of deployments?",
|
||||
"a14": "No, there is no limit on the number of deployments in any of the plans.",
|
||||
"q15": "What happens if I exceed my purchased server limit?",
|
||||
"a15": "The most recently added servers will be deactivated. You won't be able to create services on inactive servers until they are reactivated.",
|
||||
"q16": "Do you offer a refunds?",
|
||||
"a16": "We do not offer refunds. However, you can cancel your subscription at any time. Feel free to try our open-source version for free before making a purchase.",
|
||||
"q17": "What kind of support do you offer?",
|
||||
"a17": "We offer community support for the open source version and priority support for paid plans (Via Discord or Email at support@dokploy.com).",
|
||||
"q18": "What's the catch on the Paid Plan?",
|
||||
"a18": "Nothing, you link your server(VPS) to your account and you can deploy unlimited applications, databases, and users and you get unlimited updates, deployments, backups and more."
|
||||
},
|
||||
"footer": {
|
||||
"copyright": "Copyright © {year} Dokploy. All rights reserved."
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Oops! Looks like you're lost.",
|
||||
"des": "Let's get you back",
|
||||
"action": "home"
|
||||
},
|
||||
"Link": {
|
||||
"docs": {
|
||||
"intro": "https://docs.dokploy.com/docs/core",
|
||||
"install": "https://docs.dokploy.com/docs/core/installation"
|
||||
}
|
||||
},
|
||||
"Pricing": {
|
||||
"swirlyDoodleTitle": "Simple & Affordable,",
|
||||
"restTitle": "Pricing.",
|
||||
"description": "Deploy Smarter, Scale Faster – Without Breaking the Bank",
|
||||
"billingCycle": {
|
||||
"monthly": "Monthly",
|
||||
"annual": "Annual"
|
||||
},
|
||||
"plan": {
|
||||
"free": {
|
||||
"title": "Free",
|
||||
"subTitle": "Open Source",
|
||||
"section": {
|
||||
"title": "Dokploy Open Source",
|
||||
"description": "Manage your own infrastructure, installing Dokploy UI on your own server."
|
||||
},
|
||||
"features": {
|
||||
"f1": "Complete Flexibility: Install Dokploy UI on your own infrastructure",
|
||||
"f2": "Self-hosted Infrastructure",
|
||||
"f3": "Community Support",
|
||||
"f4": "Access to Core Features",
|
||||
"f5": "Access to All Updates",
|
||||
"f9": "Unlimited Servers"
|
||||
},
|
||||
"go": "Installation"
|
||||
},
|
||||
"cloud": {
|
||||
"title": "Recommended",
|
||||
"section": {
|
||||
"title": "Dokploy Plan",
|
||||
"description": " to manage Dokploy UI infrastructure, we take care of it for you."
|
||||
},
|
||||
"servers": "{serverQuantity} Servers (You bring the servers)",
|
||||
"features": {
|
||||
"f1": "Managed Hosting: No need to manage your own servers",
|
||||
"f2": "Unlimited Deployments",
|
||||
"f3": "Unlimited Databases",
|
||||
"f4": "Unlimited Applications",
|
||||
"f5": "Unlimited Users",
|
||||
"f6": "Remote Servers Monitoring",
|
||||
"f7": "Priority Support",
|
||||
"f8": "New Updates"
|
||||
},
|
||||
"go": "Subscribe"
|
||||
}
|
||||
},
|
||||
"faq": {
|
||||
"title": "Frequently asked questions",
|
||||
"description": "If you can't find what you're looking for, please send us an email to",
|
||||
"q1": "How does Dokploy's Open Source plan work?",
|
||||
"a1": "You can host Dokploy UI on your own infrastructure and you will be responsible for the maintenance and updates.",
|
||||
"q2": "Do I need to provide my own server for the managed plan?",
|
||||
"a2": "Yes, in the managed plan, you provide your own server eg(Hetzner, Hostinger, AWS, ETC.) VPS, and we manage the Dokploy UI infrastructure for you.",
|
||||
"q3": "What happens if I need more than one server?",
|
||||
"a3": "The first server costs $4.50/month, if you buy more than one it will be $3.50/month per server.",
|
||||
"q4": "Is there a limit on the number of deployments?",
|
||||
"a4": "No, there is no limit on the number of deployments in any of the plans.",
|
||||
"q5": "What happens if I exceed my purchased server limit?",
|
||||
"a5": "The most recently added servers will be deactivated. You won't be able to create services on inactive servers until they are reactivated.",
|
||||
"q6": "Do you offer a refunds?",
|
||||
"a6": "We do not offer refunds. However, you can cancel your subscription at any time. Feel free to try our open-source version for free before making a purchase.",
|
||||
"q7": "What kind of support do you offer?",
|
||||
"a7": "We offer community support for the open source version and priority support for paid plans.",
|
||||
"q8": "Is Dokploy open-source?",
|
||||
"a8": "Yes, Dokploy is fully open-source. You can contribute or modify it as needed for your projects."
|
||||
}
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Latest news, updates, and articles from Dokploy",
|
||||
"noPosts": "No posts available",
|
||||
"noResults": "No posts found matching your criteria",
|
||||
"searchPlaceholder": "Search posts...",
|
||||
"allTags": "All Tags",
|
||||
"relatedPosts": "Related Posts",
|
||||
"tagDescription": "Posts tagged with",
|
||||
"foundPosts": "{count, plural, =0 {No posts found} one {# post found} other {# posts found}}",
|
||||
"tagTitle": "Posts tagged with {tag}",
|
||||
"backToBlog": "Back to Blog",
|
||||
"tags": "Tags",
|
||||
"postsTaggedWith": "Posts tagged with"
|
||||
},
|
||||
"Contact": {
|
||||
"title": "Contact Us",
|
||||
"description": "Get in touch with our team. We're here to help with any questions about Dokploy.",
|
||||
"successTitle": "Thank you for contacting us!",
|
||||
"successMessage": "We've received your message and will get back to you as soon as possible.",
|
||||
"errorMessage": "There was an error sending your message. Please try again.",
|
||||
"fields": {
|
||||
"inquiryType": {
|
||||
"label": "What can we help you with today?",
|
||||
"placeholder": "Select an option",
|
||||
"options": {
|
||||
"support": "Support",
|
||||
"sales": "Sales",
|
||||
"other": "Other"
|
||||
}
|
||||
},
|
||||
"firstName": {
|
||||
"label": "First Name",
|
||||
"placeholder": "Your first name"
|
||||
},
|
||||
"lastName": {
|
||||
"label": "Last Name",
|
||||
"placeholder": "Your last name"
|
||||
},
|
||||
"email": {
|
||||
"label": "Email",
|
||||
"placeholder": "your.email@company.com"
|
||||
},
|
||||
"company": {
|
||||
"label": "Company Name",
|
||||
"placeholder": "Your company name"
|
||||
},
|
||||
"message": {
|
||||
"label": "How can we help?",
|
||||
"placeholder": "Tell us more about your inquiry..."
|
||||
}
|
||||
},
|
||||
"buttons": {
|
||||
"send": "Send Message",
|
||||
"sending": "Sending...",
|
||||
"sendAnother": "Send Another Message"
|
||||
},
|
||||
"errors": {
|
||||
"inquiryTypeRequired": "Please select what we can help you with",
|
||||
"firstNameRequired": "First name is required",
|
||||
"lastNameRequired": "Last name is required",
|
||||
"emailRequired": "Email is required",
|
||||
"emailInvalid": "Please enter a valid email address",
|
||||
"companyRequired": "Company name is required",
|
||||
"messageRequired": "Message is required"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@
|
||||
"framer-motion": "^11.3.19",
|
||||
"lucide-react": "0.364.0",
|
||||
"next": "15.4.5",
|
||||
"next-intl": "^3.26.5",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-ga4": "^2.1.0",
|
||||
|
||||
3168
apps/website/pnpm-lock.yaml
generated
3168
apps/website/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -36,7 +36,7 @@ install_dokploy() {
|
||||
if command_exists docker; then
|
||||
echo "Docker already installed"
|
||||
else
|
||||
curl -sSL https://get.docker.com | sh
|
||||
curl -sSL https://get.docker.com | sh -s -- --version 28.5.0
|
||||
fi
|
||||
|
||||
docker swarm leave --force 2>/dev/null
|
||||
@@ -156,7 +156,7 @@ install_dokploy() {
|
||||
--restart always \
|
||||
-v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
|
||||
-v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
-p 80:80/tcp \
|
||||
-p 443:443/tcp \
|
||||
-p 443:443/udp \
|
||||
@@ -169,9 +169,10 @@ install_dokploy() {
|
||||
# --name dokploy-traefik \
|
||||
# --constraint 'node.role==manager' \
|
||||
# --network dokploy-network \
|
||||
# --security-opt no-new-privileges:true \
|
||||
# --mount type=bind,source=/etc/dokploy/traefik/traefik.yml,target=/etc/traefik/traefik.yml \
|
||||
# --mount type=bind,source=/etc/dokploy/traefik/dynamic,target=/etc/dokploy/traefik/dynamic \
|
||||
# --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
|
||||
# --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,readonly \
|
||||
# --publish mode=host,published=443,target=443 \
|
||||
# --publish mode=host,published=80,target=80 \
|
||||
# --publish mode=host,published=443,target=443,protocol=udp \
|
||||
@@ -218,4 +219,4 @@ if [ "$1" = "update" ]; then
|
||||
update_dokploy
|
||||
else
|
||||
install_dokploy
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -36,7 +36,7 @@ install_dokploy() {
|
||||
if command_exists docker; then
|
||||
echo "Docker already installed"
|
||||
else
|
||||
curl -sSL https://get.docker.com | sh
|
||||
curl -sSL https://get.docker.com | sh -s -- --version 28.5.0
|
||||
fi
|
||||
|
||||
docker swarm leave --force 2>/dev/null
|
||||
@@ -158,7 +158,7 @@ install_dokploy() {
|
||||
--restart always \
|
||||
-v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
|
||||
-v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
-p 80:80/tcp \
|
||||
-p 443:443/tcp \
|
||||
-p 443:443/udp \
|
||||
@@ -221,4 +221,4 @@ if [ "$1" = "update" ]; then
|
||||
update_dokploy
|
||||
else
|
||||
install_dokploy
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -52,7 +52,7 @@ install_dokploy() {
|
||||
if command_exists docker; then
|
||||
echo "Docker already installed"
|
||||
else
|
||||
curl -sSL https://get.docker.com | sh
|
||||
curl -sSL https://get.docker.com | sh -s -- --version 28.5.0
|
||||
fi
|
||||
|
||||
# Check if running in Proxmox LXC container and set endpoint mode
|
||||
@@ -185,7 +185,7 @@ install_dokploy() {
|
||||
--restart always \
|
||||
-v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
|
||||
-v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
-p 80:80/tcp \
|
||||
-p 443:443/tcp \
|
||||
-p 443:443/udp \
|
||||
|
||||
77
pnpm-lock.yaml
generated
77
pnpm-lock.yaml
generated
@@ -163,9 +163,6 @@ importers:
|
||||
next:
|
||||
specifier: 15.4.5
|
||||
version: 15.4.5(@babel/core@7.26.9)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
next-intl:
|
||||
specifier: ^3.26.5
|
||||
version: 3.26.5(next@15.4.5(@babel/core@7.26.9)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0)
|
||||
prettier:
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
@@ -847,21 +844,6 @@ packages:
|
||||
'@floating-ui/utils@0.2.9':
|
||||
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
||||
|
||||
'@formatjs/ecma402-abstract@2.0.0':
|
||||
resolution: {integrity: sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==}
|
||||
|
||||
'@formatjs/fast-memoize@2.2.0':
|
||||
resolution: {integrity: sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==}
|
||||
|
||||
'@formatjs/icu-messageformat-parser@2.7.8':
|
||||
resolution: {integrity: sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==}
|
||||
|
||||
'@formatjs/icu-skeleton-parser@1.8.2':
|
||||
resolution: {integrity: sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==}
|
||||
|
||||
'@formatjs/intl-localematcher@0.5.4':
|
||||
resolution: {integrity: sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==}
|
||||
|
||||
'@formatjs/intl-localematcher@0.5.7':
|
||||
resolution: {integrity: sha512-GGFtfHGQVFe/niOZp24Kal5b2i36eE2bNL0xi9Sg/yd0TR8aLjcteApZdHmismP5QQax1cMnZM9yWySUUjJteA==}
|
||||
|
||||
@@ -2656,9 +2638,6 @@ packages:
|
||||
inline-style-parser@0.2.3:
|
||||
resolution: {integrity: sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==}
|
||||
|
||||
intl-messageformat@10.5.14:
|
||||
resolution: {integrity: sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==}
|
||||
|
||||
invariant@2.2.4:
|
||||
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||
|
||||
@@ -3100,12 +3079,6 @@ packages:
|
||||
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
next-intl@3.26.5:
|
||||
resolution: {integrity: sha512-EQlCIfY0jOhRldiFxwSXG+ImwkQtDEfQeSOEQp6ieAGSLWGlgjdb/Ck/O7wMfC430ZHGeUKVKax8KGusTPKCgg==}
|
||||
peerDependencies:
|
||||
next: ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
|
||||
|
||||
next-themes@0.4.3:
|
||||
resolution: {integrity: sha512-nG84VPkTdUHR2YeD89YchvV4I9RbiMAql3GiLEQlPvq1ioaqPaIReK+yMRdg/zgiXws620qS1rU30TiWmmG9lA==}
|
||||
peerDependencies:
|
||||
@@ -3873,11 +3846,6 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
use-intl@3.26.5:
|
||||
resolution: {integrity: sha512-OdsJnC/znPvHCHLQH/duvQNXnP1w0hPfS+tkSi3mAbfjYBGh4JnyfdwkQBfIVf7t8gs9eSX/CntxUMvtKdG2MQ==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
|
||||
|
||||
use-sidecar@1.1.2:
|
||||
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -4461,30 +4429,6 @@ snapshots:
|
||||
|
||||
'@floating-ui/utils@0.2.9': {}
|
||||
|
||||
'@formatjs/ecma402-abstract@2.0.0':
|
||||
dependencies:
|
||||
'@formatjs/intl-localematcher': 0.5.4
|
||||
tslib: 2.6.3
|
||||
|
||||
'@formatjs/fast-memoize@2.2.0':
|
||||
dependencies:
|
||||
tslib: 2.6.3
|
||||
|
||||
'@formatjs/icu-messageformat-parser@2.7.8':
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 2.0.0
|
||||
'@formatjs/icu-skeleton-parser': 1.8.2
|
||||
tslib: 2.6.3
|
||||
|
||||
'@formatjs/icu-skeleton-parser@1.8.2':
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 2.0.0
|
||||
tslib: 2.6.3
|
||||
|
||||
'@formatjs/intl-localematcher@0.5.4':
|
||||
dependencies:
|
||||
tslib: 2.6.3
|
||||
|
||||
'@formatjs/intl-localematcher@0.5.7':
|
||||
dependencies:
|
||||
tslib: 2.6.3
|
||||
@@ -6673,13 +6617,6 @@ snapshots:
|
||||
|
||||
inline-style-parser@0.2.3: {}
|
||||
|
||||
intl-messageformat@10.5.14:
|
||||
dependencies:
|
||||
'@formatjs/ecma402-abstract': 2.0.0
|
||||
'@formatjs/fast-memoize': 2.2.0
|
||||
'@formatjs/icu-messageformat-parser': 2.7.8
|
||||
tslib: 2.6.3
|
||||
|
||||
invariant@2.2.4:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
@@ -7354,14 +7291,6 @@ snapshots:
|
||||
|
||||
negotiator@1.0.0: {}
|
||||
|
||||
next-intl@3.26.5(next@15.4.5(@babel/core@7.26.9)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0):
|
||||
dependencies:
|
||||
'@formatjs/intl-localematcher': 0.5.7
|
||||
negotiator: 1.0.0
|
||||
next: 15.4.5(@babel/core@7.26.9)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
react: 18.2.0
|
||||
use-intl: 3.26.5(react@18.2.0)
|
||||
|
||||
next-themes@0.4.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
@@ -8243,12 +8172,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.5
|
||||
|
||||
use-intl@3.26.5(react@18.2.0):
|
||||
dependencies:
|
||||
'@formatjs/fast-memoize': 2.2.0
|
||||
intl-messageformat: 10.5.14
|
||||
react: 18.2.0
|
||||
|
||||
use-sidecar@1.1.2(@types/react@18.3.5)(react@18.2.0):
|
||||
dependencies:
|
||||
detect-node-es: 1.1.0
|
||||
|
||||
Reference in New Issue
Block a user