diff --git a/.DS_Store b/.DS_Store index e978918..694a98b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/dist.zip b/dist.zip index 02d5f6a..0823387 100644 Binary files a/dist.zip and b/dist.zip differ diff --git a/index.html b/index.html index fd14199..1c9e6d8 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - 慧会议 + iMeeting
diff --git a/package.json b/package.json index fab4a5d..2c3ba38 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,10 @@ "preview": "vite preview" }, "dependencies": { + "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.38.6", + "@uiw/react-codemirror": "^4.25.3", "@uiw/react-md-editor": "^4.0.8", "antd": "^5.27.3", "axios": "^1.6.2", diff --git a/src/App.jsx b/src/App.jsx index 790804f..3959146 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -96,7 +96,7 @@ function App() { user ? : } /> } /> - } /> + } /> diff --git a/src/components/MarkdownEditor.css b/src/components/MarkdownEditor.css new file mode 100644 index 0000000..b2a26d9 --- /dev/null +++ b/src/components/MarkdownEditor.css @@ -0,0 +1,280 @@ +/* Markdown Editor Component */ +.markdown-editor-wrapper { + margin-top: 0.5rem; +} + +.editor-toolbar { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.5rem; + background: #f8fafc; + border: 2px solid #e2e8f0; + border-radius: 8px 8px 0 0; + flex-wrap: wrap; +} + +.toolbar-btn { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 32px; + height: 32px; + padding: 0.25rem 0.5rem; + background: white; + border: 1px solid #d1d5db; + border-radius: 4px; + font-size: 0.875rem; + font-weight: 500; + color: #374155; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} + +.toolbar-btn:hover { + background: #f0f4ff; + border-color: #667eea; + color: #667eea; +} + +.toolbar-btn.active { + background: #667eea; + border-color: #667eea; + color: white; +} + +.toolbar-btn.active:hover { + background: #5a67d8; + border-color: #5a67d8; +} + +.toolbar-btn strong, +.toolbar-btn em { + font-style: normal; + font-weight: 600; +} + +.toolbar-divider { + width: 1px; + height: 24px; + background: #d1d5db; + margin: 0 0.25rem; +} + +/* 标题下拉菜单 */ +.toolbar-dropdown { + position: relative; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + margin-top: 0.25rem; + background: white; + border: 1px solid #d1d5db; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + z-index: 100; + min-width: 160px; + overflow: hidden; +} + +.dropdown-menu button { + display: block; + width: 100%; + padding: 0.75rem 1rem; + border: none; + background: white; + text-align: left; + cursor: pointer; + transition: background 0.2s ease; + font-family: inherit; + color: #374155; +} + +.dropdown-menu button:hover { + background: #f0f4ff; + color: #667eea; +} + +.dropdown-menu button h1, +.dropdown-menu button h2, +.dropdown-menu button h3, +.dropdown-menu button h4, +.dropdown-menu button h5, +.dropdown-menu button h6 { + font-weight: 600; + color: inherit; +} + +/* CodeMirror 样式覆盖 */ +.markdown-editor-wrapper .cm-editor { + border-top: none !important; + border-radius: 0 0 8px 8px !important; +} + +/* 预览区域 */ +.markdown-preview { + border: 2px solid #e2e8f0; + border-top: none; + border-radius: 0 0 8px 8px; + padding: 2rem; + background: white; + min-height: 400px; + font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif; +} + +.markdown-preview h1, +.markdown-preview h2, +.markdown-preview h3, +.markdown-preview h4, +.markdown-preview h5, +.markdown-preview h6 { + margin: 1.5rem 0 0.75rem 0; + font-weight: 600; + color: #1e293b; + line-height: 1.3; +} + +.markdown-preview h1:first-child, +.markdown-preview h2:first-child, +.markdown-preview h3:first-child, +.markdown-preview h4:first-child, +.markdown-preview h5:first-child, +.markdown-preview h6:first-child { + margin-top: 0; +} + +.markdown-preview h1 { font-size: 1.875rem; } +.markdown-preview h2 { font-size: 1.5rem; } +.markdown-preview h3 { font-size: 1.25rem; } +.markdown-preview h4 { font-size: 1.125rem; } +.markdown-preview h5 { font-size: 1rem; } +.markdown-preview h6 { font-size: 0.875rem; } + +.markdown-preview p { + margin: 0.75rem 0; + line-height: 1.7; + color: #475569; +} + +.markdown-preview ul, +.markdown-preview ol { + margin: 1rem 0; + padding-left: 2rem; +} + +.markdown-preview li { + margin: 0.5rem 0; + line-height: 1.6; + color: #475569; +} + +.markdown-preview strong { + font-weight: 600; + color: #1e293b; +} + +.markdown-preview em { + font-style: italic; +} + +.markdown-preview code { + background: #f1f5f9; + padding: 0.2rem 0.4rem; + border-radius: 4px; + font-family: 'Monaco', 'Consolas', 'Courier New', monospace; + font-size: 0.875rem; + color: #dc2626; +} + +.markdown-preview pre { + background: #f8fafc; + padding: 1rem; + border-radius: 8px; + overflow-x: auto; + border: 1px solid #e2e8f0; + margin: 1rem 0; +} + +.markdown-preview pre code { + background: none; + padding: 0; + color: #334155; +} + +.markdown-preview blockquote { + border-left: 4px solid #667eea; + padding-left: 1rem; + margin: 1rem 0; + font-style: italic; + color: #64748b; + background: #f8fafc; + padding: 1rem; + border-radius: 0 8px 8px 0; +} + +.markdown-preview table { + width: 100%; + border-collapse: collapse; + margin: 1.5rem 0; + border: 1px solid #e2e8f0; +} + +.markdown-preview th, +.markdown-preview td { + border: 1px solid #e2e8f0; + padding: 0.75rem; + text-align: left; +} + +.markdown-preview th { + background: #f8fafc; + font-weight: 600; + color: #334155; +} + +.markdown-preview hr { + border: none; + height: 1px; + background: #e2e8f0; + margin: 2rem 0; +} + +.markdown-preview img { + max-width: 100%; + height: auto; + border-radius: 8px; + margin: 1rem 0; +} + +.markdown-preview a { + color: #667eea; + text-decoration: none; + border-bottom: 1px solid transparent; + transition: border-color 0.2s ease; +} + +.markdown-preview a:hover { + border-bottom-color: #667eea; +} + +/* 响应式 */ +@media (max-width: 768px) { + .editor-toolbar { + gap: 0.125rem; + padding: 0.375rem; + } + + .toolbar-btn { + min-width: 28px; + height: 28px; + font-size: 0.75rem; + } + + .markdown-preview { + padding: 1rem; + } +} diff --git a/src/components/MarkdownEditor.jsx b/src/components/MarkdownEditor.jsx new file mode 100644 index 0000000..644b941 --- /dev/null +++ b/src/components/MarkdownEditor.jsx @@ -0,0 +1,233 @@ +import React, { useState, useRef, useMemo } from 'react'; +import CodeMirror from '@uiw/react-codemirror'; +import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; +import { EditorView } from '@codemirror/view'; +import ReactMarkdown from 'react-markdown'; +import remarkGfm from 'remark-gfm'; +import rehypeRaw from 'rehype-raw'; +import rehypeSanitize from 'rehype-sanitize'; +import './MarkdownEditor.css'; + +const MarkdownEditor = ({ + value, + onChange, + onImageUpload, + placeholder = '在这里编写内容...', + height = 400, + showImageUpload = true +}) => { + const editorRef = useRef(null); + const imageInputRef = useRef(null); + const [showPreview, setShowPreview] = useState(false); + const [showHeadingMenu, setShowHeadingMenu] = useState(false); + + // CodeMirror extensions + const editorExtensions = useMemo(() => [ + markdown({ base: markdownLanguage }), + EditorView.lineWrapping, + EditorView.theme({ + "&": { + fontSize: "14px", + border: "2px solid #e2e8f0", + borderRadius: "0 0 8px 8px", + borderTop: "none", + }, + ".cm-content": { + fontFamily: "'Monaco', 'Menlo', 'Consolas', monospace", + padding: "1rem", + minHeight: `${height}px`, + }, + ".cm-scroller": { + fontFamily: "'Monaco', 'Menlo', 'Consolas', monospace", + }, + "&.cm-focused": { + outline: "none", + borderColor: "#667eea", + boxShadow: "0 0 0 3px rgba(102, 126, 234, 0.1)", + } + }) + ], [height]); + + // Markdown 插入函数 + const insertMarkdown = (before, after = '', placeholder = '') => { + if (!editorRef.current?.view) return; + + const view = editorRef.current.view; + const selection = view.state.selection.main; + const selectedText = view.state.doc.sliceString(selection.from, selection.to); + const text = selectedText || placeholder; + const newText = `${before}${text}${after}`; + + view.dispatch({ + changes: { from: selection.from, to: selection.to, insert: newText }, + selection: { anchor: selection.from + before.length, head: selection.from + before.length + text.length } + }); + view.focus(); + }; + + // 工具栏操作 + const toolbarActions = { + bold: () => insertMarkdown('**', '**', '粗体文字'), + italic: () => insertMarkdown('*', '*', '斜体文字'), + heading: (level) => { + setShowHeadingMenu(false); + insertMarkdown('#'.repeat(level) + ' ', '', '标题'); + }, + quote: () => insertMarkdown('> ', '', '引用内容'), + code: () => insertMarkdown('`', '`', '代码'), + codeBlock: () => insertMarkdown('```\n', '\n```', '代码块'), + link: () => insertMarkdown('[', '](url)', '链接文字'), + unorderedList: () => insertMarkdown('- ', '', '列表项'), + orderedList: () => insertMarkdown('1. ', '', '列表项'), + table: () => { + const tableTemplate = '\n| 列1 | 列2 | 列3 |\n| --- | --- | --- |\n| 单元格 | 单元格 | 单元格 |\n| 单元格 | 单元格 | 单元格 |\n'; + insertMarkdown(tableTemplate, '', ''); + }, + hr: () => insertMarkdown('\n---\n', '', ''), + image: () => imageInputRef.current?.click(), + }; + + // 图片上传处理 + const handleImageSelect = async (event) => { + const file = event.target.files[0]; + if (file && onImageUpload) { + const imageUrl = await onImageUpload(file); + if (imageUrl) { + insertMarkdown(`![${file.name}](${imageUrl})`, '', ''); + } + } + // Reset file input + if (imageInputRef.current) { + imageInputRef.current.value = ''; + } + }; + + return ( +
+
+ + + + {/* 多级标题下拉菜单 */} +
+ + {showHeadingMenu && ( +
+ + + + + + +
+ )} +
+ + + + + + + + + {showImageUpload && ( + + )} + + + + + + + + + + {/* 预览按钮 */} + +
+ + {showPreview ? ( +
+ + {value || '*暂无内容*'} + +
+ ) : ( + + )} + + {showImageUpload && ( + + )} +
+ ); +}; + +export default MarkdownEditor; diff --git a/src/pages/EditKnowledgeBase.jsx b/src/pages/EditKnowledgeBase.jsx index 2fa506c..8fdacd2 100644 --- a/src/pages/EditKnowledgeBase.jsx +++ b/src/pages/EditKnowledgeBase.jsx @@ -1,11 +1,10 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; +import React, { useState, useEffect } from 'react'; import { Link, useNavigate, useParams } from 'react-router-dom'; import apiClient from '../utils/apiClient'; import { ArrowLeft, FileText, Tag, Save } from 'lucide-react'; -import MDEditor, * as commands from '@uiw/react-md-editor'; -import '@uiw/react-md-editor/markdown-editor.css'; import { buildApiUrl, API_ENDPOINTS } from '../config/api'; import TagEditor from '../components/TagEditor'; +import MarkdownEditor from '../components/MarkdownEditor'; import './EditKnowledgeBase.css'; const EditKnowledgeBase = ({ user }) => { @@ -21,9 +20,6 @@ const EditKnowledgeBase = ({ user }) => { const [error, setError] = useState(''); const [kb, setKb] = useState(null); - const handleContentChange = useCallback((value) => { - setFormData(prev => ({ ...prev, content: value || '' })); - }, []); useEffect(() => { fetchKbData(); @@ -88,44 +84,6 @@ const EditKnowledgeBase = ({ user }) => { } }; - // 自定义工具栏命令配置 - const customCommands = [ - commands.bold, - commands.italic, - commands.strikethrough, - commands.hr, - commands.group([ - commands.title1, - commands.title2, - commands.title3, - commands.title4, - commands.title5, - commands.title6, - ], { - name: 'title', - groupName: 'title', - buttonProps: { 'aria-label': '插入标题', title: '插入标题' } - }), - commands.divider, - commands.link, - commands.quote, - commands.code, - commands.codeBlock, - commands.image, - commands.divider, - commands.unorderedListCommand, - commands.orderedListCommand, - commands.checkedListCommand, - ]; - - // 右侧额外命令(预览、全屏等) - const customExtraCommands = [ - commands.codeEdit, - commands.codeLive, - commands.codePreview, - commands.divider, - commands.fullscreen, - ]; if (isLoading) { return ( @@ -192,35 +150,15 @@ const EditKnowledgeBase = ({ user }) => { 内容总结 -
- -
+ setFormData(prev => ({ ...prev, content: value || '' }))} + placeholder="在这里编写知识库内容摘要..." + height={500} + showImageUpload={false} + />
- 使用Markdown格式编写知识库内容,支持**粗体**、*斜体*、# 标题、- 列表等格式。 + 使用Markdown格式编写知识库内容,支持**粗体**、*斜体*、# 标题、- 列表、表格等格式。
diff --git a/src/pages/EditMeeting.css b/src/pages/EditMeeting.css index 9c41801..d0363cf 100644 --- a/src/pages/EditMeeting.css +++ b/src/pages/EditMeeting.css @@ -498,50 +498,6 @@ transform: none; } -/* Markdown Editor */ -.markdown-editor-container { - margin-top: 0.5rem; -} - -.markdown-editor-container .w-md-editor { - background-color: white; -} - -.markdown-editor-container .w-md-editor-text-input, -.markdown-editor-container .w-md-editor-text-textarea, -.markdown-editor-container .w-md-editor-text { - font-size: 0.9rem !important; - line-height: 1.6 !important; - caret-color: #667eea !important; -} - -.markdown-editor-container .w-md-editor-text-input { - resize: none !important; -} - -.markdown-editor-container .w-md-editor-text-textarea { - resize: none !important; - outline: none !important; - border: none !important; - box-shadow: none !important; -} - -.markdown-editor-container .w-md-editor-toolbar { - background-color: #f8fafc; - border-bottom: 1px solid #e2e8f0; -} - -.markdown-editor-container .w-md-editor-toolbar button { - color: #64748b; - text-align: left; -} - -.markdown-editor-container .w-md-editor-toolbar button:hover { - background-color: #e2e8f0; - color: #334155; - text-align: left; -} - /* Upload indicator */ .uploading-indicator { display: flex; diff --git a/src/pages/EditMeeting.jsx b/src/pages/EditMeeting.jsx index fa37f68..3caea07 100644 --- a/src/pages/EditMeeting.jsx +++ b/src/pages/EditMeeting.jsx @@ -1,19 +1,17 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { Link, useNavigate, useParams } from 'react-router-dom'; import apiClient from '../utils/apiClient'; import configService from '../utils/configService'; -import { ArrowLeft, Users, Calendar, FileText, X, User, Save, Upload, Plus, Image, Tag } from 'lucide-react'; -import MDEditor, * as commands from '@uiw/react-md-editor'; -import '@uiw/react-md-editor/markdown-editor.css'; +import { ArrowLeft, Users, Calendar, FileText, X, User, Save, Upload, Plus, Tag } from 'lucide-react'; import { buildApiUrl, API_ENDPOINTS, API_BASE_URL } from '../config/api'; import DateTimePicker from '../components/DateTimePicker'; import TagEditor from '../components/TagEditor'; +import MarkdownEditor from '../components/MarkdownEditor'; import './EditMeeting.css'; const EditMeeting = ({ user }) => { const navigate = useNavigate(); const { meeting_id } = useParams(); - const imageInputRef = useRef(null); const [formData, setFormData] = useState({ title: '', meeting_time: '', @@ -36,10 +34,6 @@ const EditMeeting = ({ user }) => { const [maxFileSize, setMaxFileSize] = useState(100 * 1024 * 1024); // 默认100MB const [maxImageSize, setMaxImageSize] = useState(10 * 1024 * 1024); // 默认10MB - const handleSummaryChange = useCallback((value) => { - setFormData(prev => ({ ...prev, summary: value || '' })); - }, []); - useEffect(() => { fetchMeetingData(); fetchUsers(); @@ -232,7 +226,7 @@ const EditMeeting = ({ user }) => { formData.append('image_file', file); const response = await apiClient.post( - buildApiUrl(API_ENDPOINTS.MEETINGS.UPLOAD_IMAGE(meeting_id)), + buildApiUrl(API_ENDPOINTS.MEETINGS.UPLOAD_IMAGE(meeting_id)), formData, { headers: { @@ -250,98 +244,6 @@ const EditMeeting = ({ user }) => { } }; - const insertImageMarkdown = (imageUrl, altText = '图片') => { - const imageMarkdown = `![${altText}](${imageUrl})`; - setFormData(prev => ({ - ...prev, - summary: prev.summary + '\n\n' + imageMarkdown - })); - }; - - const handleImageSelect = async (event) => { - const file = event.target.files[0]; - if (file) { - const imageUrl = await handleImageUpload(file); - if (imageUrl) { - insertImageMarkdown(imageUrl, file.name); - } - } - // Reset file input - if (imageInputRef.current) { - imageInputRef.current.value = ''; - } - }; - - // 创建自定义上传图片命令(只显示文字,不显示图标) - const uploadImageCommand = { - name: 'upload-image', - keyCommand: 'upload-image', - buttonProps: { 'aria-label': '上传本地图片', title: '上传本地图片' }, - icon: UploadImage, - execute: () => { - imageInputRef.current?.click(); - } - }; - - // 创建修改后的图片URL命令 - const imageUrlCommand = { - ...commands.image, - name: 'image-url', - icon: AddImageURL, - }; - - // 自定义工具栏命令配置 - const customCommands = [ - commands.bold, - commands.italic, - commands.strikethrough, - commands.hr, - commands.group([ - commands.title1, - commands.title2, - commands.title3, - commands.title4, - commands.title5, - commands.title6, - ], { - name: 'title', - groupName: 'title', - buttonProps: { 'aria-label': '插入标题', title: '插入标题' } - }), - commands.divider, - commands.link, - commands.quote, - commands.code, - commands.codeBlock, - // 创建图片功能组,使用系统自带的image命令和自定义上传命令 - commands.group([ - imageUrlCommand, - uploadImageCommand - ], { - name: 'image-group', - groupName: 'image', - buttonProps: { 'aria-label': '添加图片', title: '添加图片' }, - icon: ( - - - - ) - }), - commands.divider, - commands.unorderedListCommand, - commands.orderedListCommand, - commands.checkedListCommand, - ]; - - // 右侧额外命令(预览、全屏等) - const customExtraCommands = [ - commands.codeEdit, - commands.codeLive, - commands.codePreview, - commands.divider, - commands.fullscreen, - ]; - const filteredUsers = availableUsers.filter(user => { // Exclude users already selected as attendees const isAlreadySelected = formData.attendees.some(attendee => attendee.user_id === user.user_id); @@ -591,42 +493,16 @@ const EditMeeting = ({ user }) => { 会议摘要 -
- - -
+ setFormData(prev => ({ ...prev, summary: value || '' }))} + onImageUpload={handleImageUpload} + placeholder="在这里编写会议摘要..." + height={400} + showImageUpload={true} + />
- 使用Markdown格式编写会议摘要,支持**粗体**、*斜体*、# 标题、- 列表等格式。工具栏中可以上传图片或插入图片URL。 + 使用Markdown格式编写会议摘要,支持**粗体**、*斜体*、# 标题、- 列表、表格等格式。
{isUploadingImage && (
diff --git a/src/pages/HomePage.jsx b/src/pages/HomePage.jsx index a5367f8..e3b115f 100644 --- a/src/pages/HomePage.jsx +++ b/src/pages/HomePage.jsx @@ -90,7 +90,7 @@ const HomePage = ({ onLogin }) => { {/* Hero Section */}
-

“慧会议” —— 让会议更智能

+

iMeeting —— 让会议更智能

通过AI将会议音频转录并自动总结,对齐团队目标,构建企业知识库。

diff --git a/src/pages/MeetingDetails.css b/src/pages/MeetingDetails.css index afdfdd2..9ffa517 100644 --- a/src/pages/MeetingDetails.css +++ b/src/pages/MeetingDetails.css @@ -893,6 +893,19 @@ padding: 4px 10px; border-radius: 12px; border: 1px solid #e2e8f0; + display: flex; + align-items: center; + gap: 4px; +} + +.speaker-index { + font-weight: 500; + font-size: 0.75rem; + color: #64748b; + background: #e2e8f0; + padding: 2px 6px; + border-radius: 8px; + margin-left: 4px; } .timestamp { diff --git a/src/pages/MeetingDetails.jsx b/src/pages/MeetingDetails.jsx index 2fd55a3..66e7a5b 100644 --- a/src/pages/MeetingDetails.jsx +++ b/src/pages/MeetingDetails.jsx @@ -1266,19 +1266,26 @@ const MeetingDetails = ({ user }) => {
- {transcript.map((item, index) => ( -
{ + // 计算当前发言人的序号:这是该发言人的第几条发言 + const speakerSegments = transcript.filter(seg => seg.speaker_id === item.speaker_id); + const currentSpeakerIndex = speakerSegments.findIndex(seg => seg.segment_id === item.segment_id) + 1; + const totalSpeakerSegments = speakerSegments.length; + + return ( +
transcriptRefs.current[index] = el} className={`transcript-item ${currentHighlightIndex === index ? 'active' : ''}`} >
- jumpToTime(item.start_time_ms / 1000)} title="跳转到此时间点播放" > {item.speaker_tag} + {currentSpeakerIndex}/{totalSpeakerSegments}
{ )}
-
jumpToTime(item.start_time_ms / 1000)} title="跳转到此时间点播放" @@ -1307,7 +1314,8 @@ const MeetingDetails = ({ user }) => { {item.text_content}
- ))} + ); + })}
@@ -1574,7 +1582,7 @@ const MeetingDetails = ({ user }) => { setShowQRModal(false)} - url={`${window.location.origin}/meetings/${meeting_id}/preview`} + url={`${window.location.origin}/meetings/preview/${meeting_id}`} title={meeting.title} description="扫描二维码查看会议总结" /> diff --git a/src/pages/MeetingPreview.jsx b/src/pages/MeetingPreview.jsx index e70ca01..cdabe06 100644 --- a/src/pages/MeetingPreview.jsx +++ b/src/pages/MeetingPreview.jsx @@ -7,7 +7,7 @@ import rehypeSanitize from 'rehype-sanitize'; import './MeetingPreview.css'; const MeetingPreview = () => { - const { meetingId } = useParams(); + const { meeting_id } = useParams(); const [meetingData, setMeetingData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -15,13 +15,13 @@ const MeetingPreview = () => { useEffect(() => { fetchMeetingPreviewData(); - }, [meetingId]); + }, [meeting_id]); const fetchMeetingPreviewData = async () => { try { setLoading(true); const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000'; - const response = await fetch(`${apiUrl}/api/meetings/${meetingId}/preview-data`); + const response = await fetch(`${apiUrl}/api/meetings/${meeting_id}/preview-data`); const result = await response.json(); if (result.code === "200") { diff --git a/yarn.lock b/yarn.lock index a6667a1..0dcbfed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -201,7 +201,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.21.5", "@babel/runtime@^7.22.5", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.7", "@babel/runtime@^7.26.0": +"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.21.5", "@babel/runtime@^7.22.5", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.7", "@babel/runtime@^7.26.0": version "7.28.4" resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.4.tgz" integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ== @@ -246,6 +246,135 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.27.1" +"@codemirror/autocomplete@^6.0.0", "@codemirror/autocomplete@^6.7.1": + version "6.19.1" + resolved "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.19.1.tgz#355e49c9fd275b42a6e16e9ea0cf4361f67a3ec4" + integrity sha512-q6NenYkEy2fn9+JyjIxMWcNjzTL/IhwqfzOut1/G3PrIFkrbl4AL7Wkse5tLrQUUyqGoAKU5+Pi5jnnXxH5HGw== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.17.0" + "@lezer/common" "^1.0.0" + +"@codemirror/commands@^6.0.0", "@codemirror/commands@^6.1.0": + version "6.10.0" + resolved "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.10.0.tgz#b3206984fec8443c4d910565eb2e9d591c7d80b2" + integrity sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.4.0" + "@codemirror/view" "^6.27.0" + "@lezer/common" "^1.1.0" + +"@codemirror/lang-css@^6.0.0": + version "6.3.1" + resolved "https://registry.npmmirror.com/@codemirror/lang-css/-/lang-css-6.3.1.tgz#763ca41aee81bb2431be55e3cfcc7cc8e91421a3" + integrity sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@lezer/common" "^1.0.2" + "@lezer/css" "^1.1.7" + +"@codemirror/lang-html@^6.0.0": + version "6.4.11" + resolved "https://registry.npmmirror.com/@codemirror/lang-html/-/lang-html-6.4.11.tgz#c46ba46ae642fd567cf05c4129005d2913ac248d" + integrity sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/lang-css" "^6.0.0" + "@codemirror/lang-javascript" "^6.0.0" + "@codemirror/language" "^6.4.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.17.0" + "@lezer/common" "^1.0.0" + "@lezer/css" "^1.1.0" + "@lezer/html" "^1.3.12" + +"@codemirror/lang-javascript@^6.0.0": + version "6.2.4" + resolved "https://registry.npmmirror.com/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz#eef2227d1892aae762f3a0f212f72bec868a02c5" + integrity sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/language" "^6.6.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.17.0" + "@lezer/common" "^1.0.0" + "@lezer/javascript" "^1.0.0" + +"@codemirror/lang-markdown@^6.5.0": + version "6.5.0" + resolved "https://registry.npmmirror.com/@codemirror/lang-markdown/-/lang-markdown-6.5.0.tgz#29df87310a555b007beba8e12893363956a26e8e" + integrity sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw== + dependencies: + "@codemirror/autocomplete" "^6.7.1" + "@codemirror/lang-html" "^6.0.0" + "@codemirror/language" "^6.3.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.2.1" + "@lezer/markdown" "^1.0.0" + +"@codemirror/language@^6.0.0", "@codemirror/language@^6.3.0", "@codemirror/language@^6.4.0", "@codemirror/language@^6.6.0": + version "6.11.3" + resolved "https://registry.npmmirror.com/@codemirror/language/-/language-6.11.3.tgz#8e6632df566a7ed13a1bd307f9837765bb1abfdd" + integrity sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.23.0" + "@lezer/common" "^1.1.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + style-mod "^4.0.0" + +"@codemirror/lint@^6.0.0": + version "6.9.2" + resolved "https://registry.npmmirror.com/@codemirror/lint/-/lint-6.9.2.tgz#09ed0aedec13381c9e36e1ac5d126027740c3ef4" + integrity sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.35.0" + crelt "^1.0.5" + +"@codemirror/search@^6.0.0": + version "6.5.11" + resolved "https://registry.npmmirror.com/@codemirror/search/-/search-6.5.11.tgz#a324ffee36e032b7f67aa31c4fb9f3e6f9f3ed63" + integrity sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + crelt "^1.0.5" + +"@codemirror/state@^6.0.0", "@codemirror/state@^6.1.1", "@codemirror/state@^6.4.0", "@codemirror/state@^6.5.0", "@codemirror/state@^6.5.2": + version "6.5.2" + resolved "https://registry.npmmirror.com/@codemirror/state/-/state-6.5.2.tgz#8eca3a64212a83367dc85475b7d78d5c9b7076c6" + integrity sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA== + dependencies: + "@marijn/find-cluster-break" "^1.0.0" + +"@codemirror/theme-one-dark@^6.0.0": + version "6.1.3" + resolved "https://registry.npmmirror.com/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz#1dbb73f6e73c53c12ad2aed9f48c263c4e63ea37" + integrity sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/highlight" "^1.0.0" + +"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0", "@codemirror/view@^6.38.6": + version "6.38.6" + resolved "https://registry.npmmirror.com/@codemirror/view/-/view-6.38.6.tgz#25d9df071393801196c311025d2caa7a5523c26c" + integrity sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw== + dependencies: + "@codemirror/state" "^6.5.0" + crelt "^1.0.6" + style-mod "^4.1.0" + w3c-keyname "^2.2.4" + "@emotion/hash@^0.8.0": version "0.8.0" resolved "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz" @@ -513,6 +642,65 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@lezer/common@^1.0.0", "@lezer/common@^1.0.2", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0", "@lezer/common@^1.2.1", "@lezer/common@^1.3.0": + version "1.3.0" + resolved "https://registry.npmmirror.com/@lezer/common/-/common-1.3.0.tgz#123427ec4c53c2c8367415b4441e555b4f85c696" + integrity sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ== + +"@lezer/css@^1.1.0", "@lezer/css@^1.1.7": + version "1.3.0" + resolved "https://registry.npmmirror.com/@lezer/css/-/css-1.3.0.tgz#296f298814782c2fad42a936f3510042cdcd2034" + integrity sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw== + dependencies: + "@lezer/common" "^1.2.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.3.0" + +"@lezer/highlight@^1.0.0", "@lezer/highlight@^1.1.3": + version "1.2.3" + resolved "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.2.3.tgz#a20f324b71148a2ea9ba6ff42e58bbfaec702857" + integrity sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g== + dependencies: + "@lezer/common" "^1.3.0" + +"@lezer/html@^1.3.12": + version "1.3.12" + resolved "https://registry.npmmirror.com/@lezer/html/-/html-1.3.12.tgz#a438e2d04f4c863d49cad27efe714cde8cf3ff1b" + integrity sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw== + dependencies: + "@lezer/common" "^1.2.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/javascript@^1.0.0": + version "1.5.4" + resolved "https://registry.npmmirror.com/@lezer/javascript/-/javascript-1.5.4.tgz#11746955f957d33c0933f17d7594db54a8b4beea" + integrity sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA== + dependencies: + "@lezer/common" "^1.2.0" + "@lezer/highlight" "^1.1.3" + "@lezer/lr" "^1.3.0" + +"@lezer/lr@^1.0.0", "@lezer/lr@^1.3.0": + version "1.4.3" + resolved "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.3.tgz#51b252ff8ff9fea863819de7f4b6501ccf69d403" + integrity sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA== + dependencies: + "@lezer/common" "^1.0.0" + +"@lezer/markdown@^1.0.0": + version "1.6.0" + resolved "https://registry.npmmirror.com/@lezer/markdown/-/markdown-1.6.0.tgz#9db3356d52955391b021cc3ead9c79f87186840f" + integrity sha512-AXb98u3M6BEzTnreBnGtQaF7xFTiMA92Dsy5tqEjpacbjRxDSFdN4bKJo9uvU4cEEOS7D2B9MT7kvDgOEIzJSw== + dependencies: + "@lezer/common" "^1.0.0" + "@lezer/highlight" "^1.0.0" + +"@marijn/find-cluster-break@^1.0.0": + version "1.0.2" + resolved "https://registry.npmmirror.com/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz#775374306116d51c0c500b8c4face0f9a04752d8" + integrity sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g== + "@rc-component/async-validator@^5.0.3": version "5.0.4" resolved "https://registry.npmmirror.com/@rc-component/async-validator/-/async-validator-5.0.4.tgz" @@ -825,11 +1013,36 @@ resolved "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz" integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== +"@uiw/codemirror-extensions-basic-setup@4.25.3": + version "4.25.3" + resolved "https://registry.npmmirror.com/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.3.tgz#6fb28745e7012bfcad0dc5103119487e40a744bc" + integrity sha512-F1doRyD50CWScwGHG2bBUtUpwnOv/zqSnzkZqJcX5YAHQx6Z1CuX8jdnFMH6qktRrPU1tfpNYftTWu3QIoHiMA== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/commands" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/search" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@uiw/copy-to-clipboard@~1.0.12": version "1.0.17" resolved "https://registry.npmmirror.com/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.17.tgz" integrity sha512-O2GUHV90Iw2VrSLVLK0OmNIMdZ5fgEg4NhvtwINsX+eZ/Wf6DWD0TdsK9xwV7dNRnK/UI2mQtl0a2/kRgm1m1A== +"@uiw/react-codemirror@^4.25.3": + version "4.25.3" + resolved "https://registry.npmmirror.com/@uiw/react-codemirror/-/react-codemirror-4.25.3.tgz#dd61549051d4398068f087858b39f3fc988c7537" + integrity sha512-1wtBZTXPIp8u6F/xjHvsUAYlEeF5Dic4xZBnqJyLzv7o7GjGYEUfSz9Z7bo9aK9GAx2uojG/AuBMfhA4uhvIVQ== + dependencies: + "@babel/runtime" "^7.18.6" + "@codemirror/commands" "^6.1.0" + "@codemirror/state" "^6.1.1" + "@codemirror/theme-one-dark" "^6.0.0" + "@uiw/codemirror-extensions-basic-setup" "4.25.3" + codemirror "^6.0.0" + "@uiw/react-markdown-preview@^5.0.6": version "5.1.5" resolved "https://registry.npmmirror.com/@uiw/react-markdown-preview/-/react-markdown-preview-5.1.5.tgz" @@ -1137,6 +1350,19 @@ classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classna resolved "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== +codemirror@^6.0.0: + version "6.0.2" + resolved "https://registry.npmmirror.com/codemirror/-/codemirror-6.0.2.tgz#4d3fea1ad60b6753f97ca835f2f48c6936a8946e" + integrity sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/commands" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/search" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz" @@ -1203,6 +1429,11 @@ core-js@^3.6.0, core-js@^3.8.3: resolved "https://registry.npmmirror.com/core-js/-/core-js-3.45.1.tgz" integrity sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg== +crelt@^1.0.5, crelt@^1.0.6: + version "1.0.6" + resolved "https://registry.npmmirror.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== + cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz" @@ -3879,6 +4110,11 @@ strip-json-comments@^3.1.1: resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +style-mod@^4.0.0, style-mod@^4.1.0: + version "4.1.3" + resolved "https://registry.npmmirror.com/style-mod/-/style-mod-4.1.3.tgz#6e9012255bb799bdac37e288f7671b5d71bf9f73" + integrity sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ== + style-to-js@^1.0.0: version "1.1.17" resolved "https://registry.npmmirror.com/style-to-js/-/style-to-js-1.1.17.tgz" @@ -4082,6 +4318,11 @@ vite@^7.0.4: optionalDependencies: fsevents "~2.3.3" +w3c-keyname@^2.2.4: + version "2.2.8" + resolved "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== + web-namespaces@^2.0.0: version "2.0.1" resolved "https://registry.npmmirror.com/web-namespaces/-/web-namespaces-2.0.1.tgz"