mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-10 10:26:46 +08:00
* feat(web): add use-cases content pipeline with welcome page (MUL-2349) Wire fumadocs-mdx into apps/web with an independent collection rooted at content/use-cases/. Add the first page at /use-cases/welcome (header + H1 + prose + screenshot + footer) using the about-page visual shell. - source.config.ts + lib/use-cases-source.ts (separate from apps/docs) - features/landing/components/mdx/screenshot.tsx wraps next/image - public/use-cases/welcome/screenshot-1.png placeholder (55KB) - next.config.ts wraps NextConfig with createMDX() - .gitignore + eslint ignore .source/ Co-authored-by: multica-agent <[email protected]> * feat(web): bilingual db-boy use case with cookie locale (MUL-2349) Extends the use-cases pipeline into the first real article. - ZH + EN MDX (auto-data-analysis.{zh,en}.mdx) sharing three real screenshots; sensitive fields on db-boy-profile.png (RDS host, DB name, password) are blurred in-place. - Cookie-based locale: /use-cases/<slug> reads multica-locale server-side via lib/use-cases-i18n.ts (mirrors LandingLayout's cookie + Accept-Language fallback). Same URL serves either language; no [lang] segment so all other landing routes stay unchanged. - Frontmatter schema (source.config.ts): z.looseObject with declared hero_image / updated_at (required) / category (optional); a preprocess converts YAML-auto-parsed Date back to a YYYY-MM-DD string. - MDX components factory createMdxComponents(locale) routes the secondary CTA to /docs/zh (ZH) or /docs (EN); internal MDX links use <Link> for SPA nav; full-width and half-width colons both trigger [CTA: ...] / [占位图: ...] markers; 副 and Secondary both work as the secondary CTA prefix. - Index page localizes hero / subtitle / card CTA / metadata; sort fallback uses an epoch placeholder so undefined-order disappears. - Landing header + footer surface use-cases entry in both locales. - Detail route: sticky header, right-rail TOC with anchor jumps, scroll-mt-[100px] on H2/H3 so anchor jumps don't slip under the sticky header. - Drop welcome demo page. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * fix(web): resolve code review blockers on use-cases PR - Add `use-cases` to reserved_slugs.json + regenerate TS (P1: prevent future workspace slug collision) - Fix dead links in both MDX files: /features/* → /docs/* (P2) - Remove duplicate brand suffix in page title metadata (nit) Co-Authored-By: Claude Opus 4.7 <[email protected]> Co-authored-by: multica-agent <[email protected]> * fix(web): align usecases locale routing * chore: refresh web mdx lockfile * fix(web): type mdx next config adapter * fix(web): wrap settings route page --------- Co-authored-by: multica-agent <[email protected]> Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
136 lines
4.5 KiB
TypeScript
136 lines
4.5 KiB
TypeScript
import type { Metadata, Viewport } from "next";
|
|
import { Inter, Geist_Mono, Source_Serif_4 } from "next/font/google";
|
|
import { ThemeProvider } from "@/components/theme-provider";
|
|
import { Toaster } from "@multica/ui/components/ui/sonner";
|
|
import { cn } from "@multica/ui/lib/utils";
|
|
import { WebProviders } from "@/components/web-providers";
|
|
import type { SupportedLocale } from "@multica/core/i18n";
|
|
import { RESOURCES } from "@multica/views/locales";
|
|
import { getRequestLocale } from "@/lib/request-locale";
|
|
import "./globals.css";
|
|
|
|
// Font stack: Inter for Latin UI text + system Chinese fonts for zh content.
|
|
// Desktop app uses the same stack via apps/desktop/src/renderer/src/globals.css —
|
|
// keep the CJK fallback tail in sync across both files. The Inter primary family
|
|
// differs by design: next/font produces `__Inter_xxx` (with a synthetic size-adjusted
|
|
// fallback face to prevent FOUT layout shift); desktop uses fontsource's "Inter Variable".
|
|
// Both resolve to Inter glyphs, so rendering is identical in practice.
|
|
// Currently covers English + Simplified Chinese. When ja/ko i18n lands, extend
|
|
// the tail with Hiragino Kaku Gothic ProN / Yu Gothic / Apple SD Gothic Neo / Malgun Gothic.
|
|
// Per-character fallback: Latin chars render with Inter, Chinese chars with
|
|
// PingFang SC (macOS) / Microsoft YaHei (Windows) / Noto Sans CJK SC (Linux).
|
|
const inter = Inter({
|
|
subsets: ["latin"],
|
|
variable: "--font-sans",
|
|
fallback: [
|
|
"-apple-system",
|
|
"BlinkMacSystemFont",
|
|
"Segoe UI",
|
|
"PingFang SC",
|
|
"Microsoft YaHei",
|
|
"Noto Sans CJK SC",
|
|
"sans-serif",
|
|
],
|
|
});
|
|
// Mono font has no explicit CJK fallback: CJK chars in code blocks are inherently
|
|
// non-aligned with a mono grid (Chinese is proportional), so listing CJK fonts
|
|
// here would falsely signal alignment guarantees. Browser default fallback handles
|
|
// the rare mixed case correctly.
|
|
const geistMono = Geist_Mono({
|
|
subsets: ["latin"],
|
|
variable: "--font-mono",
|
|
fallback: ["ui-monospace", "SFMono-Regular", "Menlo", "Consolas", "monospace"],
|
|
});
|
|
// Editorial serif used for onboarding headlines. Italic support for h1 em
|
|
// accents (e.g. "...on one shared board."). Only loaded on routes that
|
|
// render the font; layout-shift-prevention handled by next/font's synthetic
|
|
// fallback metrics, same as Inter.
|
|
const sourceSerif = Source_Serif_4({
|
|
subsets: ["latin"],
|
|
style: ["normal", "italic"],
|
|
variable: "--font-serif",
|
|
fallback: [
|
|
"ui-serif",
|
|
"Iowan Old Style",
|
|
"Apple Garamond",
|
|
"Baskerville",
|
|
"Times New Roman",
|
|
"serif",
|
|
],
|
|
});
|
|
|
|
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 — Project Management for Human + Agent Teams",
|
|
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",
|
|
site: "@multica_hq",
|
|
creator: "@multica_hq",
|
|
},
|
|
alternates: {
|
|
canonical: "/",
|
|
},
|
|
robots: {
|
|
index: true,
|
|
follow: true,
|
|
},
|
|
};
|
|
|
|
// HTML lang attribute uses BCP-47 region tags that screen readers and font
|
|
// stacks recognize widely. i18next keeps `zh-Hans` as its internal locale
|
|
// (script subtag is what we actually translate against), but the html element
|
|
// expects a region-flavoured tag for accessibility tooling and CJK fallback.
|
|
const HTML_LANG: Record<SupportedLocale, string> = {
|
|
en: "en",
|
|
"zh-Hans": "zh-CN",
|
|
};
|
|
|
|
export default async function RootLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
const locale = await getRequestLocale();
|
|
const resources = { [locale]: RESOURCES[locale] };
|
|
|
|
return (
|
|
<html
|
|
lang={HTML_LANG[locale]}
|
|
suppressHydrationWarning
|
|
className={cn("antialiased font-sans h-full", inter.variable, geistMono.variable, sourceSerif.variable)}
|
|
>
|
|
<body className="h-full overflow-hidden">
|
|
<ThemeProvider>
|
|
<WebProviders locale={locale} resources={resources}>
|
|
{children}
|
|
</WebProviders>
|
|
<Toaster />
|
|
</ThemeProvider>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|