/** * Modul: User Multi-Select * Zweck: Wiederverwendbare Mehrfachauswahl-Komponente für Benutzer (Tasks & Kalender) * Abhängigkeiten: public/utils/html.js, public/i18n.js */ import { esc } from '/utils/html.js'; import { t } from '/i18n.js'; /** * Rendert einen Avatar-Stack für mehrere zugewiesene Benutzer. * @param {Array<{id, display_name, color}>} users * @param {object} opts * @param {number} [opts.size=28] Avatar-Größe in px * @param {number} [opts.maxVisible=3] Maximale Avatare vor "+N"-Anzeige * @returns {string} HTML-String */ export function renderAvatarStack(users, { size = 28, maxVisible = 3 } = {}) { if (!users?.length) return ''; const visible = users.slice(0, maxVisible); const overflow = users.length - visible.length; const fs = Math.round(size * 0.4); const avatars = visible.map((u) => { const initials = (u.display_name ?? '') .split(' ') .map((w) => w[0] ?? '') .join('') .toUpperCase() .slice(0, 2); return ` ${esc(initials)} `; }); if (overflow > 0) { avatars.push(`+${overflow}`); } return `${avatars.join('')}`; } /** * Rendert das Multi-Select-Widget als Dropdown-Checkbox-Liste. * @param {Array<{id, display_name, avatar_color}>} allUsers Alle verfügbaren Benutzer * @param {number[]} selectedIds Bereits ausgewählte IDs * @param {string} inputName Name-Attribut des Widgets * @param {string} labelKey i18n-Schlüssel für das Label * @returns {string} HTML-String */ export function renderUserMultiSelect(allUsers, selectedIds, inputName, labelKey) { const selectedSet = new Set(selectedIds ?? []); const items = allUsers.map((u) => { const checked = selectedSet.has(u.id) ? 'checked' : ''; const initials = (u.display_name ?? '') .split(' ') .map((w) => w[0] ?? '') .join('') .toUpperCase() .slice(0, 2); return ` `; }); const noneLabel = t('userMultiSelect.nobody'); return `