Skip to content

Commit 6175826

Browse files
committed
add darkmode to concore editor
1 parent 04a7711 commit 6175826

17 files changed

Lines changed: 991 additions & 424 deletions

src/App.css

Lines changed: 95 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,136 @@
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 {
10-
height: 100vh;
11-
display: flex;
12-
width: 100vw;
13-
flex-direction: column;
59+
height: 100vh;
60+
display: flex;
61+
width: 100vw;
62+
flex-direction: column;
1463
}
1564

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

2271
.graph {
23-
padding: 50px;
24-
background-color: rgb(240, 242, 245);
25-
height: -webkit-fill-available;
26-
flex: 80;
72+
padding: 50px;
73+
background-color: var(--bg-primary);
74+
height: -webkit-fill-available;
75+
flex: 80;
2776
}
2877

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

3382
.middle {
34-
display: flex;
35-
justify-content: center;
36-
align-items: center;
83+
display: flex;
84+
justify-content: center;
85+
align-items: center;
3786
}
3887

3988
.btn {
40-
display: inline-block;
41-
font-weight: 400;
42-
color: #212529;
43-
text-align: center;
44-
vertical-align: middle;
45-
-webkit-user-select: none;
46-
-ms-user-select: none;
47-
user-select: none;
48-
background-color: transparent;
49-
border: 1px solid transparent;
50-
padding: .375rem .75rem;
51-
line-height: 1.5;
52-
border-radius: .25rem;
89+
display: inline-block;
90+
font-weight: 400;
91+
color: var(--text-primary);
92+
text-align: center;
93+
vertical-align: middle;
94+
-webkit-user-select: none;
95+
-ms-user-select: none;
96+
user-select: none;
97+
background-color: transparent;
98+
border: 1px solid var(--border-transparent);
99+
padding: .375rem .75rem;
100+
line-height: 1.5;
101+
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) {
68-
cursor: pointer;
117+
cursor: pointer;
69118
}
70119

71120
@media screen and (max-width: 1000px) {
72-
.graph {
73-
padding: 40px;
74-
}
121+
.graph {
122+
padding: 40px;
123+
}
75124
}
76125

77126
@media screen and (max-width: 650px) {
78-
.graph {
79-
padding: 35px;
80-
}
127+
.graph {
128+
padding: 35px;
129+
}
81130
}
82131

83132
@media screen and (max-width: 500px) {
84-
.graph {
85-
padding: 20px;
86-
}
133+
.graph {
134+
padding: 20px;
135+
}
87136
}

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: 21 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, FaSun } 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,25 @@ 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+
padding: '0 15px',
56+
display: 'flex',
57+
alignItems: 'center',
58+
justifyContent: 'center',
59+
transition: 'opacity 0.2s',
60+
}}
61+
onMouseEnter={(e) => { e.currentTarget.style.opacity = '0.7'; }}
62+
onMouseLeave={(e) => { e.currentTarget.style.opacity = '1'; }}
63+
role="button"
64+
tabIndex={0}
65+
onKeyDown={(e) => e.key === 'Enter' && dispatcher({ type: T.TOGGLE_DARK_MODE })}
66+
aria-label="Toggle dark mode"
67+
>
68+
{superState.darkMode ? <FaSun size={20} /> : <FaMoon size={20} />}
69+
</div>
4970
<FullScreenButton />
5071
</div>
5172
<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>

0 commit comments

Comments
 (0)