Fix main window layout and window resizing (#4676)

- Replace flex attribute with flex-shrink and flex-grow style
  to allow elements to be resized by splitter and window resizing.
- Set the max-width on collections pane to prevent it from pushing
  other panes outside window border
- Set the min-width on window according to the size of both library
   and reader tabs
- Use stacked layout when window width is small

fix: #4669
This commit is contained in:
windingwind 2024-09-12 12:26:31 +02:00 committed by GitHub
parent 58d98af6c1
commit 78077fab9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 125 additions and 62 deletions

View file

@ -48,6 +48,19 @@ var ZoteroContextPane = new function () {
: _contextPaneSplitter)
});
Object.defineProperty(this, 'collapsed', {
get: () => {
return this.splitter.getAttribute('state') === 'collapsed';
},
set: (collapsed) => {
_contextPane.setAttribute('collapsed', !!collapsed);
_contextPaneInner.setAttribute('collapsed', !!collapsed);
_contextPaneSplitter.setAttribute('state', collapsed ? 'collapsed' : 'open');
_contextPaneSplitterStacked.setAttribute('state', collapsed ? 'collapsed' : 'open');
_update();
}
});
this.update = _update;
this.focus = () => {
@ -132,7 +145,6 @@ var ZoteroContextPane = new function () {
}
if (_isStacked()) {
_contextPaneSplitterStacked.setAttribute('hidden', false);
_contextPaneSplitter.setAttribute('state', 'open');
_contextPaneSplitter.setAttribute('hidden', true);
_contextPane.classList.add('stacked');
_contextPane.classList.remove('standard');
@ -149,7 +161,6 @@ var ZoteroContextPane = new function () {
else {
_contextPaneSplitter.setAttribute('hidden', false);
_contextPaneSplitterStacked.setAttribute('hidden', true);
_contextPaneSplitterStacked.setAttribute('state', 'open');
_contextPane.classList.add('standard');
_contextPane.classList.remove('stacked');
_readerSidenav.classList.remove('stacked');
@ -176,6 +187,8 @@ var ZoteroContextPane = new function () {
_updatePaneWidth();
_updateAddToNote();
ZoteroPane.updateLayoutConstraints();
}
function _isLibraryReadOnly(libraryID) {
@ -183,15 +196,6 @@ var ZoteroContextPane = new function () {
}
function _togglePane() {
var splitter = ZoteroContextPane.splitter;
var open = true;
if (splitter.getAttribute('state') != 'collapsed') {
open = false;
}
_contextPane.setAttribute('collapsed', !open);
splitter.setAttribute('state', open ? 'open' : 'collapsed');
_update();
this.collapsed = !this.collapsed;
}
};

View file

@ -6248,8 +6248,7 @@ var ZoteroPane = new function()
*/
this.unserializePersist = function () {
_unserialized = true;
var serializedValues = Zotero.Prefs.get("pane.persist");
if (!serializedValues) return;
var serializedValues = Zotero.Prefs.get("pane.persist") || "{}";
serializedValues = JSON.parse(serializedValues);
for (var id in serializedValues) {
@ -6354,33 +6353,73 @@ var ZoteroPane = new function()
var itemsPaneContainer = document.getElementById('zotero-items-pane-container');
var collectionsPane = document.getElementById("zotero-collections-pane");
var tagSelector = document.getElementById("zotero-tag-selector");
let layoutModeMenus = [
document.getElementById("view-menuitem-standard"),
document.getElementById("view-menuitem-stacked"),
];
let isStackedMode = Zotero.Prefs.get('layout') === 'stacked';
let isTempStackedMode = Zotero.Prefs.get('tempStackedMode');
let isItemPaneCollapsed = ZoteroPane.itemPane.collapsed && ZoteroContextPane.collapsed;
// Keep in sycn with abstracts/variables.scss > $min-width-collections-pane
const collectionsPaneMinWidth = collectionsPane.hasAttribute("collapsed") ? 0 : 200;
// Keep in sycn with abstracts/variables.scss > $min-width-item-pane
const itemPaneMinWidth = (isStackedMode || isItemPaneCollapsed) ? 0 : 320;
const libraryItemPaneMinWidth = (isStackedMode || ZoteroPane.itemPane.collapsed) ? 0 : 320;
// Keep in sycn with abstracts/variables.scss > $width-sidenav
const sideNavMinWidth = isStackedMode ? 0 : 37;
// Keep in sycn with abstracts/variables.scss > $min-width-items-pane
const itemsPaneMinWidth = 370;
let fixedComponentWidth = collectionsPaneMinWidth + itemPaneMinWidth + sideNavMinWidth;
// Calculate the heights of the components that aren't able to shrink automatically
// when the window is resized
let fixedComponentWidth = trees.scrollWidth - itemsPaneContainer.scrollWidth;
let fixedComponentHeight = titlebar.scrollHeight + trees.scrollHeight - itemsPaneContainer.scrollHeight;
document.documentElement.style.setProperty('--width-of-fixed-components', `${fixedComponentWidth}px`);
document.documentElement.style.setProperty('--height-of-fixed-components', `${fixedComponentHeight}px`);
let layoutChanged = false;
// Collections pane + items pane + items pane + sidenav + 3px for draggability
const windowAutoStackMinWidth = 930;
if (window.innerWidth < windowAutoStackMinWidth) {
// Disable layout mode menus because the standard mode is not available
layoutModeMenus.forEach(menu => menu.setAttribute("disabled", "true"));
// If the window is too small in standard mode, enter stack mode temporarily
if (!isStackedMode && !isTempStackedMode) {
Zotero.Prefs.set('tempStackedMode', true);
Zotero.Prefs.set('layout', 'stacked');
layoutChanged = true;
}
}
else {
layoutModeMenus.forEach(menu => menu.removeAttribute("disabled"));
if (isTempStackedMode) {
Zotero.Prefs.clear('tempStackedMode');
Zotero.Prefs.set('layout', 'standard');
layoutChanged = true;
}
}
if (layoutChanged) {
// Compute the layout constraints again after the layout change to avoid weirdness
setTimeout(() => {
this.updateLayoutConstraints();
}, 0);
}
// This is important to avoid other panes be pushed out of the window
collectionsPane.style.setProperty(
"--max-width-collections-pane",
`${window.innerWidth - libraryItemPaneMinWidth - sideNavMinWidth - itemsPaneMinWidth}px`);
var collectionsPaneWidth = collectionsPane.getBoundingClientRect().width;
tagSelector.style.maxWidth = collectionsPaneWidth + 'px';
if (ZoteroPane.itemsView) {
ZoteroPane.itemsView.updateHeight();
}
// Temp JS solution to shrink the collection search so that it does not overflow outside
// of the collection pane
var collectionSearch = document.getElementById("zotero-collections-search");
collectionSearch.removeAttribute("data-expanded-width");
if (collectionsPaneWidth < 220) {
collectionSearch.setAttribute("data-expanded-width", 150);
if (collectionSearch.classList.contains("visible")) {
collectionSearch.style.maxWidth = "150px";
}
}
else {
collectionSearch.style.removeProperty('max-width');
}
this.handleTagSelectorResize();
this.itemPane.handleResize();

View file

@ -1075,7 +1075,7 @@
<div id="zotero-tab-cover" class="hidden" xmlns="http://www.w3.org/1999/xhtml">
<label>&zotero.general.loading;</label>
</div>
<deck id="tabs-deck" flex="1">
<deck id="tabs-deck">
<vbox id="zotero-pane"
onkeydown="ZoteroPane_Local.handleKeyDown(event, this.id)"
onkeyup="ZoteroPane_Local.handleKeyUp(event, this.id)"
@ -1153,10 +1153,10 @@
<hbox id="zotero-trees" flex="1">
<vbox id="zotero-collections-pane" zotero-persist="width">
<toolbar id="zotero-toolbar-collection-tree" tabindex="-1" class="zotero-toolbar toolbar toolbar-primary">
<hbox id="zotero-collections-toolbar" align="center" flex="1">
<hbox id="zotero-collections-toolbar" align="center">
<toolbarbutton id="zotero-tb-collection-add" tabindex="-1" class="zotero-tb-button" tooltiptext="&zotero.toolbar.newCollection.label;" command="cmd_zotero_newCollection"/>
<spacer flex="1"></spacer>
<html:div style="display: flex;flex-direction: row;">
<html:div style="display: flex;flex-direction: row; flex-grow: 0; flex-shrink: 1; min-width: 0;">
<toolbarbutton id="zotero-tb-collections-search" data-l10n-id="zotero-collections-search-btn" tabindex="-1" class="zotero-tb-button"/>
<search-textbox
id="zotero-collections-search" class="hidden" disabled="true"
@ -1202,8 +1202,8 @@
<grippy id="zotero-collections-grippy"/>
</splitter>
<box id="zotero-layout-switcher" orient="horizontal" zotero-persist="orient" flex="1">
<vbox flex="1" id="zotero-items-pane-container">
<box id="zotero-layout-switcher" orient="horizontal" zotero-persist="orient">
<vbox id="zotero-items-pane-container">
<toolbar id="zotero-toolbar-item-tree" tabindex="-1" class="zotero-toolbar toolbar toolbar-primary">
<hbox id="zotero-items-toolbar" align="center" flex="1">
<toolbarbutton
@ -1323,7 +1323,7 @@
</splitter>
<!-- itemPane.xul -->
<item-pane id="zotero-item-pane" zotero-persist="width height" flex="0"/>
<item-pane id="zotero-item-pane" zotero-persist="width height"/>
</box>
</hbox>
</vbox>
@ -1344,7 +1344,7 @@
</splitter>
<!-- contextPane -->
<box id="zotero-context-pane" flex="0" collapsed="true" zotero-persist="width">
<box id="zotero-context-pane" collapsed="true" zotero-persist="width">
<vbox flex="1" style="min-width: 0; min-height: 0;">
<box class="stacked-context-placeholder" flex="1"/>
<splitter id="zotero-context-splitter-stacked"

View file

@ -174,29 +174,7 @@ TODO: Replace with SVG
text-decoration: underline;
}
/*
Fx115: make panes occupy all available width/height after layout switch
or splitter expand/collapse.
The splitter element stores state in the style attribute's width/height
properties, and if we remove them, the splitter breaks. So we override
them here with !important.
*/
#zotero-layout-switcher[orient="horizontal"] :is(#zotero-items-pane-container, #zotero-item-pane) {
height: auto !important;
}
#zotero-layout-switcher[orient="horizontal"] #zotero-items-pane-container {
width: 0 !important;
}
#zotero-layout-switcher[orient="vertical"],
#zotero-layout-switcher[orient="vertical"] :is(#zotero-items-pane-container, #zotero-item-pane) {
width: auto !important;
/* min-width: 0 is required here to allow the pane to shrink in Stacked view,
but the child #zotero-items-pane sets a larger min-width, and the splitter
follows that instead of this. */
min-width: 0 !important;
}
/*
Fix to odd fx115 behavior that gives an un-collapsed pane the initial width of min-width + last width

View file

@ -13,8 +13,10 @@ $icons: (
#zotero-collections-pane {
min-width: $min-width-collections-pane;
max-width: var(--max-width-collections-pane);
width: $min-width-collections-pane;
flex-shrink: 0;
flex-grow: 0;
flex-shrink: 1;
background: var(--material-sidepane);
}

View file

@ -1,5 +1,7 @@
#tabs-deck {
min-width: $min-width-tabs-deck;
flex-grow: 1;
flex-shrink: 1;
& > :not(.deck-selected) {
// Hide all sub-trees that are in the invisible tab deck
@ -11,6 +13,8 @@
#zotero-context-pane {
display: flex;
flex-grow: 0;
flex-shrink: 1;
min-width: $min-width-context-pane + $width-sidenav;
.divider {

View file

@ -1,6 +1,8 @@
@use "sass:map";
#zotero-items-pane-container {
flex-grow: 1;
flex-shrink: 1;
min-width: $min-width-items-pane;
height: 150px;
min-height: $min-height-items-pane;

View file

@ -38,4 +38,30 @@
#zotero-pane-progressmeter-container {
padding: 10px;
}
}
#zotero-layout-switcher {
flex-grow: 1;
flex-shrink: 1;
min-width: 0;
/*
Fx115: make panes occupy all available width/height after layout switch
or splitter expand/collapse.
The splitter element stores state in the style attribute's width/height
properties, and if we remove them, the splitter breaks. So we override
them here with !important.
*/
&[orient="horizontal"] :is(#zotero-items-pane-container, #zotero-item-pane) {
height: auto !important;
}
&[orient="vertical"],
&[orient="vertical"] :is(#zotero-items-pane-container, #zotero-item-pane) {
width: auto !important;
/* min-width: 0 is required here to allow the pane to shrink in Stacked view,
but the child #zotero-items-pane sets a larger min-width, and the splitter
follows that instead of this. */
min-width: 0 !important;
}
}

View file

@ -88,6 +88,12 @@
visibility: hidden;
}
#zotero-collections-toolbar {
flex-grow: 1;
flex-shrink: 1;
min-width: 0;
}
.zotero-tb-button {
-moz-user-focus: normal;
}

View file

@ -1,5 +1,7 @@
item-pane {
min-width: $min-width-item-pane + $width-sidenav;
flex-grow: 0;
flex-shrink: 1;
min-width: var(--width-available-item-pane, $min-width-item-pane + $width-sidenav);
min-height: $min-width-item-pane + $width-sidenav;
&[collapsed="true"] {