diff --git a/app/assets/css/vendor-override.css b/app/assets/css/vendor-override.css index 2c8d8a6e5..646c4fcf2 100644 --- a/app/assets/css/vendor-override.css +++ b/app/assets/css/vendor-override.css @@ -269,6 +269,7 @@ json-tree .branch-preview { .panel { border: 1px solid var(--border-panel-color); + background-color: var(--bg-panel-body-color); } .theme-information .col-sm-12 { diff --git a/app/portainer/components/theme/theme-settings.controller.js b/app/portainer/components/theme/theme-settings.controller.js index b65e4553a..e85c92d7d 100644 --- a/app/portainer/components/theme/theme-settings.controller.js +++ b/app/portainer/components/theme/theme-settings.controller.js @@ -25,7 +25,11 @@ export default class ThemeSettingsController { } setTheme(theme) { - this.ThemeManager.setTheme(theme); + if (theme === 'auto' || !theme) { + this.ThemeManager.autoTheme(); + } else { + this.ThemeManager.setTheme(theme); + } this.state.themeInProgress = true; } @@ -35,7 +39,7 @@ export default class ThemeSettingsController { userId: null, userTheme: '', initTheme: '', - defaultTheme: 'light', + defaultTheme: 'auto', themeInProgress: false, }; @@ -43,14 +47,9 @@ export default class ThemeSettingsController { buildOption('light', 'fas fa-sun', 'Light Theme', 'Default color mode', 'light'), buildOption('dark', 'fas fa-moon', 'Dark Theme', 'Dark color mode', 'dark'), buildOption('highcontrast', 'fas fa-adjust', 'High Contrast', 'High contrast color mode', 'highcontrast'), + buildOption('auto', 'fas fa-sync-alt', 'Auto', 'Sync with system theme', 'auto'), ]; - this.state.availableTheme = { - light: 'light', - dark: 'dark', - highContrast: 'highcontrast', - }; - try { this.state.userId = await this.Authentication.getUserDetails().ID; const data = await this.UserService.user(this.state.userId); diff --git a/app/portainer/services/authentication.js b/app/portainer/services/authentication.js index 3a5073301..406c03368 100644 --- a/app/portainer/services/authentication.js +++ b/app/portainer/services/authentication.js @@ -88,7 +88,11 @@ angular.module('portainer.app').factory('Authentication', [ const data = await UserService.user(user.ID); // Initialize user theme base on Usertheme from database const userTheme = data.UserTheme; - ThemeManager.setTheme(userTheme); + if (userTheme === 'auto' || !userTheme) { + ThemeManager.autoTheme(); + } else { + ThemeManager.setTheme(userTheme); + } } async function setUser(jwt) { diff --git a/app/portainer/services/themeManager.js b/app/portainer/services/themeManager.js index 9cf18137b..b5b634645 100644 --- a/app/portainer/services/themeManager.js +++ b/app/portainer/services/themeManager.js @@ -5,6 +5,7 @@ angular.module('portainer.app').service('ThemeManager', ThemeManager); export function ThemeManager(StateManager) { return { setTheme, + autoTheme, defaultTheme, }; @@ -13,8 +14,13 @@ export function ThemeManager(StateManager) { document.documentElement.removeAttribute('theme'); } else { document.documentElement.setAttribute('theme', theme); + StateManager.updateTheme(theme); } - StateManager.updateTheme(theme); + } + + function autoTheme() { + const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : ''; + this.setTheme(systemTheme); } function defaultTheme() { diff --git a/app/portainer/views/logout/logoutController.js b/app/portainer/views/logout/logoutController.js index 43c9d8878..5db7c8ba5 100644 --- a/app/portainer/views/logout/logoutController.js +++ b/app/portainer/views/logout/logoutController.js @@ -2,7 +2,7 @@ import angular from 'angular'; class LogoutController { /* @ngInject */ - constructor($async, $state, $transition$, $window, Authentication, StateManager, Notifications, LocalStorage, SettingsService, ThemeManager) { + constructor($async, $state, $transition$, $window, Authentication, StateManager, Notifications, LocalStorage, SettingsService) { this.$async = $async; this.$state = $state; this.$transition$ = $transition$; @@ -13,7 +13,6 @@ class LogoutController { this.Notifications = Notifications; this.LocalStorage = LocalStorage; this.SettingsService = SettingsService; - this.ThemeManager = ThemeManager; this.logo = this.StateManager.getState().application.logo; this.logoutAsync = this.logoutAsync.bind(this); @@ -29,8 +28,6 @@ class LogoutController { const performApiLogout = this.$transition$.params().performApiLogout; const settings = await this.SettingsService.publicSettings(); - this.ThemeManager.defaultTheme(); - try { await this.Authentication.logout(performApiLogout); } finally { diff --git a/app/portainer/views/main/mainController.js b/app/portainer/views/main/mainController.js index a942b62f3..977891fa9 100644 --- a/app/portainer/views/main/mainController.js +++ b/app/portainer/views/main/mainController.js @@ -4,7 +4,7 @@ angular.module('portainer.app').controller('MainController', [ 'StateManager', 'EndpointProvider', 'ThemeManager', - function ($scope, LocalStorage, StateManager, EndpointProvider) { + function ($scope, LocalStorage, StateManager, EndpointProvider, ThemeManager) { /** * Sidebar Toggle & Cookie Control */ @@ -33,5 +33,7 @@ angular.module('portainer.app').controller('MainController', [ window.onresize = function () { $scope.$apply(); }; + + ThemeManager.autoTheme(); }, ]);