- Validação cross-tenant no login e rotas protegidas
- File serving via /api/files/{bucket}/{path} (eliminação DNS)
- Mensagens de erro humanizadas inline (sem pop-ups)
- Middleware tenant detection via headers customizados
- Upload de logos retorna URLs via API
- README atualizado com changelog v1.4 completo
60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { Inter, Open_Sans, Fira_Code } from "next/font/google";
|
|
import "./globals.css";
|
|
import LayoutWrapper from "./LayoutWrapper";
|
|
import { ThemeProvider } from "next-themes";
|
|
import { getAgencyLogo } from "@/lib/server-api";
|
|
|
|
const inter = Inter({
|
|
variable: "--font-inter",
|
|
subsets: ["latin"],
|
|
weight: ["400", "500", "600", "700"],
|
|
});
|
|
|
|
const openSans = Open_Sans({
|
|
variable: "--font-open-sans",
|
|
subsets: ["latin"],
|
|
weight: ["600", "700"],
|
|
});
|
|
|
|
const firaCode = Fira_Code({
|
|
variable: "--font-fira-code",
|
|
subsets: ["latin"],
|
|
weight: ["400", "600"],
|
|
});
|
|
|
|
export async function generateMetadata(): Promise<Metadata> {
|
|
const logoUrl = await getAgencyLogo();
|
|
|
|
return {
|
|
title: "Aggios - Dashboard",
|
|
description: "Plataforma SaaS para agências digitais",
|
|
icons: {
|
|
icon: logoUrl || '/favicon.ico',
|
|
shortcut: logoUrl || '/favicon.ico',
|
|
apple: logoUrl || '/favicon.ico',
|
|
},
|
|
};
|
|
}
|
|
|
|
export default function RootLayout({
|
|
children,
|
|
}: Readonly<{
|
|
children: React.ReactNode;
|
|
}>) {
|
|
return (
|
|
<html lang="pt-BR" suppressHydrationWarning>
|
|
<head>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/remixicon@4.3.0/fonts/remixicon.css" />
|
|
</head>
|
|
<body className={`${inter.variable} ${openSans.variable} ${firaCode.variable} antialiased`} suppressHydrationWarning>
|
|
<ThemeProvider attribute="class" defaultTheme="light" enableSystem={false}>
|
|
<LayoutWrapper>
|
|
{children}
|
|
</LayoutWrapper>
|
|
</ThemeProvider>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|