Page actions customisation (#3485)

Co-authored-by: Samy Pessé <samypesse@gmail.com>
This commit is contained in:
Zeno Kapitein
2025-07-18 21:10:38 +02:00
committed by GitHub
parent 765141a4d8
commit 2fe58e8cbb
3 changed files with 59 additions and 23 deletions
+16
View File
@@ -932,6 +932,22 @@ const testCases: TestsCase[] = [
},
]),
},
{
name: 'Page actions',
contentBaseURL: 'https://gitbook.gitbook.io/test-gitbook-open/',
tests: [
{
name: 'Without page actions',
url: getCustomizationURL({
pageActions: {
markdown: false,
externalAI: false,
},
}),
run: waitForCookiesDialog,
},
],
},
{
name: 'Ads',
contentBaseURL: 'https://gitbook.gitbook.io/test-gitbook-open/',
@@ -8,6 +8,7 @@ import {
} from '@/components/AIActions/AIActions';
import { Button } from '@/components/primitives/Button';
import { DropdownMenu } from '@/components/primitives/DropdownMenu';
import type { SiteCustomizationSettings } from '@gitbook/api';
import { Icon } from '@gitbook/icons';
import { useRef } from 'react';
@@ -16,10 +17,7 @@ interface AIActionsDropdownProps {
markdownPageUrl: string;
withAIChat?: boolean;
trademark: boolean;
/**
* Whether to include the "Open in LLM" entries in the dropdown menu.
*/
withLLMActions?: boolean;
actions: SiteCustomizationSettings['pageActions'];
}
/**
@@ -59,7 +57,7 @@ export function AIActionsDropdown(props: AIActionsDropdownProps) {
* The content of the dropdown menu.
*/
function AIActionsDropdownMenuContent(props: AIActionsDropdownProps) {
const { markdownPageUrl, withAIChat, trademark, withLLMActions } = props;
const { markdownPageUrl, withAIChat, trademark, actions } = props;
return (
<>
@@ -67,14 +65,18 @@ function AIActionsDropdownMenuContent(props: AIActionsDropdownProps) {
<OpenDocsAssistant trademark={trademark} type="dropdown-menu-item" />
) : null}
<CopyMarkdown
isDefaultAction={!withAIChat}
markdownPageUrl={markdownPageUrl}
type="dropdown-menu-item"
/>
<ViewAsMarkdown markdownPageUrl={markdownPageUrl} type="dropdown-menu-item" />
{actions.markdown ? (
<>
<CopyMarkdown
isDefaultAction={!withAIChat}
markdownPageUrl={markdownPageUrl}
type="dropdown-menu-item"
/>
<ViewAsMarkdown markdownPageUrl={markdownPageUrl} type="dropdown-menu-item" />
</>
) : null}
{withLLMActions ? (
{actions.externalAI ? (
<>
<OpenInLLM provider="chatgpt" url={markdownPageUrl} type="dropdown-menu-item" />
<OpenInLLM provider="claude" url={markdownPageUrl} type="dropdown-menu-item" />
@@ -88,17 +90,27 @@ function AIActionsDropdownMenuContent(props: AIActionsDropdownProps) {
* A default action shown as a quick-access button beside the dropdown menu
*/
function DefaultAction(props: AIActionsDropdownProps) {
const { markdownPageUrl, withAIChat, trademark } = props;
const { markdownPageUrl, withAIChat, trademark, actions } = props;
if (withAIChat) {
return <OpenDocsAssistant trademark={trademark} type="button" />;
}
return (
<CopyMarkdown
isDefaultAction={!withAIChat}
markdownPageUrl={markdownPageUrl}
type="button"
/>
);
if (actions.markdown) {
return (
<CopyMarkdown
isDefaultAction={!withAIChat}
markdownPageUrl={markdownPageUrl}
type="button"
/>
);
}
if (actions.externalAI) {
return (
<>
<OpenInLLM provider="chatgpt" url={markdownPageUrl} type="button" />
</>
);
}
}
@@ -3,7 +3,7 @@ import { isAIChatEnabled } from '@/components/utils/isAIChatEnabled';
import type { GitBookSiteContext } from '@/lib/context';
import type { AncestorRevisionPage } from '@/lib/pages';
import { tcls } from '@/lib/tailwind';
import { type RevisionPageDocument, SiteVisibility } from '@gitbook/api';
import type { RevisionPageDocument } from '@gitbook/api';
import { Icon } from '@gitbook/icons';
import { PageIcon } from '../PageIcon';
import { StyledLink } from '../primitives';
@@ -22,6 +22,12 @@ export async function PageHeader(props: {
const withAIChat = isAIChatEnabled(context);
const pageActions = context.customization.pageActions ?? {
// TODO: After 25/07/2025, we can remove this default values as the cache will be updated
markdown: true,
externalAI: true,
};
return (
<header
className={tcls(
@@ -34,7 +40,9 @@ export async function PageHeader(props: {
'page-api-block:max-w-full'
)}
>
{page.layout.tableOfContents ? (
{page.layout.tableOfContents &&
// Show page actions if *any* of the actions are enabled
(withAIChat || pageActions.markdown || pageActions.externalAI) ? (
<div
className={tcls(
'float-right mb-2 ml-4',
@@ -45,7 +53,7 @@ export async function PageHeader(props: {
markdownPageUrl={`${context.linker.toAbsoluteURL(context.linker.toPathInSpace(page.path))}.md`}
withAIChat={withAIChat}
trademark={context.customization.trademark.enabled}
withLLMActions={context.site.visibility === SiteVisibility.Public}
actions={pageActions}
/>
</div>
) : null}