feat: render research Markdown and navigate citations to deck posts
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import Markdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
|
||||
export function ResearchMarkdown({
|
||||
text,
|
||||
onNavigateCitation,
|
||||
}: {
|
||||
text: string
|
||||
onNavigateCitation?: (url: string) => boolean
|
||||
}) {
|
||||
return (
|
||||
<div className="research-markdown">
|
||||
<Markdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
skipHtml
|
||||
components={{
|
||||
h1: ({ children }) => <h3>{children}</h3>,
|
||||
h2: ({ children }) => <h4>{children}</h4>,
|
||||
h3: ({ children }) => <h5>{children}</h5>,
|
||||
h4: ({ children }) => <h6>{children}</h6>,
|
||||
h5: ({ children }) => <h6>{children}</h6>,
|
||||
h6: ({ children }) => <h6>{children}</h6>,
|
||||
a: ({ href, children, title }) => (
|
||||
<a
|
||||
href={href}
|
||||
title={title}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={(event) => {
|
||||
if (
|
||||
href &&
|
||||
event.button === 0 &&
|
||||
!event.ctrlKey &&
|
||||
!event.metaKey &&
|
||||
!event.shiftKey &&
|
||||
!event.altKey &&
|
||||
onNavigateCitation?.(href)
|
||||
)
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
img: ({ src, alt }) =>
|
||||
typeof src === 'string' && src ? (
|
||||
<a href={src} target="_blank" rel="noopener noreferrer">
|
||||
{alt || '画像を開く'}
|
||||
</a>
|
||||
) : (
|
||||
<span>{alt || '画像'}</span>
|
||||
),
|
||||
table: ({ children }) => (
|
||||
<section
|
||||
className="research-markdown-table"
|
||||
aria-label="回答の表"
|
||||
// biome-ignore lint/a11y/noNoninteractiveTabindex: Keyboard users need to scroll wide tables inside the narrow chat pane.
|
||||
tabIndex={0}
|
||||
>
|
||||
<table>{children}</table>
|
||||
</section>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</Markdown>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user