From 8af909a1f095f55ec5b75cdc5fe5dcdb917cdeb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20T=C3=B6pfer?= Date: Sat, 21 Dec 2024 16:50:52 +0100 Subject: [PATCH 1/6] First experiments with dark mode --- src/components/layout/Layout/Layout.js | 7 +++++-- src/components/layout/PageContent/PageContent.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/layout/Layout/Layout.js b/src/components/layout/Layout/Layout.js index 82bcf7886..8c7b7f21d 100644 --- a/src/components/layout/Layout/Layout.js +++ b/src/components/layout/Layout/Layout.js @@ -21,8 +21,10 @@ const Layout = ({ relatedGroupId, memberGroups, fetchManyGroupsStatus, -}) => ( -
+}) => { + const darkMode = true; // TODO: this should be based on user settings + return ( +
); +}; Layout.propTypes = { isLoggedIn: PropTypes.bool, diff --git a/src/components/layout/PageContent/PageContent.js b/src/components/layout/PageContent/PageContent.js index fac117b43..9646bb416 100644 --- a/src/components/layout/PageContent/PageContent.js +++ b/src/components/layout/PageContent/PageContent.js @@ -27,7 +27,7 @@ const PageContent = ({ intl: { formatMessage }, title = '', windowTitle = null, {(title || icon) && (
-

+

{icon && ( {typeof icon === 'string' ? : icon} )} From af6d725d90bdc546ff90e759dfd15769ccf5daee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20T=C3=B6pfer?= Date: Sat, 21 Dec 2024 19:41:43 +0100 Subject: [PATCH 2/6] Save color mode to local storage --- .../forms/EditUserUIDataForm/EditUserUIDataForm.js | 10 ++++++++++ src/components/layout/Layout/Layout.js | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/forms/EditUserUIDataForm/EditUserUIDataForm.js b/src/components/forms/EditUserUIDataForm/EditUserUIDataForm.js index 520fc21ff..aa2a17d72 100644 --- a/src/components/forms/EditUserUIDataForm/EditUserUIDataForm.js +++ b/src/components/forms/EditUserUIDataForm/EditUserUIDataForm.js @@ -10,6 +10,7 @@ import { SaveIcon } from '../../icons'; import Explanation from '../../widgets/Explanation'; import SubmitButton from '../SubmitButton'; import { CheckboxField, SelectField, NumericTextField } from '../Fields'; +import OnOffCheckbox from '../OnOffCheckbox'; const defaultPagesCaptions = defineMessages({ dashboard: { @@ -51,6 +52,7 @@ const EditUserUIDataForm = ({ invalid, intl: { formatMessage }, }) => ( + <> } type={submitSucceeded ? 'success' : undefined} @@ -180,6 +182,14 @@ const EditUserUIDataForm = ({ } /> + {/* TODO: this is a temporary workaround (saving dark mode to local storage). It should be properly saved to the user UI data. */} +
+ { + localStorage.setItem('colorMode', event.target.checked ? 'dark' : 'light'); + }}>Dark Mode +
+ ); EditUserUIDataForm.propTypes = { diff --git a/src/components/layout/Layout/Layout.js b/src/components/layout/Layout/Layout.js index 8c7b7f21d..60903d050 100644 --- a/src/components/layout/Layout/Layout.js +++ b/src/components/layout/Layout/Layout.js @@ -22,9 +22,10 @@ const Layout = ({ memberGroups, fetchManyGroupsStatus, }) => { - const darkMode = true; // TODO: this should be based on user settings + // TODO: this should be based on user settings + const colorMode = localStorage.getItem('colorMode') ?? 'light'; return ( -
+
Date: Sat, 21 Dec 2024 19:58:58 +0100 Subject: [PATCH 3/6] Update dark styles --- src/components/layout/Navigation/Navigation.less | 4 ++++ src/components/widgets/Box/Box.js | 2 +- src/components/widgets/InsetPanel/InsetPanel.less | 5 +++++ src/containers/App/recodex.css | 4 ++++ .../SisSupervisorGroupsContainer.js | 2 +- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/layout/Navigation/Navigation.less b/src/components/layout/Navigation/Navigation.less index 5d1806532..36be41a45 100644 --- a/src/components/layout/Navigation/Navigation.less +++ b/src/components/layout/Navigation/Navigation.less @@ -34,3 +34,7 @@ color: var(--success); text-shadow: 0.1rem 0.1rem 0.3rem #aaa; } + +[data-bs-theme=dark] .links > strong { + text-shadow: 0.1rem 0.1rem 0.3rem #666; +} diff --git a/src/components/widgets/Box/Box.js b/src/components/widgets/Box/Box.js index 874503a64..3da07524c 100644 --- a/src/components/widgets/Box/Box.js +++ b/src/components/widgets/Box/Box.js @@ -59,7 +59,7 @@ class Box extends Component { title, flexTitle = false, description = null, - type = 'light', + type = null, solid = false, collapsable = false, noPadding = false, diff --git a/src/components/widgets/InsetPanel/InsetPanel.less b/src/components/widgets/InsetPanel/InsetPanel.less index dcfce8b43..999751308 100644 --- a/src/components/widgets/InsetPanel/InsetPanel.less +++ b/src/components/widgets/InsetPanel/InsetPanel.less @@ -14,6 +14,11 @@ } +[data-bs-theme=dark] .insetPanel { + background-color: var(--bs-secondary-bg); + border: 1px solid var(--bs-secondary-border-subtle); +} + .large { padding: 24px; border-radius: 5px; diff --git a/src/containers/App/recodex.css b/src/containers/App/recodex.css index 461a9594d..938fc2b59 100644 --- a/src/containers/App/recodex.css +++ b/src/containers/App/recodex.css @@ -128,6 +128,10 @@ table.table.tbody-hover tbody:hover th.selected { background-color: rgba(128, 128, 128, 0.1); padding: 0.5rem; } +[data-bs-theme=dark] .recodex-markdown-container pre { + border: 1px solid var(--bs-secondary-border-subtle); + background-color: var(--bs-secondary-bg); +} /* * AdminLTE Enhancements and Overrides diff --git a/src/containers/SisSupervisorGroupsContainer/SisSupervisorGroupsContainer.js b/src/containers/SisSupervisorGroupsContainer/SisSupervisorGroupsContainer.js index e47db82e9..5b5cdf429 100644 --- a/src/containers/SisSupervisorGroupsContainer/SisSupervisorGroupsContainer.js +++ b/src/containers/SisSupervisorGroupsContainer/SisSupervisorGroupsContainer.js @@ -250,7 +250,7 @@ class SisSupervisorGroupsContainer extends Component { ) || a.course.code.localeCompare(b.course.code, locale) ) .map(course => ( - + {course && ( From e8d6a6e05a797967ed9b9880e3feed7a700df0c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20T=C3=B6pfer?= Date: Wed, 1 Jan 2025 14:02:11 +0100 Subject: [PATCH 4/6] Load color mode from UserUIData --- .../forms/EditUserUIDataForm/EditUserUIDataForm.js | 9 --------- src/components/layout/Layout/Layout.js | 6 +++--- src/containers/LayoutContainer/LayoutContainer.js | 3 ++- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/components/forms/EditUserUIDataForm/EditUserUIDataForm.js b/src/components/forms/EditUserUIDataForm/EditUserUIDataForm.js index aa2a17d72..bd8cc9693 100644 --- a/src/components/forms/EditUserUIDataForm/EditUserUIDataForm.js +++ b/src/components/forms/EditUserUIDataForm/EditUserUIDataForm.js @@ -52,7 +52,6 @@ const EditUserUIDataForm = ({ invalid, intl: { formatMessage }, }) => ( - <> } type={submitSucceeded ? 'success' : undefined} @@ -182,14 +181,6 @@ const EditUserUIDataForm = ({ } /> - {/* TODO: this is a temporary workaround (saving dark mode to local storage). It should be properly saved to the user UI data. */} -
- { - localStorage.setItem('colorMode', event.target.checked ? 'dark' : 'light'); - }}>Dark Mode -
- ); EditUserUIDataForm.propTypes = { diff --git a/src/components/layout/Layout/Layout.js b/src/components/layout/Layout/Layout.js index 60903d050..90a127e0b 100644 --- a/src/components/layout/Layout/Layout.js +++ b/src/components/layout/Layout/Layout.js @@ -21,11 +21,10 @@ const Layout = ({ relatedGroupId, memberGroups, fetchManyGroupsStatus, + colorTheme, }) => { - // TODO: this should be based on user settings - const colorMode = localStorage.getItem('colorMode') ?? 'light'; return ( -
+
+ fetchManyGroupsStatus={fetchManyGroupsStatus} + colorTheme={userUIData.darkTheme ? 'dark' : 'light' /* TODO: we might want to add a new option for global color theme, 'darkTheme' was originally used only for text editors */}> {buildRoutes(pathname + search, isLoggedIn)} From 5811fd7a2cee6e2a0e4b1dc2a9cef8590927d491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20T=C3=B6pfer?= Date: Mon, 21 Apr 2025 10:33:56 +0200 Subject: [PATCH 5/6] Update source code (review) to dark mode --- .../SourceCodeViewer/SourceCodeViewer.css | 58 +++++++++++++++++++ .../SourceCodeViewer/SourceCodeViewer.js | 34 ++++++----- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/components/helpers/SourceCodeViewer/SourceCodeViewer.css b/src/components/helpers/SourceCodeViewer/SourceCodeViewer.css index 0ff109a63..3f679bbdd 100644 --- a/src/components/helpers/SourceCodeViewer/SourceCodeViewer.css +++ b/src/components/helpers/SourceCodeViewer/SourceCodeViewer.css @@ -156,3 +156,61 @@ pre .sourceCodeViewerComments, code .sourceCodeViewerComments { .sourceCodeViewer.addComment .scvAddButton:hover::before { opacity: 1; } + +[data-bs-theme=dark] { + .sourceCodeViewer span[data-line] .linenumber { + background-color: #2b3035; + color: #b0b0b0; + } + + .sourceCodeViewer span[data-line]:hover, .sourceCodeViewer span[data-line]:hover * { + background-color: #2b3035; + } + + .sourceCodeViewer span[data-line]:hover .linenumber { + background-color: #343a40; + } + + .sourceCodeViewer span[data-line-active] { + background-color: #333c1a; + } + + .sourceCodeViewer span[data-line-active] .linenumber { + background-color: #495c1a; + } + + .sourceCodeViewer span[data-line-active]:hover, .sourceCodeViewer span[data-line-active]:hover * { + background-color: #3d4420; + } + + .sourceCodeViewer span[data-line-active]:hover .linenumber { + background-color: #5a6b1a; + } + + .sourceCodeViewerComments { + background-color: #2b3035; + } + + .sourceCodeViewerComments > div { + border: 1px solid #343a40; + background-color: var(--bs-card-bg); + } + + .sourceCodeViewerComments > div.issue { + background-color: #3a2323; + } + + .sourceCodeViewerComments > div.commentForm { + background-color: #23271a; + } + + /* Markdown overrides */ + + .sourceCodeViewerComments > div > .recodex-markdown-container { + border-top: 1px solid #343a40; + } + + .sourceCodeViewerComments > div.issue > .recodex-markdown-container { + border-top-color: #4a2a2a; + } +} \ No newline at end of file diff --git a/src/components/helpers/SourceCodeViewer/SourceCodeViewer.js b/src/components/helpers/SourceCodeViewer/SourceCodeViewer.js index 6bc1c1b24..551804dc5 100644 --- a/src/components/helpers/SourceCodeViewer/SourceCodeViewer.js +++ b/src/components/helpers/SourceCodeViewer/SourceCodeViewer.js @@ -2,12 +2,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Prism as SyntaxHighlighter, createElement } from 'react-syntax-highlighter'; import { lruMemoize } from 'reselect'; -import { vs } from 'react-syntax-highlighter/dist/esm/styles/prism'; -import 'prismjs/themes/prism.css'; +import { prism, okaidia } from 'react-syntax-highlighter/dist/esm/styles/prism'; import ReviewCommentForm, { newCommentFormInitialValues } from '../../forms/ReviewCommentForm'; import { getPrismModeFromExtension } from '../../helpers/syntaxHighlighting.js'; import { getFileExtensionLC, canUseDOM } from '../../../helpers/common.js'; +import { UserUIDataContext } from '../../../helpers/contexts.js'; import SourceCodeComment from './SourceCodeComment.js'; import './SourceCodeViewer.css'; @@ -161,19 +161,23 @@ class SourceCodeViewer extends React.Component { render() { const { name, content = '', addComment } = this.props; return canUseDOM ? ( - - {content} - + + {({ darkTheme = false }) => ( + + {content} + )} + ) : ( <> ); From 2d4c301bd01b6ef5b8a8f03ac67de8bd22dac6c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20T=C3=B6pfer?= Date: Mon, 21 Apr 2025 11:21:03 +0200 Subject: [PATCH 6/6] Update dark styles --- .../Assignments/SolutionsTable/SolutionsTable.less | 10 ++++++++++ .../Groups/ResultsTable/ResultsTable.less | 13 +++++++++++-- .../EditExerciseSimpleConfigForm.css | 12 ++++++++++++ src/containers/App/recodex.css | 12 ++++++++++-- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/components/Assignments/SolutionsTable/SolutionsTable.less b/src/components/Assignments/SolutionsTable/SolutionsTable.less index 353b42edf..7c5e80228 100644 --- a/src/components/Assignments/SolutionsTable/SolutionsTable.less +++ b/src/components/Assignments/SolutionsTable/SolutionsTable.less @@ -21,3 +21,13 @@ table.solutionsTable td.noteRow { table.solutionsTable tbody:hover td { background-color: #f4f4f4; } + +[data-bs-theme=dark] { + table.solutionsTable tbody { + border-top: 1px solid var(--bs-card-border-color); + } + + table.solutionsTable tbody:hover td { + background-color: var(--bs-secondary-bg); + } +} \ No newline at end of file diff --git a/src/components/Groups/ResultsTable/ResultsTable.less b/src/components/Groups/ResultsTable/ResultsTable.less index 07e9a8a03..754079fd3 100644 --- a/src/components/Groups/ResultsTable/ResultsTable.less +++ b/src/components/Groups/ResultsTable/ResultsTable.less @@ -22,11 +22,20 @@ } .bonusPoints { - color: green; + color: var(--bs-success); } .malusPoints { - color: red; + color: var(--bs-danger); +} + +[data-bs-theme="dark"] { + .bonusPoints { + color: var(--bs-success-text-emphasis); + } + .malusPoints { + color: var(--bs-danger-text-emphasis); + } } .maxPointsRow { diff --git a/src/components/forms/EditExerciseSimpleConfigForm/EditExerciseSimpleConfigForm.css b/src/components/forms/EditExerciseSimpleConfigForm/EditExerciseSimpleConfigForm.css index f037cb5e3..5273a8071 100644 --- a/src/components/forms/EditExerciseSimpleConfigForm/EditExerciseSimpleConfigForm.css +++ b/src/components/forms/EditExerciseSimpleConfigForm/EditExerciseSimpleConfigForm.css @@ -5,14 +5,26 @@ border-bottom: 2px solid #ddd; } +[data-bs-theme=dark] .configRow { + border-bottom: 2px solid var(--bs-secondary-border-subtle); +} + .configRow:nth-child(1) { background-color: #f4fcf4 !important; } +[data-bs-theme=dark] .configRow:nth-child(1) { + background-color: #2b352c !important; +} + .configRow:nth-child(odd) { background-color: #F9F9F9; } +[data-bs-theme=dark] .configRow:nth-child(odd) { + background-color: var(--bs-tertiary-bg); +} + .compilation { overflow: auto; } diff --git a/src/containers/App/recodex.css b/src/containers/App/recodex.css index 938fc2b59..a2cfdee49 100644 --- a/src/containers/App/recodex.css +++ b/src/containers/App/recodex.css @@ -263,7 +263,11 @@ a:focus { * Bootstrap Enhancements */ code { - color: #072; + color: var(--success); +} + +[data-bs-theme=dark] code { + color: var(--bs-success-text-emphasis); } .recodex-markdown-container code { @@ -271,7 +275,11 @@ code { } .recodex-markdown-container code:not(pre > code) { - color: #072; + color: var(--success); +} + +[data-bs-theme=dark] .recodex-markdown-container code:not(pre > code) { + color: var(--bs-success-text-emphasis); } .wider-tooltip {