feat(ST-1114): add shared Markdown wrapper, apply to task-detail and story-dialog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-30 00:36:08 +02:00
parent 73c27ac43e
commit 353f21d69a
3 changed files with 25 additions and 11 deletions

View file

@ -1,6 +1,7 @@
'use client' 'use client'
import { useEffect, useRef, useState, useTransition } from 'react' import { useEffect, useRef, useState, useTransition } from 'react'
import { Markdown } from '@/components/markdown'
import { useActionState } from 'react' import { useActionState } from 'react'
import { useFormStatus } from 'react-dom' import { useFormStatus } from 'react-dom'
import { toast } from 'sonner' import { toast } from 'sonner'
@ -231,7 +232,7 @@ export function StoryDialog({ state, onClose, isDemo = false }: StoryDialogProps
{story?.description && ( {story?.description && (
<div> <div>
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wide mb-1">Omschrijving</p> <p className="text-xs font-medium text-muted-foreground uppercase tracking-wide mb-1">Omschrijving</p>
<p className="text-sm">{story.description}</p> <Markdown>{story.description}</Markdown>
</div> </div>
)} )}
{story?.acceptance_criteria && ( {story?.acceptance_criteria && (

21
components/markdown.tsx Normal file
View file

@ -0,0 +1,21 @@
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import { cn } from '@/lib/utils'
interface MarkdownProps {
children: string
className?: string
}
export function Markdown({ children, className }: MarkdownProps) {
return (
<div className={cn('prose prose-sm dark:prose-invert max-w-none', className)}>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
disallowedElements={['script', 'iframe']}
>
{children}
</ReactMarkdown>
</div>
)
}

View file

@ -3,8 +3,7 @@
import { useRef, useState, useTransition } from 'react' import { useRef, useState, useTransition } from 'react'
import Link from 'next/link' import Link from 'next/link'
import { toast } from 'sonner' import { toast } from 'sonner'
import ReactMarkdown from 'react-markdown' import { Markdown } from '@/components/markdown'
import remarkGfm from 'remark-gfm'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
@ -134,14 +133,7 @@ function TaskDetailContent({ task, productId, isDemo, onClose }: TaskDetailConte
{task.description && ( {task.description && (
<div> <div>
<p className="text-xs font-medium text-muted-foreground mb-1.5">Beschrijving</p> <p className="text-xs font-medium text-muted-foreground mb-1.5">Beschrijving</p>
<div className="prose prose-sm dark:prose-invert max-w-none text-foreground"> <Markdown className="text-foreground">{task.description}</Markdown>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
disallowedElements={['script', 'iframe']}
>
{task.description}
</ReactMarkdown>
</div>
</div> </div>
)} )}