Skip to content

Commit d4386ee

Browse files
author
ci-bot
committed
reusable markdown component
1 parent 9102942 commit d4386ee

File tree

1 file changed

+130
-127
lines changed
  • libs/remix-ui/remix-ai-assistant/src/components

1 file changed

+130
-127
lines changed

libs/remix-ui/remix-ai-assistant/src/components/chat.tsx

Lines changed: 130 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -115,133 +115,7 @@ export const ChatHistoryComponent: React.FC<ChatHistoryComponentProps> = ({
115115

116116
<div className="aiMarkup lh-base text-wrap">
117117
{msg.role === 'assistant' ? (
118-
<ReactMarkdown
119-
remarkPlugins={[[remarkGfm, { }]]}
120-
remarkRehypeOptions={{
121-
}}
122-
rehypePlugins={[rehypeRaw, rehypeSanitize]}
123-
linkTarget="_blank"
124-
components={{
125-
// Code blocks and inline code
126-
code({ node, inline, className, children, ...props }) {
127-
const text = String(children).replace(/\n$/, '')
128-
const match = /language-(\w+)/.exec(className || '')
129-
const language = match ? match[1] : ''
130-
if (inline) {
131-
return (
132-
<code className="ai-inline-code" {...props}>
133-
{text}
134-
</code>
135-
)
136-
}
137-
return (
138-
<div className="ai-code-block-wrapper">
139-
{language && (
140-
<div className={`ai-code-header ${theme === 'Dark' ? 'text-white' : 'text-dark'}`}>
141-
<span className="ai-code-language">{language}</span>
142-
<button
143-
type="button"
144-
className="btn btn-sm btn-outline-info border border-info"
145-
onClick={() => copy(text)}
146-
title="Copy code"
147-
>
148-
<i className="fa-regular fa-copy"></i>
149-
</button>
150-
</div>
151-
)}
152-
{!language && (
153-
<button
154-
type="button"
155-
className="ai-copy-btn ai-copy-btn-absolute"
156-
onClick={() => copy(text)}
157-
title="Copy code"
158-
>
159-
<i className="fa-regular fa-copy"></i>
160-
</button>
161-
)}
162-
<pre className="ai-code-pre">
163-
<code className={className}>{text}</code>
164-
</pre>
165-
</div>
166-
)
167-
},
168-
// Paragraphs
169-
p: ({ node, ...props }) => (
170-
<p className="ai-paragraph" {...props} />
171-
),
172-
// Headings
173-
h1: ({ node, ...props }) => (
174-
<h1 className="ai-heading ai-h1 fs-5 mb-1" {...props} />
175-
),
176-
h2: ({ node, ...props }) => (
177-
<h2 className="ai-heading ai-h2 fs-5 mb-1" {...props} />
178-
),
179-
h3: ({ node, ...props }) => (
180-
<h3 className="ai-heading ai-h3 fs-5 mb-1" {...props} />
181-
),
182-
h4: ({ node, ...props }) => (
183-
<h4 className="ai-heading ai-h4 fs-6 mb-1" {...props} />
184-
),
185-
h5: ({ node, ...props }) => (
186-
<h5 className="ai-heading ai-h5 fs-6 mb-1" {...props} />
187-
),
188-
h6: ({ node, ...props }) => (
189-
<h6 className="ai-heading ai-h6 fs-6 mb-1" {...props} />
190-
),
191-
// Lists
192-
ul: ({ node, ...props }) => (
193-
<ul className="ai-list ai-list-unordered" {...props} />
194-
),
195-
ol: ({ node, ...props }) => (
196-
<ol className="ai-list ai-list-ordered" {...props} />
197-
),
198-
li: ({ node, ...props }) => (
199-
<li className="ai-list-item" {...props} />
200-
),
201-
// Links
202-
a: ({ node, ...props }) => (
203-
<a className="ai-link" target="_blank" rel="noopener noreferrer" {...props} />
204-
),
205-
// Blockquotes
206-
blockquote: ({ node, ...props }) => (
207-
<blockquote className="ai-blockquote" {...props} />
208-
),
209-
// Tables
210-
table: ({ node, ...props }) => (
211-
<div className="ai-table-wrapper">
212-
<table className="ai-table" {...props} />
213-
</div>
214-
),
215-
thead: ({ node, ...props }) => (
216-
<thead className="ai-table-head" {...props} />
217-
),
218-
tbody: ({ node, ...props }) => (
219-
<tbody className="ai-table-body" {...props} />
220-
),
221-
tr: ({ node, ...props }) => (
222-
<tr className="ai-table-row" {...props} />
223-
),
224-
th: ({ node, ...props }) => (
225-
<th className="ai-table-header-cell" {...props} />
226-
),
227-
td: ({ node, ...props }) => (
228-
<td className="ai-table-cell" {...props} />
229-
),
230-
// Horizontal rule
231-
hr: ({ node, ...props }) => (
232-
<hr className="ai-divider" {...props} />
233-
),
234-
// Strong and emphasis
235-
strong: ({ node, ...props }) => (
236-
<strong className="ai-strong" {...props} />
237-
),
238-
em: ({ node, ...props }) => (
239-
<em className="ai-emphasis" {...props} />
240-
)
241-
}}
242-
>
243-
{normalizeMarkdown(msg.content)}
244-
</ReactMarkdown>
118+
RemixMarkdownViewer(theme, msg.content)
245119
) : (
246120
msg.content
247121
)}
@@ -297,3 +171,132 @@ export const ChatHistoryComponent: React.FC<ChatHistoryComponentProps> = ({
297171
)
298172
}
299173

174+
function RemixMarkdownViewer(theme: string, markDownContent: string): React.ReactNode {
175+
return <ReactMarkdown
176+
remarkPlugins={[[remarkGfm, {}]]}
177+
remarkRehypeOptions={{}}
178+
rehypePlugins={[rehypeRaw, rehypeSanitize]}
179+
linkTarget="_blank"
180+
components={{
181+
// Code blocks and inline code
182+
code({ node, inline, className, children, ...props }) {
183+
const text = String(children).replace(/\n$/, '')
184+
const match = /language-(\w+)/.exec(className || '')
185+
const language = match ? match[1] : ''
186+
if (inline) {
187+
return (
188+
<code className="ai-inline-code" {...props}>
189+
{text}
190+
</code>
191+
)
192+
}
193+
return (
194+
<div className="ai-code-block-wrapper">
195+
{language && (
196+
<div className={`ai-code-header ${theme === 'Dark' ? 'text-white' : 'text-dark'}`}>
197+
<span className="ai-code-language">{language}</span>
198+
<button
199+
type="button"
200+
className="btn btn-sm btn-outline-info border border-info"
201+
onClick={() => copy(text)}
202+
title="Copy code"
203+
>
204+
<i className="fa-regular fa-copy"></i>
205+
</button>
206+
</div>
207+
)}
208+
{!language && (
209+
<button
210+
type="button"
211+
className="ai-copy-btn ai-copy-btn-absolute"
212+
onClick={() => copy(text)}
213+
title="Copy code"
214+
>
215+
<i className="fa-regular fa-copy"></i>
216+
</button>
217+
)}
218+
<pre className="ai-code-pre">
219+
<code className={className}>{text}</code>
220+
</pre>
221+
</div>
222+
)
223+
},
224+
// Paragraphs
225+
p: ({ node, ...props }) => (
226+
<p className="ai-paragraph" {...props} />
227+
),
228+
// Headings
229+
h1: ({ node, ...props }) => (
230+
<h1 className="ai-heading ai-h1 fs-5 mb-1" {...props} />
231+
),
232+
h2: ({ node, ...props }) => (
233+
<h2 className="ai-heading ai-h2 fs-5 mb-1" {...props} />
234+
),
235+
h3: ({ node, ...props }) => (
236+
<h3 className="ai-heading ai-h3 fs-5 mb-1" {...props} />
237+
),
238+
h4: ({ node, ...props }) => (
239+
<h4 className="ai-heading ai-h4 fs-6 mb-1" {...props} />
240+
),
241+
h5: ({ node, ...props }) => (
242+
<h5 className="ai-heading ai-h5 fs-6 mb-1" {...props} />
243+
),
244+
h6: ({ node, ...props }) => (
245+
<h6 className="ai-heading ai-h6 fs-6 mb-1" {...props} />
246+
),
247+
// Lists
248+
ul: ({ node, ...props }) => (
249+
<ul className="ai-list ai-list-unordered" {...props} />
250+
),
251+
ol: ({ node, ...props }) => (
252+
<ol className="ai-list ai-list-ordered" {...props} />
253+
),
254+
li: ({ node, ...props }) => (
255+
<li className="ai-list-item" {...props} />
256+
),
257+
// Links
258+
a: ({ node, ...props }) => (
259+
<a className="ai-link" target="_blank" rel="noopener noreferrer" {...props} />
260+
),
261+
// Blockquotes
262+
blockquote: ({ node, ...props }) => (
263+
<blockquote className="ai-blockquote" {...props} />
264+
),
265+
// Tables
266+
table: ({ node, ...props }) => (
267+
<div className="ai-table-wrapper">
268+
<table className="ai-table" {...props} />
269+
</div>
270+
),
271+
thead: ({ node, ...props }) => (
272+
<thead className="ai-table-head" {...props} />
273+
),
274+
tbody: ({ node, ...props }) => (
275+
<tbody className="ai-table-body" {...props} />
276+
),
277+
tr: ({ node, ...props }) => (
278+
<tr className="ai-table-row" {...props} />
279+
),
280+
th: ({ node, ...props }) => (
281+
<th className="ai-table-header-cell" {...props} />
282+
),
283+
td: ({ node, ...props }) => (
284+
<td className="ai-table-cell" {...props} />
285+
),
286+
// Horizontal rule
287+
hr: ({ node, ...props }) => (
288+
<hr className="ai-divider" {...props} />
289+
),
290+
// Strong and emphasis
291+
strong: ({ node, ...props }) => (
292+
<strong className="ai-strong" {...props} />
293+
),
294+
em: ({ node, ...props }) => (
295+
<em className="ai-emphasis" {...props} />
296+
)
297+
}}
298+
>
299+
{normalizeMarkdown(markDownContent)}
300+
</ReactMarkdown>
301+
}
302+

0 commit comments

Comments
 (0)