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} />
|
||||
),
|
||||
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 || ""} />}
|
||||
</div>
|
||||
</span>
|
||||
),
|
||||
code: ({ inline, className, children, ...props }: CodeProps) => {
|
||||
const match = /language-(\w+)/.exec(className || "");
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import * as xmlPlugin from "@prettier/plugin-xml";
|
||||
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 { useEffect, useState } from "react";
|
||||
|
||||
@@ -11,64 +12,53 @@ interface CodeBlockProps {
|
||||
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) {
|
||||
const [formattedCode, setFormattedCode] = useState(code);
|
||||
|
||||
useEffect(() => {
|
||||
const formatCode = async () => {
|
||||
try {
|
||||
// Determine the parser based on the language
|
||||
let parser = language;
|
||||
let plugins: any[] = [];
|
||||
const parser = getParserForLanguage(language);
|
||||
|
||||
// Map common languages to their appropriate parsers
|
||||
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;
|
||||
}
|
||||
// Eliminar espacios en blanco al inicio y final, pero mantener la indentación interna
|
||||
|
||||
const formatted = await prettier.format(code, {
|
||||
parser,
|
||||
plugins,
|
||||
const formatted = await prettier.format(formattedCode, {
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
printWidth: 80,
|
||||
parser,
|
||||
plugins: [prettierPluginBabel, prettierPluginEstree],
|
||||
});
|
||||
|
||||
setFormattedCode(formatted.trim());
|
||||
setFormattedCode(formatted);
|
||||
} catch (error) {
|
||||
console.warn("Error formatting code:", error);
|
||||
// If formatting fails, just clean up the whitespace
|
||||
setFormattedCode(code.trim());
|
||||
// Si falla el formateo, al menos limpiamos los espacios en blanco extra
|
||||
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 "@/styles/tailwind.css";
|
||||
import { NextIntlClientProvider } from "next-intl";
|
||||
import { getMessages } from "next-intl/server";
|
||||
import "react-photo-view/dist/react-photo-view.css";
|
||||
import { Footer } from "@/components/Footer";
|
||||
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({
|
||||
children,
|
||||
params,
|
||||
@@ -90,28 +75,11 @@ export default async function RootLayout({
|
||||
children: React.ReactNode;
|
||||
params: { locale: string };
|
||||
}) {
|
||||
const { locale } = params;
|
||||
const messages = await getMessages();
|
||||
return (
|
||||
<html
|
||||
lang={locale}
|
||||
className={clsx("h-full scroll-smooth", inter.variable, lexend.variable)}
|
||||
>
|
||||
<head>
|
||||
<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>
|
||||
<div className="flex h-full flex-col">
|
||||
<Header />
|
||||
{children}
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import clsx from "clsx";
|
||||
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";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
@@ -26,13 +29,42 @@ type Props = {
|
||||
// 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
|
||||
// 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 (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
<html
|
||||
lang={locale}
|
||||
className={clsx(
|
||||
"h-full scroll-smooth antialiased",
|
||||
inter.variable,
|
||||
lexend.variable,
|
||||
)}
|
||||
>
|
||||
<body>
|
||||
<NextIntlClientProvider messages={messages}>
|
||||
{children}
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user