diff --git a/packages/gitbook/.env.example b/packages/gitbook/.env.example index fb641c408..3d6e8bd14 100644 --- a/packages/gitbook/.env.example +++ b/packages/gitbook/.env.example @@ -25,3 +25,6 @@ ### Sentry ### # SENTRY_DSN=xxx + +### Silent logs +# SILENT=true \ No newline at end of file diff --git a/packages/gitbook/e2e/pages.spec.ts b/packages/gitbook/e2e/pages.spec.ts index 63a9ad4d6..b61dbbc20 100644 --- a/packages/gitbook/e2e/pages.spec.ts +++ b/packages/gitbook/e2e/pages.spec.ts @@ -18,6 +18,7 @@ interface Test { run?: (page: Page) => Promise; // The test to run fullPage?: boolean; // Whether the test should be fullscreened during testing screenshot?: false; // Should a screenshot be stored + only?: boolean; // Only run this test } interface TestsCase { @@ -452,6 +453,29 @@ const testCases: TestsCase[] = [ }), run: waitForCookiesDialog, }, + { + name: 'With header buttons', + url: getCustomizationURL({ + header: { + preset: CustomizationHeaderPreset.Default, + links: [ + { + title: 'Secondary button', + to: { kind: 'url', url: 'https://www.gitbook.com' }, + // @ts-ignore Remove once we upgrade to the latest version of the API + style: 'button-secondary', + }, + { + title: 'Primary button', + to: { kind: 'url', url: 'https://www.gitbook.com' }, + // @ts-ignore Remove once we upgrade to the latest version of the API + style: 'button-primary', + }, + ], + }, + }), + run: waitForCookiesDialog, + }, ], }, { @@ -744,7 +768,8 @@ const testCases: TestsCase[] = [ for (const testCase of testCases) { test.describe(testCase.name, () => { for (const testEntry of testCase.tests) { - test(testEntry.name, async ({ page, baseURL }) => { + const testFn = testEntry.only ? test.only : test; + testFn(testEntry.name, async ({ page, baseURL }) => { const contentUrl = new URL(testEntry.url, testCase.baseUrl); const url = getContentTestURL(contentUrl.toString(), baseURL); await page.goto(url); diff --git a/packages/gitbook/src/app/(space)/layout.tsx b/packages/gitbook/src/app/(space)/layout.tsx index 49abe014e..3fd86c7b3 100644 --- a/packages/gitbook/src/app/(space)/layout.tsx +++ b/packages/gitbook/src/app/(space)/layout.tsx @@ -98,6 +98,7 @@ export default async function SpaceRootLayout(props: { children: React.ReactNode headerTheme.backgroundColor.light, )} ${generateColorVariable('header-link', headerTheme.linkColor.light)} + ${generateColorVariable('header-button-text', colorContrast(headerTheme.linkColor.light as string, ['#000', '#fff']))} } .dark { ${generateColorVariable( @@ -127,6 +128,7 @@ export default async function SpaceRootLayout(props: { children: React.ReactNode headerTheme.backgroundColor.dark, )} ${generateColorVariable('header-link', headerTheme.linkColor.dark)} + ${generateColorVariable('header-button-text', colorContrast(headerTheme.linkColor.dark as string, ['#000', '#fff']))} } `} diff --git a/packages/gitbook/src/components/Header/Dropdown.tsx b/packages/gitbook/src/components/Header/Dropdown.tsx index faae4cf48..f12d86dff 100644 --- a/packages/gitbook/src/components/Header/Dropdown.tsx +++ b/packages/gitbook/src/components/Header/Dropdown.tsx @@ -25,7 +25,7 @@ export function Dropdown(props: { const dropdownId = useId(); return ( -
+
{button({ id: dropdownId, tabIndex: 0, diff --git a/packages/gitbook/src/components/Header/HeaderLink.tsx b/packages/gitbook/src/components/Header/HeaderLink.tsx index 46a037d6f..33b30863b 100644 --- a/packages/gitbook/src/components/Header/HeaderLink.tsx +++ b/packages/gitbook/src/components/Header/HeaderLink.tsx @@ -5,6 +5,7 @@ import { CustomizationHeaderPreset, SiteCustomizationSettings, } from '@gitbook/api'; +import assertNever from 'assert-never'; import { ContentRefContext, resolveContentRef } from '@/lib/references'; import { tcls } from '@/lib/tailwind'; @@ -16,56 +17,95 @@ import { DropdownMenu, DropdownMenuItem, } from './Dropdown'; -import { Link } from '../primitives'; +import { Button, Link } from '../primitives'; + +// @TODO Remove it once we have the proper types in API +type CustomizationHeaderLinkWithStyle = CustomizationHeaderLink & { + style?: 'link' | 'button-primary' | 'button-secondary'; +}; export async function HeaderLink(props: { context: ContentRefContext; - link: CustomizationHeaderLink; + link: CustomizationHeaderLinkWithStyle; customization: CustomizationSettings | SiteCustomizationSettings; }) { const { context, link, customization } = props; - const isCustomizationCustom = customization.header.preset === CustomizationHeaderPreset.Custom; - - const isCustomizationDefault = - customization.header.preset === CustomizationHeaderPreset.Default; - const target = await resolveContentRef(link.to, context); if (!target) { return null; } - const renderLink = (linkProps: DropdownButtonProps) => ( - - {link.title} + const renderLink = (linkProps: DropdownButtonProps) => { + const linkStyle = link.style ?? 'link'; - {link.links && link.links.length > 0 ? : null} - - ); + switch (linkStyle) { + case 'button-secondary': + case 'button-primary': { + const variant = (() => { + switch (linkStyle) { + case 'button-secondary': + return 'secondary'; + case 'button-primary': + return 'primary'; + default: + assertNever(linkStyle); + } + })(); + return ( + + ); + } + case 'link': { + return ( + + {link.title} + {link.links && link.links.length > 0 ? : null} + + ); + } + default: + assertNever(linkStyle); + } + }; if (link.links && link.links.length > 0) { return ( diff --git a/packages/gitbook/src/components/Header/HeaderLinks.tsx b/packages/gitbook/src/components/Header/HeaderLinks.tsx index b7d3bc200..fc609949b 100644 --- a/packages/gitbook/src/components/Header/HeaderLinks.tsx +++ b/packages/gitbook/src/components/Header/HeaderLinks.tsx @@ -10,21 +10,13 @@ interface HeaderLinksProps { export async function HeaderLinks({ children }: HeaderLinksProps) { return ( -
-
- {children} -
+
+ {children}
); } diff --git a/packages/gitbook/src/components/Header/headerLinks.module.css b/packages/gitbook/src/components/Header/headerLinks.module.css index 3f4ca5133..14a83f804 100644 --- a/packages/gitbook/src/components/Header/headerLinks.module.css +++ b/packages/gitbook/src/components/Header/headerLinks.module.css @@ -3,9 +3,6 @@ container-name: headerlinks; } -.containerHeaderlinks > * { - display: flex; -} .linkEllipsis { display: none; & div > a { @@ -79,8 +76,3 @@ } } } -@container headerlinks ( width > 900px ) { - .containerHeaderlinks > *:not(.linkEllipsis) { - display: flex; - } -} diff --git a/packages/gitbook/src/components/primitives/Button.tsx b/packages/gitbook/src/components/primitives/Button.tsx index 1406068ac..26c9c6e3e 100644 --- a/packages/gitbook/src/components/primitives/Button.tsx +++ b/packages/gitbook/src/components/primitives/Button.tsx @@ -51,6 +51,7 @@ export function Button({ ['text-xs', 'px-3 py-2']; const domClassName = tcls( + 'inline-block', 'rounded-md', 'straight-corners:rounded-none', 'place-self-start', @@ -58,6 +59,7 @@ export function Button({ 'ring-inset', 'grow-0', 'shrink-0', + 'truncate', variantClasses, sizeClasses, className, diff --git a/packages/gitbook/src/lib/cache/cache.ts b/packages/gitbook/src/lib/cache/cache.ts index 4dbf680c6..3552c54a6 100644 --- a/packages/gitbook/src/lib/cache/cache.ts +++ b/packages/gitbook/src/lib/cache/cache.ts @@ -197,13 +197,15 @@ export function cache( const totalDuration = now() - timeStart; // Log - console.log( - `cache: ${key} ${cacheStatus}${ - cacheStatus === 'hit' ? ` on ${backendName}` : '' - } in total ${totalDuration.toFixed(0)}ms, fetch in ${fetchDuration.toFixed( - 0, - )}ms, read in ${readCacheDuration.toFixed(0)}ms`, - ); + if (process.env.SILENT !== 'true') { + console.log( + `cache: ${key} ${cacheStatus}${ + cacheStatus === 'hit' ? ` on ${backendName}` : '' + } in total ${totalDuration.toFixed(0)}ms, fetch in ${fetchDuration.toFixed( + 0, + )}ms, read in ${readCacheDuration.toFixed(0)}ms`, + ); + } if (savedEntry.meta.revalidatesAt && savedEntry.meta.revalidatesAt < Date.now()) { // Revalidate in the background diff --git a/packages/gitbook/src/lib/references.tsx b/packages/gitbook/src/lib/references.tsx index 1664ca173..efcc5040c 100644 --- a/packages/gitbook/src/lib/references.tsx +++ b/packages/gitbook/src/lib/references.tsx @@ -213,7 +213,7 @@ export async function resolveContentRef( return { href: targetSpace.urls.published ?? targetSpace.urls.app, text: targetSpace.title, - active: true, + active: contentRef.space === space.id, }; } diff --git a/packages/gitbook/src/lib/tracing.ts b/packages/gitbook/src/lib/tracing.ts index d2a2afd23..a5fc97aea 100644 --- a/packages/gitbook/src/lib/tracing.ts +++ b/packages/gitbook/src/lib/tracing.ts @@ -43,8 +43,10 @@ export async function trace( span.setAttribute('error', true); throw error; } finally { - let end = now(); - console.log(`trace ${completeName} ${end - start}ms`, attributes); + if (process.env.SILENT !== 'true') { + let end = now(); + console.log(`trace ${completeName} ${end - start}ms`, attributes); + } } }, ); diff --git a/packages/gitbook/tailwind.config.ts b/packages/gitbook/tailwind.config.ts index 1c113f730..53ee98cec 100644 --- a/packages/gitbook/tailwind.config.ts +++ b/packages/gitbook/tailwind.config.ts @@ -77,6 +77,7 @@ const config: Config = { 'header-background': generateVarShades('header-background'), 'header-link': generateVarShades('header-link'), + 'header-button-text': generateVarShades('header-button-text'), light: { 1: `color-mix(in srgb, var(--light-1), transparent calc(100% - 100% * ))`, //1 99%