/** * Inspired from fumadocs docsite * @from https://github.com/fuma-nama/fumadocs/blob/5723bbe58ef805a5421a780abf235a10b251be2f/apps/docs/app/docs/%5B...slug%5D/page.client.tsx#L11 * @license MIT */ import { useI18n, useSite } from '@rspress/core/runtime'; import { copyToClipboard, IconDown, IconExternalLink, IconLink, SvgWrapper, } from '@rspress/core/theme'; import type React from 'react'; import { useEffect, useMemo, useRef, useState } from 'react'; import './index.scss'; import './LlmsViewOptions.scss'; import { useMdUrl } from './useMdUrl'; type Option = | { title: string; icon?: React.ReactNode; onClick?: () => void; } | { title: string; href: string; icon?: React.ReactNode; } | 'markdownLink' | 'chatgpt' | 'claude'; export interface LlmsViewOptionsProps extends React.ButtonHTMLAttributes { /** * Default options for the dropdown. * @default ['markdownLink', 'chatgpt', 'claude'] * - 'chatgpt': Open in ChatGPT * - 'claude': Open in Claude */ options?: Option[]; /** * Button text by language, used with `useLang`. * @default en: 'Open', zh: '\u6253\u5f00' */ textByLang?: Record; /** * Button text. * Priority is higher than textByLang * @default '' */ text?: string; } const DEFAULT_OPTIONS: Option[] = ['markdownLink', 'chatgpt', 'claude']; export function LlmsViewOptions({ options: propsOptions, }: LlmsViewOptionsProps) { const { site } = useSite(); const llmsUI = site?.themeConfig?.llmsUI; const options = (typeof llmsUI === 'object' ? llmsUI?.viewOptions : propsOptions) ?? DEFAULT_OPTIONS; const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( dropdownRef.current && event.target && !dropdownRef.current.contains(event.target as Node) ) { setIsOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, []); const toggleDropdown = () => { setIsOpen(!isOpen); }; const { pathname } = useMdUrl(); const t = useI18n(); const items = useMemo(() => { const fullMarkdownUrl = typeof window !== 'undefined' ? new URL(pathname, window.location.origin).toString() : 'loading'; const q = `Read ${fullMarkdownUrl}, I want to ask questions about it.`; return { markdownLink: { title: t('copyMarkdownLinkText'), icon: , onClick: () => { void copyToClipboard(fullMarkdownUrl); }, }, chatgpt: { title: t('openInText', { name: 'ChatGPT' }), href: `https://chatgpt.com/?${new URLSearchParams({ hints: 'search', q, })}`, icon: ( OpenAI ), }, claude: { title: t('openInText', { name: 'Claude' }), href: `https://claude.ai/new?${new URLSearchParams({ q, })}`, icon: ( Anthropic ), }, }; }, [pathname, t]); return ( <> ); }