refactor: improve root layout with internationalization and font configuration

This commit is contained in:
Mauricio Siu
2025-03-02 16:39:20 -06:00
parent 5f66cfd234
commit 01c75f6798
4 changed files with 75 additions and 85 deletions

View File

@@ -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 || "");

View File

@@ -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);
}
};

View File

@@ -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>
);
}

View File

@@ -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>
);
}