From b3ea3664a28d8b3d8c501a6ae675901410553460 Mon Sep 17 00:00:00 2001 From: Nicolas Chevobbe Date: Wed, 11 Dec 2024 15:37:17 +0100 Subject: [PATCH 1/2] Adapt time-slice selection in High Contrast Mode. Make sure the start and end grips look like button, make the outbound of the selection even dimmer and add border to make the selection super obvious. --- src/components/timeline/Selection.css | 51 ++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/components/timeline/Selection.css b/src/components/timeline/Selection.css index b92c5f20dd..6335f65c28 100644 --- a/src/components/timeline/Selection.css +++ b/src/components/timeline/Selection.css @@ -9,6 +9,10 @@ 100vw - var(--thread-label-column-width) - var(--vertical-scrollbar-reserved-width) ); + --grippy-range-background-color: #aaa; + --grippy-range-border-color: white; + --grippy-range-hover-background-color: #888; + --selection-outbound-opacity: 0.1; position: relative; display: flex; @@ -54,7 +58,8 @@ .timelineSelectionDimmerBefore, .timelineSelectionDimmerAfter { flex-shrink: 0; - background: rgb(12 12 13 / 0.1); + background: rgb(12 12 13 / var(--selection-outbound-opacity)); + forced-color-adjust: none; } .timelineSelectionDimmerAfter { @@ -79,10 +84,10 @@ z-index: 3; width: 0; padding: 3px; - border: 1px solid white; + border: 1px solid var(--grippy-range-border-color); border-radius: 5px; margin: 0 -4px; - background: #aaa; + background: var(--grippy-range-background-color); cursor: ew-resize; } @@ -99,7 +104,7 @@ .timelineSelectionGrippyRangeEnd:hover, .draggingEnd > .timelineSelectionGrippyRangeEnd, :not(.draggingStart, .draggingEnd) > .timelineSelectionGrippyRangeEnd.dragging { - background: #888; + background: var(--grippy-range-hover-background-color); } .timelineSelectionGrippyMoveRange { @@ -153,6 +158,14 @@ will-change: opacity; } +.timelineSelectionOverlayZoomButton::before { + position: absolute; + display: grid; + content: url(../../../res/img/svg/zoom-icon.svg); + inset: 0; + place-content: center; +} + .timelineSelectionOverlayZoomButton.hidden { opacity: 0 !important; pointer-events: none; @@ -181,4 +194,34 @@ .timelineSelectionHoverLine { background-color: CanvasText; } + + .timelineSelection { + --grippy-range-background-color: ButtonText; + --grippy-range-border-color: ButtonBorder; + --grippy-range-hover-background-color: SelectedItem; + --selection-outbound-opacity: 0.6; + } + + .timelineSelectionDimmerBefore { + border-inline-end: 1px solid CanvasText; + } + + .timelineSelectionDimmerAfter { + border-inline-start: 1px solid CanvasText; + } + + .timelineSelectionOverlayZoomButton { + border-color: ButtonText; + background-color: ButtonFace; + opacity: 1; + } + + .timelineSelectionOverlayZoomButton:hover { + background-color: SelectedItem; + } + + .timelineSelectionOverlayZoomButton:active:hover { + border-color: SelectedItem; + background-color: ButtonFace; + } } From a42f5163668009567594e9fa5f3b1a7b7e54581e Mon Sep 17 00:00:00 2001 From: Nicolas Chevobbe Date: Thu, 5 Dec 2024 10:42:59 +0100 Subject: [PATCH 2/2] Add SVG filter to be able to control icons color in CSS We can use CSS variables whose values are extracted and put into SVG filters that we can then apply on top of the icon we use, in CSS. The time-slice zoom icon takes advantage of this new capability to adapt to High Contrast Mode. --- res/css/style.css | 21 +++++++++++ res/index.html | 1 + src/components/timeline/Selection.css | 22 +++++++++--- src/index.js | 51 +++++++++++++++++++++++++++ src/types/globals/Window.js | 1 + 5 files changed, 91 insertions(+), 5 deletions(-) diff --git a/res/css/style.css b/res/css/style.css index 03e8dea49e..c8bd550a77 100644 --- a/res/css/style.css +++ b/res/css/style.css @@ -39,6 +39,19 @@ body { color: var(--grey-90); } +@media (forced-colors: active) { + :root { + /* The following properties are retrieved in index.js to create SVG filters that + * we can apply on icons to control their color. + * These variable can be declared in any rule, as long as their value is still + * a valid color (which means we can use `light-dark()` or any other color functions). + * The colors can be applied on SVG icons with `filter: url(#--var-name)` */ + --button-icon-color: ButtonText; + --button-icon-hover-color: SelectedItem; + --button-icon-active-color: SelectedItem; + } +} + .profileFilterNavigator { height: 24px; flex-shrink: 1; @@ -49,3 +62,11 @@ body { flex: 1; flex-flow: column nowrap; } + +#svg-filters { + position: absolute; + overflow: hidden; + width: 0; + height: 0; + inset-inline-start: -1000vw; +} diff --git a/res/index.html b/res/index.html index 894db7c501..0e8721a65e 100644 --- a/res/index.html +++ b/res/index.html @@ -10,6 +10,7 @@ +
diff --git a/src/components/timeline/Selection.css b/src/components/timeline/Selection.css index 6335f65c28..dc05ed3555 100644 --- a/src/components/timeline/Selection.css +++ b/src/components/timeline/Selection.css @@ -150,8 +150,7 @@ border: 1px solid rgb(0 0 0 / 0.2); border-radius: 100%; margin: -15px; - background: url(../../../res/img/svg/zoom-icon.svg) center center no-repeat - rgb(255 255 255 / 0.6); + background-color: rgb(255 255 255 / 0.6); opacity: 0.5; pointer-events: auto; transition: opacity 200ms ease-in-out; @@ -161,7 +160,7 @@ .timelineSelectionOverlayZoomButton::before { position: absolute; display: grid; - content: url(../../../res/img/svg/zoom-icon.svg); + content: url(firefox-profiler-res/img/svg/zoom-icon.svg); inset: 0; place-content: center; } @@ -216,12 +215,25 @@ opacity: 1; } + .timelineSelectionOverlayZoomButton::before { + filter: url(#--button-icon-color); + } + .timelineSelectionOverlayZoomButton:hover { - background-color: SelectedItem; + border-color: SelectedItem; + background-color: SelectedItemText; + } + + .timelineSelectionOverlayZoomButton:hover::before { + filter: url(#--button-icon-hover-color); } .timelineSelectionOverlayZoomButton:active:hover { - border-color: SelectedItem; + border-color: ButtonText; background-color: ButtonFace; } + + .timelineSelectionOverlayZoomButton:hover:active::before { + filter: url(#--button-icon-active-color); + } } diff --git a/src/index.js b/src/index.js index e12a34bf7b..efff61037d 100644 --- a/src/index.js +++ b/src/index.js @@ -44,6 +44,57 @@ window.geckoProfilerPromise = new Promise(function (resolve) { window.connectToGeckoProfiler = resolve; }); +// We're using an element from the page to apply filter from CSS rules +// to be able to dynamically change the color of SVG icons (e.g. to adapt +// to light/dark/high contrast themes). +const svgFiltersElement = document.getElementById('svg-filters'); +if (svgFiltersElement) { + const defineSvgFiltersForColors = () => { + const colors = [ + '--button-icon-color', + '--button-icon-hover-color', + '--button-icon-active-color', + ]; + for (const cssVariable of colors) { + let filterEl = document.getElementById(cssVariable); + if (!filterEl) { + svgFiltersElement.insertAdjacentHTML( + 'beforeend', + ` + + + ` + ); + filterEl = document.getElementById(cssVariable); + } + + if (!filterEl) { + continue; + } + + const feFloodEl = filterEl.querySelector('feFlood'); + + if (!feFloodEl) { + continue; + } + + const color = document.documentElement + ? getComputedStyle(document.documentElement).getPropertyValue( + cssVariable + ) + : ''; + + feFloodEl.setAttribute('flood-color', color); + } + }; + defineSvgFiltersForColors(); + + const forcedColorsMql = window.matchMedia('(forced-colors: active)'); + const darkSchemeMql = window.matchMedia('(prefers-color-scheme: dark)'); + forcedColorsMql.addEventListener('change', defineSvgFiltersForColors); + darkSchemeMql.addEventListener('change', defineSvgFiltersForColors); +} + const store = createStore(); const root = createRoot( ensureExists( diff --git a/src/types/globals/Window.js b/src/types/globals/Window.js index 5ce847297a..a9e61b8081 100644 --- a/src/types/globals/Window.js +++ b/src/types/globals/Window.js @@ -90,6 +90,7 @@ declare class Window { platform: string, }; postMessage: (message: any, targetOrigin: string) => void; + matchMedia: (matchMedia: string) => MediaQueryList; } declare var window: Window;