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>
65 lines
2.4 KiB
TypeScript
65 lines
2.4 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { AntdRegistry } from "@ant-design/nextjs-registry";
|
|
import { Providers } from "@/components/ebook/Providers";
|
|
import { buildBookMetadata } from "@/lib/ebook/metadata";
|
|
import { getSiteConfig } from "@/lib/ebook/site-config.server";
|
|
import { getServerFeatures } from "@/lib/ebook/features.server";
|
|
import { getLocale } from "@/lib/ebook/i18n/server";
|
|
import "./ebook-globals.css";
|
|
|
|
export async function generateMetadata(): Promise<Metadata> {
|
|
const locale = await getLocale();
|
|
return buildBookMetadata(locale);
|
|
}
|
|
|
|
/**
|
|
* Book section is a self-contained surface inside nomadweb:
|
|
* - Own visual system (ebook-globals), isolated under .ebook-section
|
|
* - Locale bridged with main-site cookie/localStorage via getLocale + LocaleProvider
|
|
* - Theme driven by ThemeProvider on <html> (not a forced .dark wrapper)
|
|
* - No main Navbar / SiteShell — immersive like book.nomadro.com
|
|
* - Entry from main nav `/book`; escape via cover "← nomadro"
|
|
*/
|
|
export default async function BookLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
const locale = await getLocale();
|
|
const site = getSiteConfig();
|
|
const f = getServerFeatures();
|
|
|
|
return (
|
|
<div className="ebook-section" data-ebook-root>
|
|
<script
|
|
dangerouslySetInnerHTML={{
|
|
__html: `window.__EBOOK_FEATURES__=${JSON.stringify(f).replace(/</g, "\\u003c")};window.__LOCALE__=${JSON.stringify(locale)};(function(){try{var t=localStorage.getItem("theme");if(t==="light"||t==="sepia"||t==="dark"){document.documentElement.classList.remove("light","dark","sepia");document.documentElement.classList.add(t);}else{document.documentElement.classList.add("dark");}}catch(e){document.documentElement.classList.add("dark");}document.documentElement.style.scrollPaddingTop="0";})();`,
|
|
}}
|
|
/>
|
|
<AntdRegistry>
|
|
<Providers locale={locale}>
|
|
{children}
|
|
{f.feedback.enabled && (
|
|
<FeedbackLazy
|
|
title={f.feedback.title}
|
|
subtitle={f.feedback.subtitle}
|
|
contactEmail={site.brand.contactEmail}
|
|
xHandle={site.brand.xHandle}
|
|
/>
|
|
)}
|
|
</Providers>
|
|
</AntdRegistry>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function FeedbackLazy(props: {
|
|
title: string;
|
|
subtitle: string;
|
|
contactEmail: string;
|
|
xHandle: string;
|
|
}) {
|
|
const { FeedbackPanel } = require("@/components/ebook/FeedbackPanel");
|
|
return <FeedbackPanel {...props} />;
|
|
}
|