/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import type { ReactNode } from 'react' import type { CodeBlockNode, DefinitionItemNode, DefinitionListNode, HeadingNode, ListNode, MathBlockNode, MathInlineNode, } from 'stream-markdown-parser' import { CodeBlock, CodeBlockCopyButton, } from '@/components/ai-elements/code-block' import { cn } from '@/lib/utils' import { getNodeKey } from './response-content' import type { BlockRendererOptions } from './response-types' const headingClasses = { 1: 'mt-6 mb-3 text-xl font-semibold tracking-normal', 2: 'mt-6 mb-3 text-lg font-semibold tracking-normal', 3: 'mt-5 mb-2 text-base font-semibold tracking-normal', 4: 'mt-5 mb-2 text-sm font-semibold tracking-normal', 5: 'text-muted-foreground mt-4 mb-2 text-sm font-semibold tracking-normal', 6: 'text-muted-foreground mt-4 mb-2 text-xs font-semibold tracking-normal uppercase', } satisfies Record<1 | 2 | 3 | 4 | 5 | 6, string> export function renderHeading( node: HeadingNode, key: string, options: BlockRendererOptions ): ReactNode { const headingLevel = Math.min(Math.max(node.level, 1), 6) as | 1 | 2 | 3 | 4 | 5 | 6 const className = headingClasses[headingLevel] const children = options.renderChildren(node.children) if (headingLevel === 1) { return (

{children}

) } if (headingLevel === 2) { return (

{children}

) } if (headingLevel === 3) { return (

{children}

) } if (headingLevel === 4) { return (

{children}

) } if (headingLevel === 5) { return (
{children}
) } return (
{children}
) } export function renderList( node: ListNode, key: string, options: BlockRendererOptions ): ReactNode { const className = cn( 'my-3 list-outside space-y-1.5 pl-5', node.ordered ? 'list-decimal' : 'list-disc' ) const items = node.items.map((item, index) => (
  • {options.renderChildren(item.children)}
  • )) if (node.ordered) { return (
      {items}
    ) } return ( ) } export function renderCodeBlock(node: CodeBlockNode, key: string): ReactNode { const language = node.language || 'plaintext' const lineCount = node.code.split('\n').length return ( 14} key={key} language={language} maxExpandedLines={44} showLineNumbers showToolbar title={language} > ) } export function renderDefinitionList( node: DefinitionListNode, key: string, options: BlockRendererOptions ): ReactNode { return (
    {node.items.map((item, index) => renderDefinitionItem(item, index, options) )}
    ) } function renderDefinitionItem( node: DefinitionItemNode, index: number, options: BlockRendererOptions ): ReactNode { return (
    {options.renderChildren(node.term)}
    {options.renderChildren(node.definition)}
    ) } export function renderMathBlock(node: MathBlockNode, key: string): ReactNode { return (
          {node.content}
        
    ) } export function renderMathInline(node: MathInlineNode, key: string): ReactNode { return ( {node.content} ) }