Skip to content

Commit 388b923

Browse files
committed
fix: inline code block not rendered correclty
1 parent 771e024 commit 388b923

File tree

11 files changed

+1156
-3276
lines changed

11 files changed

+1156
-3276
lines changed

frontend/.cursorrules

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Cursor Rules
2+
3+
- Use `rehypeRaw` to allow raw HTML in the markdown.
4+
- Use `pnpm` as the package manager.
5+
- Use `pnpm i` to install dependencies.

frontend/pnpm-lock.yaml

Lines changed: 1052 additions & 3221 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/app/chat/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default function Page() {
3232

3333
return (
3434
<ResizablePanelGroup direction="horizontal">
35-
<ResizablePanel defaultSize={20}>
35+
<ResizablePanel defaultSize={20} minSize={20} maxSize={40}>
3636
<div className="flex flex-col h-full w-full">
3737
<div className="flex items-center justify-between w-full border-b p-2">
3838
<span className="font-bold">Chats</span>

frontend/src/components/Markdown/index.tsx

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import React from 'react';
22
import ReactMarkdown from 'react-markdown';
33
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
4-
import { vscDarkPlus as style } from 'react-syntax-highlighter/dist/esm/styles/prism';
4+
import {
5+
vscDarkPlus,
6+
vs,
7+
} from 'react-syntax-highlighter/dist/esm/styles/prism';
58
import RemarkBreaks from 'remark-breaks';
69
import RemarkGfm from 'remark-gfm';
710
import RemarkMath from 'remark-math';
@@ -11,10 +14,12 @@ import './markdown.css';
1114
import { CopyButton } from '../copy-button';
1215
import { common, createLowlight } from 'lowlight';
1316
import clsx from 'clsx';
14-
17+
import { useTheme } from 'next-themes';
1518
const lowlight = createLowlight(common);
1619

1720
const CodeBlock = ({ language, children }: any) => {
21+
const { resolvedTheme } = useTheme();
22+
const style = resolvedTheme === 'dark' ? vscDarkPlus : vs;
1823
const detectedLanguage =
1924
language || lowlight.highlightAuto(children).data?.language;
2025
return (
@@ -30,9 +35,18 @@ const CodeBlock = ({ language, children }: any) => {
3035
};
3136

3237
const InlineCode = ({ children }: any) => (
33-
<code className="bg-base-300 p-1 rounded-md text-sm mx-1">{children}</code>
38+
<code className="px-[0.3rem] py-[0.2rem] font-mono text-sm bg-muted rounded-md">
39+
{children}
40+
</code>
3441
);
3542

43+
interface CodeProps extends React.HTMLAttributes<HTMLElement> {
44+
inline?: boolean;
45+
className?: string;
46+
children?: React.ReactNode;
47+
node?: any;
48+
}
49+
3650
const CodeComponent = ({
3751
node,
3852
inline,
@@ -42,11 +56,17 @@ const CodeComponent = ({
4256
...props
4357
}: any) => {
4458
const match = /language-(\w+)/.exec(className || '');
45-
if (inline) return <InlineCode {...props}>{children}</InlineCode>;
59+
60+
// Handle inline code differently
61+
if (inline) {
62+
return <InlineCode {...props}>{children}</InlineCode>;
63+
}
64+
65+
// Only wrap in div and add copy button for block code
4666
return (
4767
<div className="relative">
4868
<CodeBlock language={match && match[1]} {...props}>
49-
{String(children).replace(/\n$/, '')}
69+
{children}
5070
</CodeBlock>
5171
{!suppressCopy && (
5272
<CopyButton
@@ -58,7 +78,7 @@ const CodeComponent = ({
5878
);
5979
};
6080

61-
const Markdown = ({
81+
export const Markdown = ({
6282
className,
6383
suppressLink,
6484
suppressCopy,
@@ -83,8 +103,26 @@ const Markdown = ({
83103
remarkPlugins={[RemarkGfm, RemarkBreaks, RemarkMath]}
84104
rehypePlugins={[RehypeKatex]}
85105
components={{
86-
code(data): JSX.Element {
87-
return <CodeComponent {...data} suppressCopy={suppressCopy} />;
106+
code(props: any) {
107+
const isInline =
108+
props.node?.position?.start.line === props.node?.position?.end.line;
109+
console.log('Code props:', props, isInline);
110+
111+
if (isInline) {
112+
return <InlineCode>{props.children}</InlineCode>;
113+
}
114+
115+
const match = /language-(\w+)/.exec(props.className || '');
116+
return (
117+
<CodeComponent
118+
inline={false}
119+
className={props.className}
120+
language={match?.[1]}
121+
{...props}
122+
>
123+
{props.children}
124+
</CodeComponent>
125+
);
88126
},
89127
p({ node, children, ...props }) {
90128
// Replace <p> with <div>
@@ -116,5 +154,3 @@ const Markdown = ({
116154
</ReactMarkdown>
117155
);
118156
};
119-
120-
export default Markdown;

frontend/src/components/Tip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect } from 'react';
2-
import Markdown from '@/components/markdown';
2+
import { Markdown } from '@/components/markdown';
33
import { createRoot } from 'react-dom/client';
44
import clsx from 'clsx';
55
import { Icons } from './icons';

frontend/src/components/chat/chat-list.tsx

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export const ChatList = ({ className }: ChatListProps) => {
9292
)}
9393
>
9494
{editingId === chat.id ? (
95-
<div className="flex items-center gap-2 flex-1">
95+
<div className="flex items-center gap-1 flex-1">
9696
<Input
9797
value={editingName}
9898
onChange={(e) => setEditingName(e.target.value)}
@@ -104,7 +104,7 @@ export const ChatList = ({ className }: ChatListProps) => {
104104
setEditingName('');
105105
}
106106
}}
107-
className="h-8"
107+
className="h-8 w-full"
108108
autoFocus
109109
/>
110110
<Button
@@ -117,39 +117,41 @@ export const ChatList = ({ className }: ChatListProps) => {
117117
</Button>
118118
</div>
119119
) : (
120-
<>
121-
<div className="flex-1 justify-start text-sm">
120+
<div className="group relative flex-1 justify-start">
121+
<span className="text-sm line-clamp-1">
122122
{chat.name ||
123123
`Chat with ${chat.from_project || chat.from_template}`}
124+
</span>
125+
<div className="hidden group-hover:flex absolute right-0 top-0 items-center gap-1">
126+
<Button
127+
variant="secondary"
128+
size="icon"
129+
className="w-5 h-5 text-muted-foreground"
130+
onClick={() => {
131+
setEditingId(chat.id);
132+
setEditingName(chat.name || '');
133+
}}
134+
>
135+
{isUpdating ? (
136+
<Icons.spinner className="w-3 h-3 animate-spin" />
137+
) : (
138+
<Icons.edit className="w-3 h-3" />
139+
)}
140+
</Button>
141+
<Button
142+
variant="secondary"
143+
size="icon"
144+
className="w-5 h-5"
145+
onClick={() => handleDeleteChat(chat.id)}
146+
>
147+
{isDeleting ? (
148+
<Icons.spinner className="w-3 h-3 animate-spin text-red-500" />
149+
) : (
150+
<Icons.trash className="w-3 h-3 text-red-500" />
151+
)}
152+
</Button>
124153
</div>
125-
<Button
126-
variant="ghost"
127-
size="icon"
128-
className="opacity-0 group-hover:opacity-100 w-7 h-7"
129-
onClick={() => {
130-
setEditingId(chat.id);
131-
setEditingName(chat.name || '');
132-
}}
133-
>
134-
{isUpdating ? (
135-
<Icons.spinner className="w-4 h-4 animate-spin" />
136-
) : (
137-
<Icons.edit className="w-4 h-4" />
138-
)}
139-
</Button>
140-
<Button
141-
variant="ghost"
142-
size="icon"
143-
className="opacity-0 group-hover:opacity-100 w-7 h-7"
144-
onClick={() => handleDeleteChat(chat.id)}
145-
>
146-
{isDeleting ? (
147-
<Icons.spinner className="w-4 h-4 animate-spin text-red-500" />
148-
) : (
149-
<Icons.trash className="w-4 h-4 text-red-500" />
150-
)}
151-
</Button>
152-
</>
154+
</div>
153155
)}
154156
</Card>
155157
))

frontend/src/components/chat/message-list.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
import { CopyButton } from '../copy-button';
1616
import { Card } from '../ui/card';
1717
import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar';
18+
import { Markdown } from '@/components/markdown';
19+
import { ScrollArea } from '../ui/scroll-area';
1820

1921
interface MessageBubbleProps {
2022
chat: any;
@@ -125,7 +127,7 @@ const MessageBubble = ({ chat, message, onSend }: MessageBubbleProps) => {
125127
}
126128

127129
return (
128-
<Card className={`${messageClass} p-1 w-full mx-auto shadow-sm max-w-4xl`}>
130+
<Card className={`${messageClass} p-1 w-full mx-auto shadow-sm max-w-4xl `}>
129131
<div className="flex items-center gap-2">
130132
<div
131133
className={`w-8 h-8 rounded-full text-sm flex items-center justify-center`}
@@ -139,11 +141,15 @@ const MessageBubble = ({ chat, message, onSend }: MessageBubbleProps) => {
139141
<Icons.code className="w-4 h-4" />
140142
</Button>
141143
</DialogTrigger>
142-
<DialogContent>
143-
<DialogTitle>Raw Message Data</DialogTitle>
144-
<pre className="whitespace-pre-wrap">
145-
<code>{message.content}</code>
146-
</pre>
144+
<DialogContent className="max-w-4xl max-h-[calc(100vh-2rem)] overflow-hidden p-0 gap-0">
145+
<DialogTitle className="text-sm font-semibold px-2 py-3 border-b">
146+
Raw Message Content
147+
</DialogTitle>
148+
<ScrollArea className="max-h-[calc(100vh-var(--header-height))] text-sm bg-muted/20">
149+
<pre className="whitespace-pre-wrap p-2">
150+
<code>{message.content}</code>
151+
</pre>
152+
</ScrollArea>
147153
</DialogContent>
148154
</Dialog>
149155
<CopyButton content={message.content} />
@@ -152,7 +158,7 @@ const MessageBubble = ({ chat, message, onSend }: MessageBubbleProps) => {
152158
className={`relative group rounded-md p-2 text-sm break-word word-wrap overflow-x-hidden`}
153159
>
154160
{message.content ? (
155-
<div className="whitespace-pre-wrap">{message.content}</div>
161+
<Markdown>{message.content}</Markdown>
156162
) : (
157163
<span className="text-lime-600">...</span>
158164
)}

frontend/src/components/flow/message-list.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import React, { useEffect, useRef, useState } from 'react';
44
import clsx from 'clsx';
55
import { Icons } from '@/components/icons';
66
import { useSettings } from '@/hooks';
7-
import Markdown from '@/components/markdown';
7+
import { Markdown } from '@/components/markdown';
88

99
interface Message {
1010
id: string;

frontend/src/components/flow/node/note.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import React, { memo, useEffect, useState } from 'react';
44
import { useReactFlow, NodeProps } from '@xyflow/react';
5-
import Markdown from '@/components/markdown';
5+
import { Markdown } from '@/components/markdown';
66
import { setNodeData } from '@/lib/flow';
77
import { Textarea } from '@/components/ui/textarea';
88

frontend/src/components/project/project-list.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useChats, useProjects } from '@/hooks';
33
import { useRouter } from 'next/navigation';
44
import { toast } from '@/hooks/use-toast';
55
import Link from 'next/link';
6-
import Markdown from '@/components/markdown';
6+
import { Markdown } from '@/components/markdown';
77
import { ProjectPublish } from './project-publish';
88
import { useState } from 'react';
99
import { Icons } from '@/components/icons';

0 commit comments

Comments
 (0)