Skip to content

Commit 7fd3e5f

Browse files
authored
Merge pull request #269 from GREENRAT-K405/dev
Add dark mode UI throughout the concore-editor.
2 parents 8936f42 + b215d7c commit 7fd3e5f

26 files changed

Lines changed: 875 additions & 222 deletions

src/App.css

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,58 @@
1+
/* CSS Variables for Light Mode (Default) */
2+
:root {
3+
/* Background colors */
4+
--bg-primary: rgb(240, 242, 245);
5+
--bg-secondary: #fff;
6+
7+
/* Text colors */
8+
--text-primary: #212529;
9+
--text-secondary: #fff;
10+
11+
/* Border colors */
12+
--border-primary: #999;
13+
--border-transparent: transparent;
14+
15+
/* Button colors */
16+
--btn-primary-bg: #007bff;
17+
--btn-primary-border: #007bff;
18+
--btn-secondary-bg: #6c757d;
19+
--btn-secondary-border: #6c757d;
20+
}
21+
22+
/* Dark Mode Variables - Productivity Tool Theme */
23+
[data-theme='dark'] {
24+
/* Background colors - Neutral dark grays (not pure black) */
25+
--bg-primary: #1E1E1E;
26+
/* Main background - matches VS Code */
27+
--bg-secondary: #2D2D2D;
28+
/* Cards, panels, elevated surfaces */
29+
30+
/* Text colors - Clear hierarchy, not harsh white */
31+
--text-primary: #E4E4E4;
32+
/* Primary text - softer than pure white */
33+
--text-secondary: #E4E4E4;
34+
/* Secondary text on buttons */
35+
36+
/* Border colors - Subtle separation */
37+
--border-primary: #3E3E3E;
38+
/* Borders - subtle but visible */
39+
--border-transparent: transparent;
40+
41+
/* Button colors - Subtle blue accent matching brand */
42+
--btn-primary-bg: #2B8CF7;
43+
/* Accent blue - matching titlebar */
44+
--btn-primary-border: #2B8CF7;
45+
--btn-secondary-bg: #3E3E3E;
46+
/* Neutral secondary actions */
47+
--btn-secondary-border: #3E3E3E;
48+
}
49+
150
* {
2-
font-family: 'Helvetica', 'Arial', sans-serif;
51+
font-family: 'Helvetica', 'Arial', sans-serif
352
}
453

554
input {
6-
border: 1px solid #999;
55+
border: 1px solid var(--border-primary);
756
}
857

