nomadweb/frontend/src/app/layout.tsx
eric ff7b721acb feat: NomadCNA community layer, social matching, payments, and ebook
Port meetups, discussions, gigs, dating/chat, VIP pay (ZPay/XorPay), MiroTalk live, digital academy, and ebook reader. Add persistent community_store, git-first deploy docs, and env template for production secrets.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-30 09:38:13 -05:00

82 lines
2.4 KiB
TypeScript

import type { Metadata, Viewport } from "next";
import { Outfit } from "next/font/google";
import "./globals.css";
import { AuthProvider } from "@/lib/auth";
import { ToastProvider } from "@/lib/toast";
import { I18nProvider } from "@/lib/i18n";
import PwaRegister from "@/components/PwaRegister";
const SITE = process.env.NEXT_PUBLIC_SITE_URL || "https://nomadweb.nomadro.com";
const outfit = Outfit({
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
variable: "--font-outfit",
display: "swap",
});
export const metadata: Metadata = {
metadataBase: new URL(SITE),
title: "nomadro · 数字游民旅居指南",
description: "探索全球旅居生活,发现最适合数字游民的目的地、工具与社区。",
keywords: ["数字游民", "旅居", "远程工作", "nomad", "digital nomad"],
applicationName: "nomadro",
appleWebApp: {
capable: true,
statusBarStyle: "black-translucent",
title: "nomadro",
},
formatDetection: { telephone: false },
openGraph: {
title: "nomadro · 数字游民旅居指南",
description: "用一行代码环游世界 🌏",
type: "website",
locale: "zh_CN",
alternateLocale: ["en_US"],
url: SITE,
siteName: "nomadro",
},
twitter: {
card: "summary_large_image",
title: "nomadro · 数字游民旅居指南",
description: "用一行代码环游世界 🌏",
},
manifest: "/manifest.webmanifest",
icons: {
icon: [
{ url: "/icons/icon.svg", type: "image/svg+xml" },
{ url: "/icons/icon-192.png", sizes: "192x192", type: "image/png" },
{ url: "/icons/icon-512.png", sizes: "512x512", type: "image/png" },
],
apple: [{ url: "/icons/apple-touch-icon.png", sizes: "180x180" }],
},
};
export const viewport: Viewport = {
themeColor: [
{ media: "(prefers-color-scheme: dark)", color: "#0a0e17" },
{ media: "(prefers-color-scheme: light)", color: "#4ECDC4" },
],
width: "device-width",
initialScale: 1,
maximumScale: 5,
viewportFit: "cover",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="zh-CN" className={outfit.variable} suppressHydrationWarning>
<body>
<I18nProvider>
<AuthProvider>
<ToastProvider>
{children}
<PwaRegister />
</ToastProvider>
</AuthProvider>
</I18nProvider>
</body>
</html>
);
}