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:
parent
418ec5cfc0
commit
41294e0ff7
5 changed files with 82 additions and 13 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,9 @@
|
|||
overflow: hidden;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-inline-start: 4px;
|
||||
@include state(".cell.first-column:not(.hasAttachment)") {
|
||||
margin-inline-start: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue