chore: refactor website configuration structure and update related components
This commit is contained in:
parent
377f22c693
commit
4b1d888845
@ -57,9 +57,10 @@ export default async function DocsRootLayout({ children, params }: DocsLayoutPro
|
||||
};
|
||||
|
||||
// Docs layout configurations
|
||||
const showLocaleSwitch = Object.keys(websiteConfig.i18n.locales).length > 1;
|
||||
const docsOptions: BaseLayoutProps = {
|
||||
i18n: docsI18nConfig,
|
||||
githubUrl: websiteConfig.metadata.social.github ?? undefined,
|
||||
i18n: showLocaleSwitch ? docsI18nConfig : undefined,
|
||||
githubUrl: websiteConfig.metadata.social?.github ?? undefined,
|
||||
nav: {
|
||||
url: getUrlWithLocale('/docs', locale),
|
||||
title: (
|
||||
@ -84,7 +85,7 @@ export default async function DocsRootLayout({ children, params }: DocsLayoutPro
|
||||
active: 'none',
|
||||
external: false,
|
||||
},
|
||||
...(websiteConfig.metadata.social.twitter
|
||||
...(websiteConfig.metadata.social?.twitter
|
||||
? [
|
||||
{
|
||||
type: "icon" as const,
|
||||
|
@ -3,6 +3,7 @@
|
||||
import { ActiveThemeProvider } from '@/components/layout/active-theme-provider';
|
||||
import { PaymentProvider } from '@/components/layout/payment-provider';
|
||||
import { TooltipProvider } from '@/components/ui/tooltip';
|
||||
import { websiteConfig } from '@/config/website';
|
||||
import { RootProvider } from 'fumadocs-ui/provider';
|
||||
import { ThemeProvider, useTheme } from 'next-themes';
|
||||
import { PropsWithChildren } from 'react';
|
||||
@ -20,12 +21,13 @@ import { PropsWithChildren } from 'react';
|
||||
*/
|
||||
export function Providers({ children }: PropsWithChildren) {
|
||||
const theme = useTheme();
|
||||
|
||||
const defaultMode = websiteConfig.metadata.mode?.defaultMode ?? "system";
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
defaultTheme={defaultMode}
|
||||
enableSystem={true}
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<ActiveThemeProvider>
|
||||
|
@ -73,6 +73,9 @@ export function SidebarUser({ user, className }: SidebarUserProps) {
|
||||
});
|
||||
}
|
||||
|
||||
const showModeSwitch = websiteConfig.metadata.mode?.enableSwitch ?? false;
|
||||
const showLocaleSwitch = LOCALES.length > 1;
|
||||
|
||||
const handleSignOut = async () => {
|
||||
await authClient.signOut({
|
||||
fetchOptions: {
|
||||
@ -137,11 +140,17 @@ export function SidebarUser({ user, className }: SidebarUserProps) {
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
{
|
||||
(showModeSwitch || showLocaleSwitch) && (
|
||||
<DropdownMenuSeparator />
|
||||
)
|
||||
}
|
||||
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger className="cursor-pointer">
|
||||
{
|
||||
showModeSwitch && (
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger className="cursor-pointer">
|
||||
<LaptopIcon className="mr-2 size-4" />
|
||||
<span>{t('Common.mode.label')}</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
@ -167,13 +176,14 @@ export function SidebarUser({ user, className }: SidebarUserProps) {
|
||||
<LaptopIcon className="mr-2 size-4" />
|
||||
<span>{t('Common.mode.system')}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
LOCALES.length > 1 && (
|
||||
showLocaleSwitch && (
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger className="cursor-pointer">
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
} from "react";
|
||||
|
||||
const COOKIE_NAME = "active_theme";
|
||||
const DEFAULT_THEME = websiteConfig.metadata.theme ?? "default";
|
||||
const DEFAULT_THEME = websiteConfig.metadata.theme?.defaultTheme ?? "default";
|
||||
|
||||
function setThemeCookie(theme: string) {
|
||||
if (typeof window === "undefined") return;
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
} from '@/components/ui/select';
|
||||
import { websiteConfig } from '@/config/website';
|
||||
import { useLocalePathname, useLocaleRouter } from '@/i18n/navigation';
|
||||
import { DEFAULT_LOCALE, LOCALES } from '@/i18n/routing';
|
||||
import { DEFAULT_LOCALE } from '@/i18n/routing';
|
||||
import { useLocaleStore } from '@/stores/locale-store';
|
||||
import { Locale, useLocale } from 'next-intl';
|
||||
import { useParams } from 'next/navigation';
|
||||
@ -27,7 +27,8 @@ import { useEffect, useTransition } from 'react';
|
||||
*/
|
||||
export default function LocaleSelector() {
|
||||
// Return null if there's only one locale available
|
||||
if (LOCALES.length <= 1) {
|
||||
const showLocaleSwitch = Object.keys(websiteConfig.i18n.locales).length > 1;
|
||||
if (!showLocaleSwitch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { websiteConfig } from '@/config/website';
|
||||
import { useLocalePathname, useLocaleRouter } from '@/i18n/navigation';
|
||||
import { LOCALES } from '@/i18n/routing';
|
||||
import { useLocaleStore } from '@/stores/locale-store';
|
||||
import { Languages } from 'lucide-react';
|
||||
import { Locale, useLocale, useTranslations } from 'next-intl';
|
||||
@ -26,7 +25,8 @@ import { useEffect, useTransition } from 'react';
|
||||
*/
|
||||
export default function LocaleSwitcher() {
|
||||
// Return null if there's only one locale available
|
||||
if (LOCALES.length <= 1) {
|
||||
const showLocaleSwitch = Object.keys(websiteConfig.i18n.locales).length > 1;
|
||||
if (!showLocaleSwitch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,8 @@ import { useEffect, useState } from 'react';
|
||||
export function Logo({ className }: { className?: string }) {
|
||||
const { theme } = useTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const logoLight = websiteConfig.metadata.logoLight ?? '/logo.png';
|
||||
const logoDark = websiteConfig.metadata.logoDark ?? logoLight;
|
||||
const logoLight = websiteConfig.metadata.images?.logoLight ?? '/logo.png';
|
||||
const logoDark = websiteConfig.metadata.images?.logoDark ?? logoLight;
|
||||
|
||||
// During server-side rendering and initial client render, always use logoLight
|
||||
// This prevents hydration mismatch
|
||||
|
@ -1,16 +1,21 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { LaptopIcon, MoonIcon, SunIcon } from 'lucide-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { websiteConfig } from '@/config/website';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { LaptopIcon, MoonIcon, SunIcon } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
/**
|
||||
* Mode switcher component, used in the footer
|
||||
*/
|
||||
export function ModeSwitcherHorizontal() {
|
||||
if (!websiteConfig.metadata.mode?.enableSwitch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { theme, setTheme } = useTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const t = useTranslations('Common.mode');
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { websiteConfig } from '@/config/website';
|
||||
import { LaptopIcon, MoonIcon, SunIcon } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useTheme } from 'next-themes';
|
||||
@ -15,6 +16,10 @@ import { useTheme } from 'next-themes';
|
||||
* Mode switcher component, used in the navbar
|
||||
*/
|
||||
export function ModeSwitcher() {
|
||||
if (!websiteConfig.metadata.mode?.enableSwitch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { setTheme } = useTheme();
|
||||
const t = useTranslations('Common.mode');
|
||||
|
||||
|
@ -6,10 +6,10 @@ import {
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue
|
||||
} from "@/components/ui/select";
|
||||
import { websiteConfig } from "@/config/website";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useThemeConfig } from "./active-theme-provider";
|
||||
|
||||
@ -21,6 +21,10 @@ import { useThemeConfig } from "./active-theme-provider";
|
||||
* https://github.com/TheOrcDev/orcish-dashboard/blob/main/components/theme-selector.tsx
|
||||
*/
|
||||
export function ThemeSelector() {
|
||||
if (!websiteConfig.metadata.theme?.enableSwitch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { activeTheme, setActiveTheme } = useThemeConfig();
|
||||
const t = useTranslations('Common.theme');
|
||||
|
||||
|
@ -6,10 +6,19 @@ import { WebsiteConfig } from '@/types';
|
||||
*/
|
||||
export const websiteConfig: WebsiteConfig = {
|
||||
metadata: {
|
||||
theme: "default",
|
||||
ogImage: '/og.png',
|
||||
logoLight: '/logo.png',
|
||||
logoDark: '/logo-dark.png',
|
||||
theme: {
|
||||
defaultTheme: "default",
|
||||
enableSwitch: true,
|
||||
},
|
||||
mode: {
|
||||
defaultMode: "system",
|
||||
enableSwitch: true,
|
||||
},
|
||||
images: {
|
||||
ogImage: '/og.png',
|
||||
logoLight: '/logo.png',
|
||||
logoDark: '/logo-dark.png',
|
||||
},
|
||||
social: {
|
||||
github: 'https://github.com/MkSaaSHQ',
|
||||
twitter: 'https://x.com/mksaascom',
|
||||
|
@ -24,7 +24,7 @@ export function constructMetadata({
|
||||
} = {}): Metadata {
|
||||
title = title || defaultMessages.Metadata.name;
|
||||
description = description || defaultMessages.Metadata.description;
|
||||
image = image || websiteConfig.metadata.ogImage;
|
||||
image = image || websiteConfig.metadata.images?.ogImage;
|
||||
const ogImageUrl = new URL(`${getBaseUrl()}${image}`);
|
||||
return {
|
||||
title,
|
||||
|
19
src/types/index.d.ts
vendored
19
src/types/index.d.ts
vendored
@ -17,11 +17,26 @@ export type WebsiteConfig = {
|
||||
* Website metadata
|
||||
*/
|
||||
export interface MetadataConfig {
|
||||
theme?: "default" | "blue" | "green" | "amber" | "neutral"; // The theme
|
||||
mode?: ModeConfig;
|
||||
theme?: ThemeConfig;
|
||||
images?: ImagesConfig;
|
||||
social?: SocialConfig;
|
||||
}
|
||||
|
||||
export interface ModeConfig {
|
||||
defaultMode?: "light" | "dark" | "system"; // The default mode of the website
|
||||
enableSwitch?: boolean; // Whether to enable the mode switch
|
||||
}
|
||||
|
||||
export interface ThemeConfig {
|
||||
defaultTheme?: "default" | "blue" | "green" | "amber" | "neutral"; // The default theme of the website
|
||||
enableSwitch?: boolean; // Whether to enable the theme switch
|
||||
}
|
||||
|
||||
export interface ImagesConfig {
|
||||
ogImage?: string; // The image as Open Graph image
|
||||
logoLight?: string; // The light logo image
|
||||
logoDark?: string; // The dark logo image
|
||||
social: SocialConfig; // The social media configuration
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user