feat(list view): show the owner of the File or Folder in list view
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* UserVignette — reusable user avatar + name inline component.
|
||||
*
|
||||
* Renders a coloured circle with initials (or photo when available) alongside
|
||||
* an asynchronously-resolved display name. Used in:
|
||||
* • Owner column (list view) via `ui.resolveOwnerCells()`
|
||||
* • ShareModal member rows / chips / suggestion items
|
||||
*
|
||||
* Usage:
|
||||
* import { createUserVignette } from './userVignette.js';
|
||||
* cell.replaceChildren(createUserVignette(userId, 'sm'));
|
||||
*/
|
||||
|
||||
import { systemUsers } from '../model/systemUsers.js';
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Get initials for an avatar (1-2 characters).
|
||||
* @param {string} name
|
||||
* @returns {string}
|
||||
*/
|
||||
export function _initials(name) {
|
||||
const parts = name.trim().split(/\s+/);
|
||||
if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
||||
return name.slice(0, 2).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deterministic color index 0-4 derived from a userId string.
|
||||
* Same userId always maps to the same color across all components.
|
||||
* @param {string} userId
|
||||
* @returns {number}
|
||||
*/
|
||||
export function _colorIndex(userId) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < userId.length; i++) {
|
||||
hash = (hash * 31 + userId.charCodeAt(i)) | 0;
|
||||
}
|
||||
return Math.abs(hash) % 5;
|
||||
}
|
||||
|
||||
// ── Component ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @typedef {'xs'|'sm'|'md'|'lg'} VignetteSize
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a user vignette element: a coloured initials circle + async-resolved
|
||||
* display name span. The element is returned immediately with a short-UUID
|
||||
* placeholder; the name resolves in the background via `systemUsers`.
|
||||
*
|
||||
* @param {string} userId UUID of the user
|
||||
* @param {VignetteSize} [size='sm']
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function createUserVignette(userId, size = 'sm') {
|
||||
const colorIdx = _colorIndex(userId);
|
||||
|
||||
const wrapper = /** @type {HTMLElement} */ (document.createElement('span'));
|
||||
wrapper.className = `user-vignette user-vignette--${size}`;
|
||||
|
||||
const avatar = document.createElement('span');
|
||||
avatar.className = `user-vignette__avatar uv-color-${colorIdx}`;
|
||||
// Temporary placeholder: first two chars of UUID
|
||||
avatar.textContent = userId.slice(0, 2).toUpperCase();
|
||||
|
||||
const nameEl = document.createElement('span');
|
||||
nameEl.className = 'user-vignette__name';
|
||||
nameEl.textContent = `${userId.slice(0, 8)}…`;
|
||||
|
||||
wrapper.appendChild(avatar);
|
||||
wrapper.appendChild(nameEl);
|
||||
|
||||
// Resolve full name asynchronously and update both avatar initials and name
|
||||
systemUsers.getDisplayName(userId).then((name) => {
|
||||
avatar.textContent = _initials(name);
|
||||
nameEl.textContent = name;
|
||||
});
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
Reference in New Issue
Block a user