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>
82 lines
2.4 KiB
TypeScript
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>
|
|
);
|
|
}
|