mirror of
https://github.com/HeyPuter/puter.git
synced 2026-11-04 13:03:37 +00:00
fix(dashboard): keep the name column readable beside "Shared by"
In a listing between the phone layout and about 700px wide, the fixed 160px "Shared by" column squeezed an auto-width name down to a few characters. Beside an auto-width name, "Shared by" now takes at most 40% of the room the two split, and resizing it stops at the same width.
This commit is contained in:
1 parent
60bfe4d54e
commit
291aee2e53
4 files changed
+84
-4
No files matched your search
@@ -46,7 +46,7 @@ import { parent_path_for, parse_shared_path, shared_crumbs_for, shared_uids_from
|
||||
import resolve_shared_item from '../../helpers/resolveSharedItem.js';
|
||||
import { is_owned_by_me } from '../../helpers/pathOwner.js';
|
||||
import parse_item_metadata from '../../helpers/parseItemMetadata.js';
|
||||
import { compareSharers, filterBySharer, sharedByCellHtml, sharerFilterHtml, summarizeSharers } from './sharedBy.js';
|
||||
import { compareSharers, filterBySharer, fitSharedByWidth, sharedByCellHtml, sharerFilterHtml, summarizeSharers } from './sharedBy.js';
|
||||
|
||||
const { html_encode, SelectionArea } = window;
|
||||
|
||||
@@ -2064,6 +2064,11 @@ const TabFiles = {
|
||||
}
|
||||
}
|
||||
this.appliedColumnWidths = { name: nameWidth, sharedBy: sharedByWidth, size: sizeWidth, modified: modifiedWidth };
|
||||
// Narrowed beside an auto-width name on every pass, so a resize of
|
||||
// another column doesn't save the narrowed width.
|
||||
if ( hasSharedBy && ! nameWidth && containerWidth > 0 ) {
|
||||
sharedByWidth = fitSharedByWidth(sharedByWidth, containerWidth - COLUMN_FIXED_WIDTH - 4 - sizeWidth - modifiedWidth);
|
||||
}
|
||||
|
||||
const nameCol = nameWidth ? `${nameWidth}px` : 'auto';
|
||||
const sharedByCols = hasSharedBy ? `${sharedByWidth}px 4px ` : '';
|
||||
@@ -2124,12 +2129,21 @@ const TabFiles = {
|
||||
modified: this.columnWidths.modified || 120,
|
||||
};
|
||||
let fixed = COLUMN_FIXED_WIDTH;
|
||||
// Beside an auto-width name, "Shared by" is narrowed as applyColumnWidths lays it out.
|
||||
const narrowsSharedBy = this.currentPath === window.shared_path && ! this.columnWidths.name;
|
||||
if ( this.currentPath === window.shared_path ) {
|
||||
widths.sharedBy = this.columnWidths.sharedBy || 160;
|
||||
fixed += 4;
|
||||
widths.sharedBy = this.columnWidths.sharedBy || 160;
|
||||
if ( narrowsSharedBy ) {
|
||||
widths.sharedBy = fitSharedByWidth(widths.sharedBy, containerWidth - fixed - widths.size - widths.modified);
|
||||
}
|
||||
}
|
||||
const others = Object.keys(widths).filter(c => c !== column).reduce((sum, c) => sum + widths[c], 0);
|
||||
return Math.max(min, Math.min(width, containerWidth - fixed - others));
|
||||
const clamped = Math.max(min, Math.min(width, containerWidth - fixed - others));
|
||||
if ( column === 'sharedBy' && narrowsSharedBy ) {
|
||||
return fitSharedByWidth(clamped, containerWidth - fixed - widths.size - widths.modified);
|
||||
}
|
||||
return clamped;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import jQuery from '../../lib/jquery-3.6.1/jquery-3.6.1.min.js';
|
||||
|
||||
// The tab's window and dialog plumbing isn't what these tests exercise.
|
||||
@@ -535,3 +535,42 @@ describe('TabFiles.applyHiddenRule', () => {
|
||||
expect($('.files .row').first().hasClass('item-revealed')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('TabFiles "Shared by" column width', () => {
|
||||
const SHARED = 'puter://shared';
|
||||
|
||||
beforeEach(() => {
|
||||
// Earlier suites stub applyColumnWidths out.
|
||||
vi.restoreAllMocks();
|
||||
window.shared_path = SHARED;
|
||||
window.trash_path = TRASH;
|
||||
mountListing([], SHARED);
|
||||
TabFiles.columnWidths = { name: null, sharedBy: 160, size: 100, modified: 120 };
|
||||
// jsdom lays nothing out; give the listing a width.
|
||||
vi.spyOn($.fn, 'width').mockImplementation(function () {
|
||||
return this.hasClass('files') ? 530 : 0;
|
||||
});
|
||||
vi.spyOn(TabFiles, 'fitItemNames').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
|
||||
it('leaves the auto-width name the larger part in a narrow listing', () => {
|
||||
TabFiles.applyColumnWidths();
|
||||
expect(TabFiles.columnGridTemplate).toBe('24px auto 4px 92px 4px 100px 4px 120px 4px 20px');
|
||||
});
|
||||
|
||||
it('keeps its own width when another column is resized', () => {
|
||||
TabFiles.applyColumnWidths();
|
||||
TabFiles.adoptAppliedColumnWidths();
|
||||
expect(TabFiles.columnWidths.sharedBy).toBe(160);
|
||||
});
|
||||
|
||||
it('leaves other columns room to resize as it is laid out', () => {
|
||||
expect(TabFiles.clampColumnWidth('size', 90)).toBe(90);
|
||||
});
|
||||
|
||||
it('is resized only as far as it is laid out', () => {
|
||||
expect(TabFiles.clampColumnWidth('sharedBy', 200)).toBe(92);
|
||||
});
|
||||
});
|
||||
@@ -77,6 +77,17 @@ export const compareSharers = (a, b) => compareNames(sharerOf(a), sharerOf(b));
|
||||
|
||||
const compareNames = (a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' });
|
||||
|
||||
/**
|
||||
* The "Shared by" column's width beside an auto-width name column: `width`,
|
||||
* held to 40% of the `room` the two split so the name keeps the larger part,
|
||||
* and never under the 60px every resizable column keeps.
|
||||
*
|
||||
* @param {number} width
|
||||
* @param {number} room
|
||||
* @returns {number}
|
||||
*/
|
||||
export const fitSharedByWidth = (width, room) => Math.max(60, Math.min(width, Math.floor(room * 0.4)));
|
||||
|
||||
/**
|
||||
* The initial-and-color avatar the share modal uses, sized by `className`.
|
||||
*
|
||||
|
||||
@@ -31,6 +31,7 @@ globalThis.window = {
|
||||
const {
|
||||
compareSharers,
|
||||
filterBySharer,
|
||||
fitSharedByWidth,
|
||||
sharedByCellHtml,
|
||||
sharedByTitle,
|
||||
sharerFilterHtml,
|
||||
@@ -95,6 +96,21 @@ describe('compareSharers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('fitSharedByWidth', () => {
|
||||
it('keeps the width while the name has the larger part', () => {
|
||||
expect(fitSharedByWidth(160, 1200)).toBe(160);
|
||||
});
|
||||
|
||||
it('yields to the name in a narrow listing', () => {
|
||||
// A 530px listing leaves 230px for the name and "Shared by" together.
|
||||
expect(fitSharedByWidth(160, 230)).toBe(92);
|
||||
});
|
||||
|
||||
it('never goes under the column minimum', () => {
|
||||
expect(fitSharedByWidth(160, 50)).toBe(60);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sharedByTitle', () => {
|
||||
it('names the sharer', () => {
|
||||
expect(sharedByTitle(row('ann'))).toBe('shared_by_user:ann');
|
||||
|
||||
Reference in new issue
Block a user