"use client"; import { useState, useEffect, useRef } from "react"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { toast } from "sonner"; import { List, ListOrdered, Heading2, Heading3, Code, Quote, ImageIcon, Link as LinkIcon, Table, Maximize2, Minimize2, Type, ChevronDown, Notebook, Component, Youtube as YoutubeIcon, HelpCircle, LayoutGrid, MousePointer2, Rows, LayoutPanelTop, Laptop2, Copy, Download, RotateCcw, Calendar } from "lucide-react"; import { Button as UIButton } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { handleParagraphClick, handleHeading2Click, handleHeading3Click, handleBulletListClick, handleNumberedListClick, handleLinkClick, handleImageClick, handleBlockquoteClick, handleCodeBlockClick, handleTableClick, handleNoteClick, handleComponentClick, handleMetadataClick, } from "@/components/playground/MarkComponent"; import "@/styles/editor.css"; const ToolbarButton = ({ icon: Icon, label, onClick }: { icon: any, label: string, onClick?: () => void }) => ( ); const ToolbarSeparator = () => ( ); const MobileMessage = () => (

Desktop View Recommended

The Playground works best on larger screens. Please switch to a desktop device for the best experience.

); export default function PlaygroundPage() { const [markdown, setMarkdown] = useState(""); const [isFullscreen, setIsFullscreen] = useState(false); const [isMobile, setIsMobile] = useState(false); const [lineCount, setLineCount] = useState(1); const editorRef = useRef(null); const lineNumbersRef = useRef(null); useEffect(() => { const checkMobile = () => { setIsMobile(window.innerWidth < 768); }; checkMobile(); window.addEventListener('resize', checkMobile); return () => { window.removeEventListener('resize', checkMobile); }; }, []); useEffect(() => { // Update line count when markdown content changes const lines = markdown.split('\n').length; setLineCount(Math.max(lines, 1)); }, [markdown]); // Sync scroll position between editor and line numbers useEffect(() => { const textarea = editorRef.current; const lineNumbers = lineNumbersRef.current; if (!textarea || !lineNumbers) return; const handleScroll = () => { lineNumbers.scrollTop = textarea.scrollTop; }; textarea.addEventListener('scroll', handleScroll); return () => textarea.removeEventListener('scroll', handleScroll); }, []); const toggleFullscreen = () => { setIsFullscreen(!isFullscreen); }; const handleCopy = async () => { try { await navigator.clipboard.writeText(markdown); toast.success('Content copied to clipboard'); } catch (err) { toast.error('Failed to copy content'); } }; const handleDownload = () => { try { const blob = new Blob([markdown], { type: 'text/markdown' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'index.mdx'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); toast.success('Content downloaded successfully'); } catch (err) { toast.error('Failed to download content'); } }; const handleReset = () => { if (markdown.trim()) { toast.custom((t) => (

Clear editor content?

This action cannot be undone.

{ setMarkdown(''); toast.success('all content in the editor has been cleaned'); toast.dismiss(t); }} > Clear toast.dismiss(t)} > Cancel
), { duration: 10000 }); } }; const insertAtCursor = (textArea: HTMLTextAreaElement, text: string) => { const start = textArea.selectionStart; const end = textArea.selectionEnd; const before = markdown.substring(0, start); const after = markdown.substring(end); const needsLeadingNewline = before && !before.endsWith('\n\n') ? '\n\n' : ''; const needsTrailingNewline = after && !after.startsWith('\n\n') ? '\n\n' : ''; const newText = `${before}${needsLeadingNewline}${text}${needsTrailingNewline}${after}`; setMarkdown(newText); requestAnimationFrame(() => { textArea.focus(); const newPosition = before.length + needsLeadingNewline.length + text.length + 1; textArea.setSelectionRange(newPosition, newPosition); }); }; if (isMobile) { return ; } return (

DocuPLAY

Test and experiment with DocuBook markdown components in real-time

{markdown.trim() && ( <> Copy Download Reset )}
{isFullscreen ? ( <> Exit Fullscreen ) : ( <> Fullscreen )}
handleMetadataClick(insertAtCursor)} /> handleParagraphClick(insertAtCursor)} /> handleHeading2Click(insertAtCursor)} /> handleHeading3Click(insertAtCursor)} /> handleBulletListClick(insertAtCursor)} /> handleNumberedListClick(insertAtCursor)} /> handleLinkClick(insertAtCursor)} /> handleImageClick(insertAtCursor)} /> handleBlockquoteClick(insertAtCursor)} /> handleCodeBlockClick(insertAtCursor)} /> handleTableClick(insertAtCursor)} /> Note Danger Warning Success Stepper Card Button Accordion Tabs Youtube Tooltip
{Array.from({ length: lineCount }).map((_, i) => (
))}