"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 } from "lucide-react"; import { Button as UIButton } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator, } from "@/components/ui/dropdown-menu"; 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 newText = before + text + after; setMarkdown(newText); requestAnimationFrame(() => { textArea.focus(); const newPosition = start + text.length; textArea.setSelectionRange(newPosition, newPosition); }); }; const handleParagraphClick = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, 'this is regular text, **bold text**, *italic text*\n'); } }; const handleHeading2Click = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, '## Heading 2\n'); } }; const handleHeading3Click = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, '### Heading 3\n'); } }; const handleBulletListClick = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, '- List One\n- List Two\n- Other List\n'); } }; const handleNumberedListClick = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, '1. Number One\n2. Number Two\n3. Number Three\n'); } }; const handleLinkClick = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, '[Visit OpenAI](https://www.openai.com)\n'); } }; const handleImageClick = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, '![Alt text for the image](https://via.placeholder.com/150)\n'); } }; const handleBlockquoteClick = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, '> The overriding design goal for Markdown\'s formatting syntax is to make it as readable as possible.\n'); } }; const handleCodeBlockClick = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, '```javascript:main.js showLineNumbers {3-4}\nfunction isRocketAboutToCrash() {\n // Check if the rocket is stable\n if (!isStable()) {\n NoCrash(); // Prevent the crash\n }\n}\n```\n'); } }; const handleTableClick = () => { const textArea = document.querySelector('textarea'); if (textArea) { insertAtCursor(textArea, `| **Feature** | **Description** | | ------------------------------- | ----------------------------------------------------- | | MDX Support | Write interactive documentation with MDX. | | Nested Pages | Organize content in a nested, hierarchical structure. | | Blog Section | Include a dedicated blog section. | | Pagination | Split content across multiple pages. | `); } }; const handleNoteClick = (type: string) => { const textArea = document.querySelector('textarea'); if (textArea) { const noteTemplate = `\n This is a ${type} message.\n\n`; insertAtCursor(textArea, noteTemplate); } }; const handleComponentClick = (component: string) => { const textArea = document.querySelector('textarea'); if (!textArea) return; const templates: { [key: string]: string } = { stepper: ` Content for step 1 Content for step 2 \n`, card: ` This is how you use a card with an icon and a link. Clicking on this card brings you to the Card Group page. \n`, button: `