diff --git a/.changeset/olive-parts-ring.md b/.changeset/olive-parts-ring.md new file mode 100644 index 0000000000..a7371ce912 --- /dev/null +++ b/.changeset/olive-parts-ring.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Add support for button actions diff --git a/bun.lock b/bun.lock index b7d5adcd99..8965ac6cfc 100644 --- a/bun.lock +++ b/bun.lock @@ -346,7 +346,7 @@ "react-dom": "catalog:", }, "catalog": { - "@gitbook/api": "0.154.0", + "@gitbook/api": "0.155.0", "@scalar/api-client-react": "^1.3.46", "@tsconfig/node20": "^20.1.6", "@tsconfig/strictest": "^2.0.6", @@ -727,7 +727,7 @@ "@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@7.1.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" } }, "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA=="], - "@gitbook/api": ["@gitbook/api@0.154.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-huEgWWa2H+H4ofYEAQl9r49u0gVjDHHWVNJKhd6SgGCfefjNPHkQj9zaky/5DBQzlu/+SDmutWiOtYdrykQO8w=="], + "@gitbook/api": ["@gitbook/api@0.155.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-g4UfJRnej/GZ9pORHcS9mV0kKiJLRvhMlGOeOoEVU/LSIz6s35VDqauSBs7rH00AOaMABDg7uEko8tUSA4aaww=="], "@gitbook/browser-types": ["@gitbook/browser-types@workspace:packages/browser-types"], diff --git a/package.json b/package.json index adf3c65d60..9b30e2d6ef 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "catalog": { "@tsconfig/strictest": "^2.0.6", "@tsconfig/node20": "^20.1.6", - "@gitbook/api": "0.154.0", + "@gitbook/api": "0.155.0", "@scalar/api-client-react": "^1.3.46", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", diff --git a/packages/gitbook/src/components/DocumentView/InlineActionButton.tsx b/packages/gitbook/src/components/DocumentView/InlineActionButton.tsx new file mode 100644 index 0000000000..1d148a1edf --- /dev/null +++ b/packages/gitbook/src/components/DocumentView/InlineActionButton.tsx @@ -0,0 +1,75 @@ +'use client'; +import { tString, useLanguage } from '@/intl/client'; +import { useAI, useAIChatController, useAIChatState } from '../AI'; +import { useSearch } from '../Search'; +import { Button, type ButtonProps, Input } from '../primitives'; + +export function InlineActionButton( + props: { action: 'ask' | 'search'; query?: string } & { buttonProps: ButtonProps } // TODO: Type this properly: Pick & { buttonProps: ButtonProps } +) { + const { action, query, buttonProps } = props; + + const { assistants } = useAI(); + const chatController = useAIChatController(); + const chatState = useAIChatState(); + const [, setSearchState] = useSearch(); + const language = useLanguage(); + + const handleSubmit = (value: string) => { + if (action === 'ask') { + chatController.open(); + if (value ?? query) { + chatController.postMessage({ message: value ?? query }); + } + } else if (action === 'search') { + setSearchState((prev) => ({ + ...prev, + ask: null, + scope: 'default', + query: value ?? query, + open: true, + })); + } + }; + + const icon = + action === 'ask' && buttonProps.icon === 'gitbook-assistant' && assistants.length > 0 + ? assistants[0]?.icon + : buttonProps.icon; + + if (!query) { + return ( + handleSubmit(value as string)} + containerStyle={{ + width: `${buttonProps.label ? buttonProps.label.toString().length + 10 : 20}ch`, + }} + /> + ); + } + + const label = action === 'ask' ? `Ask "${query}"` : `Search for "${query}"`; + + const button = ( + + ); + + return button; +} diff --git a/packages/gitbook/src/components/DocumentView/InlineButton.tsx b/packages/gitbook/src/components/DocumentView/InlineButton.tsx index 2257e20439..283dc757d3 100644 --- a/packages/gitbook/src/components/DocumentView/InlineButton.tsx +++ b/packages/gitbook/src/components/DocumentView/InlineButton.tsx @@ -1,44 +1,65 @@ import { resolveContentRef, resolveContentRefFallback } from '@/lib/references'; -import * as api from '@gitbook/api'; +import type * as api from '@gitbook/api'; import type { IconName } from '@gitbook/icons'; -import { Button } from '../primitives'; +import { Button, type ButtonProps } from '../primitives'; import type { InlineProps } from './Inline'; +import { InlineActionButton } from './InlineActionButton'; import { NotFoundRefHoverCard } from './NotFoundRefHoverCard'; -export async function InlineButton(props: InlineProps) { - const { inline, context } = props; +export function InlineButton(props: InlineProps) { + const { inline } = props; - const resolved = context.contentContext - ? await resolveContentRef(inline.data.ref, context.contentContext) - : null; + const buttonProps: ButtonProps = { + label: inline.data.label, + variant: inline.data.kind, + icon: inline.data.icon as IconName | undefined, + }; - const href = resolved?.href ?? resolveContentRefFallback(inline.data.ref)?.href; + const ButtonImplementation = () => { + if ('action' in inline.data && 'query' in inline.data.action) { + return ( + + ); + } + + return ; + }; const inlineElement = ( // Set the leading to have some vertical space between adjacent buttons -