@hadoku/task-ui-components 4.23.6 → 4.23.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"cosmetics.js","sources":["../../../../../node_modules/.pnpm/@wolffm+prefs-client@1.1.12_react@19.2.8_zod@4.6.7/node_modules/@wolffm/prefs-client/dist/cosmetics.js"],"sourcesContent":["// src/cosmetics-contract.ts\nvar COSMETIC_SLOTS = [\"effect\", \"gradient\", \"font\", \"overlay\", \"message\"];\nvar COSMETIC_ID_PATTERN = /^(effect|gradient|font|overlay|message)\\.[a-z0-9-]{1,32}$/;\nvar item = (slot, name, label, earn, art) => ({ id: `${slot}.${name}`, slot, label, earn, ...art ? { art } : {} });\nvar COSMETICS = [\n item(\"effect\", \"glint\", \"Glint\", \"Win a cardtable match\"),\n item(\"effect\", \"aura\", \"Aura\", \"Attend 10 watchparties\"),\n item(\"effect\", \"hop\", \"Hop\", \"Win 25 bomberman rounds\"),\n item(\"effect\", \"outline\", \"Outline\", \"Finish 3 tournaments\"),\n item(\"effect\", \"twinkle\", \"Twinkle\", \"Top four in a Major\"),\n item(\"gradient\", \"gild\", \"Gilded\", \"Your first win in any game\"),\n item(\"gradient\", \"gloss\", \"Gloss\", \"Win 10 games\"),\n item(\"gradient\", \"split\", \"Split\", \"Finish 5 tournaments\"),\n item(\"gradient\", \"brushed\", \"Brushed\", \"Play 100 games\"),\n item(\"gradient\", \"lumen\", \"Lumen\", \"Host 5 watchparties\"),\n item(\"font\", \"caps\", \"Small caps\", \"Finish a tournament\"),\n item(\"font\", \"wide\", \"Wide\", \"Finish 5 tournaments\"),\n item(\"font\", \"script\", \"Script\", \"Attend 25 watchparties\"),\n item(\"font\", \"surf\", \"Surf\", \"Attend a summer watchparty\"),\n item(\"font\", \"gothic\", \"Gothic\", \"Win an arcane-set game\"),\n item(\"font\", \"runic\", \"Runic\", \"Win a fantasy-set game\"),\n item(\"font\", \"corsair\", \"Corsair\", \"Win 3 matches in one night\"),\n item(\"font\", \"metal\", \"Metal\", \"Win a Major final\"),\n item(\"font\", \"comic\", \"Comic\", \"Win from behind\"),\n item(\"font\", \"circuit\", \"Circuit\", \"Play 25 cyber-set games\"),\n item(\"font\", \"hover\", \"Hover\", \"Win a race\"),\n item(\"font\", \"retro\", \"Retro\", \"Play for a year\"),\n item(\"font\", \"arcade\", \"Arcade\", \"Play 50 bomberman games\"),\n item(\"font\", \"pixel\", \"Pixel\", \"Win 10 bomberman rounds\"),\n item(\"overlay\", \"crown\", \"Crown\", \"Win a Major\", {\n file: \"crown.webp\",\n top: -40,\n width: 70,\n tilt: -8,\n pixel: false,\n visible: [0.027, 0.137, 0.973, 0.863]\n }),\n item(\"overlay\", \"halo\", \"Halo\", \"Help a new player (gift)\", {\n file: \"halo.webp\",\n top: -34,\n width: 76,\n tilt: 0,\n pixel: true,\n visible: [0.023, 0.316, 0.969, 0.684]\n }),\n item(\"overlay\", \"horns\", \"Horns\", \"Win 10 games as the villain\", {\n file: \"horns.webp\",\n top: -26,\n width: 100,\n tilt: 0,\n pixel: true,\n visible: [0.023, 0.129, 0.969, 0.871]\n }),\n item(\"overlay\", \"flowers\", \"Flower crown\", \"The anniversary of joining\", {\n file: \"flowers.webp\",\n top: -22,\n width: 96,\n tilt: 0,\n pixel: false,\n visible: [0.027, 0.258, 0.969, 0.746]\n }),\n item(\"overlay\", \"runes\", \"Runes\", \"Finish a Major\"),\n item(\"overlay\", \"comet\", \"Comet\", \"A 10-game win streak\"),\n item(\"overlay\", \"shine\", \"Shine\", \"Win a cardtable match\"),\n item(\"overlay\", \"glow\", \"Glow\", \"Attend 25 watchparties\"),\n item(\"overlay\", \"petals\", \"Petals\", \"The anniversary of joining\"),\n item(\"message\", \"type\", \"Typewriter\", \"Send 1000 chat messages\"),\n item(\"message\", \"decode\", \"Decode\", \"Win 25 cyber-set games\"),\n item(\"message\", \"cascade\", \"Cascade\", \"Win 3 games in a row\"),\n item(\"message\", \"words\", \"Word by word\", \"Send 100 chat messages\"),\n item(\"message\", \"bubble\", \"Bubble\", \"Host 3 watchparties\"),\n item(\"message\", \"drift\", \"Drift\", \"Attend 20 watchparties\")\n];\nvar COSMETICS_BY_ID = new Map(\n COSMETICS.map((i) => [i.id, i])\n);\nvar PLACEMENT_DEFAULT = { x: 0, y: 0, r: 0, s: 100, flip: false, back: false };\nvar PLACEMENT_LIMITS = {\n x: [-60, 60],\n y: [-60, 100],\n r: [-45, 45],\n s: [70, 140]\n};\nfunction overlayBounds(art, p) {\n const [a, b, c, d] = art.visible;\n const x0 = p.flip ? 1 - c : a;\n const x1 = p.flip ? 1 - a : c;\n const L = 50 - art.width / 2;\n const T = art.top;\n const W = art.width;\n const ox = L + W * 0.5;\n const oy = T + W * 0.6;\n const cx = L + W / 2;\n const cy = T + W / 2;\n const t = art.tilt * Math.PI / 180;\n const r = p.r * Math.PI / 180;\n const sc = p.s / 100;\n const xs = [];\n const ys = [];\n for (const [fx, fy] of [\n [x0, b],\n [x1, b],\n [x0, d],\n [x1, d]\n ]) {\n const px = L + fx * W;\n const py = T + fy * W;\n const tx = cx + (px - cx) * Math.cos(t) - (py - cy) * Math.sin(t);\n const ty = cy + (px - cx) * Math.sin(t) + (py - cy) * Math.cos(t);\n const dx = (tx - ox) * sc;\n const dy = (ty - oy) * sc;\n xs.push(ox + p.x + dx * Math.cos(r) - dy * Math.sin(r));\n ys.push(oy + p.y + dx * Math.sin(r) + dy * Math.cos(r));\n }\n return {\n left: Math.min(...xs),\n top: Math.min(...ys),\n right: Math.max(...xs),\n bottom: Math.max(...ys)\n };\n}\nvar ART_ITEMS = COSMETICS.filter((i) => !!i.art);\nvar PLACEMENT_ZONE = {\n left: -25,\n top: Math.floor(Math.min(...ART_ITEMS.map((i) => overlayBounds(i.art, PLACEMENT_DEFAULT).top))),\n right: 125,\n bottom: 110\n};\nvar clamp = (v, [lo, hi]) => Math.min(hi, Math.max(lo, v));\nfunction fitPlacement(art, raw) {\n const num = (v, fallback) => typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n const p = {\n x: Math.round(clamp(num(raw.x, 0), PLACEMENT_LIMITS.x)),\n y: Math.round(clamp(num(raw.y, 0), PLACEMENT_LIMITS.y)),\n r: Math.round(clamp(num(raw.r, 0), PLACEMENT_LIMITS.r)),\n s: Math.round(clamp(num(raw.s, 100), PLACEMENT_LIMITS.s)),\n flip: raw.flip === true,\n back: raw.back === true\n };\n const z = PLACEMENT_ZONE;\n let box = overlayBounds(art, p);\n const room = Math.min(\n (z.right - z.left - 2) / (box.right - box.left),\n (z.bottom - z.top - 2) / (box.bottom - box.top)\n );\n if (room < 1) {\n p.s = Math.max(PLACEMENT_LIMITS.s[0], Math.floor(p.s * room));\n box = overlayBounds(art, p);\n }\n p.x += Math.ceil(Math.max(0, z.left - box.left)) - Math.ceil(Math.max(0, box.right - z.right));\n p.y += Math.ceil(Math.max(0, z.top - box.top)) - Math.ceil(Math.max(0, box.bottom - z.bottom));\n return p;\n}\nfunction emptyLoadout() {\n return {\n equipped: { effect: null, gradient: null, font: null, overlay: null, message: null },\n placement: {}\n };\n}\nfunction cleanLoadout(raw, owned) {\n const out = emptyLoadout();\n const src = raw && typeof raw === \"object\" ? raw : {};\n for (const slot of COSMETIC_SLOTS) {\n const id = src.equipped?.[slot];\n if (typeof id === \"string\" && owned.has(id) && COSMETICS_BY_ID.get(id)?.slot === slot) {\n out.equipped[slot] = id;\n }\n }\n for (const [id, p] of Object.entries(src.placement ?? {})) {\n const art = COSMETICS_BY_ID.get(id)?.art;\n if (art && owned.has(id) && p && typeof p === \"object\") {\n out.placement[id] = fitPlacement(art, p);\n }\n }\n return out;\n}\nfunction wornCosmetics(loadout) {\n const worn = {};\n for (const slot of COSMETIC_SLOTS) {\n const id = loadout.equipped[slot];\n if (id) worn[slot] = id;\n }\n const overlay = loadout.equipped.overlay;\n if (overlay && COSMETICS_BY_ID.get(overlay)?.art && loadout.placement[overlay]) {\n worn.placement = loadout.placement[overlay];\n }\n return Object.keys(worn).length ? worn : void 0;\n}\n\n// src/cosmetics.ts\nvar COSMETICS_ASSET_BASE = \"/cosmetics\";\nvar STYLE_ID = \"hadoku-cosmetics\";\nvar esc = (s) => s.replace(\n /[&<>\"']/g,\n (c) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" })[c]\n);\nvar nameOf = (id) => id ? id.slice(id.indexOf(\".\") + 1) : \"none\";\nfunction colourStyle(hex) {\n return hex && /^#[0-9a-f]{6}$/i.test(hex) ? `--hc-base:${hex}` : \"\";\n}\nfunction placementTransform(p) {\n const sx = p.s / 100 * (p.flip ? -1 : 1);\n return `translate(calc(var(--hc-sz) * ${(p.x / 100).toFixed(3)}),calc(var(--hc-sz) * ${(p.y / 100).toFixed(3)})) rotate(${p.r}deg) scale(${sx.toFixed(3)},${(p.s / 100).toFixed(3)})`;\n}\nvar SPLIT_EFFECTS = /* @__PURE__ */ new Set([\"hop\"]);\nfunction nameHtml(text, worn, opts = {}) {\n const fx = nameOf(worn?.effect);\n const gr = nameOf(worn?.gradient);\n const font = nameOf(worn?.font);\n const t = esc(text);\n const split = SPLIT_EFFECTS.has(fx);\n const tx = split ? `<span class=\"hc-tx\">${[...text].map(\n (c, i) => `<span class=\"hc-ch\" style=\"--hc-i:${i}\"><span class=\"hc-c\">${c === \" \" ? \"&nbsp;\" : esc(c)}</span></span>`\n ).join(\"\")}</span>` : `<span class=\"hc-tx\">${t}</span>`;\n const layer = (cls2) => `<span class=\"hc-lyr${cls2}\" aria-hidden=\"true\">${t}</span>`;\n let back = \"\";\n let front = \"\";\n if (fx === \"aura\" || fx === \"outline\") back += layer(\" hc-g\");\n if (fx === \"glint\") front += `<span class=\"hc-win\" aria-hidden=\"true\">${layer(\"\")}</span>`;\n if (fx === \"twinkle\") {\n front += [\n [-6, -25, 0],\n [52, 55, 0.95],\n [94, -15, 1.9]\n ].map(\n ([x, y, d]) => `<i class=\"hc-tw\" aria-hidden=\"true\" style=\"left:${x}%;top:${y}%;animation-delay:${d}s\"></i>`\n ).join(\"\");\n }\n const cls = `hc-name hc-fx-${fx} hc-gr-${gr} hc-font-${font}${split ? \" hc-split\" : \"\"}${opts.large ? \" hc-large\" : \"\"}`;\n return `<span class=\"${cls}\">${back}${tx}${front}</span>`;\n}\nvar RUNES_SVG = (() => {\n let marks = \"\";\n for (let i = 0; i < 12; i++) {\n marks += `<g transform=\"rotate(${i * 30} 50 50)\"><path d=\"M50 3 l2.5 4 -2.5 4 -2.5 -4z\" fill=\"currentColor\" opacity=\"${i % 3 ? 0.55 : 1}\"/></g>`;\n }\n return `<svg viewBox=\"0 0 100 100\" aria-hidden=\"true\"><circle cx=\"50\" cy=\"50\" r=\"44\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\" stroke-dasharray=\"3 5\" opacity=\".7\"/>${marks}</svg>`;\n})();\nfunction decorHtml(worn, assetBase = COSMETICS_ASSET_BASE) {\n const id = worn?.overlay;\n if (!id) return \"\";\n const art = COSMETICS_BY_ID.get(id)?.art;\n if (art) {\n const p = worn?.placement ?? PLACEMENT_DEFAULT;\n return `<span class=\"hc-ol hc-art${art.pixel ? \" hc-px\" : \"\"}\" data-hc-art=\"${esc(id)}\" style=\"left:${50 - art.width / 2}%;top:${art.top}%;width:${art.width}%;z-index:${p.back ? 0 : 3}\"><span class=\"hc-adj\" style=\"transform:${placementTransform(p)}\"><img alt=\"\" draggable=\"false\" style=\"--hc-tilt:${art.tilt}deg\" src=\"${esc(`${assetBase}/art/${art.file}`)}\"></span></span>`;\n }\n switch (nameOf(id)) {\n case \"runes\":\n return `<span class=\"hc-ol hc-runes\">${RUNES_SVG}</span>`;\n case \"comet\":\n return `<span class=\"hc-ol hc-comet\"></span>`;\n case \"shine\":\n return `<span class=\"hc-ol hc-clip\"><span class=\"hc-band\"></span></span>`;\n case \"glow\":\n return `<span class=\"hc-ol hc-glow\"></span>`;\n case \"petals\":\n return [15, 40, 62, 85].map(\n (l, i) => `<i class=\"hc-ol hc-petal\" style=\"left:${l}%;animation-delay:${(i * 0.85).toFixed(2)}s\"></i>`\n ).join(\"\");\n default:\n return \"\";\n }\n}\nfunction avatarHtml(o) {\n const pic = o.src ? `<img alt=\"\" src=\"${esc(o.src)}\">` : \"\";\n return `<span class=\"hc-av\" style=\"--hc-sz:${o.size}px\"><span class=\"hc-pic\">${pic}</span>${decorHtml(o.worn, o.assetBase)}</span>`;\n}\nvar GLYPHS = \"!<>-_/[]{}=+*^?#%&01\";\nvar LETTER_MODES = /* @__PURE__ */ new Set([\"type\", \"decode\", \"cascade\"]);\nvar REVEAL_MS = 1400;\nvar LETTER_LIMIT = 160;\nfunction messageHtml(text, worn, opts = {}) {\n let mode = nameOf(worn?.message);\n if (mode === \"none\") return `<span class=\"hc-msg\">${esc(text)}</span>`;\n const words = text.split(/\\s+/).filter(Boolean);\n if (LETTER_MODES.has(mode) && text.length > LETTER_LIMIT) mode = \"words\";\n const keep = opts.keep ? \" data-hc-keep\" : \"\";\n let body;\n let step;\n if (LETTER_MODES.has(mode)) {\n step = Math.min(38, REVEAL_MS / Math.max(1, text.length));\n let n = 0;\n const rnd = () => GLYPHS[Math.floor(Math.random() * GLYPHS.length)];\n body = words.map(\n (w) => `<span class=\"hc-w\">${[...w].map((c) => {\n const i = n++;\n return mode === \"decode\" ? `<span class=\"hc-ch\" style=\"--hc-i:${i}\" data-g=\"${esc(rnd())}\" data-h=\"${esc(rnd())}\"><span class=\"hc-r\">${esc(c)}</span></span>` : `<span class=\"hc-ch\" style=\"--hc-i:${i}\">${esc(c)}</span>`;\n }).join(\"\")}</span>`\n ).join(\" \");\n if (mode === \"type\") body += `<span class=\"hc-caret\" style=\"--hc-i:${n}\"></span>`;\n const lastClass = mode === \"type\" ? \"hc-caret\" : mode === \"decode\" ? \"hc-r\" : \"hc-ch\";\n const at = body.lastIndexOf(`<span class=\"${lastClass}\"`);\n body = `${body.slice(0, at)}<span data-hc-last class=\"${lastClass}\"${body.slice(at + `<span class=\"${lastClass}\"`.length)}`;\n } else {\n step = Math.min(90, REVEAL_MS / Math.max(1, words.length));\n body = words.map(\n (w, i) => `<span class=\"hc-w\" style=\"--hc-i:${i}\"${i === words.length - 1 ? \" data-hc-last\" : \"\"}>${esc(w)}</span>`\n ).join(\" \");\n }\n return `<span class=\"hc-msg hc-mt-${mode}\" style=\"--hc-step:${step.toFixed(1)}ms\" data-text=\"${esc(text)}\"${keep}><span class=\"hc-sr\">${esc(text)}</span><span aria-hidden=\"true\">${body}</span></span>`;\n}\nfunction finishReveal(e) {\n const t = e.target;\n if (e.pseudoElement || !t?.hasAttribute?.(\"data-hc-last\")) return;\n const msg = t.closest(\".hc-msg\");\n if (!msg || msg.hasAttribute(\"data-hc-keep\")) return;\n msg.className = \"hc-msg\";\n msg.removeAttribute(\"style\");\n msg.textContent = msg.getAttribute(\"data-text\") ?? \"\";\n}\nvar FONTS = {\n script: {\n file: \"caveat\",\n family: \"Caveat\",\n generic: \"cursive\",\n css: \"font-weight:700;font-size:1.3em;line-height:1\"\n },\n surf: {\n file: \"pacifico\",\n family: \"Pacifico\",\n generic: \"cursive\",\n css: \"font-weight:400;font-size:1.02em;line-height:1.1\"\n },\n gothic: {\n file: \"gothic\",\n family: \"Grenze Gotisch\",\n generic: \"serif\",\n css: \"font-weight:600;font-size:1.15em\"\n },\n runic: { file: \"uncial\", family: \"Uncial Antiqua\", generic: \"serif\", css: \"font-weight:400\" },\n corsair: {\n file: \"pirata\",\n family: \"Pirata One\",\n generic: \"serif\",\n css: \"font-weight:400;font-size:1.12em;letter-spacing:.02em\"\n },\n metal: {\n file: \"metal\",\n family: \"Metal Mania\",\n generic: \"cursive\",\n css: \"font-weight:400;font-size:1.12em;letter-spacing:.02em\"\n },\n comic: {\n file: \"bangers\",\n family: \"Bangers\",\n generic: \"cursive\",\n css: \"font-weight:400;font-size:1.15em;letter-spacing:.05em\"\n },\n circuit: {\n file: \"orbitron\",\n family: \"Orbitron\",\n generic: \"sans-serif\",\n css: \"font-weight:700;letter-spacing:.03em\"\n },\n hover: {\n file: \"audiowide\",\n family: \"Audiowide\",\n generic: \"sans-serif\",\n css: \"font-weight:400;font-size:.92em\"\n },\n retro: { file: \"righteous\", family: \"Righteous\", generic: \"sans-serif\", css: \"font-weight:400\" },\n arcade: {\n file: \"bungee\",\n family: \"Bungee\",\n generic: \"sans-serif\",\n css: \"font-weight:400;font-size:.9em\"\n },\n pixel: {\n file: \"pixel\",\n family: \"Press Start 2P\",\n generic: \"monospace\",\n css: \"font-weight:400;font-size:.62em;line-height:1.6\"\n }\n};\nfunction cosmeticsCss(assetBase = COSMETICS_ASSET_BASE) {\n const fontFaces = Object.entries(FONTS).map(\n ([k, f]) => `@font-face{font-family:\"hc-${k}\";src:url(\"${assetBase}/fonts/${f.file}.woff2\") format(\"woff2\");font-display:swap}`\n ).join(\"\\n\");\n const fontRules = Object.entries(FONTS).map(([k, f]) => `.hc-font-${k}{font-family:\"hc-${k}\",\"${f.family}\",${f.generic};${f.css}}`).join(\"\\n\");\n return `${fontFaces}\n/* Colours: everything derives from the character colour. */\n.hc-name,.hc-av,.hc-msg{--hc-b:var(--hc-base,currentColor);--hc-hi:color-mix(in oklch,var(--hc-b),white 50%);--hc-lo:color-mix(in oklch,var(--hc-b),black 50%);--hc-glow:color-mix(in oklch,var(--hc-b) 75%,transparent)}\n\n/* --- name ---\n Bleed: a gradient is a background clipped to the letters, and a background covers only the box; script\n swashes reach outside it. So the text box and every layer over it get room on all sides, cancelled by a\n negative margin so nothing moves. */\n.hc-name{--hc-bx:.4em;--hc-by:.3em;--hc-grad:none;position:relative;display:inline-block;white-space:nowrap;color:var(--hc-b);font-weight:700;line-height:1.25}\n.hc-name.hc-large{font-size:1.6em}\n.hc-name .hc-tx{position:relative;z-index:1;display:inline-block;padding:var(--hc-by) var(--hc-bx);margin:calc(-1 * var(--hc-by)) calc(-1 * var(--hc-bx))}\n.hc-name .hc-lyr{position:absolute;left:calc(-1 * var(--hc-bx));top:calc(-1 * var(--hc-by));padding:var(--hc-by) var(--hc-bx);pointer-events:none;white-space:nowrap}\n.hc-name .hc-win{position:absolute;inset:calc(-1 * var(--hc-by)) calc(-1 * var(--hc-bx));overflow:hidden}\n.hc-name .hc-win .hc-lyr{left:0;top:0}\n.hc-name .hc-ch,.hc-name .hc-c{display:inline-block}\n.hc-gr-gild{--hc-grad:linear-gradient(180deg,var(--hc-hi) 0%,var(--hc-b) 55%,var(--hc-lo) 100%)}\n.hc-gr-gloss{--hc-grad:linear-gradient(180deg,color-mix(in oklch,var(--hc-hi),white 35%) 0%,var(--hc-hi) 36%,color-mix(in oklch,var(--hc-hi),var(--hc-b)) 48%,var(--hc-b) 60%,var(--hc-lo) 100%)}\n.hc-gr-split{--hc-grad:linear-gradient(180deg,var(--hc-hi) 0 52%,var(--hc-b) 52% 100%)}\n.hc-gr-brushed{--hc-grad:repeating-linear-gradient(90deg,transparent 0 1px,color-mix(in oklch,var(--hc-hi) 40%,transparent) 1px 2px),linear-gradient(180deg,var(--hc-hi),var(--hc-b) 55%,var(--hc-lo))}\n.hc-gr-lumen{--hc-grad:radial-gradient(ellipse 60% 90% at 50% 35%,var(--hc-hi),var(--hc-b) 55%,var(--hc-lo) 100%)}\n.hc-name:not(.hc-gr-none) .hc-tx{background:var(--hc-grad);-webkit-background-clip:text;background-clip:text;color:transparent}\n.hc-name.hc-split:not(.hc-gr-none) .hc-tx{background:none}\n.hc-name.hc-split:not(.hc-gr-none) .hc-tx .hc-c{padding:var(--hc-by) var(--hc-bx);margin:calc(-1 * var(--hc-by)) calc(-1 * var(--hc-bx));background:var(--hc-grad);-webkit-background-clip:text;background-clip:text;color:transparent}\n.hc-fx-glint .hc-win{z-index:3;animation:hc-win-go 4.5s cubic-bezier(.4,0,.2,1) infinite;-webkit-mask-image:linear-gradient(100deg,transparent 35%,#000 50%,transparent 65%);mask-image:linear-gradient(100deg,transparent 35%,#000 50%,transparent 65%)}\n.hc-fx-glint .hc-win .hc-lyr{color:var(--hc-hi);animation:hc-win-back 4.5s cubic-bezier(.4,0,.2,1) infinite}\n@keyframes hc-win-go{0%{transform:translateX(-100%)}55%,100%{transform:translateX(100%)}}\n@keyframes hc-win-back{0%{transform:translateX(100%)}55%,100%{transform:translateX(-100%)}}\n.hc-fx-aura .hc-lyr.hc-g{color:transparent;text-shadow:0 0 6px var(--hc-glow),0 0 14px var(--hc-glow);animation:hc-breathe 3s ease-in-out infinite}\n.hc-fx-outline .hc-lyr.hc-g{color:transparent;-webkit-text-stroke:3px var(--hc-hi);animation:hc-breathe 3.6s ease-in-out infinite}\n@keyframes hc-breathe{0%,100%{opacity:.25}50%{opacity:1}}\n.hc-fx-hop .hc-c{animation:hc-hop 3.6s ease-in-out calc(var(--hc-i) * 45ms) infinite}\n@keyframes hc-hop{0%,14%,100%{transform:none}5%{transform:translateY(-4px)}10%{transform:translateY(.5px)}}\n.hc-fx-twinkle .hc-tw{position:absolute;width:7px;height:7px;z-index:3;pointer-events:none;background:linear-gradient(var(--hc-hi),var(--hc-hi)) center/1.4px 100% no-repeat,linear-gradient(90deg,var(--hc-hi),var(--hc-hi)) center/100% 1.4px no-repeat;animation:hc-star 2.8s ease-in-out infinite both}\n@keyframes hc-star{0%,100%{opacity:0;transform:scale(.3) rotate(0deg)}25%{opacity:1;transform:scale(1) rotate(45deg)}50%{opacity:0;transform:scale(.3) rotate(90deg)}}\n.hc-font-caps{font-variant:small-caps;letter-spacing:.08em}\n.hc-font-wide{letter-spacing:.22em;font-weight:600;text-transform:uppercase;font-size:.82em}\n${fontRules}\n\n/* --- avatar --- */\n.hc-av{--hc-sz:40px;position:relative;display:inline-block;width:var(--hc-sz);height:var(--hc-sz);flex:none;isolation:isolate;vertical-align:middle}\n.hc-av .hc-pic{position:absolute;inset:0;border-radius:50%;overflow:hidden;z-index:1;background:color-mix(in oklch,var(--hc-b) 30%,transparent)}\n.hc-av .hc-pic img{width:100%;height:100%;display:block;object-fit:cover;image-rendering:pixelated}\n.hc-av .hc-ol{position:absolute;pointer-events:none}\n.hc-ol.hc-art{display:block}\n.hc-ol.hc-art .hc-adj{display:block;position:relative;transform-origin:50% 60%}\n.hc-ol.hc-art img{display:block;width:100%;height:auto;filter:drop-shadow(0 1px 1px rgba(0,0,0,.45));animation:hc-art-bob 3.4s ease-in-out infinite;-webkit-user-drag:none;user-select:none}\n.hc-ol.hc-art.hc-px img{image-rendering:pixelated}\n@keyframes hc-art-bob{0%,100%{transform:rotate(var(--hc-tilt,0deg)) translateY(0)}50%{transform:rotate(var(--hc-tilt,0deg)) translateY(-2px)}}\n.hc-ol.hc-runes{inset:-9px;z-index:2;color:var(--hc-hi);animation:hc-turn 14s linear infinite}\n.hc-ol.hc-runes svg{width:100%;height:100%;display:block}\n@keyframes hc-turn{to{transform:rotate(360deg)}}\n.hc-ol.hc-comet{inset:-6px;z-index:2;border-radius:50%;background:conic-gradient(from 0deg,transparent 0 270deg,color-mix(in oklch,var(--hc-hi) 10%,transparent) 300deg,var(--hc-hi) 358deg,transparent 360deg);-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 3px));mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 3px));animation:hc-turn 2.4s linear infinite}\n.hc-ol.hc-clip{inset:0;border-radius:50%;overflow:hidden;z-index:2}\n.hc-ol .hc-band{position:absolute;top:-30%;left:0;width:45%;height:160%;background:linear-gradient(90deg,transparent,color-mix(in oklch,var(--hc-hi) 70%,transparent),transparent);transform:translateX(-130%) rotate(20deg);animation:hc-band 5s ease-in-out infinite}\n@keyframes hc-band{0%{transform:translateX(-130%) rotate(20deg)}45%,100%{transform:translateX(260%) rotate(20deg)}}\n.hc-ol.hc-glow{inset:-30%;border-radius:50%;z-index:0;background:radial-gradient(circle,var(--hc-glow) 0,transparent 65%);animation:hc-glowp 3.2s ease-in-out infinite}\n@keyframes hc-glowp{0%,100%{opacity:.35;transform:scale(.92)}50%{opacity:.9;transform:scale(1.04)}}\n.hc-ol.hc-petal{top:-8%;height:100%;width:5px;z-index:2;animation:hc-fall 3.4s linear infinite both}\n.hc-ol.hc-petal::after{content:\"\";position:absolute;left:0;top:0;width:5px;height:7px;border-radius:5px 0;background:#f7b6c8;transform:rotate(35deg)}\n@keyframes hc-fall{0%{transform:translate(0,0);opacity:0}12%{opacity:.9}100%{transform:translate(-6px,100%);opacity:0}}\n\n/* --- message reveal: fill backwards only; the page swaps back to plain text when it ends --- */\n.hc-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n.hc-msg .hc-w{display:inline-block;white-space:nowrap}\n.hc-msg .hc-ch{display:inline-block}\n.hc-mt-type .hc-ch{animation:hc-in .01s linear calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-type .hc-caret{display:inline-block;width:2px;height:1em;margin-left:2px;vertical-align:-2px;background:var(--hc-b);opacity:0;animation:hc-caret 1.5s steps(1) calc(var(--hc-i) * var(--hc-step)) backwards}\n@keyframes hc-caret{0%{opacity:0}1%{opacity:1}20%{opacity:0}40%{opacity:1}60%{opacity:0}80%{opacity:1}100%{opacity:0}}\n.hc-mt-cascade .hc-ch{animation:hc-drop .35s cubic-bezier(.3,1.5,.5,1) calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-decode .hc-ch{position:relative}\n.hc-mt-decode .hc-ch .hc-r{display:inline-block;animation:hc-in .01s linear calc(var(--hc-i) * var(--hc-step) + 260ms) backwards}\n.hc-mt-decode .hc-ch::before,.hc-mt-decode .hc-ch::after{position:absolute;left:0;top:0;color:var(--hc-b);opacity:0;animation:hc-dec-a .26s steps(1) calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-decode .hc-ch::before{content:attr(data-g)}\n.hc-mt-decode .hc-ch::after{content:attr(data-h);animation-name:hc-dec-b}\n@keyframes hc-dec-a{0%{opacity:.85}50%,100%{opacity:0}}\n@keyframes hc-dec-b{0%{opacity:0}50%{opacity:.85}100%{opacity:0}}\n.hc-mt-words .hc-w{animation:hc-rise .4s ease-out calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-bubble .hc-w{animation:hc-pop .35s cubic-bezier(.3,1.6,.5,1) calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-drift .hc-w{animation:hc-slide .45s cubic-bezier(.2,.8,.2,1) calc(var(--hc-i) * var(--hc-step)) backwards}\n@keyframes hc-in{from{opacity:0}to{opacity:1}}\n@keyframes hc-drop{0%{transform:translateY(-10px);opacity:0}100%{transform:none;opacity:1}}\n@keyframes hc-rise{0%{transform:translateY(10px);opacity:0}100%{transform:none;opacity:1}}\n@keyframes hc-pop{0%{transform:scale(.6);opacity:0}100%{transform:scale(1);opacity:1}}\n@keyframes hc-slide{0%{transform:translateX(-18px);opacity:0}100%{transform:none;opacity:1}}\n\n.hc-idle .hc-name,.hc-idle .hc-name *,.hc-idle .hc-av *,.hc-idle .hc-av *::after{animation-play-state:paused!important}\n@media (prefers-reduced-motion:reduce){.hc-name *,.hc-av *,.hc-av *::after,.hc-msg *,.hc-msg *::before,.hc-msg *::after{animation:none!important}}\n`;\n}\nfunction ensureCosmeticsStyles(doc = document, assetBase = COSMETICS_ASSET_BASE) {\n if (doc.getElementById(STYLE_ID)) return;\n const style = doc.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = cosmeticsCss(assetBase);\n doc.head.appendChild(style);\n doc.addEventListener(\"animationend\", finishReveal);\n}\nexport {\n COSMETICS,\n COSMETICS_ASSET_BASE,\n COSMETICS_BY_ID,\n COSMETIC_ID_PATTERN,\n COSMETIC_SLOTS,\n PLACEMENT_DEFAULT,\n PLACEMENT_LIMITS,\n PLACEMENT_ZONE,\n avatarHtml,\n cleanLoadout,\n colourStyle,\n cosmeticsCss,\n decorHtml,\n emptyLoadout,\n ensureCosmeticsStyles,\n fitPlacement,\n messageHtml,\n nameHtml,\n overlayBounds,\n placementTransform,\n wornCosmetics\n};\n"],"names":[],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"cosmetics.js","sources":["../../../../../node_modules/.pnpm/@wolffm+prefs-client@1.1.13_react@19.2.8_zod@4.6.7/node_modules/@wolffm/prefs-client/dist/cosmetics.js"],"sourcesContent":["// src/cosmetics-contract.ts\nvar COSMETIC_SLOTS = [\"effect\", \"gradient\", \"font\", \"overlay\", \"message\"];\nvar COSMETIC_ID_PATTERN = /^(effect|gradient|font|overlay|message)\\.[a-z0-9-]{1,32}$/;\nvar item = (slot, name, label, earn, art) => ({ id: `${slot}.${name}`, slot, label, earn, ...art ? { art } : {} });\nvar COSMETICS = [\n item(\"effect\", \"glint\", \"Glint\", \"Win a cardtable match\"),\n item(\"effect\", \"aura\", \"Aura\", \"Attend 10 watchparties\"),\n item(\"effect\", \"hop\", \"Hop\", \"Win 25 bomberman rounds\"),\n item(\"effect\", \"outline\", \"Outline\", \"Finish 3 tournaments\"),\n item(\"effect\", \"twinkle\", \"Twinkle\", \"Top four in a Major\"),\n item(\"gradient\", \"gild\", \"Gilded\", \"Your first win in any game\"),\n item(\"gradient\", \"gloss\", \"Gloss\", \"Win 10 games\"),\n item(\"gradient\", \"split\", \"Split\", \"Finish 5 tournaments\"),\n item(\"gradient\", \"brushed\", \"Brushed\", \"Play 100 games\"),\n item(\"gradient\", \"lumen\", \"Lumen\", \"Host 5 watchparties\"),\n item(\"font\", \"caps\", \"Small caps\", \"Finish a tournament\"),\n item(\"font\", \"wide\", \"Wide\", \"Finish 5 tournaments\"),\n item(\"font\", \"script\", \"Script\", \"Attend 25 watchparties\"),\n item(\"font\", \"surf\", \"Surf\", \"Attend a summer watchparty\"),\n item(\"font\", \"gothic\", \"Gothic\", \"Win an arcane-set game\"),\n item(\"font\", \"runic\", \"Runic\", \"Win a fantasy-set game\"),\n item(\"font\", \"corsair\", \"Corsair\", \"Win 3 matches in one night\"),\n item(\"font\", \"metal\", \"Metal\", \"Win a Major final\"),\n item(\"font\", \"comic\", \"Comic\", \"Win from behind\"),\n item(\"font\", \"circuit\", \"Circuit\", \"Play 25 cyber-set games\"),\n item(\"font\", \"hover\", \"Hover\", \"Win a race\"),\n item(\"font\", \"retro\", \"Retro\", \"Play for a year\"),\n item(\"font\", \"arcade\", \"Arcade\", \"Play 50 bomberman games\"),\n item(\"font\", \"pixel\", \"Pixel\", \"Win 10 bomberman rounds\"),\n item(\"overlay\", \"crown\", \"Crown\", \"Win a Major\", {\n file: \"crown.webp\",\n top: -40,\n width: 70,\n tilt: -8,\n pixel: false,\n visible: [0.027, 0.137, 0.973, 0.863]\n }),\n item(\"overlay\", \"halo\", \"Halo\", \"Help a new player (gift)\", {\n file: \"halo.webp\",\n top: -34,\n width: 76,\n tilt: 0,\n pixel: true,\n visible: [0.033, 0.333, 0.967, 0.667]\n }),\n item(\"overlay\", \"horns\", \"Horns\", \"Win 10 games as the villain\", {\n file: \"horns.webp\",\n top: -26,\n width: 100,\n tilt: 0,\n pixel: true,\n visible: [0.033, 0.133, 0.967, 0.867]\n }),\n item(\"overlay\", \"flowers\", \"Flower crown\", \"The anniversary of joining\", {\n file: \"flowers.webp\",\n top: -22,\n width: 96,\n tilt: 0,\n pixel: false,\n visible: [0.027, 0.258, 0.969, 0.746]\n }),\n item(\"overlay\", \"runes\", \"Runes\", \"Finish a Major\"),\n item(\"overlay\", \"comet\", \"Comet\", \"A 10-game win streak\"),\n item(\"overlay\", \"shine\", \"Shine\", \"Win a cardtable match\"),\n item(\"overlay\", \"glow\", \"Glow\", \"Attend 25 watchparties\"),\n item(\"overlay\", \"petals\", \"Petals\", \"The anniversary of joining\"),\n item(\"message\", \"type\", \"Typewriter\", \"Send 1000 chat messages\"),\n item(\"message\", \"decode\", \"Decode\", \"Win 25 cyber-set games\"),\n item(\"message\", \"cascade\", \"Cascade\", \"Win 3 games in a row\"),\n item(\"message\", \"words\", \"Word by word\", \"Send 100 chat messages\"),\n item(\"message\", \"bubble\", \"Bubble\", \"Host 3 watchparties\"),\n item(\"message\", \"drift\", \"Drift\", \"Attend 20 watchparties\")\n];\nvar COSMETICS_BY_ID = new Map(\n COSMETICS.map((i) => [i.id, i])\n);\nvar PLACEMENT_DEFAULT = { x: 0, y: 0, r: 0, s: 100, flip: false, back: false };\nvar PLACEMENT_LIMITS = {\n x: [-60, 60],\n y: [-60, 100],\n r: [-45, 45],\n s: [70, 140]\n};\nfunction overlayBounds(art, p) {\n const [a, b, c, d] = art.visible;\n const x0 = p.flip ? 1 - c : a;\n const x1 = p.flip ? 1 - a : c;\n const L = 50 - art.width / 2;\n const T = art.top;\n const W = art.width;\n const ox = L + W * 0.5;\n const oy = T + W * 0.6;\n const cx = L + W / 2;\n const cy = T + W / 2;\n const t = art.tilt * Math.PI / 180;\n const r = p.r * Math.PI / 180;\n const sc = p.s / 100;\n const xs = [];\n const ys = [];\n for (const [fx, fy] of [\n [x0, b],\n [x1, b],\n [x0, d],\n [x1, d]\n ]) {\n const px = L + fx * W;\n const py = T + fy * W;\n const tx = cx + (px - cx) * Math.cos(t) - (py - cy) * Math.sin(t);\n const ty = cy + (px - cx) * Math.sin(t) + (py - cy) * Math.cos(t);\n const dx = (tx - ox) * sc;\n const dy = (ty - oy) * sc;\n xs.push(ox + p.x + dx * Math.cos(r) - dy * Math.sin(r));\n ys.push(oy + p.y + dx * Math.sin(r) + dy * Math.cos(r));\n }\n return {\n left: Math.min(...xs),\n top: Math.min(...ys),\n right: Math.max(...xs),\n bottom: Math.max(...ys)\n };\n}\nvar ART_ITEMS = COSMETICS.filter((i) => !!i.art);\nvar PLACEMENT_ZONE = {\n left: -25,\n top: Math.floor(Math.min(...ART_ITEMS.map((i) => overlayBounds(i.art, PLACEMENT_DEFAULT).top))),\n right: 125,\n bottom: 110\n};\nvar clamp = (v, [lo, hi]) => Math.min(hi, Math.max(lo, v));\nfunction fitPlacement(art, raw) {\n const num = (v, fallback) => typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n const p = {\n x: Math.round(clamp(num(raw.x, 0), PLACEMENT_LIMITS.x)),\n y: Math.round(clamp(num(raw.y, 0), PLACEMENT_LIMITS.y)),\n r: Math.round(clamp(num(raw.r, 0), PLACEMENT_LIMITS.r)),\n s: Math.round(clamp(num(raw.s, 100), PLACEMENT_LIMITS.s)),\n flip: raw.flip === true,\n back: raw.back === true\n };\n const z = PLACEMENT_ZONE;\n let box = overlayBounds(art, p);\n const room = Math.min(\n (z.right - z.left - 2) / (box.right - box.left),\n (z.bottom - z.top - 2) / (box.bottom - box.top)\n );\n if (room < 1) {\n p.s = Math.max(PLACEMENT_LIMITS.s[0], Math.floor(p.s * room));\n box = overlayBounds(art, p);\n }\n p.x += Math.ceil(Math.max(0, z.left - box.left)) - Math.ceil(Math.max(0, box.right - z.right));\n p.y += Math.ceil(Math.max(0, z.top - box.top)) - Math.ceil(Math.max(0, box.bottom - z.bottom));\n return p;\n}\nfunction emptyLoadout() {\n return {\n equipped: { effect: null, gradient: null, font: null, overlay: null, message: null },\n placement: {}\n };\n}\nfunction cleanLoadout(raw, owned) {\n const out = emptyLoadout();\n const src = raw && typeof raw === \"object\" ? raw : {};\n for (const slot of COSMETIC_SLOTS) {\n const id = src.equipped?.[slot];\n if (typeof id === \"string\" && owned.has(id) && COSMETICS_BY_ID.get(id)?.slot === slot) {\n out.equipped[slot] = id;\n }\n }\n for (const [id, p] of Object.entries(src.placement ?? {})) {\n const art = COSMETICS_BY_ID.get(id)?.art;\n if (art && owned.has(id) && p && typeof p === \"object\") {\n out.placement[id] = fitPlacement(art, p);\n }\n }\n return out;\n}\nfunction wornCosmetics(loadout) {\n const worn = {};\n for (const slot of COSMETIC_SLOTS) {\n const id = loadout.equipped[slot];\n if (id) worn[slot] = id;\n }\n const overlay = loadout.equipped.overlay;\n if (overlay && COSMETICS_BY_ID.get(overlay)?.art && loadout.placement[overlay]) {\n worn.placement = loadout.placement[overlay];\n }\n return Object.keys(worn).length ? worn : void 0;\n}\n\n// src/cosmetics.ts\nvar COSMETICS_ASSET_BASE = \"/cosmetics\";\nvar STYLE_ID = \"hadoku-cosmetics\";\nvar esc = (s) => s.replace(\n /[&<>\"']/g,\n (c) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" })[c]\n);\nvar nameOf = (id) => id ? id.slice(id.indexOf(\".\") + 1) : \"none\";\nfunction colourStyle(hex) {\n return hex && /^#[0-9a-f]{6}$/i.test(hex) ? `--hc-base:${hex}` : \"\";\n}\nfunction placementTransform(p) {\n const sx = p.s / 100 * (p.flip ? -1 : 1);\n return `translate(calc(var(--hc-sz) * ${(p.x / 100).toFixed(3)}),calc(var(--hc-sz) * ${(p.y / 100).toFixed(3)})) rotate(${p.r}deg) scale(${sx.toFixed(3)},${(p.s / 100).toFixed(3)})`;\n}\nvar SPLIT_EFFECTS = /* @__PURE__ */ new Set([\"hop\"]);\nfunction nameHtml(text, worn, opts = {}) {\n const fx = nameOf(worn?.effect);\n const gr = nameOf(worn?.gradient);\n const font = nameOf(worn?.font);\n const t = esc(text);\n const split = SPLIT_EFFECTS.has(fx);\n const tx = split ? `<span class=\"hc-tx\">${[...text].map(\n (c, i) => `<span class=\"hc-ch\" style=\"--hc-i:${i}\"><span class=\"hc-c\">${c === \" \" ? \"&nbsp;\" : esc(c)}</span></span>`\n ).join(\"\")}</span>` : `<span class=\"hc-tx\">${t}</span>`;\n const layer = (cls2) => `<span class=\"hc-lyr${cls2}\" aria-hidden=\"true\">${t}</span>`;\n let back = \"\";\n let front = \"\";\n if (fx === \"aura\" || fx === \"outline\") back += layer(\" hc-g\");\n if (fx === \"glint\") front += `<span class=\"hc-win\" aria-hidden=\"true\">${layer(\"\")}</span>`;\n if (fx === \"twinkle\") {\n front += [\n [-6, -25, 0],\n [52, 55, 0.95],\n [94, -15, 1.9]\n ].map(\n ([x, y, d]) => `<i class=\"hc-tw\" aria-hidden=\"true\" style=\"left:${x}%;top:${y}%;animation-delay:${d}s\"></i>`\n ).join(\"\");\n }\n const cls = `hc-name hc-fx-${fx} hc-gr-${gr} hc-font-${font}${split ? \" hc-split\" : \"\"}${opts.large ? \" hc-large\" : \"\"}`;\n return `<span class=\"${cls}\">${back}${tx}${front}</span>`;\n}\nvar RUNES_SVG = (() => {\n let marks = \"\";\n for (let i = 0; i < 12; i++) {\n marks += `<g transform=\"rotate(${i * 30} 50 50)\"><path d=\"M50 3 l2.5 4 -2.5 4 -2.5 -4z\" fill=\"currentColor\" opacity=\"${i % 3 ? 0.55 : 1}\"/></g>`;\n }\n return `<svg viewBox=\"0 0 100 100\" aria-hidden=\"true\"><circle cx=\"50\" cy=\"50\" r=\"44\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\" stroke-dasharray=\"3 5\" opacity=\".7\"/>${marks}</svg>`;\n})();\nfunction decorHtml(worn, assetBase = COSMETICS_ASSET_BASE) {\n const id = worn?.overlay;\n if (!id) return \"\";\n const art = COSMETICS_BY_ID.get(id)?.art;\n if (art) {\n const p = worn?.placement ?? PLACEMENT_DEFAULT;\n return `<span class=\"hc-ol hc-art${art.pixel ? \" hc-px\" : \"\"}\" data-hc-art=\"${esc(id)}\" style=\"left:${50 - art.width / 2}%;top:${art.top}%;width:${art.width}%;z-index:${p.back ? 0 : 3}\"><span class=\"hc-adj\" style=\"transform:${placementTransform(p)}\"><img alt=\"\" draggable=\"false\" style=\"--hc-tilt:${art.tilt}deg\" src=\"${esc(`${assetBase}/art/${art.file}`)}\"></span></span>`;\n }\n switch (nameOf(id)) {\n case \"runes\":\n return `<span class=\"hc-ol hc-runes\">${RUNES_SVG}</span>`;\n case \"comet\":\n return `<span class=\"hc-ol hc-comet\"></span>`;\n case \"shine\":\n return `<span class=\"hc-ol hc-clip\"><span class=\"hc-band\"></span></span>`;\n case \"glow\":\n return `<span class=\"hc-ol hc-glow\"></span>`;\n case \"petals\":\n return [15, 40, 62, 85].map(\n (l, i) => `<i class=\"hc-ol hc-petal\" style=\"left:${l}%;animation-delay:${(i * 0.85).toFixed(2)}s\"></i>`\n ).join(\"\");\n default:\n return \"\";\n }\n}\nfunction avatarHtml(o) {\n const pic = o.src ? `<img alt=\"\" src=\"${esc(o.src)}\">` : \"\";\n return `<span class=\"hc-av\" style=\"--hc-sz:${o.size}px\"><span class=\"hc-pic\">${pic}</span>${decorHtml(o.worn, o.assetBase)}</span>`;\n}\nvar GLYPHS = \"!<>-_/[]{}=+*^?#%&01\";\nvar LETTER_MODES = /* @__PURE__ */ new Set([\"type\", \"decode\", \"cascade\"]);\nvar REVEAL_MS = 1400;\nvar LETTER_LIMIT = 160;\nfunction messageHtml(text, worn, opts = {}) {\n let mode = nameOf(worn?.message);\n if (mode === \"none\") return `<span class=\"hc-msg\">${esc(text)}</span>`;\n const words = text.split(/\\s+/).filter(Boolean);\n if (LETTER_MODES.has(mode) && text.length > LETTER_LIMIT) mode = \"words\";\n const keep = opts.keep ? \" data-hc-keep\" : \"\";\n let body;\n let step;\n if (LETTER_MODES.has(mode)) {\n step = Math.min(38, REVEAL_MS / Math.max(1, text.length));\n let n = 0;\n const rnd = () => GLYPHS[Math.floor(Math.random() * GLYPHS.length)];\n body = words.map(\n (w) => `<span class=\"hc-w\">${[...w].map((c) => {\n const i = n++;\n return mode === \"decode\" ? `<span class=\"hc-ch\" style=\"--hc-i:${i}\" data-g=\"${esc(rnd())}\" data-h=\"${esc(rnd())}\"><span class=\"hc-r\">${esc(c)}</span></span>` : `<span class=\"hc-ch\" style=\"--hc-i:${i}\">${esc(c)}</span>`;\n }).join(\"\")}</span>`\n ).join(\" \");\n if (mode === \"type\") body += `<span class=\"hc-caret\" style=\"--hc-i:${n}\"></span>`;\n const lastClass = mode === \"type\" ? \"hc-caret\" : mode === \"decode\" ? \"hc-r\" : \"hc-ch\";\n const at = body.lastIndexOf(`<span class=\"${lastClass}\"`);\n body = `${body.slice(0, at)}<span data-hc-last class=\"${lastClass}\"${body.slice(at + `<span class=\"${lastClass}\"`.length)}`;\n } else {\n step = Math.min(90, REVEAL_MS / Math.max(1, words.length));\n body = words.map(\n (w, i) => `<span class=\"hc-w\" style=\"--hc-i:${i}\"${i === words.length - 1 ? \" data-hc-last\" : \"\"}>${esc(w)}</span>`\n ).join(\" \");\n }\n return `<span class=\"hc-msg hc-mt-${mode}\" style=\"--hc-step:${step.toFixed(1)}ms\" data-text=\"${esc(text)}\"${keep}><span class=\"hc-sr\">${esc(text)}</span><span aria-hidden=\"true\">${body}</span></span>`;\n}\nfunction finishReveal(e) {\n const t = e.target;\n if (e.pseudoElement || !t?.hasAttribute?.(\"data-hc-last\")) return;\n const msg = t.closest(\".hc-msg\");\n if (!msg || msg.hasAttribute(\"data-hc-keep\")) return;\n msg.className = \"hc-msg\";\n msg.removeAttribute(\"style\");\n msg.textContent = msg.getAttribute(\"data-text\") ?? \"\";\n}\nvar FONTS = {\n script: {\n file: \"caveat\",\n family: \"Caveat\",\n generic: \"cursive\",\n css: \"font-weight:700;font-size:1.3em;line-height:1\"\n },\n surf: {\n file: \"pacifico\",\n family: \"Pacifico\",\n generic: \"cursive\",\n css: \"font-weight:400;font-size:1.02em;line-height:1.1\"\n },\n gothic: {\n file: \"gothic\",\n family: \"Grenze Gotisch\",\n generic: \"serif\",\n css: \"font-weight:600;font-size:1.15em\"\n },\n runic: { file: \"uncial\", family: \"Uncial Antiqua\", generic: \"serif\", css: \"font-weight:400\" },\n corsair: {\n file: \"pirata\",\n family: \"Pirata One\",\n generic: \"serif\",\n css: \"font-weight:400;font-size:1.12em;letter-spacing:.02em\"\n },\n metal: {\n file: \"metal\",\n family: \"Metal Mania\",\n generic: \"cursive\",\n css: \"font-weight:400;font-size:1.12em;letter-spacing:.02em\"\n },\n comic: {\n file: \"bangers\",\n family: \"Bangers\",\n generic: \"cursive\",\n css: \"font-weight:400;font-size:1.15em;letter-spacing:.05em\"\n },\n circuit: {\n file: \"orbitron\",\n family: \"Orbitron\",\n generic: \"sans-serif\",\n css: \"font-weight:700;letter-spacing:.03em\"\n },\n hover: {\n file: \"audiowide\",\n family: \"Audiowide\",\n generic: \"sans-serif\",\n css: \"font-weight:400;font-size:.92em\"\n },\n retro: { file: \"righteous\", family: \"Righteous\", generic: \"sans-serif\", css: \"font-weight:400\" },\n arcade: {\n file: \"bungee\",\n family: \"Bungee\",\n generic: \"sans-serif\",\n css: \"font-weight:400;font-size:.9em\"\n },\n pixel: {\n file: \"pixel\",\n family: \"Press Start 2P\",\n generic: \"monospace\",\n css: \"font-weight:400;font-size:.62em;line-height:1.6\"\n }\n};\nfunction cosmeticsCss(assetBase = COSMETICS_ASSET_BASE) {\n const fontFaces = Object.entries(FONTS).map(\n ([k, f]) => `@font-face{font-family:\"hc-${k}\";src:url(\"${assetBase}/fonts/${f.file}.woff2\") format(\"woff2\");font-display:swap}`\n ).join(\"\\n\");\n const fontRules = Object.entries(FONTS).map(([k, f]) => `.hc-font-${k}{font-family:\"hc-${k}\",\"${f.family}\",${f.generic};${f.css}}`).join(\"\\n\");\n return `${fontFaces}\n/* Colours: everything derives from the character colour. */\n.hc-name,.hc-av,.hc-msg{--hc-b:var(--hc-base,currentColor);--hc-hi:color-mix(in oklch,var(--hc-b),white 50%);--hc-lo:color-mix(in oklch,var(--hc-b),black 50%);--hc-glow:color-mix(in oklch,var(--hc-b) 75%,transparent)}\n\n/* --- name ---\n Bleed: a gradient is a background clipped to the letters, and a background covers only the box; script\n swashes reach outside it. So the text box and every layer over it get room on all sides, cancelled by a\n negative margin so nothing moves. */\n.hc-name{--hc-bx:.4em;--hc-by:.3em;--hc-grad:none;position:relative;display:inline-block;white-space:nowrap;color:var(--hc-b);font-weight:700;line-height:1.25}\n.hc-name.hc-large{font-size:1.6em}\n.hc-name .hc-tx{position:relative;z-index:1;display:inline-block;padding:var(--hc-by) var(--hc-bx);margin:calc(-1 * var(--hc-by)) calc(-1 * var(--hc-bx))}\n.hc-name .hc-lyr{position:absolute;left:calc(-1 * var(--hc-bx));top:calc(-1 * var(--hc-by));padding:var(--hc-by) var(--hc-bx);pointer-events:none;white-space:nowrap}\n.hc-name .hc-win{position:absolute;inset:calc(-1 * var(--hc-by)) calc(-1 * var(--hc-bx));overflow:hidden}\n.hc-name .hc-win .hc-lyr{left:0;top:0}\n.hc-name .hc-ch,.hc-name .hc-c{display:inline-block}\n.hc-gr-gild{--hc-grad:linear-gradient(180deg,var(--hc-hi) 0%,var(--hc-b) 55%,var(--hc-lo) 100%)}\n.hc-gr-gloss{--hc-grad:linear-gradient(180deg,color-mix(in oklch,var(--hc-hi),white 35%) 0%,var(--hc-hi) 36%,color-mix(in oklch,var(--hc-hi),var(--hc-b)) 48%,var(--hc-b) 60%,var(--hc-lo) 100%)}\n.hc-gr-split{--hc-grad:linear-gradient(180deg,var(--hc-hi) 0 52%,var(--hc-b) 52% 100%)}\n.hc-gr-brushed{--hc-grad:repeating-linear-gradient(90deg,transparent 0 1px,color-mix(in oklch,var(--hc-hi) 40%,transparent) 1px 2px),linear-gradient(180deg,var(--hc-hi),var(--hc-b) 55%,var(--hc-lo))}\n.hc-gr-lumen{--hc-grad:radial-gradient(ellipse 60% 90% at 50% 35%,var(--hc-hi),var(--hc-b) 55%,var(--hc-lo) 100%)}\n.hc-name:not(.hc-gr-none) .hc-tx{background:var(--hc-grad);-webkit-background-clip:text;background-clip:text;color:transparent}\n.hc-name.hc-split:not(.hc-gr-none) .hc-tx{background:none}\n.hc-name.hc-split:not(.hc-gr-none) .hc-tx .hc-c{padding:var(--hc-by) var(--hc-bx);margin:calc(-1 * var(--hc-by)) calc(-1 * var(--hc-bx));background:var(--hc-grad);-webkit-background-clip:text;background-clip:text;color:transparent}\n.hc-fx-glint .hc-win{z-index:3;animation:hc-win-go 4.5s cubic-bezier(.4,0,.2,1) infinite;-webkit-mask-image:linear-gradient(100deg,transparent 35%,#000 50%,transparent 65%);mask-image:linear-gradient(100deg,transparent 35%,#000 50%,transparent 65%)}\n.hc-fx-glint .hc-win .hc-lyr{color:var(--hc-hi);animation:hc-win-back 4.5s cubic-bezier(.4,0,.2,1) infinite}\n@keyframes hc-win-go{0%{transform:translateX(-100%)}55%,100%{transform:translateX(100%)}}\n@keyframes hc-win-back{0%{transform:translateX(100%)}55%,100%{transform:translateX(-100%)}}\n.hc-fx-aura .hc-lyr.hc-g{color:transparent;text-shadow:0 0 6px var(--hc-glow),0 0 14px var(--hc-glow);animation:hc-breathe 3s ease-in-out infinite}\n.hc-fx-outline .hc-lyr.hc-g{color:transparent;-webkit-text-stroke:3px var(--hc-hi);animation:hc-breathe 3.6s ease-in-out infinite}\n@keyframes hc-breathe{0%,100%{opacity:.25}50%{opacity:1}}\n.hc-fx-hop .hc-c{animation:hc-hop 3.6s ease-in-out calc(var(--hc-i) * 45ms) infinite}\n@keyframes hc-hop{0%,14%,100%{transform:none}5%{transform:translateY(-4px)}10%{transform:translateY(.5px)}}\n.hc-fx-twinkle .hc-tw{position:absolute;width:7px;height:7px;z-index:3;pointer-events:none;background:linear-gradient(var(--hc-hi),var(--hc-hi)) center/1.4px 100% no-repeat,linear-gradient(90deg,var(--hc-hi),var(--hc-hi)) center/100% 1.4px no-repeat;animation:hc-star 2.8s ease-in-out infinite both}\n@keyframes hc-star{0%,100%{opacity:0;transform:scale(.3) rotate(0deg)}25%{opacity:1;transform:scale(1) rotate(45deg)}50%{opacity:0;transform:scale(.3) rotate(90deg)}}\n.hc-font-caps{font-variant:small-caps;letter-spacing:.08em}\n.hc-font-wide{letter-spacing:.22em;font-weight:600;text-transform:uppercase;font-size:.82em}\n${fontRules}\n\n/* --- avatar --- */\n.hc-av{--hc-sz:40px;position:relative;display:inline-block;width:var(--hc-sz);height:var(--hc-sz);flex:none;isolation:isolate;vertical-align:middle}\n.hc-av .hc-pic{position:absolute;inset:0;border-radius:50%;overflow:hidden;z-index:1;background:color-mix(in oklch,var(--hc-b) 30%,transparent)}\n.hc-av .hc-pic img{width:100%;height:100%;display:block;object-fit:cover;image-rendering:pixelated}\n.hc-av .hc-ol{position:absolute;pointer-events:none}\n.hc-ol.hc-art{display:block}\n.hc-ol.hc-art .hc-adj{display:block;position:relative;transform-origin:50% 60%}\n.hc-ol.hc-art img{display:block;width:100%;height:auto;filter:drop-shadow(0 1px 1px rgba(0,0,0,.45));animation:hc-art-bob 3.4s ease-in-out infinite;-webkit-user-drag:none;user-select:none}\n.hc-ol.hc-art.hc-px img{image-rendering:pixelated}\n@keyframes hc-art-bob{0%,100%{transform:rotate(var(--hc-tilt,0deg)) translateY(0)}50%{transform:rotate(var(--hc-tilt,0deg)) translateY(-2px)}}\n.hc-ol.hc-runes{inset:-9px;z-index:2;color:var(--hc-hi);animation:hc-turn 14s linear infinite}\n.hc-ol.hc-runes svg{width:100%;height:100%;display:block}\n@keyframes hc-turn{to{transform:rotate(360deg)}}\n.hc-ol.hc-comet{inset:-6px;z-index:2;border-radius:50%;background:conic-gradient(from 0deg,transparent 0 270deg,color-mix(in oklch,var(--hc-hi) 10%,transparent) 300deg,var(--hc-hi) 358deg,transparent 360deg);-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 3px));mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 3px));animation:hc-turn 2.4s linear infinite}\n.hc-ol.hc-clip{inset:0;border-radius:50%;overflow:hidden;z-index:2}\n.hc-ol .hc-band{position:absolute;top:-30%;left:0;width:45%;height:160%;background:linear-gradient(90deg,transparent,color-mix(in oklch,var(--hc-hi) 70%,transparent),transparent);transform:translateX(-130%) rotate(20deg);animation:hc-band 5s ease-in-out infinite}\n@keyframes hc-band{0%{transform:translateX(-130%) rotate(20deg)}45%,100%{transform:translateX(260%) rotate(20deg)}}\n.hc-ol.hc-glow{inset:-30%;border-radius:50%;z-index:0;background:radial-gradient(circle,var(--hc-glow) 0,transparent 65%);animation:hc-glowp 3.2s ease-in-out infinite}\n@keyframes hc-glowp{0%,100%{opacity:.35;transform:scale(.92)}50%{opacity:.9;transform:scale(1.04)}}\n.hc-ol.hc-petal{top:-8%;height:100%;width:5px;z-index:2;animation:hc-fall 3.4s linear infinite both}\n.hc-ol.hc-petal::after{content:\"\";position:absolute;left:0;top:0;width:5px;height:7px;border-radius:5px 0;background:#f7b6c8;transform:rotate(35deg)}\n@keyframes hc-fall{0%{transform:translate(0,0);opacity:0}12%{opacity:.9}100%{transform:translate(-6px,100%);opacity:0}}\n\n/* --- message reveal: fill backwards only; the page swaps back to plain text when it ends --- */\n.hc-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n.hc-msg .hc-w{display:inline-block;white-space:nowrap}\n.hc-msg .hc-ch{display:inline-block}\n.hc-mt-type .hc-ch{animation:hc-in .01s linear calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-type .hc-caret{display:inline-block;width:2px;height:1em;margin-left:2px;vertical-align:-2px;background:var(--hc-b);opacity:0;animation:hc-caret 1.5s steps(1) calc(var(--hc-i) * var(--hc-step)) backwards}\n@keyframes hc-caret{0%{opacity:0}1%{opacity:1}20%{opacity:0}40%{opacity:1}60%{opacity:0}80%{opacity:1}100%{opacity:0}}\n.hc-mt-cascade .hc-ch{animation:hc-drop .35s cubic-bezier(.3,1.5,.5,1) calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-decode .hc-ch{position:relative}\n.hc-mt-decode .hc-ch .hc-r{display:inline-block;animation:hc-in .01s linear calc(var(--hc-i) * var(--hc-step) + 260ms) backwards}\n.hc-mt-decode .hc-ch::before,.hc-mt-decode .hc-ch::after{position:absolute;left:0;top:0;color:var(--hc-b);opacity:0;animation:hc-dec-a .26s steps(1) calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-decode .hc-ch::before{content:attr(data-g)}\n.hc-mt-decode .hc-ch::after{content:attr(data-h);animation-name:hc-dec-b}\n@keyframes hc-dec-a{0%{opacity:.85}50%,100%{opacity:0}}\n@keyframes hc-dec-b{0%{opacity:0}50%{opacity:.85}100%{opacity:0}}\n.hc-mt-words .hc-w{animation:hc-rise .4s ease-out calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-bubble .hc-w{animation:hc-pop .35s cubic-bezier(.3,1.6,.5,1) calc(var(--hc-i) * var(--hc-step)) backwards}\n.hc-mt-drift .hc-w{animation:hc-slide .45s cubic-bezier(.2,.8,.2,1) calc(var(--hc-i) * var(--hc-step)) backwards}\n@keyframes hc-in{from{opacity:0}to{opacity:1}}\n@keyframes hc-drop{0%{transform:translateY(-10px);opacity:0}100%{transform:none;opacity:1}}\n@keyframes hc-rise{0%{transform:translateY(10px);opacity:0}100%{transform:none;opacity:1}}\n@keyframes hc-pop{0%{transform:scale(.6);opacity:0}100%{transform:scale(1);opacity:1}}\n@keyframes hc-slide{0%{transform:translateX(-18px);opacity:0}100%{transform:none;opacity:1}}\n\n.hc-idle .hc-name,.hc-idle .hc-name *,.hc-idle .hc-av *,.hc-idle .hc-av *::after{animation-play-state:paused!important}\n@media (prefers-reduced-motion:reduce){.hc-name *,.hc-av *,.hc-av *::after,.hc-msg *,.hc-msg *::before,.hc-msg *::after{animation:none!important}}\n`;\n}\nfunction ensureCosmeticsStyles(doc = document, assetBase = COSMETICS_ASSET_BASE) {\n if (doc.getElementById(STYLE_ID)) return;\n const style = doc.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = cosmeticsCss(assetBase);\n doc.head.appendChild(style);\n doc.addEventListener(\"animationend\", finishReveal);\n}\nexport {\n COSMETICS,\n COSMETICS_ASSET_BASE,\n COSMETICS_BY_ID,\n COSMETIC_ID_PATTERN,\n COSMETIC_SLOTS,\n PLACEMENT_DEFAULT,\n PLACEMENT_LIMITS,\n PLACEMENT_ZONE,\n avatarHtml,\n cleanLoadout,\n colourStyle,\n cosmeticsCss,\n decorHtml,\n emptyLoadout,\n ensureCosmeticsStyles,\n fitPlacement,\n messageHtml,\n nameHtml,\n overlayBounds,\n placementTransform,\n wornCosmetics\n};\n"],"names":[],"mappings":"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","x_google_ignoreList":[0]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hadoku/task-ui-components",
3
- "version": "4.23.6",
4
- "gitHead": "459534e129227eafa31bb3e2dca277dc332b215c",
3
+ "version": "4.23.8",
4
+ "gitHead": "4c02672374fac2fd4499c073331908b7751d6a14",
5
5
  "description": "Reusable UI components with Bento grid and metallic gradient support",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -158,6 +158,8 @@ const S = {
158
158
  tabs: {
159
159
  display: 'flex',
160
160
  gap: 2,
161
+ cursor: 'grab',
162
+ touchAction: 'pan-x',
161
163
  borderBottom: '1px solid var(--color-border)',
162
164
  overflowX: 'auto',
163
165
  scrollbarWidth: 'none'
@@ -280,6 +282,68 @@ function withLoadout(s: AvatarSettings, loadout: Loadout): AvatarSettings {
280
282
  }
281
283
  }
282
284
 
285
+ /**
286
+ * A row that overflows sideways scrolls by dragging it (the operator's ask: the
287
+ * tab strip is wider than its column and hides its scrollbar) and by the
288
+ * mouse wheel. A drag of more than a few pixels is not a click.
289
+ */
290
+ function useDragScroll<T extends HTMLElement>() {
291
+ // A callback ref, not useRef: the row appears only once the settings load,
292
+ // after the first render, and the listeners must attach when it does.
293
+ const [el, setEl] = useState<T | null>(null)
294
+ useEffect(() => {
295
+ if (!el) return
296
+ let start: { x: number; left: number } | null = null
297
+ let dragged = false
298
+ const down = (e: PointerEvent) => {
299
+ if (e.button !== 0) return
300
+ start = { x: e.clientX, left: el.scrollLeft }
301
+ dragged = false
302
+ }
303
+ const move = (e: PointerEvent) => {
304
+ if (!start) return
305
+ const dx = e.clientX - start.x
306
+ if (!dragged && Math.abs(dx) > 4) {
307
+ dragged = true
308
+ el.setPointerCapture(e.pointerId)
309
+ el.style.cursor = 'grabbing'
310
+ }
311
+ if (dragged) el.scrollLeft = start.left - dx
312
+ }
313
+ const up = () => {
314
+ start = null
315
+ el.style.cursor = ''
316
+ }
317
+ // The click that ends a drag is not a tab choice.
318
+ const click = (e: MouseEvent) => {
319
+ if (!dragged) return
320
+ e.preventDefault()
321
+ e.stopPropagation()
322
+ dragged = false
323
+ }
324
+ const wheel = (e: globalThis.WheelEvent) => {
325
+ if (el.scrollWidth <= el.clientWidth || Math.abs(e.deltaX) > Math.abs(e.deltaY)) return
326
+ e.preventDefault()
327
+ el.scrollLeft += e.deltaY
328
+ }
329
+ el.addEventListener('pointerdown', down)
330
+ el.addEventListener('pointermove', move)
331
+ el.addEventListener('pointerup', up)
332
+ el.addEventListener('pointercancel', up)
333
+ el.addEventListener('click', click, true)
334
+ el.addEventListener('wheel', wheel, { passive: false })
335
+ return () => {
336
+ el.removeEventListener('pointerdown', down)
337
+ el.removeEventListener('pointermove', move)
338
+ el.removeEventListener('pointerup', up)
339
+ el.removeEventListener('pointercancel', up)
340
+ el.removeEventListener('click', click, true)
341
+ el.removeEventListener('wheel', wheel)
342
+ }
343
+ }, [el])
344
+ return setEl
345
+ }
346
+
283
347
  export interface AvatarBuilderProps {
284
348
  /** The person's display name, for the preview. */
285
349
  name: string | null
@@ -296,6 +360,7 @@ export function AvatarBuilder({ name }: AvatarBuilderProps) {
296
360
  const [replay, setReplay] = useState(0)
297
361
  const narrow = useNarrow()
298
362
  const root = useRef<HTMLDivElement>(null)
363
+ const tabStrip = useDragScroll<HTMLDivElement>()
299
364
  // Only the newest cosmetics request may set state: equips sent quickly in a
300
365
  // row can answer out of order.
301
366
  const seq = useRef(0)
@@ -550,7 +615,7 @@ export function AvatarBuilder({ name }: AvatarBuilderProps) {
550
615
  {placement}
551
616
  </div>
552
617
  <div style={{ minWidth: 0 }}>
553
- <div style={S.tabs} role="tablist" aria-label="Avatar">
618
+ <div ref={tabStrip} style={S.tabs} role="tablist" aria-label="Avatar">
554
619
  {tabs.map(t => {
555
620
  const items = t === 'picture' ? [] : COSMETICS.filter(i => i.slot === t)
556
621
  return (
@@ -560,9 +625,10 @@ export function AvatarBuilder({ name }: AvatarBuilderProps) {
560
625
  role="tab"
561
626
  aria-selected={tab === t}
562
627
  style={{ ...S.tab, ...(tab === t ? S.tabOn : {}) }}
563
- onClick={() => {
628
+ onClick={e => {
564
629
  setTab(t)
565
630
  setTryOn(null)
631
+ e.currentTarget.scrollIntoView({ block: 'nearest', inline: 'nearest' })
566
632
  }}
567
633
  >
568
634
  {tabLabel(t)}
@@ -7,29 +7,19 @@
7
7
  * protocol cannot drift from the callback page).
8
8
  *
9
9
  * Everything happens in place: picking, uploading and removing are requests
10
- * from here, and linking Discord or Steam signs in through a popup
11
- * (`linkInPopup`), so the page under the popout never navigates and a game
12
- * keeps running.
10
+ * from here. Linking Discord or Steam lives in the popout's Account tab
11
+ * (LinkedAccounts); a linked account's picture is a choice here.
13
12
  *
14
13
  * AvatarBuilder owns the settings and the character table and loads them only
15
14
  * when the dialog opens; this component draws them and sends changes through
16
15
  * `run`, which applies the answer everywhere in the dialog.
17
16
  *
18
- * COMPLIANCE (Steam Web API terms; Discord developer terms), carried over from
19
- * hadoku.me/account: nothing is fetched from a provider until the person reads
20
- * what is read and kept and presses Continue; Steam attribution and a privacy
21
- * link sit under the controls; no provider logos, and no implied endorsement.
22
- *
23
17
  * Styles are inline for the reason PASSKEY_DOT's are (ConnectedSettings.tsx):
24
18
  * apps compile app-header.css at their own build, so a new rule there reaches
25
19
  * an app only when it rebuilds.
26
20
  */
27
21
  import React, { useEffect, useState } from 'react'
28
- import {
29
- type AvatarSettings,
30
- type AvatarSource,
31
- type LinkProvider
32
- } from '@wolffm/prefs-client/avatar'
22
+ import { type AvatarSettings, type AvatarSource } from '@wolffm/prefs-client/avatar'
33
23
  import { avatarClient, portraitUrl, type CharacterSet } from '../lib/avatarData'
34
24
 
35
25
  const LABEL: Record<AvatarSource, string> = {
@@ -39,27 +29,6 @@ const LABEL: Record<AvatarSource, string> = {
39
29
  upload: 'Upload'
40
30
  }
41
31
 
42
- const CONSENT: Record<LinkProvider, { points: string[]; go: string }> = {
43
- discord: {
44
- points: [
45
- 'Discord asks you to share your basic profile ("identify").',
46
- 'Kept: your Discord user ID and the address of your profile picture, refreshed while linked.',
47
- 'Not kept: your username, email, servers or any token.',
48
- 'Unlink deletes both.'
49
- ],
50
- go: 'Continue to Discord'
51
- },
52
- steam: {
53
- points: [
54
- 'You sign in on steamcommunity.com; your password never reaches hadoku.me.',
55
- 'Your public Steam profile picture is then read through the Steam Web API, now and periodically while linked.',
56
- 'Kept: your Steam ID and the address of that picture.',
57
- 'Unlink deletes both and stops the reads.'
58
- ],
59
- go: 'Continue to Steam'
60
- }
61
- }
62
-
63
32
  const S = {
64
33
  stack: { display: 'flex', flexDirection: 'column', gap: 10, width: '100%' },
65
34
  img: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' },
@@ -100,8 +69,7 @@ const S = {
100
69
  cursor: 'pointer'
101
70
  },
102
71
  line: { display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' },
103
- grow: { flex: 1, minWidth: 0 },
104
- list: { margin: 0, paddingLeft: 18, fontSize: '0.75rem', lineHeight: 1.45 }
72
+ grow: { flex: 1, minWidth: 0 }
105
73
  } satisfies Record<string, React.CSSProperties>
106
74
 
107
75
  function Picture({ src, style }: { src: string | null; style: React.CSSProperties }) {
@@ -132,7 +100,6 @@ export interface AvatarPickerProps {
132
100
 
133
101
  export function AvatarPicker({ settings, sets, busy, run }: AvatarPickerProps) {
134
102
  const [setIdx, setSetIdx] = useState(0)
135
- const [consent, setConsent] = useState<LinkProvider | null>(null)
136
103
  // Open on the set holding the person's character.
137
104
  useEffect(() => {
138
105
  const at = sets?.findIndex(s => s.characters.some(c => c.id === settings.sprite)) ?? -1
@@ -162,17 +129,6 @@ export function AvatarPicker({ settings, sets, busy, run }: AvatarPickerProps) {
162
129
  const shown = settings.avatar
163
130
  const current = sets?.[setIdx]
164
131
 
165
- // Must stay synchronous up to linkInPopup: the popup opens before its first
166
- // await, inside this click, which is what popup blockers allow.
167
- const link = (provider: LinkProvider) => {
168
- setConsent(null)
169
- run(async () => {
170
- const next = await avatarClient.linkInPopup(provider)
171
- // Linking is choosing, when the account came back with a picture.
172
- return next.linked[provider]?.avatarUrl ? avatarClient.choose(provider) : next
173
- }).catch(reportErr)
174
- }
175
-
176
132
  return (
177
133
  <div style={S.stack}>
178
134
  {settings.choice && settings.choice !== shown.source && (
@@ -189,7 +145,13 @@ export function AvatarPicker({ settings, sets, busy, run }: AvatarPickerProps) {
189
145
  role="radio"
190
146
  aria-checked={shown.source === src}
191
147
  disabled={busy || !available[src]}
192
- title={available[src] ? undefined : 'Link or upload one first'}
148
+ title={
149
+ available[src]
150
+ ? undefined
151
+ : src === 'upload'
152
+ ? 'Upload a picture below first'
153
+ : `Link ${LABEL[src]} under Settings › Account first`
154
+ }
193
155
  style={{
194
156
  ...S.source,
195
157
  ...(shown.source === src ? S.sourceOn : {}),
@@ -249,69 +211,6 @@ export function AvatarPicker({ settings, sets, busy, run }: AvatarPickerProps) {
249
211
  <span className="settings-popout__hint">…</span>
250
212
  ))}
251
213
 
252
- {(['discord', 'steam'] as const).map(p => {
253
- const linked = settings.linked[p]
254
- return (
255
- <div key={p} style={S.line}>
256
- <span className="settings-popout__label" style={S.grow}>
257
- {LABEL[p]}
258
- {!settings.providers[p]
259
- ? ' · not available yet'
260
- : linked
261
- ? linked.avatarUrl
262
- ? ' · linked'
263
- : ' · linked, no picture'
264
- : ''}
265
- </span>
266
- {settings.providers[p] && !linked && (
267
- <button
268
- type="button"
269
- className="settings-popout__btn"
270
- disabled={busy}
271
- onClick={() => setConsent(consent === p ? null : p)}
272
- >
273
- Link
274
- </button>
275
- )}
276
- {linked && (
277
- <button
278
- type="button"
279
- className="settings-popout__btn"
280
- disabled={busy}
281
- onClick={() => {
282
- run(() => avatarClient.unlink(p)).catch(reportErr)
283
- }}
284
- >
285
- Unlink
286
- </button>
287
- )}
288
- </div>
289
- )
290
- })}
291
-
292
- {consent && (
293
- <div style={S.stack}>
294
- <ul style={S.list}>
295
- {CONSENT[consent].points.map(t => (
296
- <li key={t}>{t}</li>
297
- ))}
298
- </ul>
299
- <span style={S.line}>
300
- <button
301
- type="button"
302
- className="settings-popout__btn settings-popout__btn--primary"
303
- disabled={busy}
304
- onClick={() => link(consent)}
305
- >
306
- {CONSENT[consent].go}
307
- </button>
308
- <button type="button" className="settings-popout__btn" onClick={() => setConsent(null)}>
309
- Cancel
310
- </button>
311
- </span>
312
- </div>
313
- )}
314
-
315
214
  <div style={S.line}>
316
215
  <span className="settings-popout__label" style={S.grow}>
317
216
  Upload
@@ -33,6 +33,7 @@ import React, { useCallback, useEffect, useId, useRef, useState } from 'react'
33
33
  import { useSettingsTab } from '@wolffm/themes'
34
34
  import { SettingsIcon } from './ThemeIcons'
35
35
  import { AvatarDialog } from './AvatarDialog'
36
+ import { LinkedAccounts } from './LinkedAccounts'
36
37
 
37
38
  // A grantee's own service credentials, with a QR encoder for TOTP enrolment:
38
39
  // its own chunk, fetched only when a grantee opens it.
@@ -267,6 +268,8 @@ export function ConnectedSettings({
267
268
 
268
269
  // Avatar: the dialog's picker loads only when opened, never at mount (AvatarPicker).
269
270
  const [avatarOpen, setAvatarOpen] = useState(false)
271
+ // Linked accounts: loaded only when the row is opened (LinkedAccounts).
272
+ const [linksOpen, setLinksOpen] = useState(false)
270
273
  const avatarBtn = useRef<HTMLButtonElement>(null)
271
274
  // Service identities this person may mint for (whoami.serviceGrants).
272
275
  const [serviceGrants, setServiceGrants] = useState(0)
@@ -952,6 +955,28 @@ export function ConnectedSettings({
952
955
  </section>
953
956
  )}
954
957
 
958
+ {/* Discord and Steam: linked here, so their pictures can be chosen in
959
+ the avatar dialog. Collapsed until Open: the read can refresh a
960
+ linked picture, which opening the gear must not cost. */}
961
+ {!resolving && userType !== 'public' && (
962
+ <section className="settings-popout__row settings-popout__row--stack">
963
+ <span className="settings-popout__inline">
964
+ <span className="settings-popout__label settings-popout__label--grow">
965
+ Linked accounts
966
+ </span>
967
+ <button
968
+ type="button"
969
+ className="settings-popout__btn"
970
+ aria-expanded={linksOpen}
971
+ onClick={() => setLinksOpen(v => !v)}
972
+ >
973
+ {linksOpen ? 'Done' : 'Open'}
974
+ </button>
975
+ </span>
976
+ {linksOpen && <LinkedAccounts />}
977
+ </section>
978
+ )}
979
+
955
980
  {/* A self-made account (member) can delete itself. The confirm is a
956
981
  separate button on its own line, so a double click on Delete
957
982
  never confirms. */}