import { FC, useEffect, useState } from "react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import rehypeHighlight from "rehype-highlight"; import rehypeRaw from "rehype-raw"; import rehypeSanitize from "rehype-sanitize"; import axios from "../../axios"; import "highlight.js/styles/github-dark.css"; import Header from "../mission/statement/Header"; import { defaultSchema } from "hast-util-sanitize"; const schema = { ...defaultSchema, attributes: { ...defaultSchema.attributes, div: [ ...(defaultSchema.attributes?.div || []), ["style"] // разрешаем атрибут style на div ] } }; interface MarkdownEditorProps { defaultValue?: string; onChange: (value: string) => void; } const MarkdownEditor: FC = ({ defaultValue, onChange }) => { const [markdown, setMarkdown] = useState(defaultValue || `# 🌙 Добро пожаловать в Markdown-редактор Добро пожаловать в **Markdown-редактор**! Здесь ты можешь писать в формате Markdown и видеть результат **в реальном времени** 👇 --- ## 🧱 1. Форматирование текста Вот примеры базового форматирования: - **Жирный текст** - *Курсивный текст* - ***Жирный курсив*** - ~~Зачёркнутый~~ > 💬 _Цитаты_ можно использовать для выделения текста, заметок или описаний. --- ## 🧩 2. Списки ### 🔹 Маркированный список - Один - Два - Вложенный уровень - Ещё глубже - Три ### 🔸 Нумерованный список 1. Первый 2. Второй 3. Третий 1. Вложенный 2. Ещё один --- ## ✅ 3. Чеклисты (GFM) - [x] Поддержка Markdown - [x] Подсветка кода - [x] Таблицы - [x] Эмодзи 😎 - [ ] Экспорт в PDF (в будущем) --- ## 💻 4. Код и подсветка Пример **TypeScript**: \`\`\`tsx type User = { name: string; role: "Разработчик" | "Помощник"; }; function greet(user: User) { return \`Привет, \${user.name}! 👋 Роль: \${user.role}\`; } console.log(greet({ name: "Ты", role: "Разработчик" })); \`\`\` Пример **JavaScript**: \`\`\`js const sum = (a, b) => a + b; console.log(sum(2, 3)); // 5 \`\`\` Пример **Python**: \`\`\`python def greet(name): return f"Привет, {name}! 👋" print(greet("Мир")) \`\`\` --- ## 📊 5. Таблицы (GFM) | Имя | Роль | Активен | Эмодзи | |-------------|----------------|----------|--------| | ChatGPT | Помощник 🤖 | ✅ | 🤓 | | Ты | Разработчик 💻 | ✅ | 🚀 | | TailwindCSS | Стилизация 🎨 | 🟢 | 💅 | > Таблицы поддерживают **жирный текст**, _курсив_ и даже \`инлайн-код\` внутри ячеек. --- ## 🔗 6. Ссылки - [Документация Markdown](https://www.markdownguide.org/) - [React Markdown на GitHub](https://github.com/remarkjs/react-markdown) - Автоматическая ссылка: https://github.com --- ## 🖼️ 7. Изображения ### Markdown-логотип: ![Markdown Logo](https://upload.wikimedia.org/wikipedia/commons/4/48/Markdown-mark.svg) или \"img\"/ или если нужно выравнивание по центру
\"img\"/
--- ## 🧠 8. Цитаты и вложенность > 💭 Это обычная цитата. > > > А это — **вложенная цитата**. > > > > > Можно вкладывать сколько угодно уровней! --- ## ⚙️ 9. Горизонтальные линии --- *** --- ## 🧮 10. Таблица внутри цитаты > Вот таблица прямо внутри блока цитаты: > > | Язык | Назначение | > |-------|-------------| > | JS | Web-разработка | > | TS | Строгая типизация | > | PY | Скрипты и AI | --- ## 🧩 11. Встроенный HTML
📂 Раскрывающийся блок Этот текст виден только после раскрытия!
  • HTML списки работают
  • И даже жирный текст
--- ## 🎨 12. Вложенные списки с кодом - Этапы: 1. Создай проект 2. Добавь зависимости: \`\`\`bash npm install react-markdown remark-gfm rehype-highlight highlight.js \`\`\` 3. Импортируй стили: \`\`\`tsx import "highlight.js/styles/github-dark.css"; \`\`\` 4. Готово! --- ## 🚀 13. Финал Поздравляю! 🎉 Ты только что увидел все ключевые возможности **Markdown + GFM** в действии. > ✨ Используй этот текст как шаблон для тестирования рендерера. > 💡 Совет: попробуй поменять тему \`highlight.js\` (например \`monokai.css\` или \`atom-one-dark.css\`). --- **🖤 Конец демонстрации. Спасибо, что используешь Markdown-редактор!** `); useEffect(() => { onChange(markdown); }, [markdown]); // Обработчик вставки const handlePaste = async (e: React.ClipboardEvent) => { const items = e.clipboardData.items; for (const item of items) { if (item.type.startsWith("image/")) { e.preventDefault(); // предотвращаем вставку картинки как текста const file = item.getAsFile(); if (!file) return; const formData = new FormData(); formData.append("file", file); try { const response = await axios.post("/media/upload", formData, { headers: { "Content-Type": "multipart/form-data" }, }); const imageUrl = response.data.url; // Вставляем ссылку на картинку в текст const cursorPos = (e.target as HTMLTextAreaElement).selectionStart; const newText = markdown.slice(0, cursorPos) + `\"img\"/` + markdown.slice(cursorPos); setMarkdown(newText); } catch (err) { console.error("Ошибка загрузки изображения:", err); } } } }; return (
{/* Предпросмотр */}

👀 Предпросмотр

{markdown}
{/* Редактор */}

📝 Редактор