"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) => (
))}
);
}