mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-06 16:04:23 +00:00
Add preview mode
This commit is contained in:
@@ -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;
|
||||
17
frontend/src/components/Header.js
Normal file
17
frontend/src/components/Header.js
Normal 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;
|
||||
73
frontend/src/components/MainContent.js
Normal file
73
frontend/src/components/MainContent.js
Normal 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;
|
||||
41
frontend/src/components/MarkdownPreview.js
Normal file
41
frontend/src/components/MarkdownPreview.js
Normal 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;
|
||||
Reference in New Issue
Block a user