|
| 1 | +'use client'; |
| 2 | + |
| 3 | +import { CodeBlock } from '@/components/code-block'; |
| 4 | +import { |
| 5 | + Accordion, |
| 6 | + AccordionContent, |
| 7 | + AccordionItem, |
| 8 | + AccordionTrigger, |
| 9 | +} from '@/components/ui/accordion'; |
| 10 | + |
| 11 | +const faqs = [ |
| 12 | + { |
| 13 | + id: 'streamdown-difference', |
| 14 | + question: 'What makes Streamdown different from react-markdown?', |
| 15 | + answer: |
| 16 | + "Streamdown is specifically designed for AI-powered streaming applications. It includes built-in support for incomplete markdown parsing, which means it can render markdown even while it's being generated by AI models. It also includes security features like URL prefix restrictions and better performance optimizations for streaming contexts.", |
| 17 | + }, |
| 18 | + { |
| 19 | + id: 'custom-components', |
| 20 | + question: 'Can I use custom components with Streamdown?', |
| 21 | + answer: |
| 22 | + 'Yes! Streamdown fully supports custom components through the `components` prop, just like react-markdown. You can override any markdown element with your own React components to customize the rendering.', |
| 23 | + }, |
| 24 | + { |
| 25 | + id: 'incomplete-parsing', |
| 26 | + question: 'How does the incomplete markdown parsing work?', |
| 27 | + answer: |
| 28 | + 'When `parseIncompleteMarkdown` is enabled (default), Streamdown automatically detects and fixes common issues in incomplete markdown like unclosed code blocks, incomplete lists, and partial formatting. This ensures smooth rendering even as markdown is being streamed from AI models.', |
| 29 | + }, |
| 30 | + { |
| 31 | + id: 'plugin-compatibility', |
| 32 | + question: 'Is Streamdown compatible with all react-markdown plugins?', |
| 33 | + answer: |
| 34 | + 'Streamdown supports both remark and rehype plugins, making it compatible with most react-markdown plugins. It includes popular plugins like remarkGfm, remarkMath, and rehypeKatex by default, and you can add your own through the `remarkPlugins` and `rehypePlugins` props.', |
| 35 | + }, |
| 36 | + { |
| 37 | + id: 'shiki-warning', |
| 38 | + question: ( |
| 39 | + <span> |
| 40 | + Why do I get a{' '} |
| 41 | + <code className="rounded-md bg-foreground/5 px-2 py-1 font-mono text-sm tracking-tight"> |
| 42 | + Package shiki can't be external |
| 43 | + </code>{' '} |
| 44 | + warning? |
| 45 | + </span> |
| 46 | + ), |
| 47 | + answer: ( |
| 48 | + <div> |
| 49 | + <p> |
| 50 | + This warning occurs when Next.js tries to treat Shiki as an external |
| 51 | + package. To fix this, you need to install Shiki explicitly with{' '} |
| 52 | + <code className="rounded-md bg-foreground/5 px-2 py-1 font-mono text-sm tracking-tight"> |
| 53 | + npm install shiki |
| 54 | + </code>{' '} |
| 55 | + and add it to your{' '} |
| 56 | + <code className="rounded-md bg-foreground/5 px-2 py-1 font-mono text-sm tracking-tight"> |
| 57 | + transpilePackages |
| 58 | + </code>{' '} |
| 59 | + array in your{' '} |
| 60 | + <code className="rounded-md bg-foreground/5 px-2 py-1 font-mono text-sm tracking-tight"> |
| 61 | + next.config.ts |
| 62 | + </code> |
| 63 | + : |
| 64 | + </p> |
| 65 | + <div className="my-2"> |
| 66 | + <CodeBlock |
| 67 | + className="my-4 rounded-md border p-4" |
| 68 | + code={`{ |
| 69 | + // ... other config |
| 70 | + transpilePackages: ["shiki"], |
| 71 | +}`} |
| 72 | + language="tsx" |
| 73 | + /> |
| 74 | + </div> |
| 75 | + <p>This ensures Shiki is properly bundled with your application.</p> |
| 76 | + </div> |
| 77 | + ), |
| 78 | + }, |
| 79 | + { |
| 80 | + id: 'tailwind-config', |
| 81 | + question: 'How do I configure Tailwind CSS to work with Streamdown?', |
| 82 | + answer: ( |
| 83 | + <> |
| 84 | + <div> |
| 85 | + <p> |
| 86 | + For <span className="font-medium">Tailwind v4</span>, add a{' '} |
| 87 | + <code className="rounded-md bg-foreground/5 px-2 py-1 font-mono text-sm tracking-tight"> |
| 88 | + @source |
| 89 | + </code>{' '} |
| 90 | + directive to your{' '} |
| 91 | + <code className="rounded-md bg-foreground/5 px-2 py-1 font-mono text-sm tracking-tight"> |
| 92 | + globals.css |
| 93 | + </code>{' '} |
| 94 | + file with the path to Streamdown's distribution files: |
| 95 | + </p> |
| 96 | + <div className="my-2"> |
| 97 | + <CodeBlock |
| 98 | + className="my-4 rounded-md border p-4" |
| 99 | + code={`@source "../node_modules/streamdown/dist/index.js";`} |
| 100 | + language="css" |
| 101 | + /> |
| 102 | + </div> |
| 103 | + </div> |
| 104 | + <div> |
| 105 | + <p> |
| 106 | + For <span className="font-medium">Tailwind v3</span>, add Streamdown |
| 107 | + to your{' '} |
| 108 | + <code className="rounded-md bg-foreground/5 px-2 py-1 font-mono text-sm tracking-tight"> |
| 109 | + content |
| 110 | + </code>{' '} |
| 111 | + array in{' '} |
| 112 | + <code className="rounded-md bg-foreground/5 px-2 py-1 font-mono text-sm tracking-tight"> |
| 113 | + tailwind.config.js |
| 114 | + </code> |
| 115 | + : |
| 116 | + </p> |
| 117 | + <div className="my-2"> |
| 118 | + <CodeBlock |
| 119 | + className="my-4 rounded-md border p-4" |
| 120 | + code={`content: [ |
| 121 | + // ... your other content paths |
| 122 | + "./node_modules/streamdown/dist/**/*.js", |
| 123 | +]`} |
| 124 | + language="js" |
| 125 | + /> |
| 126 | + </div> |
| 127 | + </div> |
| 128 | + <p> |
| 129 | + Adjust the paths based on your project structure. This ensures |
| 130 | + Tailwind scans Streamdown's files for any utility classes used in the |
| 131 | + component. |
| 132 | + </p> |
| 133 | + </> |
| 134 | + ), |
| 135 | + }, |
| 136 | +]; |
| 137 | + |
| 138 | +export const FAQ = () => ( |
| 139 | + <div className="divide-y sm:grid sm:grid-cols-3 sm:divide-x sm:divide-y-0"> |
| 140 | + <div className="space-y-2 p-4 sm:p-8"> |
| 141 | + <h2 className="font-semibold text-2xl tracking-tight">FAQ</h2> |
| 142 | + <p className="text-muted-foreground"> |
| 143 | + Common questions about Streamdown and how it works with AI-powered |
| 144 | + streaming applications. |
| 145 | + </p> |
| 146 | + </div> |
| 147 | + <div className="sm:col-span-2"> |
| 148 | + <Accordion className="w-full" collapsible type="single"> |
| 149 | + {faqs.map((faq) => ( |
| 150 | + <AccordionItem key={faq.id} value={faq.id}> |
| 151 | + <AccordionTrigger className="p-4 text-left text-base sm:p-8"> |
| 152 | + {faq.question} |
| 153 | + </AccordionTrigger> |
| 154 | + <AccordionContent className="p-4 pt-0 text-base leading-relaxed sm:p-8 sm:pt-0"> |
| 155 | + {faq.answer} |
| 156 | + </AccordionContent> |
| 157 | + </AccordionItem> |
| 158 | + ))} |
| 159 | + </Accordion> |
| 160 | + </div> |
| 161 | + </div> |
| 162 | +); |
0 commit comments