Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions apps/masterbots.ai/components/layout/sidebar/sidebar-link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ const ChatbotComponent: React.FC<ChatbotComponentProps> = React.memo(
const { userSlug, domain } = useParams()
const { setIsOpenPopup, setActiveThread } = useThread()

const isPro = routeType === 'pro'
const canonicalDomain = getCanonicalDomain(chatbot.name)
// * Default to prompt when no metadata found... Special case for BlankBot
const chatbotDomain = canonicalDomain || (domain as string) || 'prompt'
Expand Down Expand Up @@ -274,7 +275,7 @@ const ChatbotComponent: React.FC<ChatbotComponentProps> = React.memo(
return navigateTo({
urlType: 'chatbotThreadListUrl',
navigationParams: {
type: isPublic ? 'public' : 'personal',
type: isPro ? 'pro' : isPublic ? 'public' : 'personal',
category: category.name,
domain: chatbotDomain,
chatbot: chatbot.name,
Expand Down Expand Up @@ -303,7 +304,7 @@ const ChatbotComponent: React.FC<ChatbotComponentProps> = React.memo(
chatbot: chatbot?.name,
})
: urlBuilders.chatbotThreadListUrl({
type: isPublic ? 'public' : 'personal',
type: isPro ? 'pro' : isPublic ? 'public' : 'personal',
category: category.name,
domain: chatbotDomain,
chatbot: chatbot?.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
*/

import { MemoizedReactMarkdown } from '@/components/shared/markdown'
import { CodeBlock } from '@/components/ui/codeblock'
import { cleanPrompt } from '@/lib/helpers/ai-helpers'
import { memoizedMarkdownComponents } from '@/lib/memoized-markdown-components'
import { cn } from '@/lib/utils'
import type { Message } from 'ai'
import type { Chatbot } from 'mb-genql'
Expand All @@ -51,65 +51,7 @@ export function BrowseChatMessage({
<MemoizedReactMarkdown
className="min-w-full prose break-words dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 !max-w-5xl"
remarkPlugins={[remarkGfm, rehypeMathJax, remarkRehype]}
components={{
// @ts-ignore
p({ children }) {
return (
<p className="mb-2 whitespace-pre-line last:mb-0">{children}</p>
)
},
// @ts-ignore
ol({ children }) {
return (
<ol className="text-left list-decimal list-inside">
{children}
</ol>
)
},
// @ts-ignore
ul({ children }) {
return (
<ul className="text-left list-disc list-inside">{children}</ul>
)
},
// @ts-ignore
code({
node,
inline = false,
className,
children,
...props
}: React.HTMLAttributes<HTMLElement> & {
node: unknown
inline?: boolean
}) {
const childrenText = String(children)
if (childrenText?.startsWith('▍')) {
return (
<span className="mt-1 cursor-default animate-pulse">▍</span>
)
}

const match = /language-(\w+)/.exec(className || '')

if (inline) {
return (
<code className={className} {...props}>
{children}
</code>
)
}

return (
<CodeBlock
key={Math.random()}
language={match?.[1] || ''}
value={String(children).replace(/\n$/, '')}
{...props}
/>
)
},
}}
components={memoizedMarkdownComponents()}
>
{cleanMessage.content}
</MemoizedReactMarkdown>
Expand Down
189 changes: 6 additions & 183 deletions apps/masterbots.ai/components/routes/chat/chat-message.tsx
Original file line number Diff line number Diff line change
@@ -1,66 +1,18 @@
import { ChatMessageActions } from '@/components/routes/chat/chat-message-actions'
import { MemoizedReactMarkdown } from '@/components/shared/markdown'
import { CodeBlock } from '@/components/ui/codeblock'
import {
cleanClickableText,
extractFollowUpContext,
getTextFromChildren,
} from '@/lib/chat-clickable-text'
import { cleanPrompt } from '@/lib/helpers/ai-helpers'
import { memoizedMarkdownComponents } from '@/lib/memoized-markdown-components'
import { cn } from '@/lib/utils'
import type { ChatMessageProps, WebSearchResult } from '@/types/types'
import React, { useState } from 'react'
import { useState } from 'react'
import rehypeMathJax from 'rehype-mathjax'
import remarkGfm from 'remark-gfm'
import remarkRehype from 'remark-rehype'

/**
* Preprocesses the children to combine adjacent nodes with a colon.
*
* @param children The children nodes.
* @returns The preprocessed children.
*/

const preprocessChildren = (children: React.ReactNode): React.ReactNode => {
if (!Array.isArray(children)) return children

const result: React.ReactNode[] = []
let i = 0

while (i < children.length) {
const current = children[i]
const next = i + 1 < children.length ? children[i + 1] : null

// If we detect a pattern where a node is immediately followed by ":"
if (next && typeof next === 'string' && next.trim() === ':') {
if (typeof current === 'string') {
result.push(`${current}:`)
} else if (React.isValidElement(current)) {
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
const element = current as React.ReactElement<any>
const currentChildren = element.props.children
result.push(
React.cloneElement(element, {
children:
typeof currentChildren === 'string'
? `${currentChildren}:`
: currentChildren,
}),
)
} else {
result.push(current)
result.push(next)
}
i += 2
} else {
result.push(current)
i += 1
}
}

return result
}

/**
* Displays a chat message with clickable text elements.
*
Expand Down Expand Up @@ -137,139 +89,10 @@ export function ChatMessage({
<MemoizedReactMarkdown
className="min-w-full prose break-words dark:prose-invert prose-p:leading-relaxed prose-pre:p-0"
remarkPlugins={[remarkGfm, rehypeMathJax, remarkRehype]}
components={{
// Process paragraph nodes.
// @ts-ignore
p({ children }) {
return (
<p className="text-left whitespace-pre-line">
{preprocessChildren(children)}
</p>
)
},
// Process heading nodes with clickable functionality.
// @ts-ignore
h1({ children }) {
const text = getTextFromChildren(children)
return (
// biome-ignore lint/a11y/useKeyWithClickEvents: <explanation>
<h1
className="mb-2 text-2xl font-bold cursor-pointer clickable-heading"
onClick={() => handleClickableClick(text)}
>
{preprocessChildren(children)}
</h1>
)
},
// @ts-ignore
h2({ children }) {
const text = getTextFromChildren(children)
return (
// biome-ignore lint/a11y/useKeyWithClickEvents: <explanation>
<h2
className="mb-2 text-xl font-bold cursor-pointer clickable-heading"
onClick={() => handleClickableClick(text)}
>
{preprocessChildren(children)}
</h2>
)
},
// @ts-ignore
h3({ children }) {
const text = getTextFromChildren(children)
return (
// biome-ignore lint/a11y/useKeyWithClickEvents: <explanation>
<h3
className="mb-2 text-lg font-bold cursor-pointer clickable-heading"
onClick={() => handleClickableClick(text)}
>
{preprocessChildren(children)}
</h3>
)
},
// Process strong/emphasis nodes.
// @ts-ignore
strong({ children }) {
return <strong>{preprocessChildren(children)}</strong>
},
// List handling.
// @ts-ignore
ul({ children }) {
return <ul className="ml-2 space-y-2 list-disc">{children}</ul>
},
// @ts-ignore
ol({ children }) {
return <ol className="ml-2 space-y-2 list-decimal">{children}</ol>
},
// @ts-ignore
li({ children }) {
const processedChildren = preprocessChildren(children)
const text = getTextFromChildren(processedChildren)
const hasNestedList = React.Children.toArray(
processedChildren,
).some(
(child) =>
React.isValidElement(child) &&
(child.type === 'ul' || child.type === 'ol'),
)

return (
// biome-ignore lint/a11y/useKeyWithClickEvents: <explanation>
<li
className={cn(
'ml-4',
hasNestedList && 'mt-2',
'clickable-list-heading',
)}
onClick={() => handleClickableClick(text)}
>
{processedChildren}
</li>
)
},
// Process link nodes.
// @ts-ignore
a({ href, children, ...props }) {
return (
<a
className="text-blue-500 underline"
target="_blank"
rel="noopener noreferrer"
href={href}
{...props}
>
{children}
</a>
)
},
// Process code blocks.
// @ts-ignore
code({ inline, className, children, ...props }) {
const childrenText = String(children)
if (childrenText?.startsWith('▍')) {
return (
<span className="mt-1 cursor-default animate-pulse">▍</span>
)
}

const match = /language-(\w+)/.exec(className || '')
if (inline) {
return (
<code className={className} {...props}>
{children}
</code>
)
}
return (
<CodeBlock
key={Math.random()}
language={match?.[1] || ''}
value={String(children).replace(/\n$/, '')}
{...props}
/>
)
},
}}
components={memoizedMarkdownComponents({
handleClickableClick,
shouldPreProcessChildren: true,
})}
>
{cleanMessage.content}
</MemoizedReactMarkdown>
Expand Down
Loading