perf: make lovart home shell load first
This commit is contained in:
parent
1db4444c7b
commit
bac7d6f196
@ -1,51 +0,0 @@
|
||||
import { Suspense } from "react";
|
||||
import { LovartHome } from "@/components/home/lovart-home";
|
||||
import { auth } from "../(auth)/auth";
|
||||
import { getSiteSettings, getSystemSetting } from "@/lib/db/queries";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Suspense fallback={<div className="flex h-dvh" />}>
|
||||
<NewChatPage />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
async function NewChatPage() {
|
||||
const [session, siteSettings, surpriseCategoriesSetting] =
|
||||
await Promise.all([
|
||||
auth(),
|
||||
getSiteSettings(),
|
||||
getSystemSetting({ key: "home_surprise_categories" }).catch(() => undefined),
|
||||
]);
|
||||
|
||||
const surpriseCategories = Array.isArray(surpriseCategoriesSetting?.value)
|
||||
? surpriseCategoriesSetting?.value
|
||||
.map((item: unknown) => String(item || "").trim())
|
||||
.filter(Boolean)
|
||||
: ["全部", "精选"];
|
||||
|
||||
return (
|
||||
<LovartHome
|
||||
user={
|
||||
session?.user
|
||||
? {
|
||||
id: session.user.id,
|
||||
email: session.user.email,
|
||||
name: session.user.name,
|
||||
type: session.user.type,
|
||||
}
|
||||
: null
|
||||
}
|
||||
isAuthenticated={Boolean(session?.user && session.user.type !== "guest")}
|
||||
siteName={siteSettings.siteName || "AI Chatbot"}
|
||||
siteLogo={siteSettings.siteLogo || ""}
|
||||
siteLogoDark={siteSettings.siteLogoDark || ""}
|
||||
surpriseCategories={surpriseCategories}
|
||||
heroPromoText={siteSettings.lovartPromoText}
|
||||
heroPromoActionText={siteSettings.lovartPromoActionText}
|
||||
heroTitleText={siteSettings.lovartHeroTitle}
|
||||
heroSubtitleText={siteSettings.lovartHeroSubtitle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -798,6 +798,7 @@ async function getScopedPublicSiteSettings(
|
||||
}
|
||||
|
||||
const { settings, valueByKey } = await readScopedSiteSettings([
|
||||
HOME_SURPRISE_CATEGORIES_KEY,
|
||||
LOVART_COMPOSER_PREVIEW_TEXTS_KEY,
|
||||
LOVART_COMPOSER_PREFIX_KEY,
|
||||
LOVART_PROMPT_TAG_VISIBILITY_KEY,
|
||||
@ -813,6 +814,16 @@ async function getScopedPublicSiteSettings(
|
||||
|
||||
return createScopedSiteSettingsResponse(scope, {
|
||||
...createBrandingSettings(typedSettings),
|
||||
lovartPromoText:
|
||||
typedSettings?.lovartPromoText ||
|
||||
"现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
|
||||
lovartPromoActionText: typedSettings?.lovartPromoActionText || "立即升级",
|
||||
lovartHeroTitle: typedSettings?.lovartHeroTitle || "由壹点AI 让设计更简单",
|
||||
lovartHeroSubtitle:
|
||||
typedSettings?.lovartHeroSubtitle || "懂你的设计代理,帮你搞定一切",
|
||||
surpriseCategories: normalizeSurpriseCategories(
|
||||
valueByKey.get(HOME_SURPRISE_CATEGORIES_KEY)
|
||||
),
|
||||
canvasDefaultModelId: typedSettings?.canvasDefaultModelId || null,
|
||||
lovartComposerPrefix: normalizeLovartComposerPrefix(
|
||||
valueByKey.get(LOVART_COMPOSER_PREFIX_KEY)
|
||||
|
||||
@ -7,36 +7,26 @@ import { ImageDeliveryOptimizer } from "@/components/image-delivery-optimizer";
|
||||
import "./globals.css";
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
|
||||
import { getSiteSettings } from "@/lib/db/queries";
|
||||
const metadataBase = process.env.AUTH_URL
|
||||
? new URL(process.env.AUTH_URL)
|
||||
: undefined;
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const settings = await getSiteSettings();
|
||||
const updatedAt =
|
||||
"updatedAt" in settings && settings.updatedAt
|
||||
? new Date(settings.updatedAt).getTime()
|
||||
: "default";
|
||||
const faviconUrl = `/api/favicon?v=${updatedAt}`;
|
||||
const metadataBase = process.env.AUTH_URL
|
||||
? new URL(process.env.AUTH_URL)
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
metadataBase,
|
||||
title: {
|
||||
template: `%s | ${settings.siteName}`,
|
||||
default: settings.siteName,
|
||||
},
|
||||
description: settings.siteName,
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: faviconUrl, sizes: "any" },
|
||||
{ url: faviconUrl, type: "image/x-icon" },
|
||||
],
|
||||
apple: faviconUrl,
|
||||
shortcut: faviconUrl,
|
||||
},
|
||||
};
|
||||
}
|
||||
export const metadata: Metadata = {
|
||||
metadataBase,
|
||||
title: {
|
||||
template: "%s | AI Chatbot",
|
||||
default: "AI Chatbot",
|
||||
},
|
||||
description: "AI Chatbot",
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: "/api/favicon", sizes: "any" },
|
||||
{ url: "/api/favicon", type: "image/x-icon" },
|
||||
],
|
||||
apple: "/api/favicon",
|
||||
shortcut: "/api/favicon",
|
||||
},
|
||||
};
|
||||
|
||||
export const viewport = {
|
||||
maximumScale: 1, // Disable auto-zoom on mobile Safari
|
||||
@ -153,15 +143,11 @@ const CHUNK_ERROR_RECOVERY_SCRIPT = `\
|
||||
});
|
||||
})();`;
|
||||
|
||||
export default async function RootLayout({
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
// 获取网站设置中的默认主题
|
||||
const settings = await getSiteSettings();
|
||||
const defaultTheme = settings.defaultTheme || "system";
|
||||
|
||||
return (
|
||||
<html
|
||||
// `next-themes` injects an extra classname to the body element to avoid
|
||||
@ -188,7 +174,7 @@ export default async function RootLayout({
|
||||
<ImageDeliveryOptimizer />
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme={defaultTheme}
|
||||
defaultTheme="system"
|
||||
disableTransitionOnChange
|
||||
enableSystem
|
||||
>
|
||||
|
||||
5
app/page.tsx
Normal file
5
app/page.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LovartHome } from "@/components/home/lovart-home";
|
||||
|
||||
export default function Page() {
|
||||
return <LovartHome />;
|
||||
}
|
||||
@ -228,12 +228,12 @@ type AccountCenterResponse = {
|
||||
};
|
||||
|
||||
type LovartHomeProps = {
|
||||
user: HomeUser | null;
|
||||
isAuthenticated: boolean;
|
||||
siteName: string;
|
||||
user?: HomeUser | null;
|
||||
isAuthenticated?: boolean;
|
||||
siteName?: string;
|
||||
siteLogo?: string | null;
|
||||
siteLogoDark?: string | null;
|
||||
surpriseCategories: string[];
|
||||
surpriseCategories?: string[];
|
||||
heroPromoText?: string | null;
|
||||
heroPromoActionText?: string | null;
|
||||
heroTitleText?: string | null;
|
||||
@ -422,27 +422,19 @@ function AccountMenuItem({
|
||||
}
|
||||
|
||||
export function LovartHome({
|
||||
user,
|
||||
isAuthenticated,
|
||||
siteName,
|
||||
siteLogo,
|
||||
siteLogoDark,
|
||||
surpriseCategories,
|
||||
heroPromoText,
|
||||
heroPromoActionText,
|
||||
heroTitleText,
|
||||
heroSubtitleText,
|
||||
}: LovartHomeProps) {
|
||||
user = null,
|
||||
isAuthenticated = false,
|
||||
siteName: initialSiteName = "AI Chatbot",
|
||||
siteLogo: initialSiteLogo = null,
|
||||
siteLogoDark: initialSiteLogoDark = null,
|
||||
surpriseCategories: initialSurpriseCategories = ["全部", "精选"],
|
||||
heroPromoText: initialHeroPromoText = null,
|
||||
heroPromoActionText: initialHeroPromoActionText = null,
|
||||
heroTitleText: initialHeroTitleText = null,
|
||||
heroSubtitleText: initialHeroSubtitleText = null,
|
||||
}: LovartHomeProps = {}) {
|
||||
const router = useRouter();
|
||||
const { theme, resolvedTheme, setTheme } = useTheme();
|
||||
const displayLogo =
|
||||
resolvedTheme === "dark"
|
||||
? siteLogoDark?.trim() || siteLogo?.trim() || ""
|
||||
: siteLogo?.trim() || siteLogoDark?.trim() || "";
|
||||
const shouldInvertLogo =
|
||||
resolvedTheme === "dark" &&
|
||||
!siteLogoDark?.trim() &&
|
||||
Boolean(siteLogo?.trim());
|
||||
const sidebarPopupBaseClass =
|
||||
"rounded-[24px] border border-black/8 bg-white/96 p-2.5 text-[#111827] shadow-[0_24px_64px_rgba(15,23,42,0.12)] backdrop-blur-xl";
|
||||
const lovartSidebarButtonClass = (active = false) =>
|
||||
@ -578,6 +570,14 @@ export function LovartHome({
|
||||
);
|
||||
|
||||
const { data: siteSettingsData } = useSWR<{
|
||||
siteName?: string | null;
|
||||
siteLogo?: string | null;
|
||||
siteLogoDark?: string | null;
|
||||
lovartPromoText?: string | null;
|
||||
lovartPromoActionText?: string | null;
|
||||
lovartHeroTitle?: string | null;
|
||||
lovartHeroSubtitle?: string | null;
|
||||
surpriseCategories?: string[];
|
||||
canvasDefaultModelId?: string | null;
|
||||
lovartComposerPrefix?: string | null;
|
||||
lovartComposerPreviewTexts?: string[];
|
||||
@ -603,6 +603,30 @@ export function LovartHome({
|
||||
lovartHomeSidebarConfig?: unknown;
|
||||
}>("/api/site-settings?scope=home", fetcher);
|
||||
|
||||
const siteName = String(
|
||||
siteSettingsData?.siteName || initialSiteName || "AI Chatbot"
|
||||
).trim();
|
||||
const siteLogo = String(siteSettingsData?.siteLogo || initialSiteLogo || "").trim();
|
||||
const siteLogoDark = String(
|
||||
siteSettingsData?.siteLogoDark || initialSiteLogoDark || ""
|
||||
).trim();
|
||||
const heroPromoText =
|
||||
siteSettingsData?.lovartPromoText ?? initialHeroPromoText;
|
||||
const heroPromoActionText =
|
||||
siteSettingsData?.lovartPromoActionText ?? initialHeroPromoActionText;
|
||||
const heroTitleText =
|
||||
siteSettingsData?.lovartHeroTitle ?? initialHeroTitleText;
|
||||
const heroSubtitleText =
|
||||
siteSettingsData?.lovartHeroSubtitle ?? initialHeroSubtitleText;
|
||||
const surpriseCategories =
|
||||
siteSettingsData?.surpriseCategories ?? initialSurpriseCategories;
|
||||
const displayLogo =
|
||||
resolvedTheme === "dark"
|
||||
? siteLogoDark || siteLogo || ""
|
||||
: siteLogo || siteLogoDark || "";
|
||||
const shouldInvertLogo =
|
||||
resolvedTheme === "dark" && !siteLogoDark && Boolean(siteLogo);
|
||||
|
||||
const { data: tutorialVideosData } = useSWR<{ videos: TutorialVideo[] }>(
|
||||
isSecondaryDataReady && siteSettingsData?.tutorialEnabled
|
||||
? "/api/tutorial-videos"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user