diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5a4ec02..914b830 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "@codemirror/commands": "^6.6.2", "@codemirror/lang-markdown": "^6.2.5", "@codemirror/state": "^6.4.1", + "@codemirror/theme-one-dark": "^6.1.2", "@codemirror/view": "^6.34.0", "@geist-ui/core": "^2.3.8", "@geist-ui/icons": "^1.0.2", @@ -2096,6 +2097,18 @@ "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==", "license": "MIT" }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz", + "integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, "node_modules/@codemirror/view": { "version": "6.34.0", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index ec77c86..cc8e08f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,6 +26,7 @@ "@codemirror/commands": "^6.6.2", "@codemirror/lang-markdown": "^6.2.5", "@codemirror/state": "^6.4.1", + "@codemirror/theme-one-dark": "^6.1.2", "@codemirror/view": "^6.34.0", "@geist-ui/core": "^2.3.8", "@geist-ui/icons": "^1.0.2", diff --git a/frontend/src/App.js b/frontend/src/App.js index e2b5f85..4b1f1c2 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { GeistProvider, CssBaseline, Page } from '@geist-ui/core'; import Header from './components/Header'; import MainContent from './components/MainContent'; @@ -6,6 +6,7 @@ import useFileManagement from './hooks/useFileManagement'; import './App.scss'; function App() { + const [themeType, setThemeType] = useState('light'); const { content, files, @@ -18,11 +19,15 @@ function App() { handleSave, } = useFileManagement(); + const toggleTheme = () => { + setThemeType(prevTheme => prevTheme === 'light' ? 'dark' : 'light'); + }; + return ( - + -
+
{ +const Editor = ({ content, onChange, onSave, filePath, themeType }) => { const editorRef = useRef(); const viewRef = useRef(); @@ -15,6 +16,24 @@ const Editor = ({ content, onChange, onSave, filePath }) => { return true; }; + const theme = EditorView.theme({ + "&": { + height: "100%", + fontSize: "14px", + }, + ".cm-scroller": { + overflow: "auto", + }, + ".cm-gutters": { + backgroundColor: themeType === "dark" ? "#1e1e1e" : "#f5f5f5", + color: themeType === "dark" ? "#858585" : "#999", + border: "none", + }, + ".cm-activeLineGutter": { + backgroundColor: themeType === "dark" ? "#2c313a" : "#e8e8e8", + }, + }); + const state = EditorState.create({ doc: content, extensions: [ @@ -32,6 +51,8 @@ const Editor = ({ content, onChange, onSave, filePath }) => { onChange(update.state.doc.toString()); } }), + theme, + themeType === "dark" ? oneDark : [], ], }); @@ -45,7 +66,7 @@ const Editor = ({ content, onChange, onSave, filePath }) => { return () => { view.destroy(); }; - }, [filePath]); + }, [filePath, themeType]); useEffect(() => { if (viewRef.current && content !== viewRef.current.state.doc.toString()) { diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js index 6fa632c..585d188 100644 --- a/frontend/src/components/Header.js +++ b/frontend/src/components/Header.js @@ -3,7 +3,7 @@ import { Page, Text, User, Button, Spacer } from '@geist-ui/core'; import { Settings as SettingsIcon } from '@geist-ui/icons'; import Settings from './Settings'; -const Header = () => { +const Header = ({ currentTheme, onThemeChange }) => { const [settingsVisible, setSettingsVisible] = useState(false); const openSettings = () => setSettingsVisible(true); @@ -16,7 +16,12 @@ const Header = () => {