import Timer from '../../components/Timer.vue'; import { Button } from '../../components/ui/button'; import { TooltipWrapper } from '../../components/ui/tooltip'; import { ArrowUpDown } from 'lucide-vue-next'; import { getFaviconUrl, languageClass, openExternalLink, statusClass, userImage } from '../../shared/utils'; import { i18n } from '../../plugin'; const { t } = i18n.global; const sortButton = ({ column, label, descFirst = false }) => ( ); const getInstanceIconWeight = (item) => { if (!item) return 0; let value = 0; if (item.isMaster) value += 1000; if (item.isModerator) value += 500; if (item.isFriend) value += 200; if (item.isBlocked) value -= 100; if (item.isMuted) value -= 50; if (item.isAvatarInteractionDisabled) value -= 20; if (item.isChatBoxMuted) value -= 10; if (item.ageVerified) value += 5; return value; }; const sortInstanceIcon = (a, b) => getInstanceIconWeight(b) - getInstanceIconWeight(a); export const createColumns = ({ randomUserColours, photonLoggingEnabled, chatboxUserBlacklist, onBlockChatbox, onUnblockChatbox, sortAlphabetically }) => { /** @type {import('@tanstack/vue-table').ColumnDef[]} */ const cols = [ { id: 'avatar', accessorFn: (row) => row?.photo, header: () => t('table.playerList.avatar'), size: 70, enableSorting: false, enableResizing: false, cell: ({ row }) => { const userRef = row.original?.ref; const src = userImage(userRef); if (!src) return null; return (
); } }, { id: 'timer', accessorFn: (row) => row?.timer, header: ({ column }) => sortButton({ column, label: t('table.playerList.timer') }), size: 90, enableResizing: false, sortingFn: (rowA, rowB) => (rowA.original?.timer ?? 0) - (rowB.original?.timer ?? 0), cell: ({ row }) => }, { id: 'displayName', accessorFn: (row) => row?.displayName, header: ({ column }) => sortButton({ column, label: t('table.playerList.displayName') }), size: 200, sortingFn: (rowA, rowB) => sortAlphabetically(rowA.original, rowB.original, 'displayName'), cell: ({ row }) => { const userRef = row.original?.ref; const style = randomUserColours?.value ? { color: userRef?.$userColour } : null; return ( {userRef?.displayName ?? ''} ); } }, { id: 'rank', accessorFn: (row) => row?.ref?.$trustSortNum, header: ({ column }) => sortButton({ column, label: t('table.playerList.rank') }), size: 110, sortingFn: (rowA, rowB) => (rowA.original?.ref?.$trustSortNum ?? 0) - (rowB.original?.ref?.$trustSortNum ?? 0), cell: ({ row }) => { const userRef = row.original?.ref; return ( {userRef?.$trustLevel ?? ''} ); } }, { id: 'status', accessorFn: (row) => row?.ref?.statusDescription, header: () => t('table.playerList.status'), minSize: 200, enableSorting: false, cell: ({ row }) => { const userRef = row.original?.ref; const status = userRef?.status; return ( {userRef?.statusDescription ?? ''} ); } } ]; if (photonLoggingEnabled?.value) { cols.push({ id: 'photonId', accessorFn: (row) => row?.photonId, header: ({ column }) => sortButton({ column, label: t('table.playerList.photonId') }), size: 110, sortingFn: (rowA, rowB) => (rowA.original?.photonId ?? 0) - (rowB.original?.photonId ?? 0), cell: ({ row }) => { const userRef = row.original?.ref; const userId = userRef?.id; const isBlocked = userId && chatboxUserBlacklist?.value?.has?.(userId); return (
{userId ? ( ) : null} {String(row.original?.photonId ?? '')}
); } }); } cols.push( { id: 'icon', header: ({ column }) => sortButton({ column, label: t('table.playerList.icon'), descFirst: true }), size: 90, accessorFn: (row) => getInstanceIconWeight(row), meta: { class: 'text-center' }, sortingFn: (rowA, rowB, columnId) => { const a = rowA.original; const b = rowB.original; return -sortInstanceIcon(a, b); }, cell: ({ row }) => { const r = row.original; return (
{r?.isMaster ? ( 👑 ) : null} {r?.isModerator ? ( ⚔️ ) : null} {r?.isFriend ? ( 💚 ) : null} {r?.isBlocked ? ( ) : null} {r?.isMuted ? ( 🔇 ) : null} {r?.isAvatarInteractionDisabled ? ( 🚫 ) : null} {r?.isChatBoxMuted ? ( 💬 ) : null} {r?.timeoutTime ? ( 🔴{r.timeoutTime}s ) : null} {r?.ageVerified ? ( ) : null}
); } }, { id: 'platform', header: () => t('table.playerList.platform'), size: 90, enableSorting: false, cell: ({ row }) => { const userRef = row.original?.ref; const platform = userRef?.$platform; const inVRMode = row.original?.inVRMode; const platformIcon = platform === 'standalonewindows' ? ( ) : platform === 'android' ? ( ) : platform === 'ios' ? ( ) : platform ? ( {String(platform)} ) : null; const mode = inVRMode === null || inVRMode === undefined ? null : inVRMode ? 'VR' : userRef?.last_platform === 'android' || userRef?.last_platform === 'ios' ? 'M' : 'D'; return (
{platformIcon} {mode ? {mode} : null}
); } }, { id: 'language', header: () => t('table.playerList.language'), size: 100, enableSorting: false, cell: ({ row }) => { const userRef = row.original?.ref; const langs = userRef?.$languages ?? []; return (
{langs.map((item) => ( ( {item.value} ({item.key}) ) }} > ))}
); } }, { id: 'bioLink', header: () => t('table.playerList.bioLink'), size: 100, enableSorting: false, cell: ({ row }) => { const links = row.original?.ref?.bioLinks?.filter(Boolean) ?? []; return (
{links.map((link, index) => ( ( {String(link ?? '')} ) }} > { e.stopPropagation(); openExternalLink(String(link)); }} /> ))}
); } }, { id: 'note', accessorFn: (row) => row?.ref?.note, header: () => t('table.playerList.note'), size: 150, minSize: 40, meta: { stretch: true }, enableSorting: false, cell: ({ row }) => { const note = row.original?.ref?.note; const text = typeof note === 'string' || typeof note === 'number' ? String(note) : ''; return {text}; } } ); return cols; };