Markdown Content
simple-ai/markdown-contentFreeComponent
A component that renders markdown content.
Live preview
live · rendered by the registry
Rendered by simple-ai on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://simple-ai.dev/r/markdown-content.jsonSource
1import { marked } from "marked";2import type * as React from "react";3import { isValidElement, memo, Suspense, useMemo } from "react";4import ReactMarkdown, { type Components } from "react-markdown";5import rehypeRaw from "rehype-raw";6import remarkGfm from "remark-gfm";7import { cn } from "@/lib/utils";89const DEFAULT_PRE_BLOCK_CLASS =10 "my-4 overflow-x-auto w-fit rounded-xl bg-zinc-950 text-zinc-50 dark:bg-zinc-900 border border-border p-4";1112const extractTextContent = (node: React.ReactNode): string => {13 if (typeof node === "string") {14 return node;15 }16 if (Array.isArray(node)) {17 return node.map(extractTextContent).join("");18 }19 if (isValidElement(node)) {20 // @ts-expect-error21 return extractTextContent(node.props.children);22 }23 return "";24};2526interface HighlightedPreProps extends React.HTMLAttributes<HTMLPreElement> {27 language: string;28}2930const HighlightedPre = memo(31 async ({32 children,33 className,34 language,35 ...props36 }: HighlightedPreProps) => {37 const { codeToTokens, bundledLanguages } = await import("shiki");38 const code = extractTextContent(children);3940 if (!(language in bundledLanguages)) {41 return (42 <pre43 {...props}44 className={cn(DEFAULT_PRE_BLOCK_CLASS, className)}45 >46 <code className="whitespace-pre-wrap">{children}</code>47 </pre>48 );49 }5051 const { tokens } = await codeToTokens(code, {52 lang: language as keyof typeof bundledLanguages,53 themes: {54 light: "github-dark",55 dark: "github-dark",56 },57 });5859 return (60 <pre {...props} className={cn(DEFAULT_PRE_BLOCK_CLASS, className)}>61 <code className="whitespace-pre-wrap break-all">62 {tokens.map((line, lineIndex) => (63 <span64 key={`line-${65 // biome-ignore lint/suspicious/noArrayIndexKey: Needed for react key66 lineIndex67 }`}68 >69 {line.map((token, tokenIndex) => {70 const style =71 typeof token.htmlStyle === "string"72 ? undefined73 : token.htmlStyle;7475 return (76 <span77 key={`token-${78 // biome-ignore lint/suspicious/noArrayIndexKey: Needed for react key79 tokenIndex80 }`}81 style={style}82 >83 {token.content}84 </span>85 );86 })}87 {lineIndex !== tokens.length - 1 && "\n"}88 </span>89 ))}90 </code>91 </pre>92 );93 },94);9596HighlightedPre.displayName = "HighlightedPre";9798interface CodeBlockProps extends React.HTMLAttributes<HTMLPreElement> {99 language: string;100}101102// … truncated
What it pulls in
npm packages
Files it writes
More from simple-ai
All 77 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| base-handlebase-handle | simple-ai | Components | Free | 1 dep | |
| base-nodebase-node | simple-ai | Components | Free | no deps | |
| Chat Inputchat-input | simple-ai | Components | Free | 7 deps | |
| Chat Messagechat-message | simple-ai | Components | Free | no deps | |
| Chat Message Areachat-message-area | simple-ai | Components | Free | 1 dep | |
| Chat Suggestionschat-suggestions | simple-ai | Components | Free | no deps | |
| Editable Handleeditable-handle | simple-ai | Components | Free | 1 dep | |
| Generate Text Nodegenerate-text-node | simple-ai | Components | Free | 1 dep |
