Start theming header

This commit is contained in:
Samy Pessé
2023-11-03 22:58:04 -04:00
parent 13df0d69f4
commit abb3ed132a
6 changed files with 164 additions and 20 deletions
+80 -2
View File
@@ -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 (
<html lang={customization.internationalization.locale}>
@@ -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)}
}
`}</style>
</head>
@@ -37,8 +50,9 @@ export default async function SpaceRootLayout(props: {
);
}
function generateCSSVariable(name: string, color: string) {
const shades: Record<number, string> = shadesOf(color);
type ColorInput = string | Record<string, string>;
function generateCSSVariable(name: string, color: ColorInput) {
const shades: Record<string, string> = 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);
}
}
}
-2
View File
@@ -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)
+12 -3
View File
@@ -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'],
)}
>
<HeaderLogo space={space} customization={customization} />
<HeaderLogo
space={space}
customization={customization}
textStyle={[
'text-header-link-500',
'group-headerlogo/hover:text-header-link-700',
]}
/>
<div className={tcls('flex', 'basis-56', 'grow-0', 'shrink-0')}>
<Suspense fallback={null}>
<SearchButton>{t({ space }, 'search')}</SearchButton>
<SearchButton style={['bg-header-background-300']}>
{t({ space }, 'search')}
</SearchButton>
</Suspense>
</div>
</div>
+13 -5
View File
@@ -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 (
<Link href={absoluteHref('')} className={tcls('flex-1')}>
<h1 className={tcls('text-lg', 'text-slate-800', 'font-semibold')}>{space.title}</h1>
<Link href={absoluteHref('')} className={tcls('flex-1', 'group/headerlogo')}>
<h1 className={tcls('text-lg', 'text-slate-800', 'font-semibold', textStyle)}>
{space.title}
</h1>
</Link>
);
}
+56 -7
View File
@@ -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'],
{
+3 -1
View File
@@ -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'),
},
},
},