multica/apps/web/app/layout.tsx
Naiyuan Qing 2be9f6cd2f feat(web): add TanStack Query infrastructure (Phase 0)
- Install @tanstack/react-query v5 + devtools
- Create core/query-client.ts with WS-optimized defaults (staleTime: Infinity)
- Create QueryProvider and wire into root layout
- Add @core/* path alias to tsconfig + vitest
- Add useWorkspaceId() bridge hook for query key scoping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:43:51 +08:00

82 lines
2.3 KiB
TypeScript

import type { Metadata, Viewport } from "next";
import { cookies } from "next/headers";
import { Geist, Geist_Mono } from "next/font/google";
import { ThemeProvider } from "@/components/theme-provider";
import { Toaster } from "@/components/ui/sonner";
import { cn } from "@/lib/utils";
import { QueryProvider } from "@core/provider";
import { AuthInitializer } from "@/features/auth";
import { WSProvider } from "@/features/realtime";
import { ModalRegistry } from "@/features/modals";
import "./globals.css";
const geist = Geist({ subsets: ["latin"], variable: "--font-sans" });
const geistMono = Geist_Mono({ subsets: ["latin"], variable: "--font-mono" });
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#ffffff" },
{ media: "(prefers-color-scheme: dark)", color: "#05070b" },
],
};
export const metadata: Metadata = {
metadataBase: new URL("https://www.multica.ai"),
title: {
default: "Multica — AI-Native Task Management",
template: "%s | Multica",
},
description:
"Open-source platform that turns coding agents into real teammates. Assign tasks, track progress, compound skills.",
icons: {
icon: [{ url: "/favicon.svg", type: "image/svg+xml" }],
shortcut: ["/favicon.svg"],
},
openGraph: {
type: "website",
siteName: "Multica",
locale: "en_US",
},
twitter: {
card: "summary_large_image",
},
alternates: {
canonical: "/",
},
robots: {
index: true,
follow: true,
},
};
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const cookieStore = await cookies();
const locale = cookieStore.get("multica-locale")?.value;
const lang = locale === "zh" ? "zh" : "en";
return (
<html
lang={lang}
suppressHydrationWarning
className={cn("antialiased font-sans h-full", geist.variable, geistMono.variable)}
>
<body className="h-full overflow-hidden">
<ThemeProvider>
<QueryProvider>
<AuthInitializer>
<WSProvider>{children}</WSProvider>
</AuthInitializer>
<ModalRegistry />
<Toaster />
</QueryProvider>
</ThemeProvider>
</body>
</html>
);
}