mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-07 00:14:25 +00:00
Initial frontend implementation
This commit is contained in:
23
frontend/src/App.js
Normal file
23
frontend/src/App.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import React, { useState } from 'react';
|
||||
import Editor from './components/Editor';
|
||||
import FileTree from './components/FileTree';
|
||||
import './App.scss';
|
||||
|
||||
function App() {
|
||||
const [content, setContent] = useState('# Welcome to NovaMD\n\nStart editing here!');
|
||||
const [files, setFiles] = useState(['README.md', 'chapter1.md', 'chapter2.md']);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<div className="sidebar">
|
||||
<FileTree files={files} />
|
||||
</div>
|
||||
<div className="main-content">
|
||||
<h1>NovaMD</h1>
|
||||
<Editor content={content} onChange={setContent} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
33
frontend/src/App.scss
Normal file
33
frontend/src/App.scss
Normal file
@@ -0,0 +1,33 @@
|
||||
.App {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
background-color: #f0f0f0;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex-grow: 1;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.file-tree {
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 5px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
frontend/src/components/Editor.js
Normal file
50
frontend/src/components/Editor.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { basicSetup } from "codemirror";
|
||||
import { EditorState } from "@codemirror/state";
|
||||
import { EditorView, keymap } from "@codemirror/view";
|
||||
import { markdown } from "@codemirror/lang-markdown";
|
||||
import { defaultKeymap } from "@codemirror/commands";
|
||||
|
||||
const Editor = ({ content, onChange }) => {
|
||||
const editorRef = useRef();
|
||||
const viewRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
const state = EditorState.create({
|
||||
doc: content,
|
||||
extensions: [
|
||||
basicSetup,
|
||||
markdown(),
|
||||
keymap.of(defaultKeymap),
|
||||
EditorView.updateListener.of((update) => {
|
||||
if (update.docChanged) {
|
||||
onChange(update.state.doc.toString());
|
||||
}
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const view = new EditorView({
|
||||
state,
|
||||
parent: editorRef.current,
|
||||
});
|
||||
|
||||
viewRef.current = view;
|
||||
|
||||
return () => {
|
||||
view.destroy();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (viewRef.current && content !== viewRef.current.state.doc.toString()) {
|
||||
viewRef.current.dispatch({
|
||||
changes: { from: 0, to: viewRef.current.state.doc.length, insert: content }
|
||||
});
|
||||
}
|
||||
}, [content]);
|
||||
|
||||
return <div ref={editorRef} />;
|
||||
};
|
||||
|
||||
export default Editor;
|
||||
16
frontend/src/components/FileTree.js
Normal file
16
frontend/src/components/FileTree.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
|
||||
const FileTree = ({ files }) => {
|
||||
return (
|
||||
<div className="file-tree">
|
||||
<h3>Files</h3>
|
||||
<ul>
|
||||
{files.map((file, index) => (
|
||||
<li key={index}>{file}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FileTree;
|
||||
10
frontend/src/index.js
Normal file
10
frontend/src/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
Reference in New Issue
Block a user