Back to Black Site
SOURCE / PINNED RELEASE

Made of little things.

Black Site

Release
666bc7c74ebd…
Author-recorded commit
05e95af79676…
License
LICENSE
Author’s source reference
nostr://npub12lm3rxsva8kfempyjkxupt09e02n3fezurkyadyqfejdc5e0r2kscqty6r/wss%3A%2F%2Fgit.napplet.soy%2F/n-d2225ddc391

Archive hash verified: 1544e072e245c4a8…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

src/armory-ui.ts
import type { ArmorySync, SyncState } from './armory-sync.js';

type SyncActions = Pick<ArmorySync, 'enable' | 'save' | 'restore' | 'importGuest'>;
export function mountArmoryControls(actions: () => SyncActions, customization = false) {
  const panels: { panel: HTMLElement; heading: HTMLElement; buttons: HTMLElement; status: HTMLElement; enable: HTMLButtonElement; save: HTMLButtonElement; load: HTMLButtonElement; importGuest: HTMLButtonElement; disclosure: HTMLElement }[] = [];
  for (const id of customization ? ['playerAccount'] : ['playerAccount', 'shop']) {
    const parent = document.getElementById(id);
    if (!parent) continue;
    const panel = document.createElement('section');
    panel.className = 'armory-sync';
    panel.dataset.syncGroup = customization ? 'customization' : 'armory';
    panel.setAttribute('aria-label', customization ? 'Player choice sync' : 'Armory sync');
    const heading = document.createElement('h3'); heading.textContent = customization ? 'PLAYER CHOICE SYNC' : 'ARMORY SYNC';
    const status = document.createElement('p'); status.setAttribute('role', 'status');
    const disclosure = document.createElement('p'); disclosure.className = 'sync-disclosure';
    disclosure.textContent = customization ? 'Save your character, loadout, equipped armor, difficulty and map to your account. Account choices are public. Each save asks for your approval.' : 'Save permanent unlocks and upgrades to your account for use on another device. Account progress is public. Each save asks for your approval.';
    const buttons = document.createElement('div'); buttons.className = 'sync-actions';
    const button = (name: string, action: () => void | Promise<void>) => {
      const control = document.createElement('button'); control.type = 'button'; control.textContent = name;
      control.addEventListener('click', () => { void Promise.resolve().then(action).catch(() => { status.textContent = 'Armory sync failed · Device progress kept'; }); });
      buttons.append(control); return control;
    };
    const enable = button(customization ? 'ENABLE PLAYER CHOICE SYNC' : 'ENABLE ARMORY SYNC', () => actions().enable()); enable.dataset.sync = 'enable';
    const save = button(customization ? 'SAVE PLAYER CHOICES' : 'SAVE ARMORY TO ACCOUNT', () => actions().save()); save.dataset.sync = 'save';
    const load = button(customization ? 'LOAD ACCOUNT CHOICES' : 'LOAD ACCOUNT ARMORY', () => actions().restore()); load.dataset.sync = 'load';
    const importGuest = button(customization ? "USE THIS DEVICE'S CHOICES" : "USE THIS DEVICE'S ARMORY", () => actions().importGuest()); importGuest.dataset.sync = 'import';
    panel.append(heading, status, disclosure, buttons);
    if (id === 'shop') parent.querySelector('.lbar')?.after(panel); else parent.append(panel);
    panels.push({ panel, heading, buttons, status, disclosure, enable, save, load, importGuest });
  }
  return (state: SyncState) => {
    for (const panel of panels) {
      panel.panel.hidden = customization && state.unsupported;
      panel.panel.classList.toggle('sync-warning', state.unsupported);
      panel.heading.hidden = state.unsupported || !state.supported;
      panel.buttons.hidden = state.unsupported || !state.supported || (!state.busy && !state.canEnable && !state.canSave && !state.canImport && !state.canLoad);
      panel.status.textContent = state.message;
      panel.disclosure.hidden = state.unsupported || !state.supported || state.enabled;
      panel.enable.hidden = !state.canEnable;
      panel.save.hidden = !state.enabled;
      panel.save.disabled = !state.canSave;
      panel.load.disabled = !state.canLoad;
      panel.importGuest.hidden = !state.canImport;
      for (const control of [panel.enable, panel.importGuest]) control.disabled = state.busy;
    }
  };
}