no-bug: Small changes

This commit is contained in:
mr. m
2026-09-07 17:17:18 +02:00
parent f257ff6d8a
commit 2564a8973e
3 changed files with 111 additions and 107 deletions

View File

@@ -86,11 +86,18 @@ export class ZenLibrary extends MozLitElement {
this.addEventListener("animationend", this);
// Add connected call back and make `appContentWrapper` transform translate the oposite of this element
this.#resizeObserver = new ResizeObserver(() => {
if (this._swipeActive) {
this._swipeWrapperTargetPx = this.#computeWrapperTargetPx();
ZenLibrary.updateSwipeProgress(this._swipeProgress ?? 0);
return;
}
if (gZenWorkspaces._swipeManager._swipeState.librarySwiping) {
return;
}
let translateX = this.#computeWrapperTargetPx();
lazy.appContentWrapper.style.transform = `translateX(${translateX}px)`;
requestAnimationFrame(() => {
lazy.appContentWrapper.style.transform = `translateX(${translateX}px)`;
});
});
this.#resizeObserver.observe(this);
for (const Section of Object.values(lazy.ZenLibrarySections)) {
@@ -221,7 +228,7 @@ export class ZenLibrary extends MozLitElement {
break;
}
case "animationend": {
if (event.animationName === "zen-library-tab-icon-play") {
if (event.animationName === "zen-library-sprite-play") {
event.target.closest(".zen-library-tab")?.removeAttribute("animate");
}
break;
@@ -313,9 +320,12 @@ export class ZenLibrary extends MozLitElement {
*/
#computeWrapperTargetPx() {
const isRightSide = gZenVerticalTabsManager._prefsRightSide;
let translateX = this.getBoundingClientRect()[
isRightSide ? "left" : "right"
];
const selfTransform = getComputedStyle(this).transform;
const selfOffset =
selfTransform === "none" ? 0 : new DOMMatrix(selfTransform).m41;
let translateX =
this.getBoundingClientRect()[isRightSide ? "left" : "right"] -
selfOffset;
const contentPosition = window.windowUtils.getBoundsWithoutFlushing(
lazy.appContentWrapper
)[isRightSide ? "right" : "left"];
@@ -396,21 +406,11 @@ export class ZenLibrary extends MozLitElement {
instance.#cancelActiveAnimations();
const wasOpen = instance.hasAttribute("open");
if (wasOpen) {
// Library is already open; the wrapper's current inline transform IS
// the target — no remeasure needed.
instance._swipeWrapperTargetPx =
new DOMMatrix(lazy.appContentWrapper.style.transform).m41 ||
instance.#computeWrapperTargetPx();
} else {
// Measure the open-state wrapper target without flashing: temporarily
// mark [open] so layout reflects the open position, then revert.
instance.setAttribute("open", "true");
instance.style.visibility = "hidden";
await new Promise(r => requestAnimationFrame(r));
instance._swipeWrapperTargetPx = instance.#computeWrapperTargetPx();
instance.style.visibility = "";
instance.removeAttribute("open");
lazy.appContentWrapper.style.transform = "";
}
instance._swipeActive = true;
// Initialize visual state to match the current attribute.

View File

@@ -475,21 +475,18 @@ class SearchSection extends LibrarySection {
}
/**
* Open `url` in a Glance overlay anchored to the clicked item.
* Open `url` in a Glance overlay.
*
* @param {Event} event
* @param {string} url
*/
_openInGlance(event, url) {
const itemEl = event.currentTarget;
const rect = window.windowUtils.getBoundsWithoutFlushing(itemEl);
_openInGlance(url) {
const tabPanelRect = window.windowUtils.getBoundsWithoutFlushing(
window.gBrowser.tabpanels
);
window.gZenGlanceManager.openGlance({
url,
clientX: rect.left - tabPanelRect.left,
clientY: rect.top - tabPanelRect.top,
clientX: window.innerWidth / 2 - tabPanelRect.left,
clientY: window.innerHeight / 2 - tabPanelRect.top,
width: 0,
height: 0,
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
@@ -515,6 +512,26 @@ class SearchSection extends LibrarySection {
return html``;
}
/**
* Shared empty-state markup: the section's sprite icon above the localized
* message. The [data-section] attribute picks the sprite strip, see
* zen-library.css.
*
* @param {string} emptyL10nId - message shown when the section has no data.
*/
_renderEmptyState(emptyL10nId) {
return html`
<div class="empty-state" data-section=${this.constructor.id}>
<div class="empty-state-icon">
<div class="empty-state-icon-image"></div>
</div>
<label
data-l10n-id=${this.searchTerm ? "library-search-no-results" : emptyL10nId}
></label>
</div>
`;
}
render() {
const hasFilters = !!this._filters().length;
return html`
@@ -917,12 +934,7 @@ class ZenLibraryHistorySection extends ProgressiveSearchSection {
return html``;
}
if (this.isEmpty) {
return html`
<div
class="empty-state"
data-l10n-id=${this.searchTerm ? "library-search-no-results" : "library-history-empty"}
></div>
`;
return this._renderEmptyState("library-history-empty");
}
const slice = this._getRenderedSlice();
@@ -960,9 +972,7 @@ class ZenLibraryHistorySection extends ProgressiveSearchSection {
}
/**
* Plain click on a history row opens the page in a Glance overlay; holding
* Ctrl (or any other modifier / middle-click) falls back to the standard
* "where to open" routing.
* Clicking a history row opens the page in a new tab.
*
* @param {Event} event
* @param {object} item
@@ -976,21 +986,6 @@ class ZenLibraryHistorySection extends ProgressiveSearchSection {
}
event.preventDefault();
const hasModifier =
event.ctrlKey || event.metaKey || event.shiftKey || event.altKey;
const isMiddleClick = event.button === 1;
if (
!hasModifier &&
!isMiddleClick &&
Services.prefs.getBoolPref("zen.glance.enabled", true)
) {
// Glance overlays on top of the library; keep the library open so the
// user can fire another glance without re-opening it.
this._openInGlance(event, item.url);
return;
}
const where = lazy.BrowserUtils.whereToOpenLink(event, false, true);
window.openTrustedLinkIn(item.url, where === "current" ? "tab" : where);
this._closeLibrary();
@@ -1031,15 +1026,6 @@ class ZenLibraryHistorySection extends ProgressiveSearchSection {
this._closeLibrary();
},
},
{
l10nId: "library-item-context-open-glance",
onClick: () => {
// Use the section element as the anchor — context menu opens at
// the cursor and the original item element isn't tracked here.
const fakeEvent = { currentTarget: this };
this._openInGlance(fakeEvent, item.url);
},
},
{
l10nId: "library-item-context-open-new-window",
onClick: () => {
@@ -1177,12 +1163,7 @@ class ZenLibraryDownloadsSection extends ProgressiveSearchSection {
const slice = this._getRenderedSlice();
if (this.isEmpty) {
return html`
<div
class="empty-state"
data-l10n-id=${this.searchTerm ? "library-search-no-results" : "library-downloads-empty"}
></div>
`;
return this._renderEmptyState("library-downloads-empty");
}
const groups = this.#groupByDate(slice);
@@ -1313,7 +1294,7 @@ class ZenLibraryDownloadsSection extends ProgressiveSearchSection {
const previewUrl =
dl.source.referrerInfo?.originalReferrer?.spec || dl.source.url;
if (previewUrl) {
this._openInGlance(event, previewUrl);
this._openInGlance(previewUrl);
}
return;
}
@@ -1631,12 +1612,7 @@ class ZenLibraryBoostsSection extends SearchSection {
renderSearchResults() {
const boosts = this.#getBoosts();
if (boosts.length === 0) {
return html`
<div
class="empty-state"
data-l10n-id=${this.searchTerm ? "library-search-no-results" : "library-boosts-empty"}
></div>
`;
return this._renderEmptyState("library-boosts-empty");
}
return html`${boosts.map(b => this.#renderBoost(b))}`;
}
@@ -1647,7 +1623,7 @@ class ZenLibraryBoostsSection extends SearchSection {
class="library-item library-boost-item"
data-key=${`${boost.domain}|${boost.id}`}
?active=${boost.isActive}
@click=${e => this.#openBoost(e, boost)}
@click=${() => this.#openBoost(boost)}
@contextmenu=${e => this._onItemContextMenu(e, boost)}
>
<div class="library-item-stack">
@@ -1693,12 +1669,11 @@ class ZenLibraryBoostsSection extends SearchSection {
* Open the boost's domain in a Glance overlay and pop the boost editor
* window next to it so the user can tweak the boost while previewing.
*
* @param {Event} event
* @param {object} boost
*/
#openBoost(event, boost) {
#openBoost(boost) {
const url = `https://${boost.domain}/`;
this._openInGlance(event, url);
this._openInGlance(url);
try {
const stored = lazy.gZenBoostsManager.loadBoostFromStore(
boost.domain,

View File

@@ -83,6 +83,8 @@ zen-library[open] {
}
.zen-library-tab {
--zen-library-sprite-size: 28px;
display: flex;
position: relative;
justify-content: center;
@@ -114,54 +116,56 @@ zen-library[open] {
}
& .zen-library-tab-icon {
width: 28px;
height: 28px;
width: var(--zen-library-sprite-size);
height: var(--zen-library-sprite-size);
overflow: clip;
}
& .zen-library-tab-icon-image {
width: calc(36 * 28px);
height: 28px;
fill: rgba(255, 255, 255, 0.8);
stroke: var(--zen-colors-primary);
-moz-context-properties: fill, stroke;
transform: translateX(0);
}
&[data-section="history"] .zen-library-tab-icon-image {
background-image: url("chrome://browser/skin/zen-icons/library/library-history-sprite.svg");
}
&[data-section="downloads"] .zen-library-tab-icon-image {
background-image: url("chrome://browser/skin/zen-icons/library/library-downloads-sprite.svg");
}
&[data-section="boosts"] .zen-library-tab-icon-image {
background-image: url("chrome://browser/skin/zen-icons/library/library-boosts-sprite.svg");
}
&[data-section="spaces"] .zen-library-tab-icon-image {
background-image: url("chrome://browser/skin/zen-icons/library/library-spaces-sprite.svg");
}
&[data-section="media"] .zen-library-tab-icon-image {
background-image: url("chrome://browser/skin/zen-icons/library/library-media-sprite.svg");
}
@media (prefers-reduced-motion: no-preference) {
&[animate] .zen-library-tab-icon-image {
animation: zen-library-tab-icon-play 0.583s steps(36, jump-none);
animation: zen-library-sprite-play 0.583s steps(36, jump-none);
}
}
}
@keyframes zen-library-tab-icon-play {
.zen-library-tab-icon-image,
.empty-state-icon-image {
width: calc(36 * var(--zen-library-sprite-size));
height: var(--zen-library-sprite-size);
background-size: 100% 100%;
fill: rgba(255, 255, 255, 0.8);
stroke: var(--zen-colors-primary);
-moz-context-properties: fill, stroke;
transform: translateX(0);
}
[data-section="history"] :is(.zen-library-tab-icon-image, .empty-state-icon-image) {
background-image: url("chrome://browser/skin/zen-icons/library/library-history-sprite.svg");
}
[data-section="downloads"] :is(.zen-library-tab-icon-image, .empty-state-icon-image) {
background-image: url("chrome://browser/skin/zen-icons/library/library-downloads-sprite.svg");
}
[data-section="boosts"] :is(.zen-library-tab-icon-image, .empty-state-icon-image) {
background-image: url("chrome://browser/skin/zen-icons/library/library-boosts-sprite.svg");
}
[data-section="spaces"] :is(.zen-library-tab-icon-image, .empty-state-icon-image) {
background-image: url("chrome://browser/skin/zen-icons/library/library-spaces-sprite.svg");
}
[data-section="media"] :is(.zen-library-tab-icon-image, .empty-state-icon-image) {
background-image: url("chrome://browser/skin/zen-icons/library/library-media-sprite.svg");
}
@keyframes zen-library-sprite-play {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(35 * -28px));
transform: translateX(calc(35 * -1 * var(--zen-library-sprite-size)));
}
}
@@ -361,7 +365,7 @@ zen-library[open] {
}
.library-item:hover .library-item-background {
background-color: var(--tab-hover-background-color);
background-color: var(--tab-background-color-hover);
outline-color: var(--tab-hover-outline-color);
}
@@ -573,11 +577,36 @@ zen-library[open] {
.empty-state {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
font-size: 2em;
font-weight: 600;
opacity: 0.5;
@media (prefers-reduced-motion: no-preference) {
animation: zen-library-empty-state-enter 0.3s cubic-bezier(0.32, 0.72, 0, 1);
& .empty-state-icon-image {
animation: zen-library-sprite-play 0.583s steps(36, jump-none);
}
}
}
@keyframes zen-library-empty-state-enter {
from {
opacity: 0;
transform: translateY(12px) scale(0.98);
}
}
.empty-state-icon {
--zen-library-sprite-size: 56px;
width: var(--zen-library-sprite-size);
height: var(--zen-library-sprite-size);
overflow: clip;
}
/* Boosts section */