Fix a bug where first column is clipped if it has fixed or static width (#3605)

Also:

* Fix issues with notes and attachment columns
* Tweak first-column attachment column alignment
This commit is contained in:
Tom Najdek 2024-01-29 07:37:46 +00:00 committed by GitHub
parent 418ec5cfc0
commit 41294e0ff7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 82 additions and 13 deletions

View file

@ -36,7 +36,7 @@ const TYPING_TIMEOUT = 1000;
const MINIMUM_ROW_HEIGHT = 20; // px
const RESIZER_WIDTH = 5; // px
const COLUMN_MIN_WIDTH = 20;
const COLUMN_PADDING = 10; // N.B. MUST BE INLINE WITH CSS!!!
const COLUMN_PADDING = 16; // N.B. MUST BE INLINE WITH CSS!!!
const noop = () => 0;
@ -414,6 +414,7 @@ class VirtualizedTable extends React.Component {
staticColumns: PropTypes.bool,
// Used for initial column widths calculation
containerWidth: PropTypes.number,
firstColumnExtraWidth: PropTypes.number,
// Internal windowed-list ref
treeboxRef: PropTypes.func,
@ -848,8 +849,8 @@ class VirtualizedTable extends React.Component {
offset += resizingRect.width;
}
const widthSum = aRect.width + bRect.width;
const aSpacingOffset = (aColumn.minWidth ? aColumn.minWidth : COLUMN_MIN_WIDTH) + COLUMN_PADDING;
const bSpacingOffset = (bColumn.minWidth ? bColumn.minWidth : COLUMN_MIN_WIDTH) + COLUMN_PADDING;
const aSpacingOffset = (aColumn.minWidth ? aColumn.minWidth : COLUMN_MIN_WIDTH) + (aColumn.noPadding ? 0 : COLUMN_PADDING);
const bSpacingOffset = (bColumn.minWidth ? bColumn.minWidth : COLUMN_MIN_WIDTH) + (bColumn.noPadding ? 0 : COLUMN_PADDING);
const aColumnWidth = Math.min(widthSum - bSpacingOffset, Math.max(aSpacingOffset, event.clientX - (RESIZER_WIDTH / 2) - offset));
const bColumnWidth = widthSum - aColumnWidth;
let onResizeData = {};
@ -1425,6 +1426,12 @@ var Columns = class {
if (column.type) {
column.className += ` cell-${column.type}`;
}
if (column.fixedWidth) {
column.originalWidth = column.width;
}
if (column.staticWidth) {
column.originalMinWidth = column.minWidth || 20;
}
columns.push(column);
}
// Sort columns by their `ordinal` field
@ -1456,6 +1463,7 @@ var Columns = class {
// Storing back persist settings to account for legacy upgrades
this._storePrefs(columnsSettings);
this._adjustColumnWidths();
// Set column width CSS rules
this.onResize(columnWidths);
// Whew, all this just to get a list of columns
@ -1520,6 +1528,24 @@ var Columns = class {
this._virtualizedTable.props.storeColumnPrefs(prefs);
}
_adjustColumnWidths = () => {
if (!this._virtualizedTable.props.firstColumnExtraWidth) {
return;
}
const extraWidth = this._virtualizedTable.props.firstColumnExtraWidth;
this._columns.filter(c => !c.hidden).forEach((column, index) => {
const isFirstColumn = index === 0;
if (column.fixedWidth) {
column.width = isFirstColumn ? parseInt(column.originalWidth) + extraWidth : column.originalWidth;
}
if (column.staticWidth) {
column.minWidth = isFirstColumn ? (column.originalMinWidth ?? 20) + extraWidth : column.originalMinWidth;
column.width = isFirstColumn ? Math.max(parseInt(column.width) ?? 0, column.minWidth) : column.width;
}
});
};
/**
* Programatically sets the injected CSS width rules for each column.
* This is necessary for performance reasons
@ -1530,8 +1556,7 @@ var Columns = class {
if (storePrefs) {
var prefs = this._getPrefs();
}
const header = document.querySelector(`#${this._styleKey} .virtualized-table-header`);
const headerWidth = header ? header.getBoundingClientRect().width : 300;
for (let [dataKey, width] of Object.entries(columnWidths)) {
if (typeof dataKey == "number") {
dataKey = this._columns[dataKey].dataKey;
@ -1569,6 +1594,10 @@ var Columns = class {
if (a.ordinal == b.ordinal) return a == column ? -1 : 1;
return a.ordinal - b.ordinal;
});
this._adjustColumnWidths();
this.onResize(Object.fromEntries(this._columns.map(c => [c.dataKey, c.width])));
let prefs = this._getPrefs();
// reassign columns their ordinal values and set the prefs
this._columns.forEach((column, index) => {
@ -1596,6 +1625,8 @@ var Columns = class {
}
}
this._columns.sort((a, b) => a.ordinal - b.ordinal);
this._adjustColumnWidths();
this.onResize(Object.fromEntries(this._columns.map(c => [c.dataKey, c.width])));
this._storePrefs(prefs);
this._updateVirtualizedTable();
}
@ -1608,6 +1639,8 @@ var Columns = class {
if (prefs[column.dataKey]) {
prefs[column.dataKey].hidden = column.hidden;
}
this._adjustColumnWidths();
this.onResize(Object.fromEntries(this._columns.map(c => [c.dataKey, c.width])));
this._storePrefs(prefs);
this._updateVirtualizedTable();
}

View file

@ -985,6 +985,7 @@ var ItemTree = class ItemTree extends LibraryTree {
storeColumnPrefs: this._storeColumnPrefs,
getDefaultColumnOrder: this._getDefaultColumnOrder,
containerWidth: this.domEl.clientWidth,
firstColumnExtraWidth: 28, // 16px for twisty + 16px for icon - 8px column padding + 4px margin
multiSelect: true,
@ -2720,6 +2721,10 @@ var ItemTree = class ItemTree extends LibraryTree {
}
}
if (column.noPadding) {
cell.classList.add('no-padding');
}
if (isFirstColumn) {
// Add depth indent, twisty and icon
const depth = this.getLevel(index);

View file

@ -40,6 +40,7 @@ const Icons = require('components/icons');
* @property {string} [width] - A column width instead of flex ratio. See above.
* @property {boolean} [fixedWidth] - Default: false. Set to true to disable column resizing
* @property {boolean} [staticWidth] - Default: false. Set to true to prevent columns from changing width when the width of the tree increases or decreases
* @property {boolean} [noPadding] - Set to true for columns with padding disabled in stylesheet
* @property {number} [minWidth] - Override the default [20px] column min-width for resizing
* @property {React.Component} [iconLabel] - Set an Icon label instead of a text-based one
* @property {string} [iconPath] - Set an Icon path, overrides {iconLabel}
@ -337,7 +338,8 @@ const COLUMNS = [
label: "zotero.tabs.attachments.label",
iconLabel: <Icons.IconAttachSmall />,
fixedWidth: true,
width: "16",
width: "32",
noPadding: true,
zoteroPersist: ["hidden", "sortDirection"]
},
{
@ -346,9 +348,10 @@ const COLUMNS = [
showInColumnPicker: true,
label: "zotero.tabs.notes.label",
iconLabel: <Icons.IconTreeitemNoteSmall />,
width: "14",
minWidth: 14,
width: "26",
minWidth: 26,
staticWidth: true,
noPadding: true,
zoteroPersist: ["width", "hidden", "sortDirection"]
},
{

View file

@ -21,6 +21,16 @@
padding-inline-end: calc(8px + var(--scrollbar-width, 0px));
box-sizing: border-box;
.cell.hasAttachment,
.cell.numNotes {
padding: 0;
text-align: center;
&.first-column {
padding-inline-start: 32px;
}
}
.first-column {
&::before {
content: "";
@ -150,18 +160,34 @@
}
}
.cell.no-padding {
padding: 0;
}
.cell.hasAttachment {
box-sizing: content-box;
// Don't show ellipsis
text-overflow: unset;
align-items: center;
display: flex;
justify-content: center;
.cell-text {
text-overflow: unset;
align-items: center;
display: flex;
justify-content: center;
}
.icon-missing-file {
opacity: 0.4;
}
}
.cell.numNotes {
.numNotes, .hasAttachment {
text-align: center;
.cell-text {
text-align: center;
}
}
}
}

View file

@ -71,9 +71,11 @@
overflow: hidden;
&:not(:first-child) {
@include state(".cell.first-column:not(.hasAttachment)") {
margin-inline-start: 4px;
}
}
}
.twisty + .cell-text, .spacer-twisty + .cell-text {
margin-inline-start: 0;