import { useEffect, useState } from 'react'; import MDEditor from '@uiw/react-md-editor'; import { useTheme } from '@/components/theme/ThemeProvider'; import { useAutoSave } from '@/hooks/useAutoSave'; import { CheckCircle2, Loader2, AlertCircle } from 'lucide-react'; import { cn } from '@/lib/utils'; import rehypeSanitize from 'rehype-sanitize'; interface MarkdownEditorProps { value: string; onChange: (value: string) => void; onSave?: (value: string) => Promise; autoSave?: boolean; height?: number; placeholder?: string; } export function MarkdownEditor({ value, onChange, onSave, autoSave = false, height = 600, placeholder = 'Write your content in markdown...' }: MarkdownEditorProps) { const { theme } = useTheme(); const [mounted, setMounted] = useState(false); // Auto-save integration const { isSaving, lastSaved, error } = useAutoSave({ data: value, onSave: onSave || (async () => {}), debounceMs: 3000, enabled: autoSave && !!onSave, isValid: value.length > 0 }); useEffect(() => { setMounted(true); }, []); // Prevent hydration mismatch if (!mounted) { return (
); } const getLastSavedText = () => { if (!lastSaved) return null; const seconds = Math.floor((Date.now() - lastSaved.getTime()) / 1000); if (seconds < 60) return `Saved ${seconds}s ago`; const minutes = Math.floor(seconds / 60); return `Saved ${minutes}m ago`; }; return (
onChange(val || '')} height={height} preview="live" hideToolbar={false} enableScroll={true} textareaProps={{ placeholder }} previewOptions={{ rehypePlugins: [[rehypeSanitize]], className: 'prose dark:prose-invert max-w-none p-4' }} />
{/* Auto-save status indicator */} {autoSave && onSave && (
{isSaving && ( <> Saving... )} {!isSaving && lastSaved && !error && ( <> {getLastSavedText()} )} {error && ( <> Failed to save: {error} )}
)} {/* Word and character count */}
Supports markdown formatting with live preview {value.split(/\s+/).filter(Boolean).length} words ยท {value.length} characters
); }