mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
chore(website): make biome happy
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { notFound } from 'next/navigation'
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
export default function CatchAll() {
|
export default function CatchAll() {
|
||||||
notFound()
|
notFound();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,94 +1,90 @@
|
|||||||
import clsx from 'clsx'
|
import clsx from "clsx";
|
||||||
import { Inter, Lexend } from 'next/font/google'
|
import { Inter, Lexend } from "next/font/google";
|
||||||
import '@/styles/tailwind.css'
|
import "@/styles/tailwind.css";
|
||||||
import GoogleAnalytics from '@/components/analitycs/google'
|
import GoogleAnalytics from "@/components/analitycs/google";
|
||||||
|
|
||||||
import { NextIntlClientProvider } from 'next-intl'
|
import { NextIntlClientProvider } from "next-intl";
|
||||||
import { getMessages } from 'next-intl/server'
|
import { getMessages } from "next-intl/server";
|
||||||
|
|
||||||
import type { Metadata } from 'next'
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: {
|
title: {
|
||||||
default: 'Dokploy - Effortless Deployment Solutions',
|
default: "Dokploy - Effortless Deployment Solutions",
|
||||||
template: '%s | Simplify Your DevOps',
|
template: "%s | Simplify Your DevOps",
|
||||||
},
|
},
|
||||||
alternates: {
|
alternates: {
|
||||||
canonical: 'https://dokploy.com',
|
canonical: "https://dokploy.com",
|
||||||
languages: {
|
languages: {
|
||||||
en: 'https://dokploy.com',
|
en: "https://dokploy.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
description:
|
description:
|
||||||
'Streamline your deployment process with Dokploy. Effortlessly manage applications and databases on any VPS using Docker and Traefik for improved performance and security.',
|
"Streamline your deployment process with Dokploy. Effortlessly manage applications and databases on any VPS using Docker and Traefik for improved performance and security.",
|
||||||
applicationName: 'Dokploy',
|
applicationName: "Dokploy",
|
||||||
keywords: [
|
keywords: [
|
||||||
'Dokploy',
|
"Dokploy",
|
||||||
'Docker',
|
"Docker",
|
||||||
'Traefik',
|
"Traefik",
|
||||||
'deployment',
|
"deployment",
|
||||||
'VPS',
|
"VPS",
|
||||||
'application management',
|
"application management",
|
||||||
'database management',
|
"database management",
|
||||||
'DevOps',
|
"DevOps",
|
||||||
'cloud infrastructure',
|
"cloud infrastructure",
|
||||||
'UI Self hosted',
|
"UI Self hosted",
|
||||||
],
|
],
|
||||||
referrer: 'origin',
|
referrer: "origin",
|
||||||
robots: 'index, follow',
|
robots: "index, follow",
|
||||||
openGraph: {
|
openGraph: {
|
||||||
type: 'website',
|
type: "website",
|
||||||
url: 'https://dokploy.com',
|
url: "https://dokploy.com",
|
||||||
title: 'Dokploy - Effortless Deployment Solutions',
|
title: "Dokploy - Effortless Deployment Solutions",
|
||||||
description:
|
description:
|
||||||
'Simplify your DevOps with Dokploy. Deploy applications and manage databases efficiently on any VPS.',
|
"Simplify your DevOps with Dokploy. Deploy applications and manage databases efficiently on any VPS.",
|
||||||
siteName: 'Dokploy',
|
siteName: "Dokploy",
|
||||||
images: [
|
images: [
|
||||||
{
|
{
|
||||||
url: 'http://dokploy.com/og.png',
|
url: "http://dokploy.com/og.png",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: 'summary_large_image',
|
card: "summary_large_image",
|
||||||
site: '@Dokploy',
|
site: "@Dokploy",
|
||||||
creator: '@Dokploy',
|
creator: "@Dokploy",
|
||||||
title: 'Dokploy - Simplify Your DevOps',
|
title: "Dokploy - Simplify Your DevOps",
|
||||||
description:
|
description:
|
||||||
'Deploy applications and manage databases with ease using Dokploy. Learn how our platform can elevate your infrastructure management.',
|
"Deploy applications and manage databases with ease using Dokploy. Learn how our platform can elevate your infrastructure management.",
|
||||||
images: 'https://dokploy.com/og.png',
|
images: "https://dokploy.com/og.png",
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const inter = Inter({
|
const inter = Inter({
|
||||||
subsets: ['latin'],
|
subsets: ["latin"],
|
||||||
display: 'swap',
|
display: "swap",
|
||||||
variable: '--font-inter',
|
variable: "--font-inter",
|
||||||
})
|
});
|
||||||
|
|
||||||
const lexend = Lexend({
|
const lexend = Lexend({
|
||||||
subsets: ['latin'],
|
subsets: ["latin"],
|
||||||
display: 'swap',
|
display: "swap",
|
||||||
variable: '--font-lexend',
|
variable: "--font-lexend",
|
||||||
})
|
});
|
||||||
|
|
||||||
export default async function RootLayout({
|
export default async function RootLayout({
|
||||||
children,
|
children,
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode
|
children: React.ReactNode;
|
||||||
params: { locale: string }
|
params: { locale: string };
|
||||||
}) {
|
}) {
|
||||||
const { locale } = params
|
const { locale } = params;
|
||||||
const messages = await getMessages()
|
const messages = await getMessages();
|
||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
lang={locale}
|
lang={locale}
|
||||||
className={clsx(
|
className={clsx("h-full scroll-smooth", inter.variable, lexend.variable)}
|
||||||
'h-full scroll-smooth',
|
|
||||||
inter.variable,
|
|
||||||
lexend.variable,
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<GoogleAnalytics />
|
<GoogleAnalytics />
|
||||||
<body className="flex h-full flex-col">
|
<body className="flex h-full flex-col">
|
||||||
@@ -97,5 +93,5 @@ export default async function RootLayout({
|
|||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { SlimLayout } from '@/components/SlimLayout'
|
import { SlimLayout } from "@/components/SlimLayout";
|
||||||
|
|
||||||
export default function NotFound() {
|
export default function NotFound() {
|
||||||
return <SlimLayout />
|
return <SlimLayout />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { CallToAction } from '@/components/CallToAction'
|
import { CallToAction } from "@/components/CallToAction";
|
||||||
import { Faqs } from '@/components/Faqs'
|
import { Faqs } from "@/components/Faqs";
|
||||||
import { Footer } from '@/components/Footer'
|
import { Footer } from "@/components/Footer";
|
||||||
import { Header } from '@/components/Header'
|
import { Header } from "@/components/Header";
|
||||||
import { Hero } from '@/components/Hero'
|
import { Hero } from "@/components/Hero";
|
||||||
import { PrimaryFeatures } from '@/components/PrimaryFeatures'
|
import { PrimaryFeatures } from "@/components/PrimaryFeatures";
|
||||||
import { SecondaryFeatures } from '@/components/SecondaryFeatures'
|
import { SecondaryFeatures } from "@/components/SecondaryFeatures";
|
||||||
import { Testimonials } from '../../components/Testimonials'
|
import { Testimonials } from "../../components/Testimonials";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
@@ -21,5 +21,5 @@ export default function Home() {
|
|||||||
<Footer />
|
<Footer />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { ReactNode } from 'react'
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: ReactNode
|
children: ReactNode;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Since we have a `not-found.tsx` page on the root, a layout file
|
// Since we have a `not-found.tsx` page on the root, a layout file
|
||||||
// is required, even if it's just passing children through.
|
// is required, even if it's just passing children through.
|
||||||
export default function RootLayout({ children }: Props) {
|
export default function RootLayout({ children }: Props) {
|
||||||
return children
|
return children;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
'use client'
|
"use client";
|
||||||
|
|
||||||
import Error from 'next/error'
|
import NextError from "next/error";
|
||||||
|
|
||||||
export default function NotFound() {
|
export default function NotFound() {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body>
|
<body>
|
||||||
<Error statusCode={404} />
|
<NextError statusCode={404} />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,58 +1,57 @@
|
|||||||
import { useTranslations } from 'next-intl'
|
import { useTranslations } from "next-intl";
|
||||||
import { Container } from './Container'
|
import { Container } from "./Container";
|
||||||
|
|
||||||
const faqs = [
|
const faqs = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
question: 'faq.q1',
|
question: "faq.q1",
|
||||||
answer: 'faq.a1',
|
answer: "faq.a1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'faq.q2',
|
question: "faq.q2",
|
||||||
answer: 'faq.a2',
|
answer: "faq.a2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'faq.q3',
|
question: "faq.q3",
|
||||||
answer: 'faq.a3',
|
answer: "faq.a3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'faq.q4',
|
question: "faq.q4",
|
||||||
answer: 'faq.a4',
|
answer: "faq.a4",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
question: 'faq.q5',
|
question: "faq.q5",
|
||||||
answer: 'faq.a5',
|
answer: "faq.a5",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'faq.q6',
|
question: "faq.q6",
|
||||||
answer: 'faq.a6',
|
answer: "faq.a6",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'faq.q7',
|
question: "faq.q7",
|
||||||
answer: "faq.a7",
|
answer: "faq.a7",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
question:
|
question: "faq.q8",
|
||||||
'faq.q8',
|
answer: "faq.a8",
|
||||||
answer: 'faq.a8',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'faq.q9',
|
question: "faq.q9",
|
||||||
answer: 'faq.a9',
|
answer: "faq.a9",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'faq.q10',
|
question: "faq.q10",
|
||||||
answer: 'faq.a10',
|
answer: "faq.a10",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
]
|
];
|
||||||
|
|
||||||
export function Faqs() {
|
export function Faqs() {
|
||||||
const t = useTranslations('HomePage')
|
const t = useTranslations("HomePage");
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
id="faqs"
|
id="faqs"
|
||||||
@@ -65,10 +64,10 @@ export function Faqs() {
|
|||||||
id="faq-title"
|
id="faq-title"
|
||||||
className="font-display text-3xl tracking-tight text-primary sm:text-4xl"
|
className="font-display text-3xl tracking-tight text-primary sm:text-4xl"
|
||||||
>
|
>
|
||||||
{t('faq.title')}
|
{t("faq.title")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-4 text-lg tracking-tight text-muted-foreground">
|
<p className="mt-4 text-lg tracking-tight text-muted-foreground">
|
||||||
{t('faq.des')}
|
{t("faq.des")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<ul className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-8 lg:max-w-none lg:grid-cols-3">
|
<ul className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-8 lg:max-w-none lg:grid-cols-3">
|
||||||
@@ -91,5 +90,5 @@ export function Faqs() {
|
|||||||
</ul>
|
</ul>
|
||||||
</Container>
|
</Container>
|
||||||
</section>
|
</section>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import Link from 'next/link'
|
import Link from "next/link";
|
||||||
|
|
||||||
import { Container } from './Container'
|
import { useTranslations } from "next-intl";
|
||||||
import { NavLink } from './NavLink'
|
import { Container } from "./Container";
|
||||||
import { Logo } from './shared/Logo'
|
import { NavLink } from "./NavLink";
|
||||||
import { useTranslations } from 'next-intl'
|
import { Logo } from "./shared/Logo";
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
const t = useTranslations('HomePage')
|
const t = useTranslations("HomePage");
|
||||||
const linkT = useTranslations('Link')
|
const linkT = useTranslations("Link");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="bg-black">
|
<footer className="bg-black">
|
||||||
@@ -22,14 +22,10 @@ export function Footer() {
|
|||||||
|
|
||||||
<nav className="mt-10 text-sm" aria-label="quick links">
|
<nav className="mt-10 text-sm" aria-label="quick links">
|
||||||
<div className="-my-1 flex flex-wrap justify-center gap-6">
|
<div className="-my-1 flex flex-wrap justify-center gap-6">
|
||||||
<NavLink href="/#features">
|
<NavLink href="/#features">{t("navigation.features")}</NavLink>
|
||||||
{t('navigation.features')}
|
<NavLink href="/#faqs">{t("navigation.faqs")}</NavLink>
|
||||||
</NavLink>
|
<NavLink href={linkT("docs.intro")} target="_blank">
|
||||||
<NavLink href="/#faqs">
|
{t("navigation.docs")}
|
||||||
{t('navigation.faqs')}
|
|
||||||
</NavLink>
|
|
||||||
<NavLink href={linkT('docs.intro')} target="_blank">
|
|
||||||
{t('navigation.docs')}
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -62,12 +58,12 @@ export function Footer() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-6 text-sm text-muted-foreground sm:mt-0">
|
<p className="mt-6 text-sm text-muted-foreground sm:mt-0">
|
||||||
{t('footer.copyright', {
|
{t("footer.copyright", {
|
||||||
year: new Date().getFullYear(),
|
year: new Date().getFullYear(),
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
</footer>
|
</footer>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
'use client'
|
"use client";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import { Popover, Transition } from '@headlessui/react'
|
|
||||||
import { HeartIcon } from 'lucide-react'
|
|
||||||
import { Fragment, JSX, SVGProps } from 'react'
|
|
||||||
import { Container } from './Container'
|
|
||||||
import { NavLink } from './NavLink'
|
|
||||||
import { trackGAEvent } from './analitycs'
|
|
||||||
import { Logo } from './shared/Logo'
|
|
||||||
import { Button, buttonVariants } from './ui/button'
|
|
||||||
import { useLocale, useTranslations } from 'next-intl'
|
|
||||||
import { Link, useRouter } from '@/i18n/routing'
|
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
} from '@/components/ui/select'
|
} from "@/components/ui/select";
|
||||||
|
import { Link, useRouter } from "@/i18n/routing";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
|
import { HeartIcon } from "lucide-react";
|
||||||
|
import { useLocale, useTranslations } from "next-intl";
|
||||||
|
import { Fragment, type JSX, type SVGProps } from "react";
|
||||||
|
import { Container } from "./Container";
|
||||||
|
import { NavLink } from "./NavLink";
|
||||||
|
import { trackGAEvent } from "./analitycs";
|
||||||
|
import { Logo } from "./shared/Logo";
|
||||||
|
import { Button, buttonVariants } from "./ui/button";
|
||||||
|
|
||||||
function MobileNavLink({
|
function MobileNavLink({
|
||||||
href,
|
href,
|
||||||
children,
|
children,
|
||||||
target,
|
target,
|
||||||
}: {
|
}: {
|
||||||
href: string
|
href: string;
|
||||||
children: React.ReactNode
|
children: React.ReactNode;
|
||||||
target?: string
|
target?: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
trackGAEvent({
|
trackGAEvent({
|
||||||
action: 'Nav Link Clicked',
|
action: "Nav Link Clicked",
|
||||||
category: 'Navigation',
|
category: "Navigation",
|
||||||
label: href,
|
label: href,
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
as={Link}
|
as={Link}
|
||||||
href={href}
|
href={href}
|
||||||
@@ -43,7 +43,7 @@ function MobileNavLink({
|
|||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MobileNavIcon({ open }: { open: boolean }) {
|
function MobileNavIcon({ open }: { open: boolean }) {
|
||||||
@@ -57,20 +57,17 @@ function MobileNavIcon({ open }: { open: boolean }) {
|
|||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M0 1H14M0 7H14M0 13H14"
|
d="M0 1H14M0 7H14M0 13H14"
|
||||||
className={cn(
|
className={cn("origin-center transition", open && "scale-90 opacity-0")}
|
||||||
'origin-center transition',
|
|
||||||
open && 'scale-90 opacity-0',
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M2 2L12 12M12 2L2 12"
|
d="M2 2L12 12M12 2L2 12"
|
||||||
className={cn(
|
className={cn(
|
||||||
'origin-center transition',
|
"origin-center transition",
|
||||||
!open && 'scale-90 opacity-0',
|
!open && "scale-90 opacity-0",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const I18nIcon = (props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) => (
|
const I18nIcon = (props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) => (
|
||||||
@@ -89,11 +86,11 @@ const I18nIcon = (props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) => (
|
|||||||
d="m478.33 433.6-90-218a22 22 0 0 0-40.67 0l-90 218a22 22 0 1 0 40.67 16.79L316.66 406h102.67l18.33 44.39A22 22 0 0 0 458 464a22 22 0 0 0 20.32-30.4zM334.83 362 368 281.65 401.17 362zm-66.99-19.08a22 22 0 0 0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73 39.65-53.68 62.11-114.75 71.27-143.49H330a22 22 0 0 0 0-44H214V70a22 22 0 0 0-44 0v20H54a22 22 0 0 0 0 44h197.25c-9.52 26.95-27.05 69.5-53.79 108.36-31.41-41.68-43.08-68.65-43.17-68.87a22 22 0 0 0-40.58 17c.58 1.38 14.55 34.23 52.86 83.93.92 1.19 1.83 2.35 2.74 3.51-39.24 44.35-77.74 71.86-93.85 80.74a22 22 0 1 0 21.07 38.63c2.16-1.18 48.6-26.89 101.63-85.59 22.52 24.08 38 35.44 38.93 36.1a22 22 0 0 0 30.75-4.9z"
|
d="m478.33 433.6-90-218a22 22 0 0 0-40.67 0l-90 218a22 22 0 1 0 40.67 16.79L316.66 406h102.67l18.33 44.39A22 22 0 0 0 458 464a22 22 0 0 0 20.32-30.4zM334.83 362 368 281.65 401.17 362zm-66.99-19.08a22 22 0 0 0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73 39.65-53.68 62.11-114.75 71.27-143.49H330a22 22 0 0 0 0-44H214V70a22 22 0 0 0-44 0v20H54a22 22 0 0 0 0 44h197.25c-9.52 26.95-27.05 69.5-53.79 108.36-31.41-41.68-43.08-68.65-43.17-68.87a22 22 0 0 0-40.58 17c.58 1.38 14.55 34.23 52.86 83.93.92 1.19 1.83 2.35 2.74 3.51-39.24 44.35-77.74 71.86-93.85 80.74a22 22 0 1 0 21.07 38.63c2.16-1.18 48.6-26.89 101.63-85.59 22.52 24.08 38 35.44 38.93 36.1a22 22 0 0 0 30.75-4.9z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
);
|
||||||
|
|
||||||
function MobileNavigation() {
|
function MobileNavigation() {
|
||||||
const t = useTranslations('HomePage')
|
const t = useTranslations("HomePage");
|
||||||
const linkT = useTranslations('Link')
|
const linkT = useTranslations("Link");
|
||||||
return (
|
return (
|
||||||
<Popover>
|
<Popover>
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
@@ -129,30 +126,25 @@ function MobileNavigation() {
|
|||||||
className="absolute inset-x-0 top-full mt-4 flex origin-top flex-col rounded-2xl border border-border bg-background p-4 text-lg tracking-tight text-primary shadow-xl ring-1 ring-border/5"
|
className="absolute inset-x-0 top-full mt-4 flex origin-top flex-col rounded-2xl border border-border bg-background p-4 text-lg tracking-tight text-primary shadow-xl ring-1 ring-border/5"
|
||||||
>
|
>
|
||||||
<MobileNavLink href="/#features">
|
<MobileNavLink href="/#features">
|
||||||
{t('navigation.features')}
|
{t("navigation.features")}
|
||||||
</MobileNavLink>
|
</MobileNavLink>
|
||||||
{/* <MobileNavLink href="/#testimonials">Testimonials</MobileNavLink> */}
|
{/* <MobileNavLink href="/#testimonials">Testimonials</MobileNavLink> */}
|
||||||
<MobileNavLink href="/#faqs">
|
<MobileNavLink href="/#faqs">{t("navigation.faqs")}</MobileNavLink>
|
||||||
{t('navigation.faqs')}
|
<MobileNavLink href={linkT("docs.intro")} target="_blank">
|
||||||
</MobileNavLink>
|
{t("navigation.docs")}
|
||||||
<MobileNavLink
|
|
||||||
href={linkT('docs.intro')}
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
{t('navigation.docs')}
|
|
||||||
</MobileNavLink>
|
</MobileNavLink>
|
||||||
</Popover.Panel>
|
</Popover.Panel>
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
</Popover>
|
</Popover>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
const locale = useLocale()
|
const locale = useLocale();
|
||||||
const t = useTranslations('HomePage')
|
const t = useTranslations("HomePage");
|
||||||
const linkT = useTranslations('Link')
|
const linkT = useTranslations("Link");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="bg-background py-10">
|
<header className="bg-background py-10">
|
||||||
@@ -163,57 +155,50 @@ export function Header() {
|
|||||||
<Logo className="h-10 w-auto" />
|
<Logo className="h-10 w-auto" />
|
||||||
</Link>
|
</Link>
|
||||||
<div className="hidden md:flex md:gap-x-6">
|
<div className="hidden md:flex md:gap-x-6">
|
||||||
<NavLink href="/#features">
|
<NavLink href="/#features">{t("navigation.features")}</NavLink>
|
||||||
{t('navigation.features')}
|
|
||||||
</NavLink>
|
|
||||||
{/* <NavLink href="/#testimonials">Testimonials</NavLink> */}
|
{/* <NavLink href="/#testimonials">Testimonials</NavLink> */}
|
||||||
<NavLink href="/#faqs">
|
<NavLink href="/#faqs">{t("navigation.faqs")}</NavLink>
|
||||||
{t('navigation.faqs')}
|
<NavLink href={linkT("docs.intro")} target="_blank">
|
||||||
</NavLink>
|
{t("navigation.docs")}
|
||||||
<NavLink href={linkT('docs.intro')} target="_blank">
|
|
||||||
{t('navigation.docs')}
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-x-2 md:gap-x-5">
|
<div className="flex items-center gap-x-2 md:gap-x-5">
|
||||||
<Select
|
<Select
|
||||||
onValueChange={(locale) => {
|
onValueChange={(locale) => {
|
||||||
router.replace('/', {
|
router.replace("/", {
|
||||||
locale: locale as 'en' | 'zh-Hans',
|
locale: locale as "en" | "zh-Hans",
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
value={locale}
|
value={locale}
|
||||||
>
|
>
|
||||||
<SelectTrigger
|
<SelectTrigger
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
variant: 'outline',
|
variant: "outline",
|
||||||
className:
|
className:
|
||||||
' flex items-center gap-2 !rounded-full visited:outline-none focus-within:outline-none focus:outline-none',
|
" flex items-center gap-2 !rounded-full visited:outline-none focus-within:outline-none focus:outline-none",
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<I18nIcon width={20} height={20} />
|
<I18nIcon width={20} height={20} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="en">
|
<SelectItem value="en">{t("navigation.i18nEn")}</SelectItem>
|
||||||
{t('navigation.i18nEn')}
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="zh-Hans">
|
<SelectItem value="zh-Hans">
|
||||||
{t('navigation.i18nZh-Hans')}
|
{t("navigation.i18nZh-Hans")}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
variant: 'outline',
|
variant: "outline",
|
||||||
className:
|
className: " flex items-center gap-2 !rounded-full",
|
||||||
' flex items-center gap-2 !rounded-full',
|
|
||||||
})}
|
})}
|
||||||
href="https://opencollective.com/dokploy"
|
href="https://opencollective.com/dokploy"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<span className="text-sm font-semibold">
|
<span className="text-sm font-semibold">
|
||||||
{t('navigation.support')}{' '}
|
{t("navigation.support")}{" "}
|
||||||
</span>
|
</span>
|
||||||
<HeartIcon className="animate-heartbeat size-4 fill-red-600 text-red-500 " />
|
<HeartIcon className="animate-heartbeat size-4 fill-red-600 text-red-500 " />
|
||||||
</Link>
|
</Link>
|
||||||
@@ -236,7 +221,7 @@ export function Header() {
|
|||||||
>
|
>
|
||||||
<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" />
|
<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>
|
</svg>
|
||||||
{t('navigation.discord')}
|
{t("navigation.discord")}
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<div className="-mr-1 md:hidden">
|
<div className="-mr-1 md:hidden">
|
||||||
@@ -246,5 +231,5 @@ export function Header() {
|
|||||||
</nav>
|
</nav>
|
||||||
</Container>
|
</Container>
|
||||||
</header>
|
</header>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { Link } from "@/i18n/routing";
|
||||||
import { trackGAEvent } from "./analitycs";
|
import { trackGAEvent } from "./analitycs";
|
||||||
import { Link } from '@/i18n/routing'
|
|
||||||
|
|
||||||
export function NavLink({
|
export function NavLink({
|
||||||
href,
|
href,
|
||||||
|
|||||||
@@ -1,73 +1,73 @@
|
|||||||
'use client'
|
"use client";
|
||||||
|
|
||||||
import { Tab } from '@headlessui/react'
|
import { Tab } from "@headlessui/react";
|
||||||
import { AnimatePresence, motion } from 'framer-motion'
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
import { Container } from './Container'
|
import { useTranslations } from "next-intl";
|
||||||
import { useTranslations } from 'next-intl'
|
import { Container } from "./Container";
|
||||||
|
|
||||||
const features = [
|
const features = [
|
||||||
{
|
{
|
||||||
title: 'primaryFeatures.projects',
|
title: "primaryFeatures.projects",
|
||||||
description: 'primaryFeatures.projectsDes',
|
description: "primaryFeatures.projectsDes",
|
||||||
image: '/primary/projects.png',
|
image: "/primary/projects.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'primaryFeatures.applications',
|
title: "primaryFeatures.applications",
|
||||||
description: 'primaryFeatures.applicationsDes',
|
description: "primaryFeatures.applicationsDes",
|
||||||
image: '/primary/applications.png',
|
image: "/primary/applications.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'primaryFeatures.compose',
|
title: "primaryFeatures.compose",
|
||||||
description: 'primaryFeatures.composeDes',
|
description: "primaryFeatures.composeDes",
|
||||||
image: '/primary/compose.png',
|
image: "/primary/compose.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'primaryFeatures.multinode',
|
title: "primaryFeatures.multinode",
|
||||||
description: 'primaryFeatures.multinodeDes',
|
description: "primaryFeatures.multinodeDes",
|
||||||
image: '/primary/multinode.png',
|
image: "/primary/multinode.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'primaryFeatures.monitoring',
|
title: "primaryFeatures.monitoring",
|
||||||
description: 'primaryFeatures.monitoringDes',
|
description: "primaryFeatures.monitoringDes",
|
||||||
image: '/primary/monitoring.png',
|
image: "/primary/monitoring.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'primaryFeatures.backups',
|
title: "primaryFeatures.backups",
|
||||||
description: 'primaryFeatures.backupsDes',
|
description: "primaryFeatures.backupsDes",
|
||||||
image: '/primary/backups.png',
|
image: "/primary/backups.png",
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export function PrimaryFeatures() {
|
export function PrimaryFeatures() {
|
||||||
const t = useTranslations('HomePage')
|
const t = useTranslations("HomePage");
|
||||||
const [tabOrientation, setTabOrientation] = useState<
|
const [tabOrientation, setTabOrientation] = useState<
|
||||||
'horizontal' | 'vertical'
|
"horizontal" | "vertical"
|
||||||
>('horizontal')
|
>("horizontal");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const lgMediaQuery = window.matchMedia('(min-width: 1024px)')
|
const lgMediaQuery = window.matchMedia("(min-width: 1024px)");
|
||||||
|
|
||||||
function onMediaQueryChange({ matches }: { matches: boolean }) {
|
function onMediaQueryChange({ matches }: { matches: boolean }) {
|
||||||
setTabOrientation(matches ? 'vertical' : 'horizontal')
|
setTabOrientation(matches ? "vertical" : "horizontal");
|
||||||
}
|
}
|
||||||
|
|
||||||
onMediaQueryChange(lgMediaQuery)
|
onMediaQueryChange(lgMediaQuery);
|
||||||
lgMediaQuery.addEventListener('change', onMediaQueryChange)
|
lgMediaQuery.addEventListener("change", onMediaQueryChange);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
lgMediaQuery.removeEventListener('change', onMediaQueryChange)
|
lgMediaQuery.removeEventListener("change", onMediaQueryChange);
|
||||||
}
|
};
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
const [isMounted, setIsMounted] = useState(false)
|
const [isMounted, setIsMounted] = useState(false);
|
||||||
|
|
||||||
// Cambiar isMounted a true después del primer render
|
// Cambiar isMounted a true después del primer render
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsMounted(true)
|
setIsMounted(true);
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
@@ -88,16 +88,16 @@ export function PrimaryFeatures() {
|
|||||||
<Container className="relative">
|
<Container className="relative">
|
||||||
<div className="max-w-2xl md:mx-auto md:text-center xl:max-w-none">
|
<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">
|
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl md:text-5xl">
|
||||||
{t('primaryFeatures.title')}
|
{t("primaryFeatures.title")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-6 text-lg tracking-tight text-muted-foreground">
|
<p className="mt-6 text-lg tracking-tight text-muted-foreground">
|
||||||
{t('primaryFeatures.des')}
|
{t("primaryFeatures.des")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Tab.Group
|
<Tab.Group
|
||||||
as="div"
|
as="div"
|
||||||
className="mt-16 grid grid-cols-1 items-center gap-y-2 pt-10 sm:gap-y-6 md:mt-20 lg:grid-cols-12 lg:pt-0"
|
className="mt-16 grid grid-cols-1 items-center gap-y-2 pt-10 sm:gap-y-6 md:mt-20 lg:grid-cols-12 lg:pt-0"
|
||||||
vertical={tabOrientation === 'vertical'}
|
vertical={tabOrientation === "vertical"}
|
||||||
>
|
>
|
||||||
{({ selectedIndex }) => (
|
{({ selectedIndex }) => (
|
||||||
<>
|
<>
|
||||||
@@ -113,12 +113,11 @@ export function PrimaryFeatures() {
|
|||||||
initial={false}
|
initial={false}
|
||||||
key={`feature-${featureIndex}`}
|
key={`feature-${featureIndex}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
'group relative rounded-full px-4 py-1 transition-colors lg:rounded-l-xl lg:rounded-r-none lg:p-6 ',
|
"group relative rounded-full px-4 py-1 transition-colors lg:rounded-l-xl lg:rounded-r-none lg:p-6 ",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{selectedIndex ===
|
{selectedIndex === featureIndex && (
|
||||||
featureIndex && (
|
|
||||||
<motion.span
|
<motion.span
|
||||||
layoutId="tab"
|
layoutId="tab"
|
||||||
className="absolute inset-0 z-10 rounded-full bg-white/5 mix-blend-difference lg:rounded-l-xl lg:rounded-r-none"
|
className="absolute inset-0 z-10 rounded-full bg-white/5 mix-blend-difference lg:rounded-l-xl lg:rounded-r-none"
|
||||||
@@ -126,7 +125,7 @@ export function PrimaryFeatures() {
|
|||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
transition={{
|
transition={{
|
||||||
type: 'spring',
|
type: "spring",
|
||||||
bounce: 0.2,
|
bounce: 0.2,
|
||||||
duration: 0.5,
|
duration: 0.5,
|
||||||
}}
|
}}
|
||||||
@@ -136,7 +135,7 @@ export function PrimaryFeatures() {
|
|||||||
<h3>
|
<h3>
|
||||||
<Tab
|
<Tab
|
||||||
className={cn(
|
className={cn(
|
||||||
'font-display text-lg text-primary ui-not-focus-visible:outline-none',
|
"font-display text-lg text-primary ui-not-focus-visible:outline-none",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="absolute inset-0 rounded-full lg:rounded-l-xl lg:rounded-r-none" />
|
<span className="absolute inset-0 rounded-full lg:rounded-l-xl lg:rounded-r-none" />
|
||||||
@@ -145,7 +144,7 @@ export function PrimaryFeatures() {
|
|||||||
</h3>
|
</h3>
|
||||||
<p
|
<p
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-2 hidden text-sm text-muted-foreground lg:block',
|
"mt-2 hidden text-sm text-muted-foreground lg:block",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{t(feature.description)}
|
{t(feature.description)}
|
||||||
@@ -166,19 +165,11 @@ export function PrimaryFeatures() {
|
|||||||
|
|
||||||
<motion.div
|
<motion.div
|
||||||
key={feature.title}
|
key={feature.title}
|
||||||
initial={
|
initial={isMounted ? { opacity: 0.8, x: 50 } : {}}
|
||||||
isMounted
|
animate={isMounted ? { opacity: 1, x: 0 } : {}}
|
||||||
? { opacity: 0.8, x: 50 }
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
animate={
|
|
||||||
isMounted
|
|
||||||
? { opacity: 1, x: 0 }
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
exit={{ opacity: 0, x: -50 }}
|
exit={{ opacity: 0, x: -50 }}
|
||||||
transition={{
|
transition={{
|
||||||
type: 'spring',
|
type: "spring",
|
||||||
bounce: 0.2,
|
bounce: 0.2,
|
||||||
duration: 0.6,
|
duration: 0.6,
|
||||||
}}
|
}}
|
||||||
@@ -199,5 +190,5 @@ export function PrimaryFeatures() {
|
|||||||
</Tab.Group>
|
</Tab.Group>
|
||||||
</Container>
|
</Container>
|
||||||
</section>
|
</section>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
'use client'
|
"use client";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
import { Tab } from '@headlessui/react'
|
import { Tab } from "@headlessui/react";
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from "framer-motion";
|
||||||
import { Layers, Terminal, Users } from 'lucide-react'
|
import { Layers, Terminal, Users } from "lucide-react";
|
||||||
import { Container } from './Container'
|
import { useTranslations } from "next-intl";
|
||||||
import { useTranslations } from 'next-intl'
|
import { Container } from "./Container";
|
||||||
interface Feature {
|
interface Feature {
|
||||||
name: React.ReactNode
|
name: React.ReactNode;
|
||||||
summary: string
|
summary: string;
|
||||||
description: string
|
description: string;
|
||||||
image: string
|
image: string;
|
||||||
icon: React.ComponentType
|
icon: React.ComponentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const features: Array<Feature> = [
|
const features: Array<Feature> = [
|
||||||
{
|
{
|
||||||
name: 'secondaryFeatures.templates',
|
name: "secondaryFeatures.templates",
|
||||||
summary: 'secondaryFeatures.templatesSummary',
|
summary: "secondaryFeatures.templatesSummary",
|
||||||
description: 'secondaryFeatures.templatesDes',
|
description: "secondaryFeatures.templatesDes",
|
||||||
image: '/secondary/templates.png',
|
image: "/secondary/templates.png",
|
||||||
icon: function ReportingIcon() {
|
icon: function ReportingIcon() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Layers className="size-5 text-primary" />
|
<Layers className="size-5 text-primary" />
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'secondaryFeatures.traefik',
|
name: "secondaryFeatures.traefik",
|
||||||
summary: 'secondaryFeatures.traefikSummary',
|
summary: "secondaryFeatures.traefikSummary",
|
||||||
description: 'secondaryFeatures.traefikDes',
|
description: "secondaryFeatures.traefikDes",
|
||||||
image: '/secondary/traefik.png',
|
image: "/secondary/traefik.png",
|
||||||
icon: function ReportingIcon() {
|
icon: function ReportingIcon() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -82,12 +82,7 @@ const features: Array<Feature> = [
|
|||||||
d="M299.847 285.567c10.027 58.288 105.304 42.877 91.619-15.91-12.271-52.716-94.951-38.124-91.619 15.91m-113.855 9.427c12.996 50.745 94.24 37.753 91.178-13.149-3.669-60.964-103.603-49.2-91.178 13.149m132.351 58.517c.044 7.79 1.843 15.403.289 24.148-1.935 3.656-5.729 4.043-9.001 5.52-4.524-.71-8.328-3.68-10.143-7.912-1.161-9.202.433-18.111.726-27.316l18.129 5.56z"
|
d="M299.847 285.567c10.027 58.288 105.304 42.877 91.619-15.91-12.271-52.716-94.951-38.124-91.619 15.91m-113.855 9.427c12.996 50.745 94.24 37.753 91.178-13.149-3.669-60.964-103.603-49.2-91.178 13.149m132.351 58.517c.044 7.79 1.843 15.403.289 24.148-1.935 3.656-5.729 4.043-9.001 5.52-4.524-.71-8.328-3.68-10.143-7.912-1.161-9.202.433-18.111.726-27.316l18.129 5.56z"
|
||||||
fill="#fff"
|
fill="#fff"
|
||||||
/>
|
/>
|
||||||
<ellipse
|
<ellipse cx="208.4" cy="286.718" rx="13.719" ry="14.86" />
|
||||||
cx="208.4"
|
|
||||||
cy="286.718"
|
|
||||||
rx="13.719"
|
|
||||||
ry="14.86"
|
|
||||||
/>
|
|
||||||
<ellipse
|
<ellipse
|
||||||
cx="214.64"
|
cx="214.64"
|
||||||
cy="290.071"
|
cy="290.071"
|
||||||
@@ -95,19 +90,9 @@ const features: Array<Feature> = [
|
|||||||
ry="3.777"
|
ry="3.777"
|
||||||
fill="#fff"
|
fill="#fff"
|
||||||
/>
|
/>
|
||||||
<ellipse
|
<ellipse cx="323.348" cy="283.017" rx="13.491" ry="14.86" />
|
||||||
cx="323.348"
|
|
||||||
cy="283.017"
|
|
||||||
rx="13.491"
|
|
||||||
ry="14.86"
|
|
||||||
/>
|
|
||||||
<g fill="#fff">
|
<g fill="#fff">
|
||||||
<ellipse
|
<ellipse cx="329.485" cy="286.371" rx="3.181" ry="3.777" />
|
||||||
cx="329.485"
|
|
||||||
cy="286.371"
|
|
||||||
rx="3.181"
|
|
||||||
ry="3.777"
|
|
||||||
/>
|
|
||||||
<path d="M279.137 354.685c-5.986 14.507 3.338 43.515 19.579 22.119-1.161-9.202.433-18.111.726-27.316l-20.305 5.197z" />
|
<path d="M279.137 354.685c-5.986 14.507 3.338 43.515 19.579 22.119-1.161-9.202.433-18.111.726-27.316l-20.305 5.197z" />
|
||||||
</g>
|
</g>
|
||||||
<path
|
<path
|
||||||
@@ -226,60 +211,60 @@ const features: Array<Feature> = [
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'secondaryFeatures.users',
|
name: "secondaryFeatures.users",
|
||||||
summary: 'secondaryFeatures.usersSummary',
|
summary: "secondaryFeatures.usersSummary",
|
||||||
description: 'secondaryFeatures.usersDes',
|
description: "secondaryFeatures.usersDes",
|
||||||
image: '/secondary/users.png',
|
image: "/secondary/users.png",
|
||||||
icon: function InventoryIcon() {
|
icon: function InventoryIcon() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Users className="size-5 text-primary" />
|
<Users className="size-5 text-primary" />
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'secondaryFeatures.terminal',
|
name: "secondaryFeatures.terminal",
|
||||||
summary: 'secondaryFeatures.terminalSummary',
|
summary: "secondaryFeatures.terminalSummary",
|
||||||
description: 'secondaryFeatures.terminalDes',
|
description: "secondaryFeatures.terminalDes",
|
||||||
image: '/secondary/terminal.png',
|
image: "/secondary/terminal.png",
|
||||||
icon: function ContactsIcon() {
|
icon: function ContactsIcon() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Terminal className="size-5 text-primary" />
|
<Terminal className="size-5 text-primary" />
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
function Feature({
|
function Feature({
|
||||||
feature,
|
feature,
|
||||||
isActive,
|
isActive,
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentPropsWithoutRef<'div'> & {
|
}: React.ComponentPropsWithoutRef<"div"> & {
|
||||||
feature: Feature
|
feature: Feature;
|
||||||
isActive: boolean
|
isActive: boolean;
|
||||||
}) {
|
}) {
|
||||||
const t = useTranslations('HomePage')
|
const t = useTranslations("HomePage");
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
className,
|
className,
|
||||||
!isActive ? 'opacity-75 hover:opacity-100 ' : 'rounded-xl',
|
!isActive ? "opacity-75 hover:opacity-100 " : "rounded-xl",
|
||||||
' relative p-4',
|
" relative p-4",
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex size-9 items-center justify-center rounded-lg',
|
"flex size-9 items-center justify-center rounded-lg",
|
||||||
isActive ? 'bg-border' : 'bg-muted',
|
isActive ? "bg-border" : "bg-muted",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<feature.icon />
|
<feature.icon />
|
||||||
@@ -289,7 +274,7 @@ function Feature({
|
|||||||
layoutId="bubble"
|
layoutId="bubble"
|
||||||
className="absolute inset-0 z-10 rounded-xl bg-white/5 mix-blend-difference"
|
className="absolute inset-0 z-10 rounded-xl bg-white/5 mix-blend-difference"
|
||||||
transition={{
|
transition={{
|
||||||
type: 'spring',
|
type: "spring",
|
||||||
bounce: 0.2,
|
bounce: 0.2,
|
||||||
duration: 0.6,
|
duration: 0.6,
|
||||||
}}
|
}}
|
||||||
@@ -297,8 +282,8 @@ function Feature({
|
|||||||
)}
|
)}
|
||||||
<h3
|
<h3
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-6 text-sm font-medium',
|
"mt-6 text-sm font-medium",
|
||||||
isActive ? 'text-primary' : 'text-primary/85',
|
isActive ? "text-primary" : "text-primary/85",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{feature.name}
|
{feature.name}
|
||||||
@@ -310,7 +295,7 @@ function Feature({
|
|||||||
{t(feature.description)}
|
{t(feature.description)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function FeaturesMobile() {
|
function FeaturesMobile() {
|
||||||
@@ -318,11 +303,7 @@ function FeaturesMobile() {
|
|||||||
<div className="-mx-4 mt-20 flex flex-col gap-y-10 overflow-hidden px-4 sm:-mx-6 sm:px-6 lg:hidden">
|
<div className="-mx-4 mt-20 flex flex-col gap-y-10 overflow-hidden px-4 sm:-mx-6 sm:px-6 lg:hidden">
|
||||||
{features.map((feature) => (
|
{features.map((feature) => (
|
||||||
<div key={feature.summary}>
|
<div key={feature.summary}>
|
||||||
<Feature
|
<Feature feature={feature} className="mx-auto max-w-2xl" isActive />
|
||||||
feature={feature}
|
|
||||||
className="mx-auto max-w-2xl"
|
|
||||||
isActive
|
|
||||||
/>
|
|
||||||
<div className="relative mt-10 pb-10">
|
<div className="relative mt-10 pb-10">
|
||||||
<div className="absolute -inset-x-4 bottom-0 top-8 bg-muted sm:-inset-x-6" />
|
<div className="absolute -inset-x-4 bottom-0 top-8 bg-muted sm:-inset-x-6" />
|
||||||
<div className="relative mx-auto w-[52.75rem] overflow-hidden rounded-xl bg-white shadow-lg shadow-slate-900/5 ring-1 ring-slate-500/10">
|
<div className="relative mx-auto w-[52.75rem] overflow-hidden rounded-xl bg-white shadow-lg shadow-slate-900/5 ring-1 ring-slate-500/10">
|
||||||
@@ -337,11 +318,11 @@ function FeaturesMobile() {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function FeaturesDesktop() {
|
function FeaturesDesktop() {
|
||||||
const t = useTranslations('HomePage')
|
const t = useTranslations("HomePage");
|
||||||
return (
|
return (
|
||||||
<Tab.Group as="div" className="hidden lg:mt-20 lg:block">
|
<Tab.Group as="div" className="hidden lg:mt-20 lg:block">
|
||||||
{({ selectedIndex }) => (
|
{({ selectedIndex }) => (
|
||||||
@@ -371,9 +352,8 @@ function FeaturesDesktop() {
|
|||||||
static
|
static
|
||||||
key={feature.summary}
|
key={feature.summary}
|
||||||
className={cn(
|
className={cn(
|
||||||
'px-5 transition duration-500 ease-in-out ui-not-focus-visible:outline-none',
|
"px-5 transition duration-500 ease-in-out ui-not-focus-visible:outline-none",
|
||||||
featureIndex !== selectedIndex &&
|
featureIndex !== selectedIndex && "opacity-60",
|
||||||
'opacity-60',
|
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
transform: `translateX(-${selectedIndex * 100}%)`,
|
transform: `translateX(-${selectedIndex * 100}%)`,
|
||||||
@@ -396,11 +376,11 @@ function FeaturesDesktop() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Tab.Group>
|
</Tab.Group>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SecondaryFeatures() {
|
export function SecondaryFeatures() {
|
||||||
const t = useTranslations('HomePage')
|
const t = useTranslations("HomePage");
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
id="secondary-features"
|
id="secondary-features"
|
||||||
@@ -410,15 +390,15 @@ export function SecondaryFeatures() {
|
|||||||
<Container className="max-w-[95rem]">
|
<Container className="max-w-[95rem]">
|
||||||
<div className="mx-auto max-w-2xl md:text-center">
|
<div className="mx-auto max-w-2xl md:text-center">
|
||||||
<h2 className="font-display text-3xl tracking-tight text-primary sm:text-4xl">
|
<h2 className="font-display text-3xl tracking-tight text-primary sm:text-4xl">
|
||||||
{t('secondaryFeatures.title')}
|
{t("secondaryFeatures.title")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-4 text-lg tracking-tight text-muted-foreground">
|
<p className="mt-4 text-lg tracking-tight text-muted-foreground">
|
||||||
{t('secondaryFeatures.des')}
|
{t("secondaryFeatures.des")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<FeaturesMobile />
|
<FeaturesMobile />
|
||||||
<FeaturesDesktop />
|
<FeaturesDesktop />
|
||||||
</Container>
|
</Container>
|
||||||
</section>
|
</section>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Link } from '@/i18n/routing'
|
import { Link } from "@/i18n/routing";
|
||||||
import { Footer } from './Footer'
|
import { useTranslations } from "next-intl";
|
||||||
import { Header } from './Header'
|
import { Footer } from "./Footer";
|
||||||
import { useTranslations } from 'next-intl'
|
import { Header } from "./Header";
|
||||||
|
|
||||||
export function SlimLayout() {
|
export function SlimLayout() {
|
||||||
const t = useTranslations('404')
|
const t = useTranslations("404");
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
@@ -12,16 +12,12 @@ export function SlimLayout() {
|
|||||||
</div>
|
</div>
|
||||||
<main className="flex flex-auto items-center justify-center text-center">
|
<main className="flex flex-auto items-center justify-center text-center">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="mb-4 text-6xl font-semibold text-primary">
|
<h1 className="mb-4 text-6xl font-semibold text-primary">404</h1>
|
||||||
404
|
<p className="mb-4 text-lg text-muted-foreground">{t("title")}</p>
|
||||||
</h1>
|
|
||||||
<p className="mb-4 text-lg text-muted-foreground">
|
|
||||||
{t('title')}
|
|
||||||
</p>
|
|
||||||
<p className="mt-4 text-muted-foreground">
|
<p className="mt-4 text-muted-foreground">
|
||||||
{t('des')}{' '}
|
{t("des")}{" "}
|
||||||
<Link href="/" className="text-primary">
|
<Link href="/" className="text-primary">
|
||||||
{t('action')}
|
{t("action")}
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -30,5 +26,5 @@ export function SlimLayout() {
|
|||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
'use client'
|
"use client";
|
||||||
|
|
||||||
import * as React from 'react'
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
||||||
import * as SelectPrimitive from '@radix-ui/react-select'
|
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
||||||
import { Check, ChevronDown, ChevronUp } from 'lucide-react'
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Select = SelectPrimitive.Root
|
const Select = SelectPrimitive.Root;
|
||||||
|
|
||||||
const SelectGroup = SelectPrimitive.Group
|
const SelectGroup = SelectPrimitive.Group;
|
||||||
|
|
||||||
const SelectValue = SelectPrimitive.Value
|
const SelectValue = SelectPrimitive.Value;
|
||||||
|
|
||||||
const SelectTrigger = React.forwardRef<
|
const SelectTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
|
|||||||
<SelectPrimitive.Trigger
|
<SelectPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -29,8 +29,8 @@ const SelectTrigger = React.forwardRef<
|
|||||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||||
</SelectPrimitive.Icon>
|
</SelectPrimitive.Icon>
|
||||||
</SelectPrimitive.Trigger>
|
</SelectPrimitive.Trigger>
|
||||||
))
|
));
|
||||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
const SelectScrollUpButton = React.forwardRef<
|
const SelectScrollUpButton = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||||
@@ -39,15 +39,15 @@ const SelectScrollUpButton = React.forwardRef<
|
|||||||
<SelectPrimitive.ScrollUpButton
|
<SelectPrimitive.ScrollUpButton
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex cursor-default items-center justify-center py-1',
|
"flex cursor-default items-center justify-center py-1",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ChevronUp className="h-4 w-4" />
|
<ChevronUp className="h-4 w-4" />
|
||||||
</SelectPrimitive.ScrollUpButton>
|
</SelectPrimitive.ScrollUpButton>
|
||||||
))
|
));
|
||||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
||||||
|
|
||||||
const SelectScrollDownButton = React.forwardRef<
|
const SelectScrollDownButton = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||||
@@ -56,28 +56,28 @@ const SelectScrollDownButton = React.forwardRef<
|
|||||||
<SelectPrimitive.ScrollDownButton
|
<SelectPrimitive.ScrollDownButton
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex cursor-default items-center justify-center py-1',
|
"flex cursor-default items-center justify-center py-1",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ChevronDown className="h-4 w-4" />
|
<ChevronDown className="h-4 w-4" />
|
||||||
</SelectPrimitive.ScrollDownButton>
|
</SelectPrimitive.ScrollDownButton>
|
||||||
))
|
));
|
||||||
SelectScrollDownButton.displayName =
|
SelectScrollDownButton.displayName =
|
||||||
SelectPrimitive.ScrollDownButton.displayName
|
SelectPrimitive.ScrollDownButton.displayName;
|
||||||
|
|
||||||
const SelectContent = React.forwardRef<
|
const SelectContent = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||||
>(({ className, children, position = 'popper', ...props }, ref) => (
|
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||||
<SelectPrimitive.Portal>
|
<SelectPrimitive.Portal>
|
||||||
<SelectPrimitive.Content
|
<SelectPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
position === 'popper' &&
|
position === "popper" &&
|
||||||
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
position={position}
|
position={position}
|
||||||
@@ -86,9 +86,9 @@ const SelectContent = React.forwardRef<
|
|||||||
<SelectScrollUpButton />
|
<SelectScrollUpButton />
|
||||||
<SelectPrimitive.Viewport
|
<SelectPrimitive.Viewport
|
||||||
className={cn(
|
className={cn(
|
||||||
'p-1',
|
"p-1",
|
||||||
position === 'popper' &&
|
position === "popper" &&
|
||||||
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -96,8 +96,8 @@ const SelectContent = React.forwardRef<
|
|||||||
<SelectScrollDownButton />
|
<SelectScrollDownButton />
|
||||||
</SelectPrimitive.Content>
|
</SelectPrimitive.Content>
|
||||||
</SelectPrimitive.Portal>
|
</SelectPrimitive.Portal>
|
||||||
))
|
));
|
||||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||||
|
|
||||||
const SelectLabel = React.forwardRef<
|
const SelectLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||||
@@ -105,11 +105,11 @@ const SelectLabel = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<SelectPrimitive.Label
|
<SelectPrimitive.Label
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
|
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||||
|
|
||||||
const SelectItem = React.forwardRef<
|
const SelectItem = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
@@ -118,7 +118,7 @@ const SelectItem = React.forwardRef<
|
|||||||
<SelectPrimitive.Item
|
<SelectPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -131,8 +131,8 @@ const SelectItem = React.forwardRef<
|
|||||||
|
|
||||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
</SelectPrimitive.Item>
|
</SelectPrimitive.Item>
|
||||||
))
|
));
|
||||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||||
|
|
||||||
const SelectSeparator = React.forwardRef<
|
const SelectSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||||
@@ -140,11 +140,11 @@ const SelectSeparator = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<SelectPrimitive.Separator
|
<SelectPrimitive.Separator
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Select,
|
Select,
|
||||||
@@ -157,4 +157,4 @@ export {
|
|||||||
SelectSeparator,
|
SelectSeparator,
|
||||||
SelectScrollUpButton,
|
SelectScrollUpButton,
|
||||||
SelectScrollDownButton,
|
SelectScrollDownButton,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { notFound } from 'next/navigation'
|
import { getRequestConfig } from "next-intl/server";
|
||||||
import { getRequestConfig } from 'next-intl/server'
|
import { notFound } from "next/navigation";
|
||||||
import { routing } from './routing'
|
import { routing } from "./routing";
|
||||||
|
|
||||||
export default getRequestConfig(async ({ locale }) => {
|
export default getRequestConfig(async ({ locale }) => {
|
||||||
// Validate that the incoming `locale` parameter is valid
|
// Validate that the incoming `locale` parameter is valid
|
||||||
if (!routing.locales.includes(locale as any)) notFound()
|
if (!routing.locales.includes(locale as any)) notFound();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
messages: (await import(`../locales/${locale}.json`)).default,
|
messages: (await import(`../locales/${locale}.json`)).default,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { defineRouting } from 'next-intl/routing'
|
import { createSharedPathnamesNavigation } from "next-intl/navigation";
|
||||||
import { createSharedPathnamesNavigation } from 'next-intl/navigation'
|
import { defineRouting } from "next-intl/routing";
|
||||||
|
|
||||||
export const routing = defineRouting({
|
export const routing = defineRouting({
|
||||||
// A list of all locales that are supported
|
// A list of all locales that are supported
|
||||||
locales: ['en', 'zh-Hans'],
|
locales: ["en", "zh-Hans"],
|
||||||
|
|
||||||
// Used when no locale matches
|
// Used when no locale matches
|
||||||
defaultLocale: 'en',
|
defaultLocale: "en",
|
||||||
localePrefix: 'as-needed',
|
localePrefix: "as-needed",
|
||||||
})
|
});
|
||||||
|
|
||||||
// Lightweight wrappers around Next.js' navigation APIs
|
// Lightweight wrappers around Next.js' navigation APIs
|
||||||
// that will consider the routing configuration
|
// that will consider the routing configuration
|
||||||
export const { Link, redirect, usePathname, useRouter } =
|
export const { Link, redirect, usePathname, useRouter } =
|
||||||
createSharedPathnamesNavigation(routing)
|
createSharedPathnamesNavigation(routing);
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
"support": "Support",
|
"support": "Support",
|
||||||
"discord": "Discord",
|
"discord": "Discord",
|
||||||
"i18nButtonPlaceholder": "Language",
|
"i18nButtonPlaceholder": "Language",
|
||||||
"i18nEn":"English",
|
"i18nEn": "English",
|
||||||
"i18nZh-Hans":"简体中文"
|
"i18nZh-Hans": "简体中文"
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"deploy": "Deploy",
|
"deploy": "Deploy",
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
"support": "赞助",
|
"support": "赞助",
|
||||||
"discord": "Discord",
|
"discord": "Discord",
|
||||||
"i18nButtonPlaceholder": "语言",
|
"i18nButtonPlaceholder": "语言",
|
||||||
"i18nEn":"English",
|
"i18nEn": "English",
|
||||||
"i18nZh-Hans":"简体中文"
|
"i18nZh-Hans": "简体中文"
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"deploy": "部署在",
|
"deploy": "部署在",
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import createMiddleware from 'next-intl/middleware'
|
import createMiddleware from "next-intl/middleware";
|
||||||
import { routing } from './i18n/routing'
|
import { routing } from "./i18n/routing";
|
||||||
|
|
||||||
export default createMiddleware(routing)
|
export default createMiddleware(routing);
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
// Match only internationalized pathnames
|
// Match only internationalized pathnames
|
||||||
matcher: ['/((?!_next|.*\\..*).*)']
|
matcher: ["/((?!_next|.*\\..*).*)"],
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
const createNextIntlPlugin = require('next-intl/plugin')
|
const createNextIntlPlugin = require("next-intl/plugin");
|
||||||
|
|
||||||
const withNextIntl = createNextIntlPlugin()
|
const withNextIntl = createNextIntlPlugin();
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
eslint: {
|
eslint: {
|
||||||
ignoreDuringBuilds: true,
|
ignoreDuringBuilds: true,
|
||||||
},
|
},
|
||||||
typescript: {
|
typescript: {
|
||||||
ignoreBuildErrors: true,
|
ignoreBuildErrors: true,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = withNextIntl(nextConfig)
|
module.exports = withNextIntl(nextConfig);
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ module.exports = {
|
|||||||
semi: false,
|
semi: false,
|
||||||
tabWidth: 4,
|
tabWidth: 4,
|
||||||
useTabs: true,
|
useTabs: true,
|
||||||
plugins: ['prettier-plugin-tailwindcss'],
|
plugins: ["prettier-plugin-tailwindcss"],
|
||||||
}
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user