From b735567504fa593662f70c440bde98a6141fb0b7 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Tue, 24 Jun 2025 14:08:40 +0200 Subject: [PATCH] Gradient hue revamp (#9093) --- l10n | 2 +- src/browser/app/profile/features/theme.inc | 1 + src/browser/app/profile/macos.inc | 2 +- .../base/content/zen-assets.jar.inc.mn | 1 - .../content/zen-panels/gradient-generator.inc | 75 +- .../shared/preferences/zen-preferences.css | 31 - src/browser/themes/shared/zen-icons/icons.css | 40 +- .../themes/shared/zen-icons/jar.inc.mn | 51 +- .../themes/shared/zen-icons/lin/face-sun.svg | 1 + .../shared/zen-icons/lin/moon-stars.svg | 1 + .../themes/shared/zen-icons/lin/sparkles.svg | 1 + src/dom/base/Document-cpp.patch | 6 +- src/widget/cocoa/nsCocoaWindow-mm.patch | 13 + .../common/styles/zen-browser-container.css | 2 +- src/zen/common/styles/zen-browser-ui.css | 6 +- src/zen/common/styles/zen-popup.css | 2 +- src/zen/common/styles/zen-theme.css | 78 +- src/zen/images/gradient.png | Bin 68548 -> 0 bytes src/zen/mods/ZenMods.mjs | 6 +- src/zen/workspaces/ZenGradientGenerator.mjs | 704 ++++++++++++------ src/zen/workspaces/ZenWorkspaceIcons.mjs | 1 + src/zen/workspaces/ZenWorkspaces.mjs | 4 +- src/zen/workspaces/overflow-icons.inc.css | 2 + src/zen/workspaces/zen-gradient-generator.css | 209 +++--- 24 files changed, 799 insertions(+), 440 deletions(-) create mode 100644 src/browser/themes/shared/zen-icons/lin/face-sun.svg create mode 100644 src/browser/themes/shared/zen-icons/lin/moon-stars.svg create mode 100644 src/browser/themes/shared/zen-icons/lin/sparkles.svg create mode 100644 src/widget/cocoa/nsCocoaWindow-mm.patch delete mode 100644 src/zen/images/gradient.png diff --git a/l10n b/l10n index 706b3333..7435b28b 160000 --- a/l10n +++ b/l10n @@ -1 +1 @@ -Subproject commit 706b33337345e4231e18313463259703b3fbc50d +Subproject commit 7435b28bdf962406f7e0ec54ed1774ede5b490a9 diff --git a/src/browser/app/profile/features/theme.inc b/src/browser/app/profile/features/theme.inc index b03c3c40..576c1bb1 100644 --- a/src/browser/app/profile/features/theme.inc +++ b/src/browser/app/profile/features/theme.inc @@ -7,6 +7,7 @@ pref('zen.theme.content-element-separation', 8); // In pixels pref('zen.theme.gradient', true); pref('zen.theme.gradient.show-custom-colors', false); pref('zen.theme.essentials-favicon-bg', true); +pref('zen.theme.window.scheme', 'auto'); // auto, light, dark #ifdef XP_MACOSX pref('zen.theme.border-radius', 10); // In pixels diff --git a/src/browser/app/profile/macos.inc b/src/browser/app/profile/macos.inc index 67c540dc..e237e401 100644 --- a/src/browser/app/profile/macos.inc +++ b/src/browser/app/profile/macos.inc @@ -11,4 +11,4 @@ pref('widget.macos.sidebar-blend-mode.behind-window', true); // 5. toolTip // 6. headerView // 7. underlay -pref('zen.widget.macos.window-material', 3); +pref('zen.widget.macos.window-material', 1); diff --git a/src/browser/base/content/zen-assets.jar.inc.mn b/src/browser/base/content/zen-assets.jar.inc.mn index c0b5488d..7e0ef36d 100644 --- a/src/browser/base/content/zen-assets.jar.inc.mn +++ b/src/browser/base/content/zen-assets.jar.inc.mn @@ -76,7 +76,6 @@ # Images - content/browser/zen-images/gradient.png (../../zen/images/gradient.png) content/browser/zen-images/brand-header.svg (../../zen/images/brand-header.svg) content/browser/zen-images/layouts/collapsed.png (../../zen/images/layouts/collapsed.png) content/browser/zen-images/layouts/multiple-toolbar.png (../../zen/images/layouts/multiple-toolbar.png) diff --git a/src/browser/base/content/zen-panels/gradient-generator.inc b/src/browser/base/content/zen-panels/gradient-generator.inc index e73cb20a..0fd734c0 100644 --- a/src/browser/base/content/zen-panels/gradient-generator.inc +++ b/src/browser/base/content/zen-panels/gradient-generator.inc @@ -5,39 +5,66 @@ - - - - - - - - - - - - - - - - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + diff --git a/src/browser/themes/shared/preferences/zen-preferences.css b/src/browser/themes/shared/preferences/zen-preferences.css index fecc4fce..5f350375 100644 --- a/src/browser/themes/shared/preferences/zen-preferences.css +++ b/src/browser/themes/shared/preferences/zen-preferences.css @@ -249,37 +249,6 @@ groupbox h2 { } } -.zenLooksAndFeelColorOption { - width: 60px; - height: 60px; - border-radius: 50%; - background: var(--zen-primary-color); - position: relative; - overflow: hidden; -} - -.zenLooksAndFeelColorOption::before { - content: ''; - display: block; - width: 50%; - height: 50%; - bottom: 0; - left: 0; - position: absolute; - background: var(--zen-colors-secondary); -} - -.zenLooksAndFeelColorOption::after { - content: ''; - display: block; - width: 50%; - height: 50%; - bottom: 0; - right: 0; - position: absolute; - background: var(--zen-colors-tertiary); -} - /* Workspace */ #category-zen-tabs-management > .category-icon { diff --git a/src/browser/themes/shared/zen-icons/icons.css b/src/browser/themes/shared/zen-icons/icons.css index af7cd472..b8df66f5 100644 --- a/src/browser/themes/shared/zen-icons/icons.css +++ b/src/browser/themes/shared/zen-icons/icons.css @@ -47,10 +47,6 @@ list-style-image: url('reload.svg') !important; } -#PanelUI-zen-gradient-generator-color-toggle-algo { - list-style-image: url('palette.svg'); -} - .tab-reset-button, #PanelUI-zen-gradient-generator-color-remove { list-style-image: url('unpin.svg') !important; @@ -101,7 +97,8 @@ list-style-image: url('chevron.svg') !important; } -#zen-rice-share-options .options-header { +#zen-rice-share-options .options-header, +#PanelUI-zen-gradient-generator-color-page-right { list-style-image: url('arrow-right.svg'); } @@ -400,7 +397,8 @@ list-style-image: url('expand-sidebar.svg') !important; } -.panel-header > .subviewbutton-back { +.panel-header > .subviewbutton-back, +#PanelUI-zen-gradient-generator-color-page-left { list-style-image: url('arrow-left.svg') !important; } @@ -768,3 +766,33 @@ background: transparent !important; } } + +#PanelUI-zen-gradient-generator-scheme-auto { + list-style-image: url('sparkles.svg'); +} + +@media -moz-pref('zen.theme.window.scheme', 'auto') { + #PanelUI-zen-gradient-generator-scheme-auto { + background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)); + } +} + +#PanelUI-zen-gradient-generator-scheme-dark { + list-style-image: url('moon-stars.svg'); +} + +@media -moz-pref('zen.theme.window.scheme', 'dark') { + #PanelUI-zen-gradient-generator-scheme-dark { + background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)); + } +} + +#PanelUI-zen-gradient-generator-scheme-light { + list-style-image: url('face-sun.svg'); +} + +@media -moz-pref('zen.theme.window.scheme', 'light') { + #PanelUI-zen-gradient-generator-scheme-light { + background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)); + } +} diff --git a/src/browser/themes/shared/zen-icons/jar.inc.mn b/src/browser/themes/shared/zen-icons/jar.inc.mn index 41218fa7..4986753b 100644 --- a/src/browser/themes/shared/zen-icons/jar.inc.mn +++ b/src/browser/themes/shared/zen-icons/jar.inc.mn @@ -35,15 +35,16 @@ skin/classic/browser/zen-icons/edit-paste.svg (../shared/zen-icons/lin/edit-paste.svg) skin/classic/browser/zen-icons/edit-redo.svg (../shared/zen-icons/lin/edit-redo.svg) skin/classic/browser/zen-icons/edit-select-all.svg (../shared/zen-icons/lin/edit-select-all.svg) - skin/classic/browser/zen-icons/edit.svg (../shared/zen-icons/lin/edit.svg) skin/classic/browser/zen-icons/edit-theme.svg (../shared/zen-icons/lin/edit-theme.svg) skin/classic/browser/zen-icons/edit-undo.svg (../shared/zen-icons/lin/edit-undo.svg) + skin/classic/browser/zen-icons/edit.svg (../shared/zen-icons/lin/edit.svg) skin/classic/browser/zen-icons/essential-add.svg (../shared/zen-icons/lin/essential-add.svg) skin/classic/browser/zen-icons/essential-remove.svg (../shared/zen-icons/lin/essential-remove.svg) skin/classic/browser/zen-icons/expand-sidebar.svg (../shared/zen-icons/lin/expand-sidebar.svg) + skin/classic/browser/zen-icons/ext-link.svg (../shared/zen-icons/lin/ext-link.svg) skin/classic/browser/zen-icons/extension-blocked.svg (../shared/zen-icons/lin/extension-blocked.svg) skin/classic/browser/zen-icons/extension.svg (../shared/zen-icons/lin/extension.svg) - skin/classic/browser/zen-icons/ext-link.svg (../shared/zen-icons/lin/ext-link.svg) + skin/classic/browser/zen-icons/face-sun.svg (../shared/zen-icons/lin/face-sun.svg) skin/classic/browser/zen-icons/firefox.svg (../shared/zen-icons/lin/firefox.svg) skin/classic/browser/zen-icons/folder.svg (../shared/zen-icons/lin/folder.svg) skin/classic/browser/zen-icons/forget.svg (../shared/zen-icons/lin/forget.svg) @@ -80,6 +81,7 @@ skin/classic/browser/zen-icons/microphone-fill.svg (../shared/zen-icons/lin/microphone-fill.svg) skin/classic/browser/zen-icons/microphone.svg (../shared/zen-icons/lin/microphone.svg) skin/classic/browser/zen-icons/midi.svg (../shared/zen-icons/lin/midi.svg) + skin/classic/browser/zen-icons/moon-stars.svg (../shared/zen-icons/lin/moon-stars.svg) skin/classic/browser/zen-icons/move-tab.svg (../shared/zen-icons/lin/move-tab.svg) skin/classic/browser/zen-icons/new-tab-image.svg (../shared/zen-icons/lin/new-tab-image.svg) skin/classic/browser/zen-icons/open.svg (../shared/zen-icons/lin/open.svg) @@ -95,27 +97,28 @@ skin/classic/browser/zen-icons/pocket-outline.svg (../shared/zen-icons/lin/pocket-outline.svg) skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/lin/popup.svg) skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/lin/print.svg) - skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/lin/privateBrowsing.svg) skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/lin/private-window.svg) + skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/lin/privateBrowsing.svg) skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/lin/reader-mode.svg) - skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/lin/reload.svg) skin/classic/browser/zen-icons/reload-to-stop.svg (../shared/zen-icons/lin/reload-to-stop.svg) + skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/lin/reload.svg) skin/classic/browser/zen-icons/report.svg (../shared/zen-icons/lin/report.svg) skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/lin/save.svg) skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/lin/screen-blocked.svg) - skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/lin/screenshot.svg) skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/lin/screen.svg) + skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/lin/screenshot.svg) skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/lin/search-glass.svg) skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/lin/search-page.svg) skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/lin/security-broken.svg) - skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/lin/security.svg) skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/lin/security-warning.svg) + skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/lin/security.svg) skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/lin/send-to-device.svg) skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/lin/settings.svg) skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/lin/share.svg) - skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/lin/sidebars-right.svg) skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/lin/sidebar.svg) + skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/lin/sidebars-right.svg) skin/classic/browser/zen-icons/source-code.svg (../shared/zen-icons/lin/source-code.svg) + skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/lin/sparkles.svg) skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/lin/spell-check.svg) skin/classic/browser/zen-icons/split.svg (../shared/zen-icons/lin/split.svg) skin/classic/browser/zen-icons/stop-to-reload.svg (../shared/zen-icons/lin/stop-to-reload.svg) @@ -174,15 +177,16 @@ skin/classic/browser/zen-icons/edit-paste.svg (../shared/zen-icons/lin/edit-paste.svg) skin/classic/browser/zen-icons/edit-redo.svg (../shared/zen-icons/lin/edit-redo.svg) skin/classic/browser/zen-icons/edit-select-all.svg (../shared/zen-icons/lin/edit-select-all.svg) - skin/classic/browser/zen-icons/edit.svg (../shared/zen-icons/lin/edit.svg) skin/classic/browser/zen-icons/edit-theme.svg (../shared/zen-icons/lin/edit-theme.svg) skin/classic/browser/zen-icons/edit-undo.svg (../shared/zen-icons/lin/edit-undo.svg) + skin/classic/browser/zen-icons/edit.svg (../shared/zen-icons/lin/edit.svg) skin/classic/browser/zen-icons/essential-add.svg (../shared/zen-icons/lin/essential-add.svg) skin/classic/browser/zen-icons/essential-remove.svg (../shared/zen-icons/lin/essential-remove.svg) skin/classic/browser/zen-icons/expand-sidebar.svg (../shared/zen-icons/lin/expand-sidebar.svg) + skin/classic/browser/zen-icons/ext-link.svg (../shared/zen-icons/lin/ext-link.svg) skin/classic/browser/zen-icons/extension-blocked.svg (../shared/zen-icons/lin/extension-blocked.svg) skin/classic/browser/zen-icons/extension.svg (../shared/zen-icons/lin/extension.svg) - skin/classic/browser/zen-icons/ext-link.svg (../shared/zen-icons/lin/ext-link.svg) + skin/classic/browser/zen-icons/face-sun.svg (../shared/zen-icons/lin/face-sun.svg) skin/classic/browser/zen-icons/firefox.svg (../shared/zen-icons/lin/firefox.svg) skin/classic/browser/zen-icons/folder.svg (../shared/zen-icons/lin/folder.svg) skin/classic/browser/zen-icons/forget.svg (../shared/zen-icons/lin/forget.svg) @@ -219,6 +223,7 @@ skin/classic/browser/zen-icons/microphone-fill.svg (../shared/zen-icons/lin/microphone-fill.svg) skin/classic/browser/zen-icons/microphone.svg (../shared/zen-icons/lin/microphone.svg) skin/classic/browser/zen-icons/midi.svg (../shared/zen-icons/lin/midi.svg) + skin/classic/browser/zen-icons/moon-stars.svg (../shared/zen-icons/lin/moon-stars.svg) skin/classic/browser/zen-icons/move-tab.svg (../shared/zen-icons/lin/move-tab.svg) skin/classic/browser/zen-icons/new-tab-image.svg (../shared/zen-icons/lin/new-tab-image.svg) skin/classic/browser/zen-icons/open.svg (../shared/zen-icons/lin/open.svg) @@ -234,27 +239,28 @@ skin/classic/browser/zen-icons/pocket-outline.svg (../shared/zen-icons/lin/pocket-outline.svg) skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/lin/popup.svg) skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/lin/print.svg) - skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/lin/privateBrowsing.svg) skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/lin/private-window.svg) + skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/lin/privateBrowsing.svg) skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/lin/reader-mode.svg) - skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/lin/reload.svg) skin/classic/browser/zen-icons/reload-to-stop.svg (../shared/zen-icons/lin/reload-to-stop.svg) + skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/lin/reload.svg) skin/classic/browser/zen-icons/report.svg (../shared/zen-icons/lin/report.svg) skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/lin/save.svg) skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/lin/screen-blocked.svg) - skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/lin/screenshot.svg) skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/lin/screen.svg) + skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/lin/screenshot.svg) skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/lin/search-glass.svg) skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/lin/search-page.svg) skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/lin/security-broken.svg) - skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/lin/security.svg) skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/lin/security-warning.svg) + skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/lin/security.svg) skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/lin/send-to-device.svg) skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/lin/settings.svg) skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/lin/share.svg) - skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/lin/sidebars-right.svg) skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/lin/sidebar.svg) + skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/lin/sidebars-right.svg) skin/classic/browser/zen-icons/source-code.svg (../shared/zen-icons/lin/source-code.svg) + skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/lin/sparkles.svg) skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/lin/spell-check.svg) skin/classic/browser/zen-icons/split.svg (../shared/zen-icons/lin/split.svg) skin/classic/browser/zen-icons/stop-to-reload.svg (../shared/zen-icons/lin/stop-to-reload.svg) @@ -313,15 +319,16 @@ skin/classic/browser/zen-icons/edit-paste.svg (../shared/zen-icons/lin/edit-paste.svg) skin/classic/browser/zen-icons/edit-redo.svg (../shared/zen-icons/lin/edit-redo.svg) skin/classic/browser/zen-icons/edit-select-all.svg (../shared/zen-icons/lin/edit-select-all.svg) - skin/classic/browser/zen-icons/edit.svg (../shared/zen-icons/lin/edit.svg) skin/classic/browser/zen-icons/edit-theme.svg (../shared/zen-icons/lin/edit-theme.svg) skin/classic/browser/zen-icons/edit-undo.svg (../shared/zen-icons/lin/edit-undo.svg) + skin/classic/browser/zen-icons/edit.svg (../shared/zen-icons/lin/edit.svg) skin/classic/browser/zen-icons/essential-add.svg (../shared/zen-icons/lin/essential-add.svg) skin/classic/browser/zen-icons/essential-remove.svg (../shared/zen-icons/lin/essential-remove.svg) skin/classic/browser/zen-icons/expand-sidebar.svg (../shared/zen-icons/lin/expand-sidebar.svg) + skin/classic/browser/zen-icons/ext-link.svg (../shared/zen-icons/lin/ext-link.svg) skin/classic/browser/zen-icons/extension-blocked.svg (../shared/zen-icons/lin/extension-blocked.svg) skin/classic/browser/zen-icons/extension.svg (../shared/zen-icons/lin/extension.svg) - skin/classic/browser/zen-icons/ext-link.svg (../shared/zen-icons/lin/ext-link.svg) + skin/classic/browser/zen-icons/face-sun.svg (../shared/zen-icons/lin/face-sun.svg) skin/classic/browser/zen-icons/firefox.svg (../shared/zen-icons/lin/firefox.svg) skin/classic/browser/zen-icons/folder.svg (../shared/zen-icons/lin/folder.svg) skin/classic/browser/zen-icons/forget.svg (../shared/zen-icons/lin/forget.svg) @@ -358,6 +365,7 @@ skin/classic/browser/zen-icons/microphone-fill.svg (../shared/zen-icons/lin/microphone-fill.svg) skin/classic/browser/zen-icons/microphone.svg (../shared/zen-icons/lin/microphone.svg) skin/classic/browser/zen-icons/midi.svg (../shared/zen-icons/lin/midi.svg) + skin/classic/browser/zen-icons/moon-stars.svg (../shared/zen-icons/lin/moon-stars.svg) skin/classic/browser/zen-icons/move-tab.svg (../shared/zen-icons/lin/move-tab.svg) skin/classic/browser/zen-icons/new-tab-image.svg (../shared/zen-icons/lin/new-tab-image.svg) skin/classic/browser/zen-icons/open.svg (../shared/zen-icons/lin/open.svg) @@ -373,27 +381,28 @@ skin/classic/browser/zen-icons/pocket-outline.svg (../shared/zen-icons/lin/pocket-outline.svg) skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/lin/popup.svg) skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/lin/print.svg) - skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/lin/privateBrowsing.svg) skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/lin/private-window.svg) + skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/lin/privateBrowsing.svg) skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/lin/reader-mode.svg) - skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/lin/reload.svg) skin/classic/browser/zen-icons/reload-to-stop.svg (../shared/zen-icons/lin/reload-to-stop.svg) + skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/lin/reload.svg) skin/classic/browser/zen-icons/report.svg (../shared/zen-icons/lin/report.svg) skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/lin/save.svg) skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/lin/screen-blocked.svg) - skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/lin/screenshot.svg) skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/lin/screen.svg) + skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/lin/screenshot.svg) skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/lin/search-glass.svg) skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/lin/search-page.svg) skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/lin/security-broken.svg) - skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/lin/security.svg) skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/lin/security-warning.svg) + skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/lin/security.svg) skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/lin/send-to-device.svg) skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/lin/settings.svg) skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/lin/share.svg) - skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/lin/sidebars-right.svg) skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/lin/sidebar.svg) + skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/lin/sidebars-right.svg) skin/classic/browser/zen-icons/source-code.svg (../shared/zen-icons/lin/source-code.svg) + skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/lin/sparkles.svg) skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/lin/spell-check.svg) skin/classic/browser/zen-icons/split.svg (../shared/zen-icons/lin/split.svg) skin/classic/browser/zen-icons/stop-to-reload.svg (../shared/zen-icons/lin/stop-to-reload.svg) diff --git a/src/browser/themes/shared/zen-icons/lin/face-sun.svg b/src/browser/themes/shared/zen-icons/lin/face-sun.svg new file mode 100644 index 00000000..20461bcf --- /dev/null +++ b/src/browser/themes/shared/zen-icons/lin/face-sun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/browser/themes/shared/zen-icons/lin/moon-stars.svg b/src/browser/themes/shared/zen-icons/lin/moon-stars.svg new file mode 100644 index 00000000..7e3698dc --- /dev/null +++ b/src/browser/themes/shared/zen-icons/lin/moon-stars.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/browser/themes/shared/zen-icons/lin/sparkles.svg b/src/browser/themes/shared/zen-icons/lin/sparkles.svg new file mode 100644 index 00000000..9c0828bd --- /dev/null +++ b/src/browser/themes/shared/zen-icons/lin/sparkles.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/dom/base/Document-cpp.patch b/src/dom/base/Document-cpp.patch index 04aa8afd..c324fda3 100644 --- a/src/dom/base/Document-cpp.patch +++ b/src/dom/base/Document-cpp.patch @@ -1,13 +1,13 @@ diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp -index a16bef739fcde0f14ba7e53e0acfa3aa2ee1dd3a..78b9d112a56b3d909e31eb4351ee9f3b06c4ef92 100644 +index a16bef739fcde0f14ba7e53e0acfa3aa2ee1dd3a..f928c0f1df4e86bd344ab7e57dab112234fb92e8 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -3332,6 +3332,15 @@ void Document::FillStyleSetUserAndUASheets() { ServoStyleSet& styleSet = EnsureStyleSet(); for (StyleSheet* sheet : *sheetService->UserStyleSheets()) { -+ // If the url starts with "chrome://" and ends with 'zen-themes.css', then -+ // skip it if the document is in a chrome docshell. ++ // If the url starts with "file://" and ends with 'zen-themes.css', then ++ // skip it if the document is not in a chrome docshell. + // This is to avoid loading the user chrome stylesheet in the content + // process, which is not allowed. + auto spec = sheet->GetSheetURI()->GetSpecOrDefault(); diff --git a/src/widget/cocoa/nsCocoaWindow-mm.patch b/src/widget/cocoa/nsCocoaWindow-mm.patch new file mode 100644 index 00000000..ce10d5cd --- /dev/null +++ b/src/widget/cocoa/nsCocoaWindow-mm.patch @@ -0,0 +1,13 @@ +diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm +index c4627621344d35081f11a7b0e03d02eca2097609..d2e5fe429aaac8b701a03380a67f4ea978d566b3 100644 +--- a/widget/cocoa/nsCocoaWindow.mm ++++ b/widget/cocoa/nsCocoaWindow.mm +@@ -7376,7 +7376,7 @@ - (id)initWithContentRect:(NSRect)aContentRect + + // Returns an autoreleased NSImage. + static NSImage* GetMenuMaskImage() { +- const CGFloat radius = 6.0f; ++ const CGFloat radius = 14.0f; + const NSSize maskSize = {radius * 3.0f, radius * 3.0f}; + NSImage* maskImage = [NSImage imageWithSize:maskSize + flipped:FALSE diff --git a/src/zen/common/styles/zen-browser-container.css b/src/zen/common/styles/zen-browser-container.css index 933bc985..abf632bd 100644 --- a/src/zen/common/styles/zen-browser-container.css +++ b/src/zen/common/styles/zen-browser-container.css @@ -17,7 +17,7 @@ } & browser[transparent='true'] { - background: rgba(255, 255, 255, 0.1); + background: light-dark(rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.1)); } } } diff --git a/src/zen/common/styles/zen-browser-ui.css b/src/zen/common/styles/zen-browser-ui.css index a8bdeda1..30fdd4b0 100644 --- a/src/zen/common/styles/zen-browser-ui.css +++ b/src/zen/common/styles/zen-browser-ui.css @@ -46,6 +46,8 @@ pointer-events: none; isolation: isolate; + background: var(--zen-themed-toolbar-bg-transparent); + transition: background-color var(--inactive-window-transition); &::after, &::before { @@ -100,7 +102,7 @@ border: none; } -@supports (-moz-osx-font-smoothing: auto) { +@media (-moz-platform: macos) { #zen-main-app-wrapper, #zen-appcontent-wrapper, #zen-sidebar-splitter { @@ -118,7 +120,7 @@ } #zen-main-app-wrapper { - background: var(--zen-themed-toolbar-bg-transparent); + background: transparent; /* See bug #8814, don't an overflow here as it causes issues * with firefox's rendering of the tab bar */ diff --git a/src/zen/common/styles/zen-popup.css b/src/zen/common/styles/zen-popup.css index 774f5e4c..35b51684 100644 --- a/src/zen/common/styles/zen-popup.css +++ b/src/zen/common/styles/zen-popup.css @@ -394,7 +394,6 @@ menuseparator { } & button { - color-scheme: dark; width: min-content; padding: 0 10px !important; min-width: unset !important; @@ -402,6 +401,7 @@ menuseparator { border-radius: calc(var(--zen-native-inner-radius) + 2px) !important; background: light-dark(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.1)) !important; border: 1px solid light-dark(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.15)) !important; + color: var(--toolbar-color); :root[zen-right-side='true'] & { order: -1; diff --git a/src/zen/common/styles/zen-theme.css b/src/zen/common/styles/zen-theme.css index e3a226fc..bc2970f0 100644 --- a/src/zen/common/styles/zen-theme.css +++ b/src/zen/common/styles/zen-theme.css @@ -9,12 +9,7 @@ */ :host(:is(.anonymous-content-host, notification-message)), -:root, -.zenLooksAndFeelColorOption { - /** We also add `.zenLooksAndFeelColorOption` so that it recalculates the colors when the theme changes - * in the preferences page. - */ - +:root { /* Default values */ --zen-border-radius: 7px; --zen-primary-color: #ffb787; @@ -92,7 +87,7 @@ --focus-outline-color: var(--button-bgcolor) !important; --toolbarbutton-icon-fill-attention: var(--zen-primary-color) !important; - --toolbarbutton-icon-fill: light-dark(rgba(57, 57, 58, 0.6), rgba(251, 251, 254, 0.6)) !important; + --toolbarbutton-icon-fill: currentColor !important; --button-primary-bgcolor: var(--in-content-primary-button-background) !important; --button-primary-hover-bgcolor: var(--in-content-primary-button-background-hover) !important; @@ -121,7 +116,10 @@ --zen-button-border-radius: 5px; --zen-button-padding: 0.6rem 1.2rem; - --zen-toolbar-element-bg: light-dark(rgba(89, 89, 89, 0.1), rgba(255, 255, 255, 0.1)); + --zen-toolbar-element-bg: light-dark( + color-mix(in srgb, currentColor 5%, transparent 5%), + color-mix(in srgb, currentColor 10%, transparent 90%) + ) !important; /* Toolbar */ --zen-toolbar-height: 38px; @@ -162,27 +160,11 @@ --input-bgcolor: var(--zen-colors-tertiary) !important; --input-border-color: var(--zen-input-border-color) !important; - --zen-themed-toolbar-bg: light-dark(rgb(240, 240, 244), #171717); --zen-themed-toolbar-bg-transparent: light-dark(var(--zen-branding-bg), #171717); --zen-workspace-indicator-height: 48px; - @media (-moz-windows-mica) or (-moz-platform: macos) { - background: transparent; - --zen-themed-toolbar-bg-transparent: transparent; - @media -moz-pref('widget.windows.mica.toplevel-backdrop', 2) { - --zen-themed-toolbar-bg-transparent: color-mix( - in srgb, - var(--zen-themed-toolbar-bg) 35%, - transparent 65% - ); - } - } - - @media (-moz-platform: linux) and -moz-pref('zen.widget.linux.transparency') { - background: transparent; - --zen-themed-toolbar-bg-transparent: transparent; - } + --toolbar-field-color: var(--toolbox-textcolor) !important; &[zen-private-window='true'] { --zen-main-browser-background: linear-gradient( @@ -239,6 +221,52 @@ #main-window:not([chromehidden~='toolbar']) { min-height: 495px !important; + + @media (-moz-windows-mica) or (-moz-platform: macos) { + background: transparent; + --zen-themed-toolbar-bg-transparent: transparent; + &[zen-should-be-dark-mode] { + --zen-themed-toolbar-bg-transparent: var(--zen-themed-browser-overlay-bg); + } + } + + @media (-moz-platform: linux) and -moz-pref('zen.widget.linux.transparency') { + background: transparent; + --zen-themed-toolbar-bg-transparent: transparent; + &[zen-should-be-dark-mode] { + --zen-themed-toolbar-bg-transparent: var(--zen-themed-browser-overlay-bg); + } + } + + &[zen-should-be-dark-mode='true'] #browser { + color-scheme: dark; + --tab-selected-color-scheme: dark; + } + + &[zen-should-be-dark-mode='false'] #browser { + color-scheme: light; + --tab-selected-color-scheme: light; + } + + &, + & #tabbrowser-tabpanels, + & panel, + & menupopup { + @media -moz-pref('zen.theme.window.scheme', 'dark') { + color-scheme: dark; + } + + @media -moz-pref('zen.theme.window.scheme', 'light') { + color-scheme: light; + } + + @media -moz-pref('zen.theme.window.scheme', 'auto') { + color-scheme: light; + @media (-moz-system-dark-theme) { + color-scheme: dark; + } + } + } } @media (prefers-color-scheme: dark) { diff --git a/src/zen/images/gradient.png b/src/zen/images/gradient.png deleted file mode 100644 index b65f34ae5362304b5cd90e124df9f0192c077458..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68548 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 { + const type = command.charAt(0); + const coordsStr = command.slice(1).trim(); + const coords = coordsStr.split(/[\s,]+/).map(Number); + + switch (type) { + case 'M': + points.push({ x: coords[0], y: coords[1], type: 'M' }); + break; + case 'C': + if (coords.length >= 6 && coords.length % 6 === 0) { + for (let i = 0; i < coords.length; i += 6) { + points.push({ + x1: coords[i], + y1: coords[i + 1], + x2: coords[i + 2], + y2: coords[i + 3], + x: coords[i + 4], + y: coords[i + 5], + type: 'C', + }); + } + } + break; + case 'L': + points.push({ x: coords[0], y: coords[1], type: 'L' }); + break; + } + }); + return points; + } + + class nsZenThemePicker extends ZenMultiWindowFeature { static MAX_DOTS = 3; currentOpacity = 0.5; - currentRotation = -45; dots = []; useAlgo = ''; + #currentLightness = 50; #allowTransparencyOnSidebar = Services.prefs.getBoolPref('zen.theme.acrylic-elements', false); + #linePath = `M 51.373 27.395 L 367.037 27.395`; + #sinePath = `M 51.373 27.395 C 60.14 -8.503 68.906 -8.503 77.671 27.395 C 86.438 63.293 95.205 63.293 103.971 27.395 C 112.738 -8.503 121.504 -8.503 130.271 27.395 C 139.037 63.293 147.803 63.293 156.57 27.395 C 165.335 -8.503 174.101 -8.503 182.868 27.395 C 191.634 63.293 200.4 63.293 209.167 27.395 C 217.933 -8.503 226.7 -8.503 235.467 27.395 C 244.233 63.293 252.999 63.293 261.765 27.395 C 270.531 -8.503 279.297 -8.503 288.064 27.395 C 296.83 63.293 305.596 63.293 314.363 27.395 C 323.13 -8.503 331.896 -8.503 340.662 27.395 M 314.438 27.395 C 323.204 -8.503 331.97 -8.503 340.737 27.395 C 349.503 63.293 358.27 63.293 367.037 27.395`; + + #sinePoints = parseSinePath(this.#sinePath); + + #colorPage = 0; + constructor() { super(); if ( @@ -39,6 +82,10 @@ document.getElementById('PanelUI-zen-gradient-generator-custom-list') ); + ChromeUtils.defineLazyGetter(this, 'sliderWavePath', () => + document.getElementById('PanelUI-zen-gradient-slider-wave').querySelector('path') + ); + this.panel.addEventListener('popupshowing', this.handlePanelOpen.bind(this)); this.panel.addEventListener('popuphidden', this.handlePanelClose.bind(this)); this.panel.addEventListener('command', this.handlePanelCommand.bind(this)); @@ -47,23 +94,53 @@ .getElementById('PanelUI-zen-gradient-generator-opacity') .addEventListener('input', this.onOpacityChange.bind(this)); - this.initCanvas(); + // Call the rest of the initialization + this.initContextMenu(); + this.initPredefinedColors(); + + this._resolveInitialized(); + delete this._resolveInitialized; + this.initCustomColorInput(); this.initTextureInput(); - this.initRotationInput(); + this.initSchemeButtons(); + this.initColorPages(); - window - .matchMedia('(prefers-color-scheme: dark)') - .addListener(this.onDarkModeChange.bind(this)); + const darkModeChange = this.handleDarkModeChange.bind(this); + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', darkModeChange); + + XPCOMUtils.defineLazyPreferenceGetter( + this, + 'windowSchemeType', + 'zen.theme.window.scheme', + true, + darkModeChange + ); + } + + handleDarkModeChange(event) { + this.updateCurrentWorkspace(); } get isDarkMode() { + switch (this.windowSchemeType) { + case 'dark': + return true; + case 'light': + return false; + default: + } return window.matchMedia('(prefers-color-scheme: dark)').matches; } - async onDarkModeChange(event, skipUpdate = false) { - const currentWorkspace = await gZenWorkspaces.getActiveWorkspace(); - this.onWorkspaceChange(currentWorkspace, skipUpdate); + get colorHarmonies() { + return [ + { type: 'complementary', angles: [180] }, + { type: 'splitComplementary', angles: [150, 210] }, + { type: 'analogous', angles: [50, 310] }, + { type: 'triadic', angles: [120, 240] }, + { type: 'floating', angles: [] }, + ]; } initContextMenu() { @@ -86,43 +163,9 @@ }); } - initCanvas() { - this.image = new Image(); - this.image.src = ZenThemePicker.GRADIENT_IMAGE_URL; - - this.canvas = document.createElement('canvas'); - this.panel.appendChild(this.canvas); - this.canvasCtx = this.canvas.getContext('2d'); - - // wait for the image to load - this.image.onload = this.onImageLoad.bind(this); - } - - onImageLoad() { - // resize the image to fit the panel - const imageSize = 350 - 20; // 20 is the padding (10px) - const scale = imageSize / Math.max(this.image.width, this.image.height); - this.image.width *= scale; - this.image.height *= scale; - - this.canvas.width = this.image.width; - this.canvas.height = this.image.height; - this.canvasCtx.drawImage(this.image, 0, 0); - - this.canvas.setAttribute('hidden', 'true'); - - // Call the rest of the initialization - this.initContextMenu(); - this.initPredefinedColors(); - - this._resolveInitialized(); - delete this._resolveInitialized; - this.onDarkModeChange(null); - } - initPredefinedColors() { document - .getElementById('PanelUI-zen-gradient-generator-predefined') + .getElementById('PanelUI-zen-gradient-generator-color-pages') .addEventListener('click', async (event) => { const target = event.target; const rawPosition = target.getAttribute('data-position'); @@ -130,6 +173,7 @@ return; } const algo = target.getAttribute('data-algo'); + const lightness = target.getAttribute('data-lightness'); const numDots = parseInt(target.getAttribute('data-num-dots')); if (algo == 'float') { for (const dot of this.dots) { @@ -157,6 +201,7 @@ }); } this.useAlgo = algo; + this.#currentLightness = lightness; dots = this.calculateCompliments(dots, 'update', this.useAlgo); if (algo == 'float') { for (const dot of dots) { @@ -173,49 +218,52 @@ this.customColorInput.addEventListener('keydown', this.onCustomColorKeydown.bind(this)); } - initRotationInput() { - const rotationInput = document.getElementById('PanelUI-zen-gradient-generator-rotation-dot'); - this._onRotationMouseDown = this.onRotationMouseDown.bind(this); - this._onRotationMouseMove = this.onRotationMouseMove.bind(this); - this._onRotationMouseUp = this.onRotationMouseUp.bind(this); - rotationInput.addEventListener('mousedown', this._onRotationMouseDown); - } - - onRotationMouseDown(event) { - event.preventDefault(); - event.stopPropagation(); - this._rotating = true; - document.addEventListener('mousemove', this._onRotationMouseMove); - document.addEventListener('mouseup', this._onRotationMouseUp); - } - - onRotationMouseMove(event) { - event.preventDefault(); - event.stopPropagation(); - const rotationInput = document.getElementById('PanelUI-zen-gradient-generator-rotation-dot'); - const containerRect = rotationInput.parentElement.getBoundingClientRect(); - // We calculate the angle based on the mouse position and the center of the container - const rotation = Math.atan2( - event.clientY - containerRect.top - containerRect.height / 2, - event.clientX - containerRect.left - containerRect.width / 2 + initColorPages() { + const leftButton = document.getElementById('PanelUI-zen-gradient-generator-color-page-left'); + const rightButton = document.getElementById( + 'PanelUI-zen-gradient-generator-color-page-right' ); - const endRotation = (rotation * 180) / Math.PI; - // Between 150 and 50, we don't update the rotation - if (!(endRotation < 45 || endRotation > 130)) { - return; - } - this.currentRotation = endRotation; - this.updateCurrentWorkspace(); + const pagesWrapper = document.getElementById('PanelUI-zen-gradient-generator-color-pages'); + const pages = pagesWrapper.children; + pagesWrapper.addEventListener('wheel', (event) => { + event.preventDefault(); + event.stopPropagation(); + }); + leftButton.addEventListener('command', () => { + this.#colorPage = (this.#colorPage - 1 + pages.length) % pages.length; + // Scroll to the next page, by using scrollLeft + pagesWrapper.scrollLeft = (this.#colorPage * pagesWrapper.scrollWidth) / pages.length; + rightButton.disabled = false; + leftButton.disabled = this.#colorPage === 0; + }); + rightButton.addEventListener('command', () => { + this.#colorPage = (this.#colorPage + 1) % pages.length; + // Scroll to the next page, by using scrollLeft + pagesWrapper.scrollLeft = (this.#colorPage * pagesWrapper.scrollWidth) / pages.length; + leftButton.disabled = false; + rightButton.disabled = this.#colorPage === pages.length - 1; + }); } - onRotationMouseUp(event) { - event.preventDefault(); - event.stopPropagation(); - document.removeEventListener('mousemove', this._onRotationMouseMove); - document.removeEventListener('mouseup', this._onRotationMouseUp); - setTimeout(() => { - this._rotating = false; - }, 100); + initSchemeButtons() { + const buttons = document.getElementById('PanelUI-zen-gradient-generator-scheme'); + buttons.addEventListener('click', (event) => { + const target = event.target.closest('.subviewbutton'); + if (!target) { + return; + } + event.preventDefault(); + event.stopPropagation(); + const scheme = target.id.replace('PanelUI-zen-gradient-generator-scheme-', ''); + if (!scheme) { + return; + } + if (this.currentScheme === scheme) { + return; + } + this.currentScheme = scheme; + Services.prefs.setStringPref('zen.theme.window.scheme', scheme); + }); } initTextureInput() { @@ -312,39 +360,110 @@ this._onThemePickerClick = null; } - calculateInitialPosition(color) { - const [r, g, b] = color.c; - const imageData = this.canvasCtx.getImageData(0, 0, this.canvas.width, this.canvas.height); - // Find all pixels that are at least 90% similar to the color - const similarPixels = []; - for (let i = 0; i < imageData.data.length; i += 4) { - const pixelR = imageData.data[i]; - const pixelG = imageData.data[i + 1]; - const pixelB = imageData.data[i + 2]; - if (Math.abs(r - pixelR) < 25 && Math.abs(g - pixelG) < 25 && Math.abs(b - pixelB) < 25) { - similarPixels.push(i); - } + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from https://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. + * + * @param {number} h The hue + * @param {number} s The saturation + * @param {number} l The lightness + * @return {Array} The RGB representation + */ + hslToRgb(h, s, l) { + const { abs, min, max, round } = Math; + let r, g, b; + + if (s === 0) { + r = g = b = l; // achromatic + } else { + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + r = this.hueToRgb(p, q, h + 1 / 3); + g = this.hueToRgb(p, q, h); + b = this.hueToRgb(p, q, h - 1 / 3); } - // Check if there's an exact match - for (const pixel of similarPixels) { - const x = (pixel / 4) % this.canvas.width; - const y = Math.floor(pixel / 4 / this.canvas.width); - const pixelColor = this.getColorFromPosition(x, y); - if (pixelColor[0] === r && pixelColor[1] === g && pixelColor[2] === b) { - return { x: x / this.canvas.width, y: y / this.canvas.height }; - } - } - // If there's no exact match, return the first similar pixel - const pixel = similarPixels[0]; - const x = (pixel / 4) % this.canvas.width; - const y = Math.floor(pixel / 4 / this.canvas.width); - return { x: x / this.canvas.width, y: y / this.canvas.height }; + + return [round(r * 255), round(g * 255), round(b * 255)]; + } + + rgbToHsl(r, g, b) { + r /= 255; + g /= 255; + b /= 255; + let max = Math.max(r, g, b); + let min = Math.min(r, g, b); + let d = max - min; + let h; + if (d === 0) h = 0; + else if (max === r) h = ((g - b) / d) % 6; + else if (max === g) h = (b - r) / d + 2; + else if (max === b) h = (r - g) / d + 4; + let l = (min + max) / 2; + let s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1)); + return [h * 60, s, l]; + } + + hueToRgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + + calculateInitialPosition([r, g, b]) { + // This function is called before the picker is even rendered, so we hard code the dimensions + // important: If any sort of sizing is changed, make sure changes are reflected here + const padding = 20; + const rect = { + width: 318, + height: 318, + }; + const centerX = rect.width / 2; + const centerY = rect.height / 2; + const radius = (rect.width - padding) / 2; + const [hue, saturation] = this.rgbToHsl(r, g, b); + const angle = (hue / 360) * 2 * Math.PI; // Convert to radians + const normalizedSaturation = saturation / 100; // Convert to [0, 1] + const x = centerX + radius * normalizedSaturation * Math.cos(angle) - padding; + const y = centerY + radius * normalizedSaturation * Math.sin(angle) - padding; + return { x, y }; } getColorFromPosition(x, y) { - // get the color from the x and y from the image - const imageData = this.canvasCtx.getImageData(x, y, 1, 1); - return imageData.data; + // Return a color as hsl based on the position in the gradient + const gradient = this.panel.querySelector('.zen-theme-picker-gradient'); + const rect = gradient.getBoundingClientRect(); + const padding = 20; // each side + rect.width += padding * 2; + rect.height += padding * 2; + const centerX = rect.width / 2; + const centerY = rect.height / 2; + const radius = (rect.width - padding) / 2; + const distance = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2); + let angle = Math.atan2(y - centerY, x - centerX); + angle = (angle * 180) / Math.PI; // Convert to degrees + if (angle < 0) { + angle += 360; // Normalize to [0, 360) + } + const normalizedDistance = 1 - Math.min(distance / radius, 1); // Normalize distance to [0, 1] + const hue = (angle / 360) * 360; // Normalize angle to [0, 360) + const saturation = normalizedDistance * 100; // Scale distance to [0, 100] + const lightness = this.#currentLightness; // Fixed lightness for simplicity + const [r, g, b] = this.hslToRgb(hue / 360, saturation / 100, lightness / 100); + return [ + Math.min(255, Math.max(0, r)), + Math.min(255, Math.max(0, g)), + Math.min(255, Math.max(0, b)), + ]; + } + + getJSONPos(x, y) { + // Return a JSON string with the position + return JSON.stringify({ x: Math.round(x), y: Math.round(y) }); } createDot(color, fromWorkspace = false) { @@ -361,13 +480,13 @@ dot.style.opacity = 0; dot.style.setProperty('--zen-theme-picker-dot-color', color.c); } else { - const { x, y } = this.calculateInitialPosition(color); + const { x, y } = color.position || this.calculateInitialPosition([r, g, b]); const dotPad = this.panel.querySelector('.zen-theme-picker-gradient'); dot.classList.add('zen-theme-picker-dot'); - dot.style.left = `${x * 100}%`; - dot.style.top = `${y * 100}%`; + dot.style.left = `${x}px`; + dot.style.top = `${y}px`; if (this.dots.length < 1) { dot.classList.add('primary'); @@ -377,6 +496,7 @@ let id = this.dots.length; dot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${r}, ${g}, ${b})`); + dot.setAttribute('data-position', this.getJSONPos(x, y)); this.dots.push({ ID: id, @@ -474,6 +594,7 @@ '--zen-theme-picker-dot-color', `rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})` ); + dot.setAttribute('data-position', this.getJSONPos(relativePosition.x, relativePosition.y)); this.dots.push({ ID: id, @@ -483,13 +604,7 @@ } calculateCompliments(dots, action = 'update', useHarmony = '') { - const colorHarmonies = [ - { type: 'complementary', angles: [180] }, - { type: 'splitComplementary', angles: [150, 210] }, - { type: 'analogous', angles: [30, 330] }, - { type: 'triadic', angles: [120, 240] }, - { type: 'floating', angles: [] }, - ]; + const colorHarmonies = this.colorHarmonies; if (dots.length === 0) { return []; @@ -614,6 +729,8 @@ '--zen-theme-picker-dot-color', `rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})` ); + + dot.element.setAttribute('data-position', this.getJSONPos(pixelX, pixelY)); }); return; @@ -630,6 +747,10 @@ '--zen-theme-picker-dot-color', `rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})` ); + existingPrimaryDot.element.setAttribute( + 'data-position', + this.getJSONPos(existingPrimaryDot.position.x, existingPrimaryDot.position.y) + ); } colorPositions.forEach((dotPosition) => { @@ -645,6 +766,10 @@ '--zen-theme-picker-dot-color', `rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})` ); + existingDot.element.setAttribute( + 'data-position', + this.getJSONPos(dotPosition.position.x, dotPosition.position.y) + ); if (!this.dragging) { gZenUIManager.motion.animate( @@ -673,10 +798,13 @@ if (this._rotating) { return; } + if (event.target.closest('#PanelUI-zen-gradient-generator-scheme')) { + return; + } event.preventDefault(); const target = event.target; if (target.id === 'PanelUI-zen-gradient-generator-color-add') { - if (this.dots.length >= ZenThemePicker.MAX_DOTS) return; + if (this.dots.length >= nsZenThemePicker.MAX_DOTS) return; let colorPositions = this.calculateCompliments(this.dots, 'add', this.useAlgo); this.handleColorPositions(colorPositions); @@ -702,30 +830,6 @@ this.handleColorPositions(colorPositions); this.updateCurrentWorkspace(); return; - } else if (target.id === 'PanelUI-zen-gradient-generator-color-toggle-algo') { - const colorHarmonies = [ - { type: 'complementary', angles: [180] }, - { type: 'splitComplementary', angles: [150, 210] }, - { type: 'analogous', angles: [30, 330] }, - { type: 'triadic', angles: [120, 240] }, - { type: 'floating', angles: [] }, - ]; - - const applicableHarmonies = colorHarmonies.filter( - (harmony) => harmony.angles.length + 1 === this.dots.length || harmony.type === 'floating' - ); - - let currentIndex = applicableHarmonies.findIndex( - (harmony) => harmony.type === this.useAlgo - ); - - let nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % applicableHarmonies.length; - this.useAlgo = applicableHarmonies[nextIndex].type; - - let colorPositions = this.calculateCompliments(this.dots, 'update', this.useAlgo); - this.handleColorPositions(colorPositions); - this.updateCurrentWorkspace(); - return; } if (event.button !== 0 || this.dragging || this.recentlyDragged) return; @@ -905,76 +1009,164 @@ } themedColors(colors) { - const isDarkMode = this.isDarkMode; - const factor = isDarkMode ? 0.5 : 1.1; - return colors.map((color) => ({ c: color.isCustom ? color.c - : [ - Math.min(255, color.c[0] * factor), - Math.min(255, color.c[1] * factor), - Math.min(255, color.c[2] * factor), - ], + : [Math.min(255, color.c[0]), Math.min(255, color.c[1]), Math.min(255, color.c[2])], isCustom: color.isCustom, algorithm: color.algorithm, + lightness: color.lightness, + position: color.position, })); } onOpacityChange(event) { - this.currentOpacity = event.target.value; + this.currentOpacity = parseFloat(event.target.value); + // If we reached a whole number (e.g., 0.1, 0.2, etc.), send a haptic feedback + if ((this.currentOpacity * 10) % 1 === 0) { + Services.zen.playHapticFeedback(); + } this.updateCurrentWorkspace(); } - getToolbarModifiedBase() { + getToolbarModifiedBaseRaw() { const opacity = this.#allowTransparencyOnSidebar ? 0.6 : 1; - return this.isDarkMode - ? `color-mix(in srgb, var(--zen-themed-toolbar-bg) 96%, rgba(255,255,255,${opacity}) 4%)` - : `color-mix(in srgb, var(--zen-themed-toolbar-bg) 96%, rgba(0,0,0,${opacity}) 4%)`; + return this.isDarkMode ? [23, 23, 26, opacity] : [240, 240, 244, opacity]; + } + + getToolbarModifiedBase() { + const baseColor = this.getToolbarModifiedBaseRaw(); + return `rgba(${baseColor[0]}, ${baseColor[1]}, ${baseColor[2]}, ${baseColor[3]})`; + } + + get canBeTransparent() { + return window.matchMedia( + '(-moz-windows-mica) or (-moz-platform: macos) or ((-moz-platform: linux) and -moz-pref("zen.widget.linux.transparency"))' + ).matches; } getSingleRGBColor(color, forToolbar = false) { if (color.isCustom) { return color.c; } + const opacity = this.currentOpacity; if (forToolbar) { const toolbarBg = this.getToolbarModifiedBase(); - return `color-mix(in srgb, rgb(${color.c[0]}, ${color.c[1]}, ${color.c[2]}) ${this.currentOpacity * 100}%, ${toolbarBg} ${(1 - this.currentOpacity) * 100}%)`; + return `color-mix(in srgb, rgb(${color.c[0]}, ${color.c[1]}, ${color.c[2]}) ${opacity * 100}%, ${toolbarBg} ${(1 - opacity) * 100}%)`; } - return `rgba(${color.c[0]}, ${color.c[1]}, ${color.c[2]}, ${this.currentOpacity})`; + return `rgba(${color.c[0]}, ${color.c[1]}, ${color.c[2]}, ${opacity})`; + } + + luminance([r, g, b]) { + const a = [r, g, b].map((v) => { + v /= 255; + return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); + }); + return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; + } + + contrastRatio(rgb1, rgb2) { + const lum1 = this.luminance(rgb1); + const lum2 = this.luminance(rgb2); + const brightest = Math.max(lum1, lum2); + const darkest = Math.min(lum1, lum2); + return (brightest + 0.05) / (darkest + 0.05); + } + + blendColorsRaw(rgb1, rgb2, percentage) { + const p = percentage / 100; + return [ + Math.round(rgb1[0] * p + rgb2[0] * (1 - p)), + Math.round(rgb1[1] * p + rgb2[1] * (1 - p)), + Math.round(rgb1[2] * p + rgb2[2] * (1 - p)), + ]; + } + + findOptimalBlend(dominantColor, blendTarget, minContrast = 4.5) { + let low = 0; + let high = 100; + let bestMatch = null; + + for (let i = 0; i < 10; i++) { + const mid = (low + high) / 2; + const blended = this.blendColorsRaw(dominantColor, blendTarget, mid); + const contrast = this.contrastRatio(blended, blendTarget); + + if (contrast >= minContrast) { + bestMatch = blended; + high = mid; + } else { + low = mid; + } + } + + return bestMatch || this.blendColorsRaw(dominantColor, blendTarget, 10); // fallback } getGradient(colors, forToolbar = false) { const themedColors = this.themedColors(colors); this.useAlgo = themedColors[0]?.algorithm ?? ''; + this.#currentLightness = themedColors[0]?.lightness ?? 70; + const rotation = -45; // TODO: Detect rotation based on the accent color if (themedColors.length === 0) { return forToolbar - ? 'var(--zen-themed-toolbar-bg)' + ? this.getToolbarModifiedBase() : 'var(--zen-themed-toolbar-bg-transparent)'; } else if (themedColors.length === 1) { return this.getSingleRGBColor(themedColors[0], forToolbar); - } else if (themedColors.length !== 3) { - return `linear-gradient(${this.currentRotation}deg, ${themedColors.map((color) => this.getSingleRGBColor(color, forToolbar)).join(', ')})`; - } else { + } else if (themedColors.length === 2) { + return [ + `linear-gradient(${rotation}deg, ${this.getSingleRGBColor(themedColors[0], forToolbar)} -25%, transparent 100%)`, + `linear-gradient(${rotation + 180}deg, ${this.getSingleRGBColor(themedColors[1], forToolbar)} -25%, transparent 100%)`, + ].join(', '); + } else if (themedColors.length === 3) { let color1 = this.getSingleRGBColor(themedColors[2], forToolbar); let color2 = this.getSingleRGBColor(themedColors[0], forToolbar); let color3 = this.getSingleRGBColor(themedColors[1], forToolbar); - return `linear-gradient(${this.currentRotation}deg, ${color1}, ${color2}, ${color3})`; + if (!forToolbar) { + return [ + `radial-gradient(circle at -30% -30%, ${color1}, transparent 100%)`, + `radial-gradient(circle at 130% -30%, ${color2}, transparent 100%)`, + `linear-gradient(to top, ${color3} -30%, transparent 60%)`, + ].join(', '); + } + return [`linear-gradient(${rotation}deg, ${color1} -30%, ${color3} 100%)`].join(', '); + } else { + // Just return a linear gradient with all colors + const gradientColors = themedColors.map((color) => + this.getSingleRGBColor(color, forToolbar) + ); + return `linear-gradient(${rotation}deg, ${gradientColors.join(', ')})`; } } - static getTheme(colors = [], opacity = 0.5, rotation = -45, texture = 0) { + shouldBeDarkMode(accentColor) { + let minimalLum = this.isDarkMode ? 0.6 : 0.5; + if (!this.canBeTransparent) { + // Blend the color with the toolbar background + const toolbarBg = this.getToolbarModifiedBaseRaw(); + accentColor = this.blendColorsRaw( + toolbarBg.slice(0, 3), + accentColor, + (1 - this.currentOpacity) * 100 + ); + minimalLum = this.isDarkMode ? 0.3 : 0.2; + } + const lum = this.luminance(accentColor); + // Return true if background is dark enough that white text is preferred + return lum < minimalLum; + } + + static getTheme(colors = [], opacity = 0.5, texture = 0) { return { type: 'gradient', gradientColors: colors ? colors.filter((color) => color) : [], // remove undefined opacity, - rotation, texture, }; } - //TODO: add a better noise system that adds noise not just changes transparency updateNoise(texture) { document.documentElement.style.setProperty('--zen-grainy-background-opacity', texture); document.documentElement.setAttribute( @@ -1101,6 +1293,11 @@ return color; } + blendColors(rgb1, rgb2, percentage) { + const blended = this.blendColorsRaw(rgb1, rgb2, percentage); + return `rgb(${blended[0]}, ${blended[1]}, ${blended[2]})`; + } + async onWorkspaceChange(workspace, skipUpdate = false, theme = null) { const uuid = workspace.uuid; // Use theme from workspace object or passed theme @@ -1132,7 +1329,18 @@ } } - const appBackground = browser.document.getElementById('zen-browser-background'); + if (this.isDarkMode) { + browser.document.documentElement.style.setProperty( + '--zen-themed-browser-overlay-bg', + 'rgba(255, 255, 255, 0.3)' + ); + } else { + browser.document.documentElement.style.setProperty( + '--zen-themed-browser-overlay-bg', + 'rgba(0, 0, 0, 0.2)' + ); + } + if (!skipUpdate) { browser.document.documentElement.style.setProperty( '--zen-main-browser-background-old', @@ -1140,7 +1348,7 @@ ); browser.document.documentElement.style.setProperty( '--zen-background-opacity', - browser.gZenThemePicker.previousBackgroundOpacity + browser.gZenThemePicker.previousBackgroundOpacity ?? 1 ); if (browser.gZenThemePicker.previousBackgroundResolve) { browser.gZenThemePicker.previousBackgroundResolve(); @@ -1148,18 +1356,6 @@ delete browser.gZenThemePicker.previousBackgroundOpacity; } - const button = browser.document.getElementById( - 'PanelUI-zen-gradient-generator-color-toggle-algo' - ); - if (browser.gZenThemePicker.useAlgo) { - document.l10n.setAttributes( - button, - `zen-panel-ui-gradient-generator-algo-${browser.gZenThemePicker.useAlgo}` - ); - } else { - button.removeAttribute('data-l10n-id'); - } - browser.gZenThemePicker.resetCustomColorList(); if (!workspaceTheme || workspaceTheme.type !== 'gradient') { const gradient = browser.gZenThemePicker.getGradient([]); @@ -1177,13 +1373,48 @@ '--zen-primary-color', this.getNativeAccentColor() ); + browser.document.documentElement.removeAttribute('zen-should-be-dark-mode'); return; } browser.gZenThemePicker.currentOpacity = workspaceTheme.opacity ?? 0.5; - browser.gZenThemePicker.currentRotation = workspaceTheme.rotation ?? -45; browser.gZenThemePicker.currentTexture = workspaceTheme.texture ?? 0; + const opacitySlider = browser.document.getElementById( + 'PanelUI-zen-gradient-generator-opacity' + ); + + { + let opacity = browser.gZenThemePicker.currentOpacity; + const svg = browser.gZenThemePicker.sliderWavePath; + const [_, secondStop, thirdStop] = document.querySelectorAll( + '#PanelUI-zen-gradient-generator-slider-wave-gradient stop' + ); + // Opacity can only be between 0.15 to 0.85. Make opacity relative to that range + // So 0.15 becomes 0, and 0.85 becomes 1. + if (opacity < 0.15) { + opacity = 0; + } else if (opacity > 0.85) { + opacity = 1; + } else { + opacity = (opacity - 0.15) / (0.85 - 0.15); + } + // Since it's sine waves, we can't just set the offset to the opacity, we need to calculate it + // The offset is the percentage of the wave that is visible, so we need to multiply + // the opacity by 100 to get the percentage. + // Set the offset of the stops + secondStop.setAttribute('offset', `${opacity * 100}%`); + thirdStop.setAttribute('offset', `${opacity * 100}%`); + const interpolatedPath = this.#interpolateWavePath(opacity); + svg.setAttribute('d', interpolatedPath); + opacitySlider.style.setProperty('--zen-thumb-height', `${40 + opacity * 12}px`); + opacitySlider.style.setProperty('--zen-thumb-width', `${10 + opacity * 10}px`); + svg.style.stroke = + interpolatedPath === this.#linePath + ? thirdStop.getAttribute('stop-color') + : 'url(#PanelUI-zen-gradient-generator-slider-wave-gradient)'; + } + for (const button of browser.document.querySelectorAll( '#PanelUI-zen-gradient-generator-color-actions button' )) { @@ -1191,15 +1422,14 @@ button.disabled = workspaceTheme.gradientColors.length === 0 || (button.id === 'PanelUI-zen-gradient-generator-color-add' - ? workspaceTheme.gradientColors.length >= ZenThemePicker.MAX_DOTS + ? workspaceTheme.gradientColors.length >= nsZenThemePicker.MAX_DOTS : false); } document .getElementById('PanelUI-zen-gradient-generator-color-click-to-add') .toggleAttribute('hidden', workspaceTheme.gradientColors.length > 0); - browser.document.getElementById('PanelUI-zen-gradient-generator-opacity').value = - browser.gZenThemePicker.currentOpacity; + opacitySlider.value = browser.gZenThemePicker.currentOpacity; const textureSelectWrapper = browser.document.getElementById( 'PanelUI-zen-gradient-generator-texture-wrapper' ); @@ -1228,35 +1458,6 @@ i = 0; } } - - const numberOfColors = workspaceTheme.gradientColors?.length; - const rotationDot = browser.document.getElementById( - 'PanelUI-zen-gradient-generator-rotation-dot' - ); - const rotationLine = browser.document.getElementById( - 'PanelUI-zen-gradient-generator-rotation-line' - ); - if (numberOfColors > 1) { - rotationDot.style.opacity = 1; - rotationLine.style.opacity = 1; - rotationDot.style.removeProperty('pointer-events'); - const rotationPadding = 20; - const rotationParentWidth = rotationDot.parentElement.getBoundingClientRect().width; - const rotationDotPosition = this.currentRotation; - const rotationDotWidth = 30; - const rotationDotX = - Math.cos((rotationDotPosition * Math.PI) / 180) * - (rotationParentWidth / 2 - rotationDotWidth / 2); - const rotationDotY = - Math.sin((rotationDotPosition * Math.PI) / 180) * - (rotationParentWidth / 2 - rotationDotWidth / 2); - rotationDot.style.left = `${rotationParentWidth / 2 + rotationDotX - rotationPadding + rotationDotWidth / 4}px`; - rotationDot.style.top = `${rotationParentWidth / 2 + rotationDotY - rotationPadding + rotationDotWidth / 4}px`; - } else { - rotationDot.style.opacity = 0; - rotationLine.style.opacity = 0; - rotationDot.style.pointerEvents = 'none'; - } } const gradient = browser.gZenThemePicker.getGradient(workspaceTheme.gradientColors); @@ -1290,6 +1491,25 @@ ? dominantColor : `rgb(${dominantColor[0]}, ${dominantColor[1]}, ${dominantColor[2]})` ); + let isDarkMode = this.isDarkMode; + if (dominantColor !== this.getNativeAccentColor()) { + isDarkMode = browser.gZenThemePicker.shouldBeDarkMode(dominantColor); + browser.document.documentElement.setAttribute('zen-should-be-dark-mode', isDarkMode); + } else { + browser.document.documentElement.removeAttribute('zen-should-be-dark-mode'); + } + // Set `--toolbox-textcolor` to have a contrast with the primary color + const blendTarget = isDarkMode ? [255, 255, 255] : [0, 0, 0]; + const blendedColor = this.blendColors(dominantColor, blendTarget, 15); // 15% dominantColor, 85% target + await gZenUIManager.motion.animate( + browser.document.documentElement, + { + '--toolbox-textcolor': blendedColor, + }, + { + duration: 0.05, + } + ); } if (!skipUpdate) { @@ -1364,19 +1584,18 @@ } const isCustom = dot.classList.contains('custom'); const algorithm = this.useAlgo; + const position = + dot.getAttribute('data-position') && JSON.parse(dot.getAttribute('data-position')); return { c: isCustom ? color : color.match(/\d+/g).map(Number), isCustom, algorithm, isPrimary, + lightness: this.#currentLightness, + position, }; }); - const gradient = ZenThemePicker.getTheme( - colors, - this.currentOpacity, - this.currentRotation, - this.currentTexture - ); + const gradient = nsZenThemePicker.getTheme(colors, this.currentOpacity, this.currentTexture); let currentWorkspace = await gZenWorkspaces.getActiveWorkspace(); if (!skipSave) { @@ -1402,7 +1621,38 @@ this.updateCurrentWorkspace(); }, 200); } + + #interpolateWavePath(progress) { + const linePath = this.#linePath; + const sinePath = this.#sinePath; + const referenceY = 27.3; + if (this.#sinePoints.length === 0) { + return progress < 0.5 ? linePath : sinePath; + } + if (progress <= 0.001) return linePath; + if (progress >= 0.999) return sinePath; + const t = progress; + let newPathData = ''; + this.#sinePoints.forEach((p) => { + switch (p.type) { + case 'M': + const interpolatedY = referenceY + (p.y - referenceY) * t; + newPathData += `M ${p.x} ${interpolatedY} `; + break; + case 'C': + const y1 = referenceY + (p.y1 - referenceY) * t; + const y2 = referenceY + (p.y2 - referenceY) * t; + const y = referenceY + (p.y - referenceY) * t; + newPathData += `C ${p.x1} ${y1} ${p.x2} ${y2} ${p.x} ${y} `; + break; + case 'L': + newPathData += `L ${p.x} ${p.y} `; + break; + } + }); + return newPathData.trim(); + } } - window.ZenThemePicker = ZenThemePicker; + window.nsZenThemePicker = nsZenThemePicker; } diff --git a/src/zen/workspaces/ZenWorkspaceIcons.mjs b/src/zen/workspaces/ZenWorkspaceIcons.mjs index b512fbe4..f04c41b6 100644 --- a/src/zen/workspaces/ZenWorkspaceIcons.mjs +++ b/src/zen/workspaces/ZenWorkspaceIcons.mjs @@ -145,6 +145,7 @@ i++; } buttons[selected].setAttribute('active', true); + this.scrollLeft = buttons[selected].offsetLeft - 10; this.setAttribute('selected', selected); } diff --git a/src/zen/workspaces/ZenWorkspaces.mjs b/src/zen/workspaces/ZenWorkspaces.mjs index 37a0c396..2bc0a62b 100644 --- a/src/zen/workspaces/ZenWorkspaces.mjs +++ b/src/zen/workspaces/ZenWorkspaces.mjs @@ -885,7 +885,7 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature { this.activeWorkspace = activeWorkspace?.uuid; try { if (activeWorkspace) { - window.gZenThemePicker = new ZenThemePicker(); + window.gZenThemePicker = new nsZenThemePicker(); await gZenThemePicker.onWorkspaceChange(activeWorkspace); } } catch (e) { @@ -2179,7 +2179,7 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature { uuid: gZenUIManager.generateUuidv4(), icon: icon, name: name, - theme: ZenThemePicker.getTheme([]), + theme: nsZenThemePicker.getTheme([]), containerTabId, }; if (moveTabs) { diff --git a/src/zen/workspaces/overflow-icons.inc.css b/src/zen/workspaces/overflow-icons.inc.css index 7d966fdd..930290bd 100644 --- a/src/zen/workspaces/overflow-icons.inc.css +++ b/src/zen/workspaces/overflow-icons.inc.css @@ -6,6 +6,8 @@ &:not(:hover) { width: min(var(--zen-overflowed-workspace-button-width), 25px); + min-width: 10px; + &::after { content: ''; position: absolute; diff --git a/src/zen/workspaces/zen-gradient-generator.css b/src/zen/workspaces/zen-gradient-generator.css index 24564c89..fff9923d 100644 --- a/src/zen/workspaces/zen-gradient-generator.css +++ b/src/zen/workspaces/zen-gradient-generator.css @@ -5,7 +5,7 @@ */ #PanelUI-zen-gradient-generator { - --panel-width: 320px; + --panel-width: 340px; --panel-padding: 10px; min-width: var(--panel-width); } @@ -20,6 +20,7 @@ #PanelUI-zen-gradient-generator-controls { align-items: center; gap: var(--panel-padding); + padding-top: 10px; } #zen-theme-picker-color { @@ -62,7 +63,11 @@ padding: 0 var(--panel-padding); @media (-moz-platform: macos) { - gap: 3rem; + gap: 2rem; + } + + #PanelUI-zen-gradient-opacity-wrapper { + position: relative; } & label { @@ -76,46 +81,58 @@ } } -#PanelUI-zen-gradient-generator-predefined { +#PanelUI-zen-gradient-generator-color-pages-wrapper { + align-items: center; +} + +#PanelUI-zen-gradient-generator-color-pages { display: flex; justify-content: space-around; + margin: 0 10px; align-items: center; - margin: 5px auto 10px auto; width: 100%; + overflow: auto; + scrollbar-width: none; + scroll-behavior: smooth; - & > box { - width: 18px; - height: 18px; - border-radius: 50%; - cursor: pointer; - position: relative; - transition: transform 0.1s; - &::after { - content: ''; - position: absolute; + & > hbox { + justify-content: space-around; + min-width: 100%; + + & > box { width: 18px; height: 18px; - top: 0; - left: 0; - outline: 2px solid var(--zen-toolbar-element-bg); border-radius: 50%; - pointer-events: none; + cursor: pointer; + position: relative; transition: transform 0.1s; - } - - &:hover { - transform: scale(1.05); - &::after { - transform: scale(1.05); + content: ''; + position: absolute; + width: 18px; + height: 18px; + top: 0; + left: 0; + outline: 2px solid var(--zen-toolbar-element-bg); + border-radius: 50%; + pointer-events: none; + transition: transform 0.1s; } - } - &:hover:active { - transform: scale(0.95); + &:hover { + transform: scale(1.05); - &::after { + &::after { + transform: scale(1.05); + } + } + + &:hover:active { transform: scale(0.95); + + &::after { + transform: scale(0.95); + } } } } @@ -164,46 +181,72 @@ } } -#PanelUI-zen-gradient-generator-opacity, -#PanelUI-zen-gradient-generator-texture { +#PanelUI-zen-gradient-slider-wave { + position: absolute; + top: 3px; + left: -3px; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 1; + display: flex; + align-items: center; + justify-content: flex-start; + scale: 1.2; + + &::before { + content: ''; + position: absolute; + width: 100%; + height: 16px; + background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)); + border-radius: 999px; + pointer-events: none; + z-index: -1; + top: -1px; + left: 4px; + scale: 0.85; + } + + & svg { + overflow: visible; + min-width: calc(100% + 2.5rem); + } +} + +#PanelUI-zen-gradient-generator-opacity { margin: 0 !important; - margin-top: 5px !important; background: transparent; + z-index: 2; &::-moz-range-thumb { - background: var(--zen-colors-tertiary); - border: 2px solid var(--zen-colors-border); - border-radius: 12px; - height: 25px; - width: 13px; + background: light-dark(black, white); + border-radius: 999px; + height: var(--zen-thumb-height); + width: var(--zen-thumb-width); cursor: pointer; + border: none; } &::-moz-range-track { - background: light-dark(rgba(0, 0, 0, 0.3), rgba(255, 255, 255, 0.3)); border-radius: 999px; - height: 6px; + height: 18px; } &::-moz-range-progress { - background: var(--zen-primary-color); - border-radius: 999px; - height: 8px; + background: transparent; } } .zen-theme-picker-gradient { position: relative; - border-radius: calc(var(--zen-border-radius) - 2px); overflow: hidden; border-radius: var(--zen-border-radius); - min-height: calc(var(--panel-width) - var(--panel-padding) * 2); - margin-bottom: 20px; - - background: var(--zen-toolbar-element-bg); + min-height: calc(var(--panel-width) - var(--panel-padding) * 2 - 2px); + background: color-mix(in srgb, var(--zen-toolbar-element-bg) 60%, transparent 40%); background-image: radial-gradient( - light-dark(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.4)) 1px, + light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.1)) 1px, transparent 0 ); background-position: -19px -19px; @@ -220,7 +263,7 @@ box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1); } cursor: pointer; - border: 2px solid #ffffff; + border: 3px solid #ffffff; animation: zen-theme-picker-dot-animation 0.5s; transform: translate(-50%, -50%); @@ -229,7 +272,7 @@ height: 36px; border-width: 4px; z-index: 2; - transition: transform 0.1s; + transition: transform 0.2s; &:hover { transform: scale(1.05) translate(-50%, -50%); } @@ -241,6 +284,10 @@ } } +#PanelUI-zen-gradient-generator-view { + gap: 10px; +} + #PanelUI-zen-gradient-generator-color-click-to-add { position: absolute; font-weight: 600; @@ -255,17 +302,15 @@ } } -#PanelUI-zen-gradient-generator-color-actions { +#PanelUI-zen-gradient-generator-color-actions, +#PanelUI-zen-gradient-generator-scheme { display: flex; position: absolute; - bottom: 8px; + bottom: 12px; left: 50%; z-index: 1; transform: translateX(-50%); - & .separator, - & #PanelUI-zen-gradient-generator-color-toggle-algo { - background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.15)); - } + gap: 5px; & button { border: none !important; @@ -273,17 +318,20 @@ min-width: fit-content !important; transition: background 0.2s; appearance: none; + max-height: 26px; + max-width: 26px; + color: light-dark(rgba(0, 0, 0, 0.7), rgba(255, 255, 255, 0.9)); & .button-box { gap: 0.1rem; } - &:not(#PanelUI-zen-gradient-generator-color-toggle-algo) .button-text { + & .button-text { display: none; } &:hover { - background: light-dark(#cfcfcf, #313131); + background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)); } &[disabled] { @@ -291,12 +339,11 @@ cursor: not-allowed; } } +} - & .separator { - width: 1px; - margin: 0 0.5rem; - height: 30px; - } +#PanelUI-zen-gradient-generator-scheme { + top: 15px; + max-height: 32px; } @media not -moz-pref('zen.theme.gradient.show-custom-colors') { @@ -311,9 +358,8 @@ position: relative; @media (-moz-platform: macos) { - width: 25%; - aspect-ratio: 1; - height: unset; + width: 5rem; + height: 5rem; } &::after { @@ -381,32 +427,9 @@ } } -#PanelUI-zen-gradient-generator-rotation-line { - border: 1px solid var(--zen-colors-border); - position: absolute; - --rotation-padding: 15px; - width: calc(100% - var(--rotation-padding) * 2); - border-bottom-color: transparent; - height: calc(100% - var(--rotation-padding) * 2); - top: var(--rotation-padding); - left: var(--rotation-padding); - border-radius: 50%; - opacity: 0; - pointer-events: none; -} - -#PanelUI-zen-gradient-generator-rotation-dot { - position: absolute; - width: 25px; - height: 25px; - border-radius: 50%; - border: 1px solid var(--zen-colors-border); - background: var(--zen-colors-tertiary); - opacity: 0; - cursor: pointer; - z-index: 2; - transition: transform 0.1s; - &:hover { - transform: scale(1.1); - } +#PanelUI-zen-gradient-generator-color-page-left, +#PanelUI-zen-gradient-generator-color-page-right { + max-width: 28px; + max-height: 28px; + margin: 0 !important; }