diff --git a/chrome/content/zotero/components/virtualized-table.jsx b/chrome/content/zotero/components/virtualized-table.jsx index 4f64a5116a..ef73f382fb 100644 --- a/chrome/content/zotero/components/virtualized-table.jsx +++ b/chrome/content/zotero/components/virtualized-table.jsx @@ -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(); } diff --git a/chrome/content/zotero/itemTree.jsx b/chrome/content/zotero/itemTree.jsx index 9f325bdae7..6f3cae3854 100644 --- a/chrome/content/zotero/itemTree.jsx +++ b/chrome/content/zotero/itemTree.jsx @@ -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); @@ -3163,7 +3168,7 @@ var ItemTree = class ItemTree extends LibraryTree { } this._columns.push(column); } - + return this._columns.sort((a, b) => a.ordinal - b.ordinal); } diff --git a/chrome/content/zotero/itemTreeColumns.jsx b/chrome/content/zotero/itemTreeColumns.jsx index 5a9d8ef165..7978e9cf9c 100644 --- a/chrome/content/zotero/itemTreeColumns.jsx +++ b/chrome/content/zotero/itemTreeColumns.jsx @@ -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: , 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: , - width: "14", - minWidth: 14, + width: "26", + minWidth: 26, staticWidth: true, + noPadding: true, zoteroPersist: ["width", "hidden", "sortDirection"] }, { diff --git a/scss/components/_item-tree.scss b/scss/components/_item-tree.scss index 83f356cf9a..848ce1a576 100644 --- a/scss/components/_item-tree.scss +++ b/scss/components/_item-tree.scss @@ -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: ""; @@ -149,19 +159,35 @@ margin-inline-start: 3px; } } + + .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; + } } } } diff --git a/scss/components/_virtualized-table.scss b/scss/components/_virtualized-table.scss index 950d1a968a..73a7584bf4 100644 --- a/scss/components/_virtualized-table.scss +++ b/scss/components/_virtualized-table.scss @@ -71,7 +71,9 @@ overflow: hidden; &:not(:first-child) { - margin-inline-start: 4px; + @include state(".cell.first-column:not(.hasAttachment)") { + margin-inline-start: 4px; + } } }