diff --git a/src/components/markdown.tsx b/src/components/markdown.tsx index 029b5d454..ac0edd7e9 100644 --- a/src/components/markdown.tsx +++ b/src/components/markdown.tsx @@ -14,21 +14,93 @@ import ReactMarkdown, { type Options } from 'react-markdown'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import rehypeKatex from 'rehype-katex'; +import { Tabs } from 'design-system/tabs'; + +const useTab = (children: ReactNode) => { + const [activeTab, setActiveTab] = React.useState(0); + + const content = React.useMemo(() => children?.toString() || ``, [children]); + const hasTabs = content.includes(`@@@`); + + const parseTabContent = React.useCallback((content: string): string[] => { + const panels = content.split(`@@@`); + return panels[0].trim() === `` ? panels.slice(1) : panels; + }, []); + + const tabs = React.useMemo( + () => (hasTabs ? parseTabContent(content) : []), + [hasTabs, content, parseTabContent], + ); + + return { + activeTab, + setActiveTab, + hasTabs, + content, + tabs, + }; +}; + +type TabCodeProps = { + tabs: string[]; + activeTab: number; + setActiveTab: React.Dispatch>; +}; + +const TabCode = ({ tabs, activeTab, setActiveTab }: TabCodeProps) => { + return ( + <> + + {tabs.map((_, index) => ( + setActiveTab(index)} + > + {`Tab ${index + 1}`} + + ))} + + {tabs.map((tab, index) => ( + { + if (index === activeTab && el) { + highlightElement(el); + } + }} + className={c(`language-javascript`, index !== activeTab && `hidden`)} + > + {tab} + + ))} + + ); +}; const Code = ({ children, }: DetailedHTMLProps, HTMLElement>) => { const ref = React.useRef(null); + const { hasTabs, tabs, activeTab, setActiveTab } = useTab(children); React.useLayoutEffect(() => { const container = ref.current; - container && highlightElement(container); - }, [children]); + if (container && !hasTabs) { + highlightElement(container); + } + }, [children, hasTabs]); + + if (!hasTabs) { + return ( + + {children} + + ); + } return ( - - {children} - + ); }; @@ -42,7 +114,7 @@ const SnippetCopyButton = ({ children }: { children: ReactNode }) => { return ( +