sifa-classification-agentic-rag
/
src
/components
/ui
/typography
/MarkdownRenderer
/inlineStyles.tsx
'use client' | |
import { useState } from 'react' | |
import Image from 'next/image' | |
import Link from 'next/link' | |
import { cn } from '@/lib/utils' | |
import type { | |
UnorderedListProps, | |
OrderedListProps, | |
EmphasizedTextProps, | |
ItalicTextProps, | |
StrongTextProps, | |
BoldTextProps, | |
DeletedTextProps, | |
UnderlinedTextProps, | |
HorizontalRuleProps, | |
BlockquoteProps, | |
AnchorLinkProps, | |
HeadingProps, | |
ImgProps, | |
ParagraphProps | |
} from './types' | |
import { PARAGRAPH_SIZES } from '../Paragraph/constants' | |
const filterProps = (props: object) => { | |
const newProps = { ...props } | |
if ('node' in newProps) { | |
delete newProps.node | |
} | |
return newProps | |
} | |
const UnorderedList = ({ className, ...props }: UnorderedListProps) => ( | |
<ul | |
className={cn( | |
className, | |
PARAGRAPH_SIZES.lead, | |
'flex list-disc flex-col pl-10' | |
)} | |
{...filterProps(props)} | |
/> | |
) | |
const OrderedList = ({ className, ...props }: OrderedListProps) => ( | |
<ol | |
className={cn( | |
className, | |
PARAGRAPH_SIZES.lead, | |
'flex list-decimal flex-col pl-10' | |
)} | |
{...filterProps(props)} | |
/> | |
) | |
const Paragraph = ({ className, ...props }: ParagraphProps) => ( | |
<p className={cn(className, PARAGRAPH_SIZES.lead)} {...filterProps(props)} /> | |
) | |
const EmphasizedText = ({ className, ...props }: EmphasizedTextProps) => ( | |
<em | |
className={cn(className, 'PARAGRAPH_SIZES.lead')} | |
{...filterProps(props)} | |
/> | |
) | |
const ItalicText = ({ className, ...props }: ItalicTextProps) => ( | |
<i className={cn(className, PARAGRAPH_SIZES.lead)} {...filterProps(props)} /> | |
) | |
const StrongText = ({ className, ...props }: StrongTextProps) => ( | |
<strong | |
className={cn(className, 'PARAGRAPH_SIZES.lead')} | |
{...filterProps(props)} | |
/> | |
) | |
const BoldText = ({ className, ...props }: BoldTextProps) => ( | |
<b | |
className={cn(className, 'PARAGRAPH_SIZES.lead')} | |
{...filterProps(props)} | |
/> | |
) | |
const UnderlinedText = ({ className, ...props }: UnderlinedTextProps) => ( | |
<u | |
className={cn(className, 'underline', PARAGRAPH_SIZES.lead)} | |
{...filterProps(props)} | |
/> | |
) | |
const DeletedText = ({ className, ...props }: DeletedTextProps) => ( | |
<del | |
className={cn(className, 'text-muted line-through', PARAGRAPH_SIZES.lead)} | |
{...filterProps(props)} | |
/> | |
) | |
const HorizontalRule = ({ className, ...props }: HorizontalRuleProps) => ( | |
<hr | |
className={cn(className, 'mx-auto w-48 border-b border-border')} | |
{...filterProps(props)} | |
/> | |
) | |
const Blockquote = ({ className, ...props }: BlockquoteProps) => ( | |
<blockquote | |
className={cn(className, PARAGRAPH_SIZES.lead)} | |
{...filterProps(props)} | |
/> | |
) | |
const AnchorLink = ({ className, ...props }: AnchorLinkProps) => ( | |
<a | |
className={cn(className, 'cursor-pointer text-xs underline')} | |
target="_blank" | |
rel="noopener noreferrer" | |
{...filterProps(props)} | |
/> | |
) | |
const Heading1 = ({ className, ...props }: HeadingProps) => ( | |
<h1 className={cn(className, PARAGRAPH_SIZES.lead)} {...filterProps(props)} /> | |
) | |
const Heading2 = ({ className, ...props }: HeadingProps) => ( | |
<h2 className={cn(className, PARAGRAPH_SIZES.lead)} {...filterProps(props)} /> | |
) | |
const Heading3 = ({ className, ...props }: HeadingProps) => ( | |
<h3 className={cn(className, PARAGRAPH_SIZES.lead)} {...filterProps(props)} /> | |
) | |
const Heading4 = ({ className, ...props }: HeadingProps) => ( | |
<h4 className={cn(className, PARAGRAPH_SIZES.lead)} {...filterProps(props)} /> | |
) | |
const Heading5 = ({ className, ...props }: HeadingProps) => ( | |
<h5 className={cn(className, PARAGRAPH_SIZES.lead)} {...filterProps(props)} /> | |
) | |
const Heading6 = ({ className, ...props }: HeadingProps) => ( | |
<h6 className={cn(className, PARAGRAPH_SIZES.lead)} {...filterProps(props)} /> | |
) | |
const Img = ({ src, alt }: ImgProps) => { | |
const [error, setError] = useState(false) | |
if (!src) return null | |
return ( | |
<div className="w-full max-w-xl"> | |
{error ? ( | |
<div className="flex h-40 flex-col items-center justify-center gap-2 rounded-md bg-secondary/50 text-muted"> | |
<Paragraph className="text-primary">Image unavailable</Paragraph> | |
<Link | |
href={typeof src === 'string' ? src : '#'} | |
target="_blank" | |
className="max-w-md truncate underline" | |
> | |
{typeof src === 'string' ? src : 'Invalid source'} | |
</Link> | |
</div> | |
) : ( | |
<Image | |
src={typeof src === 'string' ? src : ''} | |
width={96} | |
height={56} | |
alt={alt ?? 'Rendered image'} | |
className="size-full rounded-md object-cover" | |
onError={() => setError(true)} | |
unoptimized | |
/> | |
)} | |
</div> | |
) | |
} | |
export const inlineComponents = { | |
h1: Heading1, | |
h2: Heading2, | |
h3: Heading3, | |
h4: Heading4, | |
h5: Heading5, | |
h6: Heading6, | |
ul: UnorderedList, | |
ol: OrderedList, | |
em: EmphasizedText, | |
i: ItalicText, | |
strong: StrongText, | |
b: BoldText, | |
u: UnderlinedText, | |
del: DeletedText, | |
hr: HorizontalRule, | |
blockquote: Blockquote, | |
a: AnchorLink, | |
img: Img, | |
p: Paragraph | |
} | |