mirror of
https://github.com/zen-browser/desktop.git
synced 2026-01-06 13:27:50 +00:00
feat: Improved folder icon animations and dragging sensitivity, b=no-bug, c=folders, tabs
This commit is contained in:
@@ -19,9 +19,9 @@
|
||||
"update-ff:raw": "surfer update",
|
||||
"update-ff:rc": "python3 scripts/update_ff.py --rc",
|
||||
"update-ff:l10n": "python3 scripts/update_ff.py --just-l10n",
|
||||
"pretty": "prettier . --write && autopep8 -r --in-place scripts/ src/",
|
||||
"pretty": "prettier . --write --cache && autopep8 -r --in-place scripts/ src/",
|
||||
"lint": "npx eslint src/ && prettier . --check && autopep8 --diff scripts/ src/",
|
||||
"lint:fix": "npx eslint src/ --fix && npm run pretty",
|
||||
"lint:fix": "npm run pretty && npx eslint src/ --fix",
|
||||
"prepare": "husky",
|
||||
"reset-ff": "surfer reset",
|
||||
"surfer": "surfer",
|
||||
|
||||
@@ -33,41 +33,21 @@
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<!--Back Folder (path)-->
|
||||
<path d="M8 5.625H11.9473C12.4866 5.625 13.0105 5.80861 13.4316 6.14551L14.2881 6.83105C14.9308 7.34508 15.7298 7.625 16.5527 7.625H20C21.3117 7.625 22.375 8.68832 22.375 10V20C22.375 21.3117 21.3117 22.375 20 22.375H8C6.68832 22.375 5.625 21.3117 5.625 20V8C5.625 6.68832 6.68832 5.625 8 5.625Z" style="fill: var(--zen-folder-behind-bgcolor);">
|
||||
<animateTransform restart="whenNotActive" type="skewX" additive="sum" attributeName="transform" values="0;16" begin="0s" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="translate" additive="sum" attributeName="transform" values="0 0;-2 3.4" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="scale" additive="sum" attributeName="transform" values="1 1;0.85 0.85" begin="0s" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<path class="back" d="M8 5.625H11.9473C12.4866 5.625 13.0105 5.80861 13.4316 6.14551L14.2881 6.83105C14.9308 7.34508 15.7298 7.625 16.5527 7.625H20C21.3117 7.625 22.375 8.68832 22.375 10V20C22.375 21.3117 21.3117 22.375 20 22.375H8C6.68832 22.375 5.625 21.3117 5.625 20V8C5.625 6.68832 6.68832 5.625 8 5.625Z" style="fill: var(--zen-folder-behind-bgcolor);">
|
||||
</path>
|
||||
<path d="M8 5.625H11.9473C12.4866 5.625 13.0105 5.80861 13.4316 6.14551L14.2881 6.83105C14.9308 7.34508 15.7298 7.625 16.5527 7.625H20C21.3117 7.625 22.375 8.68832 22.375 10V20C22.375 21.3117 21.3117 22.375 20 22.375H8C6.68832 22.375 5.625 21.3117 5.625 20V8C5.625 6.68832 6.68832 5.625 8 5.625Z" style="stroke-width: 1.5px; stroke: var(--zen-folder-stroke); fill: url(#gradient-0); fill-opacity: 0.1;">
|
||||
<animateTransform restart="whenNotActive" type="skewX" additive="sum" attributeName="transform" values="0;16" begin="0s" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="translate" additive="sum" attributeName="transform" values="0 0;-2 3.4" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="scale" additive="sum" attributeName="transform" values="1 1;0.85 0.85" begin="0s" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<path class="back" d="M8 5.625H11.9473C12.4866 5.625 13.0105 5.80861 13.4316 6.14551L14.2881 6.83105C14.9308 7.34508 15.7298 7.625 16.5527 7.625H20C21.3117 7.625 22.375 8.68832 22.375 10V20C22.375 21.3117 21.3117 22.375 20 22.375H8C6.68832 22.375 5.625 21.3117 5.625 20V8C5.625 6.68832 6.68832 5.625 8 5.625Z" style="stroke-width: 1.5px; stroke: var(--zen-folder-stroke); fill: url(#gradient-0); fill-opacity: 0.1;">
|
||||
</path>
|
||||
<!--Front Folder (rect)-->
|
||||
<rect x="5.625" y="9.625" width="16.75" height="12.75" rx="2.375" style="fill: var(--zen-folder-front-bgcolor);">
|
||||
<animateTransform restart="whenNotActive" type="skewX" additive="sum" attributeName="transform" values="0;-16" begin="0s" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="translate" additive="sum" attributeName="transform" values="0 0;11.1 3.4" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="scale" additive="sum" attributeName="transform" values="1 1;0.85 0.85" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<rect class="front" x="5.625" y="9.625" width="16.75" height="12.75" rx="2.375" style="fill: var(--zen-folder-front-bgcolor);">
|
||||
</rect>
|
||||
<rect x="5.625" y="9.625" width="16.75" height="12.75" rx="2.375" style="stroke-width: 1.5px; stroke: var(--zen-folder-stroke); fill: url(#gradient-1); fill-opacity: 0.1;">
|
||||
<animateTransform restart="whenNotActive" type="skewX" additive="sum" attributeName="transform" values="0;-16" begin="0s" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="translate" additive="sum" attributeName="transform" values="0 0;11.1 3.4" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="scale" additive="sum" attributeName="transform" values="1 1;0.85 0.85" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<rect class="front" x="5.625" y="9.625" width="16.75" height="12.75" rx="2.375" style="stroke-width: 1.5px; stroke: var(--zen-folder-stroke); fill: url(#gradient-1); fill-opacity: 0.1;">
|
||||
</rect>
|
||||
<!--Icon (g)-->
|
||||
<g id="folder-icon" style="fill: var(--zen-folder-stroke);">
|
||||
<g class="icon" style="fill: var(--zen-folder-stroke);">
|
||||
<image href="" height="19" width="20"/>
|
||||
<animateTransform restart="whenNotActive" type="skewX" additive="sum" attributeName="transform" values="0;-16" begin="0s" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="translate" additive="sum" attributeName="transform" values="0 0;11.1 3.4" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="scale" additive="sum" attributeName="transform" values="1 1;0.85 0.85" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animate restart="whenNotActive" attributeName="opacity" values="0;0" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
</g>
|
||||
<!--End Icon (g)-->
|
||||
<g id="folder-dots" style="fill: var(--zen-folder-stroke);">
|
||||
<animateTransform restart="whenNotActive" type="skewX" additive="sum" attributeName="transform" values="0;-16" begin="0s" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="translate" additive="sum" attributeName="transform" values="0 0;11.1 3.4" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animateTransform restart="whenNotActive" type="scale" additive="sum" attributeName="transform" values="1 1;0.85 0.85" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<animate restart="whenNotActive" attributeName="opacity" values="0;0" dur="0.3s" fill="freeze" keyTimes="0; 1" calcMode="spline" keySplines="0.42 0 0 1"/>
|
||||
<g class="dots" style="fill: var(--zen-folder-stroke);">
|
||||
<ellipse cx="10" cy="16" rx="1.25" ry="1.25"/>
|
||||
<ellipse cx="14" cy="16" rx="1.25" ry="1.25"/>
|
||||
<ellipse cx="18" cy="16" rx="1.25" ry="1.25"/>
|
||||
@@ -89,13 +69,6 @@
|
||||
this.#initialized = true;
|
||||
this._activeTabs = [];
|
||||
this.icon.appendChild(ZenFolder.rawIcon.cloneNode(true));
|
||||
// Save original values for animations
|
||||
this.icon.querySelectorAll('animate, animateTransform, animateMotion').forEach((anim) => {
|
||||
const vals = anim.getAttribute('values');
|
||||
if (vals) {
|
||||
anim.dataset.origValues = vals;
|
||||
}
|
||||
});
|
||||
|
||||
this.labelElement.parentElement.setAttribute('context', 'zenFolderActions');
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#lastFolderContextMenu = null;
|
||||
|
||||
#foldersEnabled = false;
|
||||
#folderAnimCache = new Map();
|
||||
|
||||
#animationCount = 0;
|
||||
|
||||
@@ -304,7 +303,7 @@
|
||||
folder.removeAttribute('has-active');
|
||||
}
|
||||
this.collapseVisibleTab(folder, true);
|
||||
this.updateFolderIcon(folder, 'close', false);
|
||||
this.updateFolderIcon(folder, 'close');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -721,7 +720,7 @@
|
||||
async #convertFolderToSpace(folder) {
|
||||
const currentWorkspace = gZenWorkspaces.getActiveWorkspaceFromCache();
|
||||
let selectedTab = folder.tabs.find((tab) => tab.selected);
|
||||
const icon = folder.icon?.querySelector('svg #folder-icon image');
|
||||
const icon = folder.icon?.querySelector('svg .icon image');
|
||||
|
||||
const newSpace = await gZenWorkspaces.createAndSaveWorkspace(
|
||||
folder.label,
|
||||
@@ -855,7 +854,7 @@
|
||||
gBrowser.TabStateFlusher.flush(tab.linkedBrowser);
|
||||
});
|
||||
|
||||
this.updateFolderIcon(folder, 'auto', false);
|
||||
this.updateFolderIcon(folder, 'auto');
|
||||
|
||||
if (options.renameFolder) {
|
||||
folder.rename();
|
||||
@@ -1116,71 +1115,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
updateFolderIcon(group, state = 'auto', play = true) {
|
||||
updateFolderIcon(group, state = 'auto') {
|
||||
const svg = group.querySelector('svg');
|
||||
if (!svg) return [];
|
||||
let animations = this.#folderAnimCache.get(group);
|
||||
if (!animations) {
|
||||
animations = svg.querySelectorAll('animate, animateTransform, animateMotion');
|
||||
this.#folderAnimCache.set(group, animations);
|
||||
}
|
||||
|
||||
const isCollapsed = group.collapsed;
|
||||
svg.setAttribute('state', state === 'auto' ? (isCollapsed ? 'close' : 'open') : state);
|
||||
const hasActive = group.hasAttribute('has-active');
|
||||
|
||||
const OPACITY = {
|
||||
'folder-dots': { active: '0;1', baseOrig: '0;0' },
|
||||
'folder-icon': { active: '1;0', baseOrig: '1;1' },
|
||||
};
|
||||
|
||||
animations.forEach((animation) => {
|
||||
const parentId = animation.parentElement.id;
|
||||
const isOpacity = animation.getAttribute('attributeName') === 'opacity';
|
||||
|
||||
if (!animation.dataset.origValues) {
|
||||
animation.dataset.origValues = animation.getAttribute('values');
|
||||
}
|
||||
|
||||
const origValues = animation.dataset.origValues;
|
||||
const [fromValue, toValue] = origValues.split(';');
|
||||
|
||||
const isActiveState = isCollapsed && hasActive && isOpacity;
|
||||
|
||||
if (!play && !isActiveState) {
|
||||
if (isOpacity && OPACITY[parentId]) {
|
||||
const staticValue = OPACITY[parentId].baseOrig;
|
||||
animation.dataset.origValues = staticValue;
|
||||
animation.setAttribute('values', staticValue);
|
||||
animation.beginElement();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isOpacity && OPACITY[parentId]) {
|
||||
animation.dataset.origValues = OPACITY[parentId].baseOrig;
|
||||
}
|
||||
|
||||
let newValues;
|
||||
|
||||
if (isActiveState && OPACITY[parentId]) {
|
||||
newValues = OPACITY[parentId].active;
|
||||
const [activeFrom, activeTo] = newValues.split(';');
|
||||
animation.dataset.origValues = `${activeTo};${activeFrom}`;
|
||||
} else {
|
||||
const stateValues = {
|
||||
open: `${fromValue};${toValue}`,
|
||||
close: `${toValue};${fromValue}`,
|
||||
auto: isCollapsed ? `${toValue};${fromValue}` : `${fromValue};${toValue}`,
|
||||
};
|
||||
newValues = stateValues[state] || stateValues.auto;
|
||||
}
|
||||
|
||||
if (animation.getAttribute('values') !== newValues) {
|
||||
animation.setAttribute('values', newValues);
|
||||
animation.beginElement();
|
||||
}
|
||||
});
|
||||
svg.setAttribute('active', hasActive && isCollapsed ? 'true' : 'false');
|
||||
|
||||
return [];
|
||||
}
|
||||
@@ -1256,7 +1198,7 @@
|
||||
}
|
||||
|
||||
setFolderUserIcon(group, icon) {
|
||||
const svgIcon = group.icon.querySelector('svg #folder-icon image');
|
||||
const svgIcon = group.icon.querySelector('svg .icon image');
|
||||
if (!svgIcon) return;
|
||||
svgIcon.setAttribute('href', icon ?? '');
|
||||
if (svgIcon.getAttribute('href') !== icon) {
|
||||
@@ -1305,7 +1247,7 @@
|
||||
|
||||
if (group.activeTabs.length === 0) {
|
||||
group.removeAttribute('has-active');
|
||||
this.updateFolderIcon(group, 'close', false);
|
||||
this.updateFolderIcon(group, 'close');
|
||||
}
|
||||
|
||||
return this.on_TabGroupCollapse({
|
||||
@@ -1332,7 +1274,7 @@
|
||||
|
||||
if (group.activeTabs.length === 0) {
|
||||
group.removeAttribute('has-active');
|
||||
this.updateFolderIcon(group, 'close', false);
|
||||
this.updateFolderIcon(group, 'close');
|
||||
}
|
||||
|
||||
this.on_TabGroupExpand({ target: group, forExpandVisible: true });
|
||||
@@ -1408,7 +1350,7 @@
|
||||
|
||||
if (tabsContainer.hasAttribute('hidden')) tabsContainer.removeAttribute('hidden');
|
||||
|
||||
animations.push(...this.updateFolderIcon(current, 'close', false));
|
||||
animations.push(...this.updateFolderIcon(current, 'close'));
|
||||
animations.push(
|
||||
gZenUIManager.motion.animate(
|
||||
groupStart,
|
||||
@@ -1518,7 +1460,7 @@
|
||||
|
||||
#groupInit(group, stateData) {
|
||||
// Setup zen-folder icon to the correct position
|
||||
this.updateFolderIcon(group, 'auto', false);
|
||||
this.updateFolderIcon(group, 'auto');
|
||||
if (stateData?.userIcon) {
|
||||
this.setFolderUserIcon(group, stateData.userIcon);
|
||||
}
|
||||
@@ -1575,7 +1517,7 @@
|
||||
|
||||
let prevSiblingInfo = null;
|
||||
const prevSibling = folder.previousElementSibling;
|
||||
const userIcon = folder?.icon?.querySelector('svg #folder-icon image');
|
||||
const userIcon = folder?.icon?.querySelector('svg .icon image');
|
||||
|
||||
if (prevSibling) {
|
||||
if (gBrowser.isTabGroup(prevSibling)) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
tab-group[split-view-group] {
|
||||
display: block;
|
||||
min-width: 100%;
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
transition: var(--zen-tabbox-element-indent-transition);
|
||||
@@ -151,6 +150,10 @@ tab-group[split-view-group] {
|
||||
tab-group .tab-group-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
tab-group[split-view-group] {
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
tab-group[split-view-group] .tabbrowser-tab {
|
||||
@@ -295,6 +298,38 @@ zen-folder {
|
||||
fill: var(--zen-folder-stroke);
|
||||
transform: translate(4px, 6.5px);
|
||||
}
|
||||
|
||||
& g,
|
||||
& rect,
|
||||
& path {
|
||||
transition:
|
||||
transform 0.3s cubic-bezier(0.42, 0, 0, 1),
|
||||
opacity 0.3s cubic-bezier(0.42, 0, 0, 1);
|
||||
}
|
||||
|
||||
&[state='open'] .back {
|
||||
transform: skewX(16deg) translate(-2px, 3.4px) scale(0.85);
|
||||
}
|
||||
|
||||
&[state='open'] :is(.front, .dots, .icon) {
|
||||
transform: skewX(-16deg) translate(11.1px, 3.4px) scale(0.85);
|
||||
}
|
||||
|
||||
& .icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
& .dots {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&[active='true'] .icon {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&[active='true'] .dots {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1246,6 +1246,7 @@
|
||||
for (const item of this.dragShiftableItems) {
|
||||
item.style.transform = '';
|
||||
}
|
||||
delete this._topToNormalTabs;
|
||||
for (const item of gBrowser.tabContainer.ariaFocusableItems) {
|
||||
if (gBrowser.isTab(item)) {
|
||||
let isVisible = true;
|
||||
@@ -1280,7 +1281,7 @@
|
||||
: [separator];
|
||||
}
|
||||
|
||||
animateSeparatorMove(movingTabs, dropElement, isPinned, event) {
|
||||
animateSeparatorMove(movingTabs, dropElement, isPinned) {
|
||||
let draggedTab = movingTabs[0];
|
||||
if (gBrowser.isTabGroupLabel(draggedTab) && draggedTab.group.isZenFolder) {
|
||||
this._isGoingToPinnedTabs = true;
|
||||
@@ -1290,14 +1291,19 @@
|
||||
draggedTab = draggedTab.group;
|
||||
}
|
||||
const itemsToCheck = this.dragShiftableItems;
|
||||
const translate = event.screenY;
|
||||
let translate = movingTabs[isPinned ? movingTabs.length - 1 : 0].getBoundingClientRect().top;
|
||||
if (isPinned) {
|
||||
const rect = draggedTab.getBoundingClientRect();
|
||||
translate += rect.height;
|
||||
}
|
||||
const draggingTabHeight = movingTabs.reduce((acc, item) => {
|
||||
return acc + window.windowUtils.getBoundsWithoutFlushing(item).height;
|
||||
}, 0);
|
||||
let topToNormalTabs = itemsToCheck[0].screenY;
|
||||
if (!isPinned) {
|
||||
topToNormalTabs += draggedTab.getBoundingClientRect().height;
|
||||
if (typeof this._topToNormalTabs === 'undefined') {
|
||||
const rects = itemsToCheck.map((item) => window.windowUtils.getBoundsWithoutFlushing(item));
|
||||
this._topToNormalTabs = rects[0].top + rects.at(-1).height / (isPinned ? 2 : 4);
|
||||
}
|
||||
let topToNormalTabs = this._topToNormalTabs;
|
||||
const isGoingToPinnedTabs =
|
||||
translate < topToNormalTabs && gBrowser.pinnedTabCount - gBrowser._numZenEssentials > 0;
|
||||
const multiplier = isGoingToPinnedTabs !== isPinned ? (isGoingToPinnedTabs ? 1 : -1) : 0;
|
||||
|
||||
Reference in New Issue
Block a user