958
.container {
@@ -14,20 +63,20 @@ input {
1463
}
1564

1665
.body {
17-
background-color: rgb(240, 242, 245);
66+
background-color: var(--bg-primary);
1867
height: -webkit-fill-available;
1968
flex: 1;
2069
}
2170

2271
.graph {
2372
padding: 50px;
24-
background-color: rgb(240, 242, 245);
73+
background-color: var(--bg-primary);
2574
height: -webkit-fill-available;
2675
flex: 80;
2776
}
2877

2978
.graph-container {
30-
background-color: #fff;
79+
background-color: var(--bg-secondary);
3180
}
3281

3382
.middle {
@@ -39,29 +88,29 @@ input {
3988
.btn {
4089
display: inline-block;
4190
font-weight: 400;
42-
color: #212529;
91+
color: var(--text-primary);
4392
text-align: center;
4493
vertical-align: middle;
4594
-webkit-user-select: none;
4695
-ms-user-select: none;
4796
user-select: none;
4897
background-color: transparent;
49-
border: 1px solid transparent;
98+
border: 1px solid var(--border-transparent);
5099
padding: .375rem .75rem;
51100
line-height: 1.5;
52101
border-radius: .25rem;
53102
}
54103

55104
.btn-primary {
56-
color: #fff;
57-
background-color: #007bff;
58-
border-color: #007bff;
105+
color: var(--text-secondary);
106+
background-color: var(--btn-primary-bg);
107+
border-color: var(--btn-primary-border);
59108
}
60109

61110
.btn-secondary {
62-
color: #fff;
63-
background-color: #6c757d;
64-
border-color: #6c757d;
111+
color: var(--text-secondary);
112+
background-color: var(--btn-secondary-bg);
113+
border-color: var(--btn-secondary-border);
65114
}
66115

67116
.btn:not(:disabled):not(.disabled) {

src/App.jsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ const app = () => {
3131
window.onbeforeunload = null;
3232
};
3333
}, []);
34+
35+
// Update document theme attribute when darkMode changes
36+
useEffect(() => {
37+
if (superState.darkMode) {
38+
document.documentElement.setAttribute('data-theme', 'dark');
39+
} else {
40+
document.documentElement.removeAttribute('data-theme');
41+
}
42+
}, [superState.darkMode]);
43+
3444
return (
3545
<div className="container">
3646
<ProjectDetails superState={superState} dispatcher={dispatcher} />

src/GraphArea.jsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ function Graph({
1818

1919
const initialiseNewGraph = () => {
2020
const myGraph = new MyGraph(
21-
graphID, ref.current, dispatcher, superState, projectName, nodeValidator, edgeValidator, authorName,
21+
graphID,
22+
ref.current,
23+
dispatcher,
24+
superState,
25+
projectName,
26+
nodeValidator,
27+
edgeValidator,
28+
authorName,
29+
superState.darkMode,
2230
);
2331
if (graphID) myGraph.loadGraphFromLocalStorage();
2432
if (serverID) {
@@ -55,6 +63,13 @@ function Graph({
5563
}
5664
}, [ref]);
5765

66+
// Update theme when darkMode changes
67+
useEffect(() => {
68+
if (instance && instance.updateTheme) {
69+
instance.updateTheme(superState.darkMode);
70+
}
71+
}, [superState.darkMode, instance]);
72+
5873
const { id } = el;
5974

6075
return (

src/GraphWorkspace.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const GraphComp = (props) => {
5959
}}
6060
>
6161
<TabBar superState={superState} dispatcher={dispatcher} />
62-
<div style={{ flex: 1, background: 'white' }} className="graph-container" ref={graphContainerRef}>
62+
<div style={{ flex: 1 }} className="graph-container" ref={graphContainerRef}>
6363
{superState.graphs.map((el, i) => (
6464
<Graph
6565
el={el}

src/component/Header.jsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/* eslint-disable react/jsx-props-no-spreading */
22
import React from 'react';
33
import hotkeys from 'hotkeys-js';
4+
import { FaMoon } from 'react-icons/fa';
45
import toolbarList from '../toolbarActions/toolbarList';
6+
import { actionType as T } from '../reducer';
57
import '@szhsin/react-menu/dist/index.css';
68
import './header.css';
79
import {
@@ -46,6 +48,27 @@ const Header = ({ superState, dispatcher }) => {
4648
} - concore Editor` : 'untitled'
4749
}
4850
</section>
51+
<div
52+
onClick={() => dispatcher({ type: T.TOGGLE_DARK_MODE })}
53+
style={{
54+
cursor: 'pointer',
55+
border: '1px solid #ccc',
56+
padding: '0 8px',
57+
display: 'flex',
58+
alignItems: 'center',
59+
justifyContent: 'center',
60+
transition: 'opacity 0.2s',
61+
backgroundColor: '#eee',
62+
}}
63+
onMouseEnter={(e) => { e.currentTarget.style.opacity = '0.7'; }}
64+
onMouseLeave={(e) => { e.currentTarget.style.opacity = '1'; }}
65+
role="button"
66+
tabIndex={0}
67+
onKeyDown={(e) => e.key === 'Enter' && dispatcher({ type: T.TOGGLE_DARK_MODE })}
68+
aria-label="Toggle dark mode"
69+
>
70+
<FaMoon size={20} className="theme-icon" />
71+
</div>
4972
<FullScreenButton />
5073
</div>
5174
<section className="toolbar">

src/component/HeaderComps.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const FileUploader = ({
3030
);
3131

3232
const Switcher = ({
33-
text, action, active, tabIndex,
33+
text, action, active, tabIndex, Icon,
3434
}) => (
3535
<div
3636
role="button"
@@ -39,12 +39,13 @@ const Switcher = ({
3939
onClick={action}
4040
onKeyDown={(ev) => ev.key === ' ' && action()}
4141
>
42+
{Icon && <div className="icon"><Icon size="20" /></div>}
4243
<Switch
4344
onChange={action}
4445
checked={active}
4546
className="react-switch"
4647
/>
47-
<div>
48+
<div style={{ fontSize: 14 }}>
4849
{text}
4950
</div>
5051
</div>

src/component/fileBrowser.css

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,131 @@ div.rendered-file-browser div.files ul {
198198
opacity: 0.8; }
199199

200200
div.rendered-file-browser p.loading, div.rendered-file-browser p.empty {
201-
margin: 16px 0; }
201+
margin: 16px 0; }
202+
203+
/* DARK MODE - LEFT SIDEBAR / FILE BROWSER*/
204+
205+
[data-theme='dark'] {
206+
/* Main sidebar background */
207+
background: #181818;
208+
}
209+
210+
/* Upload Directory Button */
211+
[data-theme='dark'] .inputButton {
212+
background-color: #2B8CF7; /* Accent Blue */
213+
color: #FFFFFF;
214+
border: 1px solid #2B8CF7;
215+
}
216+
217+
[data-theme='dark'] .inputButton:hover {
218+
background-color: #1e88e5;
219+
}
220+
221+
/* Section Header (h4 - Folder Name) */
222+
[data-theme='dark'] h4 {
223+
background-color: #202020;
224+
color: #EAEAEA;
225+
padding: 10px;
226+
margin: 0;
227+
border-bottom: 1px solid #2C2C2C;
228+
}
229+
230+
/* Filter Input Field */
231+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.action-bar input[type="search"] {
232+
background: #242424;
233+
border: 1px solid #333333;
234+
color: #FFFFFF;
235+
}
236+
237+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.action-bar input[type="search"]::placeholder {
238+
color: #888888;
239+
}
240+
241+
/* File Browser Container */
242+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.files {
243+
background: #181818;
244+
color: #EAEAEA;
245+
}
246+
247+
/* Table Column Headers */
248+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.files table thead th {
249+
color: #9AA0A6;
250+
border-bottom: 1px solid #2C2C2C;
251+
background: #181818;
252+
}
253+
254+
/* Table Rows */
255+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.files table tr td {
256+
color: #EAEAEA;
257+
border-bottom: 1px solid #202020;
258+
}
259+
260+
/* Table Row Hover */
261+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.files table tr:hover td {
262+
background: #252525;
263+
}
264+
265+
/* Selected Row */
266+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.files table tr.selected td {
267+
background: #2A2A2A;
268+
color: #FFFFFF;
269+
}
270+
271+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.files table tr.selected td.name:after {
272+
background: #2B8CF7; /* Accent blue for selection indicator */
273+
}
274+
275+
/* Dragover State */
276+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.files table tr.dragover td,
277+
[data-theme='dark'] div.rendered-react-keyed-file-browser div.files table tr.dragover th {
278+
background: #2A2A2A;
279+
}
280+
281+
/* Empty State ("No files.") */
282+
[data-theme='dark'] div.rendered-file-browser p.empty {
283+
color: #6F6F6F;
284+
}
285+
286+
[data-theme='dark'] div.rendered-file-browser p.loading {
287+
color: #9AA0A6;
288+
}
289+
290+
/* Folder/File Items in List View */
291+
[data-theme='dark'] div.rendered-file-browser div.files ul li.folder > div.item {
292+
border: 1px solid #2C2C2C;
293+
background: #181818;
294+
}
295+
296+
[data-theme='dark'] div.rendered-file-browser div.files ul li.folder > div.item:hover {
297+
background: #252525;
298+
}
299+
300+
[data-theme='dark'] div.rendered-file-browser div.files li.file.selected > div.item,
301+
[data-theme='dark'] div.rendered-file-browser div.files li.folder.selected > div.item {
302+
background: #2A2A2A;
303+
color: #FFFFFF;
304+
border: 1px solid #2B8CF7;
305+
}
306+
307+
[data-theme='dark'] div.rendered-file-browser div.files ul li.file > div.item span.thumb {
308+
border: 1px solid #2C2C2C;
309+
background: #202020;
310+
}
311+
312+
[data-theme='dark'] div.rendered-file-browser div.files li.file.dragover,
313+
[data-theme='dark'] div.rendered-file-browser div.files li.folder.dragover {
314+
background: #2A2A2A;
315+
}
316+
317+
/* Expanded Folder Borders */
318+
[data-theme='dark'] div.rendered-file-browser div.files ul li.folder.expanded {
319+
border-bottom: 1px solid #2C2C2C;
320+
border-left: 4px solid #2C2C2C;
321+
border-right: 1px solid #2C2C2C;
322+
}
323+
324+
[data-theme='dark'] div.rendered-file-browser div.files ul li.folder.expanded.selected {
325+
border-bottom: 1px solid #2B8CF7;
326+
border-left: 4px solid #2B8CF7;
327+
border-right: 1px solid #2B8CF7;
328+
}

0 commit comments

Comments
 (0)