tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 5dafdf8873c60bd49d3d905bdb44654502177409
parent 6deebe02578a7cc69dff2ec7686948f2f436f195
Author: Stephen Thompson <sthompson@mozilla.com>
Date:   Wed, 19 Nov 2025 18:35:58 +0000

Bug 1994535 - tab note icon r=desktop-theme-reviewers,tabbrowser-reviewers,dao

Displays a tab note icon on a tab when a tab has the new `"tab-note"` attribute. There is no code connected to this yet; this is display only.

When there is enough space on the tab, the .tab-note-icon appears as a new element next to the close button at the inline end of the tab.

When space is constrained, the .tab-note-icon-overlay appears in the same place as existing media/crash indicators (.tab-icon-overlay). The tab notes icon takes lowest precedence.

Differential Revision: https://phabricator.services.mozilla.com/D271255

Diffstat:
Mbrowser/components/tabbrowser/content/tab.js | 16++++++++++++++++
Mbrowser/themes/shared/tabbrowser/tabs.css | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mtoolkit/themes/shared/desktop-jar.inc.mn | 2++
Atoolkit/themes/shared/icons/tab-notes-12.svg | 6++++++
Atoolkit/themes/shared/icons/tab-notes.svg | 5+++++
5 files changed, 165 insertions(+), 18 deletions(-)

