diff --git a/frontend/src/components/file-browser/FilePreview.tsx b/frontend/src/components/file-browser/FilePreview.tsx index 733a5bb..d916cbc 100644 --- a/frontend/src/components/file-browser/FilePreview.tsx +++ b/frontend/src/components/file-browser/FilePreview.tsx @@ -1,9 +1,10 @@ import { useState, useCallback, useRef, useEffect, memo } from 'react' import { Button } from '@/components/ui/button' -import { Download, X, Edit3, Save, X as XIcon, WrapText } from 'lucide-react' +import { Download, X, Edit3, Save, X as XIcon, WrapText, Eye, Code } from 'lucide-react' import type { FileInfo } from '@/types/files' import { API_BASE_URL } from '@/config' import { VirtualizedTextView, type VirtualizedTextViewHandle } from '@/components/ui/virtualized-text-view' +import { MarkdownRenderer } from './MarkdownRenderer' const API_BASE = API_BASE_URL @@ -20,18 +21,38 @@ interface FilePreviewProps { } export const FilePreview = memo(function FilePreview({ file, hideHeader = false, isMobileModal = false, onCloseModal, onFileSaved, initialLineNumber }: FilePreviewProps) { + const isMarkdownFile = file.name.endsWith('.md') || file.name.endsWith('.mdx') || file.mimeType === 'text/markdown' + const [viewMode, setViewMode] = useState<'preview' | 'edit'>('preview') const [editContent, setEditContent] = useState('') const [isSaving, setIsSaving] = useState(false) const [hasVirtualizedChanges, setHasVirtualizedChanges] = useState(false) const [highlightedLine, setHighlightedLine] = useState(initialLineNumber) const [lineWrap, setLineWrap] = useState(true) + const [markdownPreview, setMarkdownPreview] = useState(isMarkdownFile) + const [fullMarkdownContent, setFullMarkdownContent] = useState(null) + const [isLoadingFullContent, setIsLoadingFullContent] = useState(false) const virtualizedRef = useRef(null) const contentRef = useRef(null) const shouldVirtualize = file.size > VIRTUALIZATION_THRESHOLD_BYTES && !file.mimeType?.startsWith('image/') + useEffect(() => { + if (shouldVirtualize && isMarkdownFile && markdownPreview && !fullMarkdownContent) { + setIsLoadingFullContent(true) + fetch(`${API_BASE}/api/files/${file.path}?raw=true`) + .then(res => res.text()) + .then(content => { + setFullMarkdownContent(content) + setIsLoadingFullContent(false) + }) + .catch(() => { + setIsLoadingFullContent(false) + }) + } + }, [shouldVirtualize, isMarkdownFile, markdownPreview, fullMarkdownContent, file.path]) + useEffect(() => { @@ -165,6 +186,18 @@ export const FilePreview = memo(function FilePreview({ file, hideHeader = false, } if (shouldVirtualize && isTextFile) { + if (isMarkdownFile && markdownPreview && viewMode !== 'edit') { + if (isLoadingFullContent) { + return ( +
+
+
+ ) + } + if (fullMarkdownContent) { + return + } + } return ( ) } + + if (isMarkdownFile && markdownPreview) { + return + } + const lines = textContent.split('\n') return (
- {isTextFile && ( + {isMarkdownFile && viewMode !== 'edit' && ( + + )} + + {isTextFile && !markdownPreview && (