Add preview mode

This commit is contained in:
2024-09-26 21:47:23 +02:00
parent 79bd172f70
commit 27be41ba62
10 changed files with 2115 additions and 112 deletions

View File

@@ -20,6 +20,7 @@ const Editor = ({ content, onChange, onSave, filePath }) => {
extensions: [
basicSetup,
markdown(),
EditorView.lineWrapping,
keymap.of(defaultKeymap),
keymap.of([{
key: "Ctrl-s",
@@ -54,7 +55,7 @@ const Editor = ({ content, onChange, onSave, filePath }) => {
}
}, [content]);
return <div ref={editorRef} />;
return <div ref={editorRef} className="editor-container" />;
};
export default Editor;

View File

@@ -0,0 +1,17 @@
import React from 'react';
import { Page, Text, User, Button, Spacer } from '@geist-ui/core';
import { Settings } from '@geist-ui/icons';
const Header = () => {
return (
<Page.Header className="custom-navbar">
<Text b>NovaMD</Text>
<Spacer w={1} />
<User src="https://via.placeholder.com/40" name="User" />
<Spacer w={0.5} />
<Button auto icon={<Settings />} />
</Page.Header>
);
};
export default Header;

View File

@@ -0,0 +1,73 @@
import React, { useState } from 'react';
import { Grid, Breadcrumbs, Tabs, Dot } from '@geist-ui/core';
import { Code, Eye } from '@geist-ui/icons';
import Editor from './Editor';
import FileTree from './FileTree';
import MarkdownPreview from './MarkdownPreview';
const MainContent = ({
content,
files,
selectedFile,
hasUnsavedChanges,
error,
onFileSelect,
onContentChange,
onSave,
}) => {
const [activeTab, setActiveTab] = useState('source');
const renderBreadcrumbs = () => {
if (!selectedFile) return null;
const pathParts = selectedFile.split('/');
return (
<div className="breadcrumbs-container">
<Breadcrumbs>
{pathParts.map((part, index) => (
<Breadcrumbs.Item key={index}>{part}</Breadcrumbs.Item>
))}
</Breadcrumbs>
{hasUnsavedChanges && <Dot type="warning" className="unsaved-indicator" />}
</div>
);
};
return (
<Grid.Container gap={1} height="calc(100vh - 64px)">
<Grid xs={24} sm={6} md={5} lg={4} height="100%" className="sidebar">
{error ? (
<div className="error">{error}</div>
) : (
<FileTree
files={files}
onFileSelect={onFileSelect}
selectedFile={selectedFile}
/>
)}
</Grid>
<Grid xs={24} sm={18} md={19} lg={20} height="100%" className="main-content">
<div className="content-header">
{renderBreadcrumbs()}
<Tabs value={activeTab} onChange={setActiveTab}>
<Tabs.Item label={<Code />} value="source" />
<Tabs.Item label={<Eye />} value="preview" />
</Tabs>
</div>
<div className="content-body">
{activeTab === 'source' ? (
<Editor
content={content}
onChange={onContentChange}
onSave={onSave}
filePath={selectedFile}
/>
) : (
<MarkdownPreview content={content} />
)}
</div>
</Grid>
</Grid.Container>
);
};
export default MainContent;

View File

@@ -0,0 +1,41 @@
import React from 'react';
import ReactMarkdown from 'react-markdown';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
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 }) => {
return (
<div className="markdown-preview">
<ReactMarkdown
remarkPlugins={[remarkMath]}
rehypePlugins={[rehypeKatex]}
components={{
code({node, inline, className, children, ...props}) {
const match = /language-(\w+)/.exec(className || '')
return !inline && match ? (
<SyntaxHighlighter
style={vscDarkPlus}
language={match[1]}
PreTag="div"
{...props}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code className={className} {...props}>
{children}
</code>
)
}
}}
>
{content}
</ReactMarkdown>
</div>
);
};
export default MarkdownPreview;