feat(ui): add share modal and users
- fix(external users): fix app starting for external users
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* PendingEmailVignette — visual for an external invite *before* the
|
||||
* server has resolved (or lazily created) the recipient user.
|
||||
*
|
||||
* Used by the share modal's email-input UX:
|
||||
* 1. The user types an address in the search input.
|
||||
* 2. When the address matches no existing contact but parses as an
|
||||
* email, the dropdown surfaces an "Invite by email" suggestion
|
||||
* rendered with this vignette.
|
||||
* 3. Clicking the suggestion stages an email-typed chip that also
|
||||
* uses this vignette.
|
||||
* 4. On Apply, the modal POSTs `subject.type=email` and reloads the
|
||||
* grant list — at which point the resolved real userId takes
|
||||
* over via the regular `createUserVignette`, which paints the
|
||||
* same `fa-building-circle-xmark` badge (PR 11.2). Visual
|
||||
* continuity is intentional: the chip's look doesn't change
|
||||
* across the commit boundary.
|
||||
*
|
||||
* Reuses the userVignette CSS so size variants (xs/sm/md/list/lg/menu/xl),
|
||||
* colour palette, and the external-badge styling all apply unchanged.
|
||||
* The external badge here is FORCED visible — by definition an email
|
||||
* we don't recognise is going to mint an external user.
|
||||
*/
|
||||
|
||||
import { _colorIndex, _initials } from './userVignette.js';
|
||||
|
||||
/** @typedef {'xs'|'sm'|'list'|'md'|'lg'|'menu'|'xl'} VignetteSize */
|
||||
|
||||
/**
|
||||
* Build a transient vignette seeded from an email address (no UUID yet).
|
||||
*
|
||||
* @param {string} email
|
||||
* @param {VignetteSize} [size='sm']
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function createPendingEmailVignette(email, size = 'sm') {
|
||||
const trimmed = email.trim();
|
||||
const colorIdx = _colorIndex(trimmed);
|
||||
|
||||
const wrapper = document.createElement('span');
|
||||
wrapper.className = `user-vignette user-vignette--${size}`;
|
||||
|
||||
const avatar = document.createElement('span');
|
||||
avatar.className = `user-vignette__avatar uv-color-${colorIdx}`;
|
||||
// Synthesize initials: local-part initial + domain initial when
|
||||
// possible, otherwise fall back to the first two chars.
|
||||
const [local, domain] = trimmed.split('@');
|
||||
const synthName = local && domain ? `${local[0]} ${domain[0]}` : trimmed.slice(0, 2);
|
||||
avatar.textContent = _initials(synthName);
|
||||
|
||||
// Forced external badge — this is the whole point of the component.
|
||||
const badge = document.createElement('i');
|
||||
badge.className = 'user-vignette__origin user-vignette__origin--external fa-solid fa-building-circle-xmark';
|
||||
badge.title = 'External invitation';
|
||||
badge.setAttribute('aria-hidden', 'true');
|
||||
avatar.appendChild(badge);
|
||||
|
||||
wrapper.appendChild(avatar);
|
||||
|
||||
// The "name" for a pending invite is just the email itself — there
|
||||
// is no separate display name yet.
|
||||
const nameEl = document.createElement('span');
|
||||
nameEl.className = 'user-vignette__name';
|
||||
nameEl.textContent = trimmed;
|
||||
wrapper.appendChild(nameEl);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
Reference in New Issue
Block a user