mirror of
https://github.com/Dokploy/website
synced 2025-06-26 18:16:01 +00:00
refactor: improve root layout with internationalization and font configuration
This commit is contained in:
@@ -155,9 +155,9 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
<td className="p-4 text-muted-foreground" {...props} />
|
<td className="p-4 text-muted-foreground" {...props} />
|
||||||
),
|
),
|
||||||
img: ({ node, src, alt }) => (
|
img: ({ node, src, alt }) => (
|
||||||
<div className="relative w-full h-64 my-6 rounded-lg overflow-hidden">
|
<span className="relative w-64 h-64 my-6 rounded-lg ">
|
||||||
{src && <ZoomableImage src={src} alt={alt || ""} />}
|
{src && <ZoomableImage src={src} alt={alt || ""} />}
|
||||||
</div>
|
</span>
|
||||||
),
|
),
|
||||||
code: ({ inline, className, children, ...props }: CodeProps) => {
|
code: ({ inline, className, children, ...props }: CodeProps) => {
|
||||||
const match = /language-(\w+)/.exec(className || "");
|
const match = /language-(\w+)/.exec(className || "");
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as xmlPlugin from "@prettier/plugin-xml";
|
|
||||||
import * as prettier from "prettier";
|
import * as prettier from "prettier";
|
||||||
|
import * as prettierPluginBabel from "prettier/plugins/babel";
|
||||||
|
import * as prettierPluginEstree from "prettier/plugins/estree";
|
||||||
import { Highlight, themes } from "prism-react-renderer";
|
import { Highlight, themes } from "prism-react-renderer";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
@@ -11,64 +12,53 @@ interface CodeBlockProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getParserForLanguage = (language: string): string => {
|
||||||
|
const languageMap: { [key: string]: string } = {
|
||||||
|
js: "babel",
|
||||||
|
jsx: "babel",
|
||||||
|
ts: "typescript",
|
||||||
|
tsx: "typescript",
|
||||||
|
json: "json",
|
||||||
|
css: "css",
|
||||||
|
scss: "scss",
|
||||||
|
less: "less",
|
||||||
|
html: "html",
|
||||||
|
xml: "xml",
|
||||||
|
markdown: "markdown",
|
||||||
|
md: "markdown",
|
||||||
|
yaml: "yaml",
|
||||||
|
yml: "yaml",
|
||||||
|
};
|
||||||
|
|
||||||
|
return languageMap[language.toLowerCase()] || "babel";
|
||||||
|
};
|
||||||
|
|
||||||
export function CodeBlock({ code, language, className = "" }: CodeBlockProps) {
|
export function CodeBlock({ code, language, className = "" }: CodeBlockProps) {
|
||||||
const [formattedCode, setFormattedCode] = useState(code);
|
const [formattedCode, setFormattedCode] = useState(code);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const formatCode = async () => {
|
const formatCode = async () => {
|
||||||
try {
|
try {
|
||||||
// Determine the parser based on the language
|
const parser = getParserForLanguage(language);
|
||||||
let parser = language;
|
|
||||||
let plugins: any[] = [];
|
|
||||||
|
|
||||||
// Map common languages to their appropriate parsers
|
// Eliminar espacios en blanco al inicio y final, pero mantener la indentación interna
|
||||||
switch (language.toLowerCase()) {
|
|
||||||
case "tsx":
|
|
||||||
case "ts":
|
|
||||||
case "typescript":
|
|
||||||
parser = "babel-ts";
|
|
||||||
plugins = ["@babel/plugin-syntax-typescript"];
|
|
||||||
break;
|
|
||||||
case "jsx":
|
|
||||||
case "js":
|
|
||||||
case "javascript":
|
|
||||||
parser = "babel";
|
|
||||||
break;
|
|
||||||
case "html":
|
|
||||||
case "xml":
|
|
||||||
case "svg":
|
|
||||||
parser = "html";
|
|
||||||
plugins = [xmlPlugin];
|
|
||||||
break;
|
|
||||||
case "json":
|
|
||||||
parser = "json";
|
|
||||||
break;
|
|
||||||
case "css":
|
|
||||||
case "scss":
|
|
||||||
case "less":
|
|
||||||
parser = "css";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// For unknown languages, just clean up the whitespace
|
|
||||||
setFormattedCode(code.trim());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatted = await prettier.format(code, {
|
const formatted = await prettier.format(formattedCode, {
|
||||||
parser,
|
|
||||||
plugins,
|
|
||||||
semi: true,
|
semi: true,
|
||||||
singleQuote: false,
|
singleQuote: false,
|
||||||
tabWidth: 2,
|
tabWidth: 2,
|
||||||
useTabs: false,
|
useTabs: false,
|
||||||
printWidth: 80,
|
printWidth: 80,
|
||||||
|
parser,
|
||||||
|
plugins: [prettierPluginBabel, prettierPluginEstree],
|
||||||
});
|
});
|
||||||
|
|
||||||
setFormattedCode(formatted.trim());
|
setFormattedCode(formatted);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("Error formatting code:", error);
|
console.warn("Error formatting code:", error);
|
||||||
// If formatting fails, just clean up the whitespace
|
// Si falla el formateo, al menos limpiamos los espacios en blanco extra
|
||||||
setFormattedCode(code.trim());
|
const cleanCode = code.replace(/^\s+|\s+$/g, "");
|
||||||
|
setFormattedCode(cleanCode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
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 { NextIntlClientProvider } from "next-intl";
|
|
||||||
import { getMessages } from "next-intl/server";
|
|
||||||
import "react-photo-view/dist/react-photo-view.css";
|
import "react-photo-view/dist/react-photo-view.css";
|
||||||
import { Footer } from "@/components/Footer";
|
import { Footer } from "@/components/Footer";
|
||||||
import { Header } from "@/components/Header";
|
import { Header } from "@/components/Header";
|
||||||
@@ -71,18 +68,6 @@ export const metadata: Metadata = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const inter = Inter({
|
|
||||||
subsets: ["latin"],
|
|
||||||
display: "swap",
|
|
||||||
variable: "--font-inter",
|
|
||||||
});
|
|
||||||
|
|
||||||
const lexend = Lexend({
|
|
||||||
subsets: ["latin"],
|
|
||||||
display: "swap",
|
|
||||||
variable: "--font-lexend",
|
|
||||||
});
|
|
||||||
|
|
||||||
export default async function RootLayout({
|
export default async function RootLayout({
|
||||||
children,
|
children,
|
||||||
params,
|
params,
|
||||||
@@ -90,28 +75,11 @@ export default async function RootLayout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
params: { locale: string };
|
params: { locale: string };
|
||||||
}) {
|
}) {
|
||||||
const { locale } = params;
|
|
||||||
const messages = await getMessages();
|
|
||||||
return (
|
return (
|
||||||
<html
|
<div className="flex h-full flex-col">
|
||||||
lang={locale}
|
<Header />
|
||||||
className={clsx("h-full scroll-smooth", inter.variable, lexend.variable)}
|
{children}
|
||||||
>
|
<Footer />
|
||||||
<head>
|
</div>
|
||||||
<script
|
|
||||||
defer
|
|
||||||
src="https://umami.dokploy.com/script.js"
|
|
||||||
data-website-id="7d1422e4-3776-4870-8145-7d7b2075d470"
|
|
||||||
/>
|
|
||||||
</head>
|
|
||||||
{/* <GoogleAnalytics /> */}
|
|
||||||
<body className="flex h-full flex-col">
|
|
||||||
<NextIntlClientProvider messages={messages}>
|
|
||||||
<Header />
|
|
||||||
{children}
|
|
||||||
<Footer />
|
|
||||||
</NextIntlClientProvider>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import clsx from "clsx";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import { NextIntlClientProvider } from "next-intl";
|
||||||
|
import { getMessages } from "next-intl/server";
|
||||||
|
import { Inter, Lexend } from "next/font/google";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
};
|
};
|
||||||
@@ -26,13 +29,42 @@ type Props = {
|
|||||||
// images: ["/og.png"],
|
// images: ["/og.png"],
|
||||||
// },
|
// },
|
||||||
// };
|
// };
|
||||||
|
const inter = Inter({
|
||||||
|
subsets: ["latin"],
|
||||||
|
display: "swap",
|
||||||
|
variable: "--font-inter",
|
||||||
|
});
|
||||||
|
|
||||||
|
const lexend = Lexend({
|
||||||
|
subsets: ["latin"],
|
||||||
|
display: "swap",
|
||||||
|
variable: "--font-lexend",
|
||||||
|
});
|
||||||
// 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 async function RootLayout({
|
||||||
|
children,
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
params: { locale: string };
|
||||||
|
}) {
|
||||||
|
const { locale } = params;
|
||||||
|
const messages = await getMessages();
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html
|
||||||
<body>{children}</body>
|
lang={locale}
|
||||||
|
className={clsx(
|
||||||
|
"h-full scroll-smooth antialiased",
|
||||||
|
inter.variable,
|
||||||
|
lexend.variable,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<body>
|
||||||
|
<NextIntlClientProvider messages={messages}>
|
||||||
|
{children}
|
||||||
|
</NextIntlClientProvider>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user