diff --git a/package-lock.json b/package-lock.json index 8f794317..43100e1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@hapi/joi": "^16.1.8", "auto-launch": "^5.0.5", "bootstrap": "^4.6.0", + "bootstrap-dark": "^1.0.3", "brace-expansion": "^2.0.0", "classnames": "^2.3.1", "electron-context-menu": "^2.5.0", @@ -88,7 +89,7 @@ "sass-loader": "^10.2.0", "shebang-loader": "^0.0.1", "spectron": "^14.0.0", - "style-loader": "^0.23.1", + "style-loader": "^2.0.0", "typescript": "^4.3.4", "url-loader": "^1.1.2", "webpack": "^4.44.2", @@ -8576,6 +8577,14 @@ "popper.js": "^1.16.1" } }, + "node_modules/bootstrap-dark": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bootstrap-dark/-/bootstrap-dark-1.0.3.tgz", + "integrity": "sha512-HH/141KZ/3hm6zKKGSX/xyHlp9C0id66B9miVKFHptrBTdbC2ZEzRu0X/jw+5M2M+2kb5xgPbUfctuWaZ25GYg==", + "dependencies": { + "bootstrap": ">=4.3" + } + }, "node_modules/boxen": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", @@ -25117,16 +25126,55 @@ } }, "node_modules/style-loader": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", - "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz", + "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", "dev": true, "dependencies": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" }, "engines": { - "node": ">= 0.12.0" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/style-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/style-loader/node_modules/schema-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.0.tgz", + "integrity": "sha512-tTEaeYkyIhEZ9uWgAjDerWov3T9MgX8dhhy2r0IGeeX4W8ngtGl1++dUve/RUqzuaASSh7shwCDJjEzthxki8w==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.7", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/sumchecker": { @@ -34835,6 +34883,14 @@ "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==", "requires": {} }, + "bootstrap-dark": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bootstrap-dark/-/bootstrap-dark-1.0.3.tgz", + "integrity": "sha512-HH/141KZ/3hm6zKKGSX/xyHlp9C0id66B9miVKFHptrBTdbC2ZEzRu0X/jw+5M2M+2kb5xgPbUfctuWaZ25GYg==", + "requires": { + "bootstrap": ">=4.3" + } + }, "boxen": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", @@ -48292,13 +48348,37 @@ } }, "style-loader": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", - "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz", + "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", "dev": true, "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.0.tgz", + "integrity": "sha512-tTEaeYkyIhEZ9uWgAjDerWov3T9MgX8dhhy2r0IGeeX4W8ngtGl1++dUve/RUqzuaASSh7shwCDJjEzthxki8w==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } } }, "sumchecker": { diff --git a/package.json b/package.json index b29fa176..a866dc4d 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "sass-loader": "^10.2.0", "shebang-loader": "^0.0.1", "spectron": "^14.0.0", - "style-loader": "^0.23.1", + "style-loader": "^2.0.0", "typescript": "^4.3.4", "url-loader": "^1.1.2", "webpack": "^4.44.2", @@ -123,6 +123,7 @@ "@hapi/joi": "^16.1.8", "auto-launch": "^5.0.5", "bootstrap": "^4.6.0", + "bootstrap-dark": "^1.0.3", "brace-expansion": "^2.0.0", "classnames": "^2.3.1", "electron-context-menu": "^2.5.0", diff --git a/src/common/communication.ts b/src/common/communication.ts index 1beabb3f..48e15e90 100644 --- a/src/common/communication.ts +++ b/src/common/communication.ts @@ -20,6 +20,7 @@ export const EMIT_CONFIGURATION = 'emit-configuration'; export const UPDATE_TEAMS = 'update-teams'; export const DARK_MODE_CHANGE = 'dark_mode_change'; +export const GET_DARK_MODE = 'get-dark-mode'; export const USER_ACTIVITY_UPDATE = 'user-activity-update'; export const LOAD_RETRY = 'load_retry'; diff --git a/src/main/preload/modalPreload.js b/src/main/preload/modalPreload.js index f1d319ee..d68ffafe 100644 --- a/src/main/preload/modalPreload.js +++ b/src/main/preload/modalPreload.js @@ -6,7 +6,7 @@ import {ipcRenderer} from 'electron'; -import {MODAL_CANCEL, MODAL_RESULT, MODAL_INFO, RETRIEVE_MODAL_INFO, MODAL_SEND_IPC_MESSAGE} from 'common/communication'; +import {MODAL_CANCEL, MODAL_RESULT, MODAL_INFO, RETRIEVE_MODAL_INFO, MODAL_SEND_IPC_MESSAGE, GET_DARK_MODE, DARK_MODE_CHANGE} from 'common/communication'; console.log('preloaded for the modal!'); @@ -30,6 +30,10 @@ window.addEventListener('message', async (event) => { console.log('sending custom ipc message'); ipcRenderer.send(event.data.data.type, ...event.data.data.args); break; + case GET_DARK_MODE: + console.log('getting dark mode value'); + window.postMessage({type: DARK_MODE_CHANGE, data: await ipcRenderer.invoke(GET_DARK_MODE)}, window.location.href); + break; default: console.log(`got a message: ${event}`); console.log(event); @@ -41,3 +45,7 @@ window.addEventListener('keydown', (e) => { ipcRenderer.send(MODAL_CANCEL); } }); + +ipcRenderer.on(DARK_MODE_CHANGE, (event, darkMode) => { + window.postMessage({type: DARK_MODE_CHANGE, data: darkMode}, window.location.href); +}); diff --git a/src/main/views/modalManager.ts b/src/main/views/modalManager.ts index e68e9252..bda8e88e 100644 --- a/src/main/views/modalManager.ts +++ b/src/main/views/modalManager.ts @@ -4,7 +4,9 @@ import {BrowserWindow, ipcMain} from 'electron'; import {IpcMainEvent, IpcMainInvokeEvent} from 'electron/main'; -import {RETRIEVE_MODAL_INFO, MODAL_CANCEL, MODAL_RESULT, MODAL_OPEN, MODAL_CLOSE} from 'common/communication'; +import {CombinedConfig} from 'types/config'; + +import {RETRIEVE_MODAL_INFO, MODAL_CANCEL, MODAL_RESULT, MODAL_OPEN, MODAL_CLOSE, EMIT_CONFIGURATION, DARK_MODE_CHANGE} from 'common/communication'; import * as WindowManager from '../windows/windowManager'; @@ -107,3 +109,9 @@ export function focusCurrentModal() { modalQueue[0].view.webContents.focus(); } } + +ipcMain.on(EMIT_CONFIGURATION, (event: IpcMainEvent, config: CombinedConfig) => { + modalQueue.forEach((modal) => { + modal.view.webContents.send(DARK_MODE_CHANGE, config.darkMode); + }); +}); diff --git a/src/main/windows/windowManager.ts b/src/main/windows/windowManager.ts index 923a368c..8ee331d7 100644 --- a/src/main/windows/windowManager.ts +++ b/src/main/windows/windowManager.ts @@ -7,7 +7,7 @@ import log from 'electron-log'; import {CombinedConfig} from 'types/config'; -import {MAXIMIZE_CHANGE, HISTORY, GET_LOADING_SCREEN_DATA, REACT_APP_INITIALIZED, LOADING_SCREEN_ANIMATION_FINISHED, FOCUS_THREE_DOT_MENU} from 'common/communication'; +import {MAXIMIZE_CHANGE, HISTORY, GET_LOADING_SCREEN_DATA, REACT_APP_INITIALIZED, LOADING_SCREEN_ANIMATION_FINISHED, FOCUS_THREE_DOT_MENU, GET_DARK_MODE} from 'common/communication'; import urlUtils from 'common/utils/url'; import {getAdjustedWindowBoundaries} from '../utils'; @@ -35,6 +35,7 @@ const assetsDir = path.resolve(app.getAppPath(), 'assets'); ipcMain.on(HISTORY, handleHistory); ipcMain.handle(GET_LOADING_SCREEN_DATA, handleLoadingScreenDataRequest); +ipcMain.handle(GET_DARK_MODE, handleGetDarkMode); ipcMain.on(REACT_APP_INITIALIZED, handleReactAppInitialized); ipcMain.on(LOADING_SCREEN_ANIMATION_FINISHED, handleLoadingScreenAnimationFinished); @@ -441,3 +442,7 @@ export function handleHistory(event: IpcMainEvent, offset: number) { } } } +function handleGetDarkMode() { + return status.config?.darkMode; +} + diff --git a/src/renderer/css/lazy/modals-dark.lazy.css b/src/renderer/css/lazy/modals-dark.lazy.css new file mode 100644 index 00000000..870d0c89 --- /dev/null +++ b/src/renderer/css/lazy/modals-dark.lazy.css @@ -0,0 +1,5 @@ +@import '~bootstrap-dark/src/bootstrap-dark.css'; + +body { + background-color: transparent; +} \ No newline at end of file diff --git a/src/renderer/css/lazy/settings-dark.lazy.css b/src/renderer/css/lazy/settings-dark.lazy.css new file mode 100644 index 00000000..02e72ce4 --- /dev/null +++ b/src/renderer/css/lazy/settings-dark.lazy.css @@ -0,0 +1,5 @@ +@import '~bootstrap-dark/src/bootstrap-dark.css'; + +.TeamListItem:hover { + background: #242a30; +} \ No newline at end of file diff --git a/src/renderer/modals/certificate/certificate.tsx b/src/renderer/modals/certificate/certificate.tsx index 1d79442b..6206aea6 100644 --- a/src/renderer/modals/certificate/certificate.tsx +++ b/src/renderer/modals/certificate/certificate.tsx @@ -7,12 +7,16 @@ import {Certificate} from 'electron/renderer'; import {MODAL_CANCEL, MODAL_RESULT, RETRIEVE_MODAL_INFO} from 'common/communication'; -import SelectCertificateModal from './certificateModal'; - import 'bootstrap/dist/css/bootstrap.min.css'; import 'renderer/css/modals.css'; import 'renderer/css/components/CertificateModal.css'; +import setupDarkMode from '../darkMode'; + +import SelectCertificateModal from './certificateModal'; + +setupDarkMode(); + const handleCancel = () => { window.postMessage({type: MODAL_CANCEL}, window.location.href); }; diff --git a/src/renderer/modals/darkMode.ts b/src/renderer/modals/darkMode.ts new file mode 100644 index 00000000..f4ffe27e --- /dev/null +++ b/src/renderer/modals/darkMode.ts @@ -0,0 +1,19 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {DARK_MODE_CHANGE, GET_DARK_MODE} from 'common/communication'; + +import darkStyles from 'renderer/css/lazy/modals-dark.lazy.css'; + +export default function addDarkModeListener() { + window.addEventListener('message', async (event) => { + if (event.data.type === DARK_MODE_CHANGE) { + if (event.data.data) { + darkStyles.use(); + } else { + darkStyles.unuse(); + } + } + }); + window.postMessage({type: GET_DARK_MODE}, window.location.href); +} diff --git a/src/renderer/modals/login/login.tsx b/src/renderer/modals/login/login.tsx index 30eb7a92..1d119149 100644 --- a/src/renderer/modals/login/login.tsx +++ b/src/renderer/modals/login/login.tsx @@ -7,11 +7,15 @@ import {AuthenticationResponseDetails} from 'electron/renderer'; import {MODAL_CANCEL, MODAL_RESULT, RETRIEVE_MODAL_INFO} from 'common/communication'; -import LoginModal from './loginModal'; - import 'bootstrap/dist/css/bootstrap.min.css'; import 'renderer/css/modals.css'; +import setupDarkMode from '../darkMode'; + +import LoginModal from './loginModal'; + +setupDarkMode(); + const handleLoginCancel = (request: AuthenticationResponseDetails) => { window.postMessage({type: MODAL_CANCEL, data: {request}}, window.location.href); }; diff --git a/src/renderer/modals/newServer/newServer.tsx b/src/renderer/modals/newServer/newServer.tsx index 2c6e1835..5c7d83b6 100644 --- a/src/renderer/modals/newServer/newServer.tsx +++ b/src/renderer/modals/newServer/newServer.tsx @@ -13,6 +13,10 @@ import {MODAL_CANCEL, MODAL_RESULT} from 'common/communication'; import NewTeamModal from '../../components/NewTeamModal'; //'./addServer.jsx'; +import setupDarkMode from '../darkMode'; + +setupDarkMode(); + const onClose = () => { window.postMessage({type: MODAL_CANCEL}, window.location.href); }; diff --git a/src/renderer/modals/permission/permission.tsx b/src/renderer/modals/permission/permission.tsx index 2f664336..c7685081 100644 --- a/src/renderer/modals/permission/permission.tsx +++ b/src/renderer/modals/permission/permission.tsx @@ -6,11 +6,15 @@ import ReactDOM from 'react-dom'; import {MODAL_CANCEL, MODAL_RESULT, RETRIEVE_MODAL_INFO, MODAL_SEND_IPC_MESSAGE} from 'common/communication'; -import PermissionModal from './permissionModal'; - import 'bootstrap/dist/css/bootstrap.min.css'; import 'renderer/css/modals.css'; +import setupDarkMode from '../darkMode'; + +import PermissionModal from './permissionModal'; + +setupDarkMode(); + const handleDeny = () => { window.postMessage({type: MODAL_CANCEL}, window.location.href); }; diff --git a/src/renderer/settings.tsx b/src/renderer/settings.tsx index 73ac1bf0..9c292236 100644 --- a/src/renderer/settings.tsx +++ b/src/renderer/settings.tsx @@ -9,8 +9,23 @@ import 'renderer/css/settings.css'; import React from 'react'; import ReactDOM from 'react-dom'; +import {DARK_MODE_CHANGE, GET_DARK_MODE} from 'common/communication'; + +import darkStyles from 'renderer/css/lazy/settings-dark.lazy.css'; + import SettingsPage from './components/SettingsPage'; +const setDarkMode = (darkMode: boolean) => { + if (darkMode) { + darkStyles.use(); + } else { + darkStyles.unuse(); + } +}; + +window.ipcRenderer.on(DARK_MODE_CHANGE, (_, darkMode) => setDarkMode(darkMode)); +window.ipcRenderer.invoke(GET_DARK_MODE).then(setDarkMode); + const start = async () => { ReactDOM.render( , diff --git a/src/types/external/file-types.d.ts b/src/types/external/file-types.d.ts index dcbe0024..3bb48df7 100644 --- a/src/types/external/file-types.d.ts +++ b/src/types/external/file-types.d.ts @@ -3,3 +3,4 @@ declare module '*.mp3'; declare module '*.svg'; +declare module '*.lazy.css'; diff --git a/webpack.config.renderer.js b/webpack.config.renderer.js index 83b8863d..49a54f16 100644 --- a/webpack.config.renderer.js +++ b/webpack.config.renderer.js @@ -100,10 +100,22 @@ module.exports = merge(base, { }, }, { test: /\.css$/, + exclude: /\.lazy\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', ], + }, { + test: /\.lazy\.css$/, + use: [ + { + loader: 'style-loader', + options: { + injectType: 'lazyStyleTag', + }, + }, + 'css-loader', + ], }, { test: /\.scss$/, use: [