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