diff --git a/src/app/[spaceId]/[[...pathname]]/layout.tsx b/src/app/[spaceId]/[[...pathname]]/layout.tsx index 235568669..dc4de3ccb 100644 --- a/src/app/[spaceId]/[[...pathname]]/layout.tsx +++ b/src/app/[spaceId]/[[...pathname]]/layout.tsx @@ -1,7 +1,9 @@ import shadesOf from 'tailwind-shades'; +import colors from 'tailwindcss/colors'; import { Inter } from 'next/font/google'; import { tcls } from '@/lib/tailwind'; import { PagePathParams, fetchPageData } from '../fetch'; +import assertNever from 'assert-never'; const inter = Inter({ subsets: ['latin'] }); @@ -11,6 +13,7 @@ export default async function SpaceRootLayout(props: { }) { const { children, params } = props; const { customization } = await fetchPageData(params); + const headerTheme = generateHeaderTheme(customization); return ( @@ -21,12 +24,22 @@ export default async function SpaceRootLayout(props: { 'primary-color', customization.styling.primaryColor.light, )} + ${generateCSSVariable( + 'header-background', + headerTheme.backgroundColor.light, + )} + ${generateCSSVariable('header-link', headerTheme.linkColor.light)} } .dark { ${generateCSSVariable( 'primary-color', customization.styling.primaryColor.dark, )} + ${generateCSSVariable( + 'header-background', + headerTheme.backgroundColor.dark, + )} + ${generateCSSVariable('header-link', headerTheme.linkColor.dark)} } `} @@ -37,8 +50,9 @@ export default async function SpaceRootLayout(props: { ); } -function generateCSSVariable(name: string, color: string) { - const shades: Record = shadesOf(color); +type ColorInput = string | Record; +function generateCSSVariable(name: string, color: ColorInput) { + const shades: Record = typeof color === 'string' ? shadesOf(color) : color; return Object.entries(shades) .map(([key, value]) => { @@ -46,3 +60,67 @@ function generateCSSVariable(name: string, color: string) { }) .join('\n'); } + +function generateHeaderTheme(customization: any): { + backgroundColor: { light: ColorInput; dark: ColorInput }; + linkColor: { light: ColorInput; dark: ColorInput }; +} { + switch (customization.header.preset) { + case 'default': { + return { + backgroundColor: { + light: colors.white, + dark: colors.black, + }, + linkColor: { + light: customization.styling.primaryColor.light, + dark: customization.styling.primaryColor.dark, + }, + }; + } + case 'bold': { + return { + backgroundColor: { + light: customization.styling.primaryColor.light, + dark: customization.styling.primaryColor.dark, + }, + linkColor: { + // TODO: should depend on the color of the background + light: colors.white, + dark: colors.black, + }, + }; + } + case 'contrast': { + return { + backgroundColor: { + light: customization.styling.primaryColor.dark, + dark: customization.styling.primaryColor.light, + }, + linkColor: { + light: colors.white, + dark: colors.black, + }, + }; + } + case 'custom': { + return { + backgroundColor: { + light: customization.header.backgroundColor?.light ?? colors.white, + dark: customization.header.backgroundColor?.dark ?? colors.black, + }, + linkColor: { + light: + customization.header.linkColor?.light ?? + customization.styling.primaryColor.light, + dark: + customization.header.linkColor?.dark ?? + customization.styling.primaryColor.dark, + }, + }; + } + default: { + assertNever(customization.header.preset); + } + } +} diff --git a/src/app/[spaceId]/fetch.ts b/src/app/[spaceId]/fetch.ts index 35c12c725..8c82aedb4 100644 --- a/src/app/[spaceId]/fetch.ts +++ b/src/app/[spaceId]/fetch.ts @@ -26,8 +26,6 @@ export async function fetchPageData(params: PagePathParams | PageIdParams) { getSpaceCustomization(spaceId), ]); - console.log(customization); - const page = 'pageId' in params && params.pageId ? resolvePageId(revision, params.pageId) diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index fffef0d68..63fec7472 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -31,7 +31,7 @@ export function Header(props: { space: Space; asFullWidth: boolean; customizatio 'lg:border-b', 'lg:border-slate-900/10', 'dark:border-slate-50/[0.06]', - 'bg-white/95', + 'bg-header-background-500', 'supports-backdrop-blur:bg-white/60', 'dark:bg-transparent', )} @@ -46,10 +46,19 @@ export function Header(props: { space: Space; asFullWidth: boolean; customizatio asFullWidth ? null : [CONTAINER_MAX_WIDTH_NORMAL, 'mx-auto'], )} > - +
- {t({ space }, 'search')} + + {t({ space }, 'search')} +
diff --git a/src/components/Header/HeaderLogo.tsx b/src/components/Header/HeaderLogo.tsx index 69f93001c..1081cd6c1 100644 --- a/src/components/Header/HeaderLogo.tsx +++ b/src/components/Header/HeaderLogo.tsx @@ -1,5 +1,5 @@ import { absoluteHref } from '@/lib/links'; -import { tcls } from '@/lib/tailwind'; +import { ClassValue, tcls } from '@/lib/tailwind'; import { Space } from '@gitbook/api'; import Link from 'next/link'; @@ -9,12 +9,20 @@ import Link from 'next/link'; * - Image logo * - Or fallback to text with icon before */ -export function HeaderLogo(props: { space: Space; customization: any }) { - const { space } = props; +export function HeaderLogo(props: { + space: Space; + customization: any; + + /** Style applied when the logo is a text one */ + textStyle?: ClassValue; +}) { + const { space, textStyle } = props; return ( - -

{space.title}

+ +

+ {space.title} +

); } diff --git a/src/lib/api.ts b/src/lib/api.ts index 031594324..c4b8b006a 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -68,13 +68,62 @@ export const getPageDocument = unstable_cache( export const getSpaceCustomization = unstable_cache( async (spaceId: string) => { // TODO: use function from API client once updated - const { data } = await api().request({ - method: 'GET', - path: `/spaces/${spaceId}/publishing/customization`, - secure: true, - format: 'json', - }); - return data; + try { + throw new Error('test'); + const { data } = await api().request({ + method: 'GET', + path: `/spaces/${spaceId}/publishing/customization`, + secure: true, + format: 'json', + }); + return data; + } catch (error) { + // TODO: remove hardcoded value as soon as we ship the PAI + return { + inherit: false, + internationalization: { inherit: false, locale: 'en' }, + styling: { + font: 'Inter', + corners: 'rounded', + primaryColor: { light: '#b93d92', dark: '#346DDB' }, + }, + favicon: {}, + header: { + preset: 'bold', + links: [ + { + links: [ + { + to: { kind: 'url', url: 'https://www.google.com' }, + title: 'Sub-link', + }, + { + to: { kind: 'url', url: 'https://www.google.com' }, + title: 'Sub-link 2', + }, + ], + to: { kind: 'url', url: 'https://www.google.fr' }, + title: 'Link 1', + }, + { + links: [], + to: { kind: 'url', url: 'https://www.google.com' }, + title: 'Link 2', + }, + ], + }, + footer: { groups: [] }, + themes: { default: 'light', toggeable: false }, + trademark: { enabled: true }, + feedback: { enabled: false }, + pdf: { enabled: false }, + aiSearch: { enabled: false }, + pagination: { enabled: false }, + privacyPolicy: {}, + socialPreview: {}, + git: { showEditLink: false }, + }; + } }, ['api', 'customization'], { diff --git a/tailwind.config.ts b/tailwind.config.ts index dba693dfc..077a72258 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -22,8 +22,10 @@ const config: Config = { theme: { extend: { colors: { - // Dynamic color to present the space primary color + // Dynamic colors matching the customization settings primary: generateShades('primary-color'), + 'header-background': generateShades('header-background'), + 'header-link': generateShades('header-link'), }, }, },