diff --git a/browser/components/tabbrowser/content/tab.js b/browser/components/tabbrowser/content/tab.js @@ -27,6 +27,7 @@ <html:img class="tab-icon-image" role="presentation" decoding="sync" /> <image class="tab-sharing-icon-overlay" role="presentation"/> <image class="tab-icon-overlay" role="presentation"/> + <image class="tab-note-icon-overlay" role="presentation"/> </stack> <html:moz-button type="icon ghost" size="small" class="tab-audio-button" tabindex="-1"></html:moz-button> <vbox class="tab-label-container" @@ -38,6 +39,7 @@ <label class="tab-icon-sound-label tab-icon-sound-pip-label" data-l10n-id="browser-tab-audio-pip" role="presentation"/> </hbox> </vbox> + <image class="tab-note-icon" role="presentation"/> <image class="tab-close-button close-icon" role="button" data-l10n-id="tabbrowser-close-tabs-button" data-l10n-args='{"tabCount": 1}' keyNav="false"/> </hbox> </stack> @@ -392,6 +394,20 @@ return null; } + /** + * @returns {boolean} + */ + get hasTabNote() { + return this.hasAttribute("tab-note"); + } + + /** + * @param {boolean} val + */ + set hasTabNote(val) { + this.toggleAttribute("tab-note", val); + } + updateLastAccessed(aDate) { this._lastAccessed = this.selected ? Infinity : aDate || Date.now(); } diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css @@ -131,10 +131,13 @@ min-height: var(--tabstrip-min-height); --tab-min-width: 76px; + --tab-min-width-extra-icons: 0px; + --tab-min-width-uidensity: 0px; --tab-max-width: 225px; - :root[uidensity="touch"] & .tabbrowser-tab[fadein]:not([pinned]) { - /* Touch mode needs additional space for the close button. */ - min-width: max(var(--tab-min-width-pref, var(--tab-min-width)), 86px); + + /* Touch mode needs additional space for the close button. */ + :root[uidensity="touch"] & { + --tab-min-width-uidensity: 10px; } /* Make it easier to drag tabs by expanding the drag area downwards. */ @@ -205,13 +208,28 @@ /* Needed to avoid clipping the tab-background shadow, which has a 4px blur. */ overflow-clip-margin: var(--tab-overflow-clip-margin); - &:not([pinned]) { + #tabbrowser-tabs[orient="horizontal"] &:not([pinned]) { flex: 100 100; max-width: var(--tab-max-width); transition: var(--tab-width-transition); - #tabbrowser-tabs[orient="horizontal"] &[fadein] { - min-width: var(--tab-min-width-pref, var(--tab-min-width)); + &:not([fadein]) { + max-width: 0.1px; + min-width: 0.1px; + visibility: hidden; + } + + &[fadein] { + min-width: calc(var(--tab-min-width-pref, var(--tab-min-width)) + var(--tab-min-width-extra-icons) + var(--tab-min-width-uidensity)); + &:is([muted], [soundplaying], [activemedia-blocked]):not([tab-note]) { + --tab-min-width-extra-icons: 24px; + } + &[tab-note]:not([muted], [soundplaying], [activemedia-blocked]) { + --tab-min-width-extra-icons: 24px; + } + &[tab-note]:is([muted], [soundplaying], [activemedia-blocked]) { + --tab-min-width-extra-icons: 48px; + } } } @@ -230,12 +248,6 @@ } } - &:not([pinned], [fadein]) { - max-width: 0.1px; - min-width: 0.1px; - visibility: hidden; - } - #tabbrowser-tabs[movingtab] & { position: relative; } @@ -268,10 +280,6 @@ removed from root such as when toggling the sidebar to expand with the toolbar button. */ &:is([muted], [soundplaying], [activemedia-blocked]) { --tab-icon-end-margin: 2px; - - #tabbrowser-tabs[orient="horizontal"] &[fadein]:not([pinned]) { - min-width: max(var(--tab-min-width-pref, var(--tab-min-width)), 100px); - } } } } @@ -558,7 +566,8 @@ } .tab-sharing-icon-overlay, -.tab-icon-overlay { +.tab-icon-overlay, +.tab-note-icon-overlay { display: none; } @@ -744,6 +753,72 @@ } } +/* + * Tab note icon that overlays the favicon for pinned tabs and the collapsed + * vertical tab strip. The horizontal tab strip and expanded vertical tab strip + * get a separate, more spacious treatment using the `.tab-notes-icon` image. + * Note: This is intended to display instead of the `.tab-icon-overlay`. This + * is defined separately from `.tab-icon-overlay` since the tab notes icon has + * fewer features (e.g. no icon interactivity) and + */ +.tab-note-icon-overlay { + position: relative; + padding: 2px; + top: -7px; + inset-inline-end: -7px; + z-index: 1; /* Overlay tab title */ + list-style-image: url("chrome://global/skin/icons/tab-notes-12.svg"); + + background-color: var(--lwt-accent-color); + background-image: linear-gradient(transparent), linear-gradient(var(--toolbox-bgcolor)); + -moz-context-properties: fill; + fill: var(--icon-color); + color-scheme: var(--tab-selected-color-scheme); + border-radius: var(--border-radius-circle); + + .browser-toolbox-background:-moz-window-inactive .tabbrowser-tab:not([selected]) & { + background-image: linear-gradient(transparent), linear-gradient(var(--toolbox-bgcolor-inactive)); + } + .tabbrowser-tab[selected] & { + background-image: linear-gradient(transparent), linear-gradient(var(--tab-selected-bgcolor)), linear-gradient(var(--toolbox-bgcolor)); + } + + .browser-toolbox-background:-moz-window-inactive .tabbrowser-tab[selected] & { + background-image: linear-gradient(transparent), linear-gradient(var(--tab-selected-bgcolor)), linear-gradient(var(--toolbox-bgcolor-inactive)); + } + + #tabbrowser-tabs[orient="vertical"] & { + top: 7px; + } + + #tabbrowser-tabs[orient="vertical"]:not([expanded]) .tabbrowser-tab[tab-note]:not([crashed], [soundplaying], [muted], [activemedia-blocked]) &, + .tabbrowser-tab[pinned][tab-note]:not([crashed], [soundplaying], [muted], [activemedia-blocked]) & { + display: revert; + } + + /* stylelint-disable-next-line media-query-no-invalid */ + @media -moz-pref("sidebar.visibility", "expand-on-hover") { + /* We need these rules to apply at all times when the sidebar.visibility + pref is set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute + has been added to root. There are certain scenarios when that attribute is temporarily + removed from root such as when toggling the sidebar to expand with the toolbar button. */ + #tabbrowser-tabs[orient="vertical"] .tabbrowser-tab[tab-note]:not([crashed], [soundplaying], [muted], [activemedia-blocked]) & { + display: revert; + } + } + + /* stylelint-disable-next-line media-query-no-invalid */ + @media not -moz-pref("sidebar.visibility", "expand-on-hover") { + /* We need these rules to apply at all times when the sidebar.visibility + pref is not set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute + has not been added to root. There are certain scenarios when that attribute is temporarily + removed from root such as when toggling the sidebar to expand with the toolbar button. */ + #tabbrowser-tabs[orient="vertical"]:not([expanded]) .tabbrowser-tab[tab-note]:not([crashed], [soundplaying], [muted], [activemedia-blocked]) & { + display: revert; + } + } +} + .tab-audio-button { display: none; margin-inline-end: var(--tab-icon-end-margin); @@ -836,7 +911,7 @@ * the button has a visible outline shown */ @media not (forced-colors) { #tabbrowser-tabs[orient="horizontal"] { - .tabbrowser-tab:not([labelendaligned], :hover) > .tab-stack > .tab-content > .tab-close-button { + .tabbrowser-tab:not([labelendaligned], [tab-note], :hover) > .tab-stack > .tab-content > .tab-close-button { padding-inline-start: 0; width: 18px; } @@ -2445,6 +2520,49 @@ toolbar:not(#TabsToolbar) #firefox-view-button { } } +/* + * Tab note icon that displays inline on unpinned tabs in the horizontal tab + * strip and the expanded vertical tab strip. Pinned tabs and the collapsed + * vertical tab strip get a separate space-constrained treatment using the + * `.tab-notes-icon-overlay` image. + */ +.tab-note-icon { + display: none; + box-sizing: border-box; + + width: calc(var(--icon-size) + 8px); + height: calc(var(--icon-size) + 8px); + padding: 4px; + margin-inline-end: calc(var(--tab-inline-padding) / -2); + + list-style-image: url("chrome://global/skin/icons/tab-notes.svg"); + -moz-context-properties: fill; + fill: var(--icon-color); + + #tabbrowser-tabs[orient="vertical"][expanded] & { + /* + * Keep the tab note icon out of the way of the close button, even when + * the close button is not showing because the tab is not being hovered. + */ + .tabbrowser-tab:not(:hover) & { + margin-inline-end: calc(var(--icon-size) + 8px - var(--tab-close-button-padding)); + } + .tabbrowser-tab:is([visuallyselected], :hover) & { + margin-inline-end: calc(var(--tab-close-button-padding) / -2); + } + } +} + +/* stylelint-disable-next-line media-query-no-invalid */ +@media -moz-pref("browser.tabs.notes.enabled") and (not -moz-pref("sidebar.visibility", "expand-on-hover")) { + .tabbrowser-tab[tab-note]:not([pinned]) .tab-note-icon { + #tabbrowser-tabs[orient="horizontal"] &, + #tabbrowser-tabs[orient="vertical"][expanded] & { + display: revert; + } + } +} + /* NOTE(emilio): The double class is an specificity hack to win over the * .subviewbutton-iconic rules */ .tab-group-icon.tab-group-icon { diff --git a/toolkit/themes/shared/desktop-jar.inc.mn b/toolkit/themes/shared/desktop-jar.inc.mn @@ -115,6 +115,8 @@ skin/classic/global/icons/sort-arrow.svg (../../shared/icons/sort-arrow.svg) skin/classic/global/icons/trending.svg (../../shared/icons/trending.svg) skin/classic/global/icons/trophy.svg (../../shared/icons/trophy.svg) + skin/classic/global/icons/tab-notes-12.svg (../../shared/icons/tab-notes-12.svg) + skin/classic/global/icons/tab-notes.svg (../../shared/icons/tab-notes.svg) skin/classic/global/icons/thumbs-down-20.svg (../../shared/icons/thumbs-down-20.svg) skin/classic/global/icons/thumbs-up-20.svg (../../shared/icons/thumbs-up-20.svg) skin/classic/global/icons/update-icon.svg (../../shared/icons/update-icon.svg) diff --git a/toolkit/themes/shared/icons/tab-notes-12.svg b/toolkit/themes/shared/icons/tab-notes-12.svg @@ -0,0 +1,6 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<svg width="12" height="12" viewBox="0 0 12 12" fill="context-fill" fill-opacity="context-fill-opacity" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M9.52441 1C10.3396 1.00022 10.9992 1.66089 11.001 2.47461V7.33789C11.001 7.49909 10.9387 7.65415 10.8271 7.77051L7.91016 10.8086C7.7923 10.9313 7.62915 11.001 7.45898 11.001H2.47559C1.66073 11.0008 1.00021 10.3403 1 9.52539V2.47559C1.00022 1.66074 1.66074 1.00022 2.47559 1H9.52441ZM2.47559 2.25C2.35109 2.25022 2.25022 2.35109 2.25 2.47559V9.52539C2.25021 9.6499 2.35109 9.75075 2.47559 9.75098H7V7.5C7 7.224 7.224 7 7.5 7H9.75098V2.47754L9.74609 2.43164C9.72477 2.32779 9.63331 2.2502 9.52441 2.25H2.47559Z"/> +</svg> diff --git a/toolkit/themes/shared/icons/tab-notes.svg b/toolkit/themes/shared/icons/tab-notes.svg @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<svg width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity" xmlns="http://www.w3.org/2000/svg"><path d="m14.78 10.78-4 4a.747.747 0 0 1-.53.22H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v7.25c0 .199-.079.39-.22.53zm-1.28-.841V3c0-.275-.225-.5-.5-.5H3c-.275 0-.5.225-.5.5v10c0 .275.225.5.5.5h6.939l.061-.061V10.5a.5.5 0 0 1 .5-.5h2.939l.061-.061z"/></svg> +\ No newline at end of file