diff --git a/app/lib/frontend/templates/views/shared/site_header.dart b/app/lib/frontend/templates/views/shared/site_header.dart index 0f3c93c5f..fddec6bb3 100644 --- a/app/lib/frontend/templates/views/shared/site_header.dart +++ b/app/lib/frontend/templates/views/shared/site_header.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:pub_dev/frontend/request_context.dart'; + import '../../../../account/models.dart' show SessionData; import '../../../../shared/urls.dart' as urls; import '../../../dom/dom.dart' as d; @@ -109,12 +111,26 @@ d.Node siteHeaderNode({ _foldableMobileLinks('Dart', _dartLinks), if (userSession != null && userSession.isAuthenticated) _userBlock(userSession), + _themeSwitcher(), ], ), ], ); } +d.Node _themeSwitcher() { + // dark_mode + // light_mode + if (requestContext.experimentalFlags.isDarkModeEnabled) { + return d.fragment([ + d.button( + classes: ['-pub-theme-toggle'], ariaLabel: 'light/dark theme toggle'), + ]); + } else { + return d.fragment([]); + } +} + d.Node _userBlock(SessionData userSession) { return d.div( classes: ['nav-container', 'nav-profile-container', 'hoverable'], diff --git a/pkg/web_app/lib/script.dart b/pkg/web_app/lib/script.dart index d5556fb6c..269ffaf2f 100644 --- a/pkg/web_app/lib/script.dart +++ b/pkg/web_app/lib/script.dart @@ -26,6 +26,7 @@ void main() { window.onPageShow.listen((_) { adjustQueryTextAfterPageShow(); }); + _setupDarkThemeButton(); } void _setupAllEvents() { @@ -39,3 +40,16 @@ void _setupAllEvents() { setupLikesList(); setupScreenshotCarousel(); } + +void _setupDarkThemeButton() { + final button = document.querySelector('button.-pub-theme-toggle'); + if (button != null) { + button.onClick.listen((_) { + final classes = document.body!.classes; + final isCurrentlyDark = classes.contains('dark-theme'); + window.localStorage['colorTheme'] = isCurrentlyDark ? 'false' : 'true'; + classes.toggle('dark-theme'); + classes.toggle('light-theme'); + }); + } +} diff --git a/pkg/web_css/lib/src/_site_header.scss b/pkg/web_css/lib/src/_site_header.scss index 30d406ba9..05e68cfe3 100644 --- a/pkg/web_css/lib/src/_site_header.scss +++ b/pkg/web_css/lib/src/_site_header.scss @@ -65,6 +65,18 @@ } } + button.-pub-theme-toggle { + display: block; + background-color: transparent; + width: 24px; + background-position: center; + margin: 0 18px; + background-image: url("../img/light-mode-symbol-888888.svg"); + background-size: 100%; + background-repeat: no-repeat; + opacity: 0.8; + } + a.logo { display: inline-block; height: 30px; diff --git a/static/img/light-mode-symbol-888888.svg b/static/img/light-mode-symbol-888888.svg new file mode 100755 index 000000000..14ca634f4 --- /dev/null +++ b/static/img/light-mode-symbol-888888.svg @@ -0,0 +1 @@ + \ No newline at end of file