import type { Meta, StoryObj } from '@storybook/react'; import { MarkdownMessage } from './MarkdownMessage'; const meta: Meta = { title: 'Assistant/MarkdownMessage', component: MarkdownMessage, }; export default meta; type Story = StoryObj; export const Default: Story = { args: { content: ` # Markdown Message Example This component renders **Markdown** content sent by the AI assistant. - It supports **bold** and *italic* text. - It supports [links](https://xertica.com). - It supports code blocks: \`\`\`javascript function hello() { console.log("Hello, Xertica!"); } \`\`\` > "The advance of technology is based on making it fit in so that you don't even notice it, so it's part of everyday life." - Bill Gates `.trim(), }, }; export const Short: Story = { args: { content: '**Short message** with some `inline code`.', }, }; export const Table: Story = { args: { content: ` | Project | Status | Health | |---|---|---| | Analytics V2 | Active | ✅ Healthy | | CRM Refactor | On Hold | ⚠️ Warning | | Mobile App | Completed | 🏆 Done | `.trim(), }, }; /** * Bold, italic, strikethrough, and inline code, combined the way a real * assistant reply tends to mix them mid-sentence. */ export const TextEmphasis: Story = { args: { content: 'Este é um exemplo com **texto em negrito**, *texto em itálico*, ~~um trecho riscado~~ e `codigo_inline()` no meio da frase.', }, }; /** * GFM allows `-`, `*`, or `•` as a bullet marker — the assistant's own * backend (Gemini via FDM) reliably picks `*`. Regression coverage for a * real bug: `*` is also the italic delimiter, so a naive parser either * leaves the leading `*` as literal text, or worse, pairs it with a `*` * later in the list (or with real `*italic*` on the same line) and * corrupts both. */ export const AsteriskBulletList: Story = { args: { content: ` **Principais características:** * **Abrangência**: Cobre desde primitivas de UI até temas de marca. * **Requisitos**: Node.js >= 18, React >= 18. * Item com *itálico de verdade* no meio da frase. `.trim(), }, }; /** * h1–h4. Anything deeper (h5/h6) is not supported — assistant replies don't * realistically nest that deep. */ export const Headings: Story = { args: { content: ` # Heading 1 ## Heading 2 ### Heading 3 #### Heading 4 Texto normal abaixo do heading. `.trim(), }, }; /** * A fenced code block with a language annotation, rendered via `CodeBlock` * (syntax highlighting + copy button) — not a corrupted inline \`\`. * This is the exact shape the FDM assistant sends (fence + language, e.g. * ` ```python `). */ export const FencedCodeBlock: Story = { args: { content: ` Aqui está um exemplo de função em Python: \`\`\`python def hello_world(): print("Olá, mundo!") hello_world() \`\`\` `.trim(), }, }; /** * Code fences protect their contents from the surrounding markdown regexes — * without this, characters like \`**\` or \`_\` inside real code (exponents, * dunder methods, docstrings) would get misread as bold/italic markers. */ export const CodeBlockWithSpecialCharacters: Story = { args: { content: ` \`\`\`python class Model: def __init__(self, x): self.x = x ** 2 # not bold, not italic self._private = None \`\`\` `.trim(), }, }; /** * A fenced block with no language annotation still renders as a real code * block (no highlighting, but no corruption either) instead of breaking. */ export const CodeBlockWithoutLanguage: Story = { args: { content: '```\nplain text inside a fence, no language hint\n```', }, }; export const Blockquote: Story = { args: { content: '> Este é um exemplo de uma citação em bloco. Ela é usada para destacar um trecho de texto.', }, }; export const MultiLineBlockquote: Story = { args: { content: '> Primeira linha da citação.\n> Segunda linha, ainda na mesma citação.', }, }; /** * A realistic full assistant reply mixing several formatting types at once — * heading, prose with emphasis, a numbered list immediately after a * colon-ended line (no blank line before the list, the way the model * actually writes it), and a closing table. Modeled directly on real * responses captured from the FDM assistant, not a hypothetical example. */ export const RealisticAssistantResponse: Story = { args: { content: ` ## Resumo da Análise Aqui está um parágrafo com as formatações solicitadas: **pontos principais em negrito** e *observações em itálico*. É importante organizar as informações para: 1. Destacar informações cruciais. 2. Melhorar a legibilidade do conteúdo. 3. Organizar ideias de maneira clara. > Nota: os valores abaixo são estimativas com base nos dados disponíveis. | Produto | Quantidade Vendida | Preço Unitário | |---|---|---| | Camiseta | 150 | R$ 35,00 | | Calça Jeans | 80 | R$ 90,00 | | Tênis | 120 | R$ 120,00 | `.trim(), }, };