Add support for images

This commit is contained in:
2024-09-29 23:44:24 +02:00
parent 879c1d96ff
commit 43d647c9ea
7 changed files with 118 additions and 12 deletions

View File

@@ -22,6 +22,21 @@ $navbar-height: 64px;
}
}
.image-preview {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: auto;
}
.image-preview img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.page-content {
padding: 0 $padding;
}

View File

@@ -7,6 +7,7 @@ import {
GitCommit,
Plus,
Trash,
Image,
} from '@geist-ui/icons';
const FileTree = ({
@@ -37,8 +38,15 @@ const FileTree = ({
);
};
const renderIcon = ({ type }) =>
type === 'directory' ? <Folder /> : <File />;
const isImageFile = (fileName) => {
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg'];
return imageExtensions.some((ext) => fileName.toLowerCase().endsWith(ext));
};
const renderIcon = ({ type, name }) => {
if (type === 'directory') return <Folder />;
return isImageFile(name) ? <Image /> : <File />;
};
return (
<div>

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import {
Grid,
Breadcrumbs,
@@ -14,7 +14,17 @@ import { Code, Eye } from '@geist-ui/icons';
import Editor from './Editor';
import FileTree from './FileTree';
import MarkdownPreview from './MarkdownPreview';
import { commitAndPush, saveFileContent, deleteFile } from '../services/api';
import {
commitAndPush,
saveFileContent,
deleteFile,
getFileUrl,
} from '../services/api';
const isImageFile = (filePath) => {
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg'];
return imageExtensions.some((ext) => filePath.toLowerCase().endsWith(ext));
};
const MainContent = ({
content,
@@ -33,6 +43,21 @@ const MainContent = ({
const { setToast } = useToasts();
const [newFileModalVisible, setNewFileModalVisible] = useState(false);
const [newFileName, setNewFileName] = useState('');
const [isCurrentFileImage, setIsCurrentFileImage] = useState(false);
useEffect(() => {
const currentFileIsImage = isImageFile(selectedFile);
setIsCurrentFileImage(currentFileIsImage);
if (currentFileIsImage) {
setActiveTab('preview');
}
}, [selectedFile]);
const handleTabChange = (value) => {
if (!isCurrentFileImage || value === 'preview') {
setActiveTab(value);
}
};
const handlePull = async () => {
try {
@@ -153,13 +178,17 @@ const MainContent = ({
>
<div className="content-header">
{renderBreadcrumbs()}
<Tabs value={activeTab} onChange={setActiveTab}>
<Tabs.Item label={<Code />} value="source" />
<Tabs value={activeTab} onChange={handleTabChange}>
<Tabs.Item
label={<Code />}
value="source"
disabled={isCurrentFileImage}
/>
<Tabs.Item label={<Eye />} value="preview" />
</Tabs>
</div>
<div className="content-body">
{activeTab === 'source' ? (
{activeTab === 'source' && !isCurrentFileImage ? (
<Editor
content={content}
onChange={onContentChange}
@@ -167,8 +196,23 @@ const MainContent = ({
filePath={selectedFile}
themeType={themeType}
/>
) : isCurrentFileImage ? (
<div className="image-preview">
<img
src={getFileUrl(selectedFile)}
alt={selectedFile}
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain',
}}
/>
</div>
) : (
<MarkdownPreview content={content} />
<MarkdownPreview
content={content}
baseUrl={window.API_BASE_URL}
/>
)}
</div>
</Grid>

View File

@@ -6,7 +6,7 @@ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
import 'katex/dist/katex.min.css';
const MarkdownPreview = ({ content }) => {
const MarkdownPreview = ({ content, baseUrl }) => {
return (
<div className="markdown-preview">
<ReactMarkdown
@@ -30,6 +30,14 @@ const MarkdownPreview = ({ content }) => {
</code>
);
},
img({ src, alt, ...props }) {
// Check if the src is a relative path
if (src && !src.startsWith('http') && !src.startsWith('data:')) {
// Prepend the baseUrl to create an absolute path
src = `${baseUrl}/files/${src}`;
}
return <img src={src} alt={alt} {...props} />;
},
}}
>
{content}

View File

@@ -13,6 +13,11 @@ const DEFAULT_FILE = {
content: '# Welcome to NovaMD\n\nStart editing here!',
};
const isImageFile = (filePath) => {
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg'];
return imageExtensions.some((ext) => filePath.toLowerCase().endsWith(ext));
};
const useFileManagement = (gitEnabled = false) => {
const [content, setContent] = useState(DEFAULT_FILE.content);
const [files, setFiles] = useState([]);
@@ -76,8 +81,12 @@ const useFileManagement = (gitEnabled = false) => {
}
try {
const fileContent = await fetchFileContent(filePath);
setContent(fileContent);
if (!isImageFile(filePath)) {
const fileContent = await fetchFileContent(filePath);
setContent(fileContent);
} else {
setContent(''); // Set empty content for image files
}
setSelectedFile(filePath);
setIsNewFile(false);
setHasUnsavedChanges(false);

View File

@@ -127,3 +127,7 @@ export const commitAndPush = async (message) => {
throw error;
}
};
export const getFileUrl = (filePath) => {
return `${API_BASE_URL}/files/${filePath}`;
};