// ── A Backpacks backpack, read live (PLAN_REDESIGNS §11.3.2) ────────────── // // One component for both readers — staff on a user's admin page, a player on // their own account page — because the backpack is the same thing to both and // only the route differs. The caller hands over `read(serverId, steamId)`. // // **Opening reads once; nothing polls.** A read runs on the game's main thread // (§11.3.1), so the panel asks when somebody asks it to and not again until // they do. Nothing is stored on the site either. // // **No icons (D340).** The module has no item art (R9 kept it out of the asset // bridge), so a slot says the game's own English name, which the plugin sends. import { useState } from 'react' import { count, shortId } from '../lib/format.js' import { backpackPages, overflowCount, stackLabel } from '../lib/backpack.js' const CELL = 92 /** One slot: its name, amount, and what rides inside it. */ function Cell({ cell }) { const { stack, overflow } = cell const border = overflow ? '1px dashed #d89b3c' : '1px solid var(--line-soft)' const title = stack ? [stackLabel(stack), stack.name ? `“${stack.name}”` : null, stack.skin ? `skin ${stack.skin}` : null, overflow ? 'past the capacity' : null] .filter(Boolean) .join(' · ') : overflow ? 'past the capacity' : `slot ${cell.slot + 1}` return (
No backpack on {backpack.server} yet — it has never been opened.
} const pages = backpackPages(backpack) const waiting = overflowCount(backpack) const held = (backpack.items || []).length return ({count(held)} stack{held === 1 ? '' : 's'} in {count(backpack.capacity)} slots on {backpack.server} {waiting > 0 && ( {' '}· {count(waiting)} past the capacity, moved to the owner’s inventory (or dropped at their feet if it is full) the next time they open it )}
{pages.map((page) => ({error}
} {backpack &&