Back to Black Site Map Editor
SOURCE / PINNED RELEASE

Made of little things.

Black Site Map Editor

Release
32a57733b7e9…
Author-recorded commit
3f54890f542f…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.shakespeare.diy%2F/black-site-map-editor

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

src/components/bs-inspector.ts
import { html } from 'lit';
import { live } from 'lit/directives/live.js';
import { editor, guard } from '../editor-controller';
import { objectControls } from '../editor-controls';
import { selectionValue, type BlackSiteMap, type Layer } from '../model';
import { listedLayers, toolLabel } from '../tools';
import { keyHint } from './key-hint';
import { LightElement } from './light-element';

export class BsInspector extends LightElement {
    static properties = { layer: { state: true } };
    declare layer: Layer;
    constructor() {
        super();
        this.layer = listedLayers[0][0] as Layer;
        this.watch((s) => [
            s.map,
            s.selection,
            s.busy,
            s.dirty,
            s.base,
            s.validation,
            s.shortcutsRev,
        ]);
    }
    #objects() {
        const m = editor.map;
        const layer = this.layer;
        const items =
            layer === 'start' || layer === 'exfil' ? [m[layer]] : m[layer as keyof BlackSiteMap];
        return Array.isArray(items) ? items : [];
    }
    render() {
        const { selection, busy, dirty, base, validation } = editor.state;
        const value = selection ? selectionValue(editor.map, selection) : undefined;
        const fixed = !selection || ['start', 'exfil'].includes(selection.layer);
        const controls = () => this.querySelector<HTMLElement>('#object-controls')!;
        const moveBy = (axis: string) =>
            Number(this.querySelector<HTMLInputElement>(`#move-${axis}`)!.value);
        return html`<div class="section">
                <h3>SELECTED OBJECT</h3>
                <div id="selection-label" class="selection-label">
                    ${
                        selection
                            ? `${toolLabel(selection.layer)} #${selection.index + 1}${selection.buildingIndex !== undefined ? ` · building #${selection.buildingIndex + 1}` : ''}`
                            : 'Nothing selected'
                    }
                </div>
                <div id="object-controls">${objectControls(editor.map, selection)}</div>
                <textarea
                    id="object-json"
                    hidden
                    .value=${live(value ? JSON.stringify(value, null, 2) : '')}
                ></textarea>
                <div class="buttons">
                    <button
                        id="apply-object"
                        ?disabled=${!selection || busy}
                        @click=${guard(() => editor.applyObject(controls()))}
                    >
                        Apply changes
                    </button>
                    <button
                        id="delete-object"
                        class="danger"
                        ?disabled=${fixed || busy}
                        ${keyHint('selection.delete')}
                        @click=${guard(() => editor.deleteSelected())}
                    >
                        Delete
                    </button>
                </div>
                <div class="row">
                    <label>Move across<input id="move-x" type="number" value="0" /></label>
                    <label>Move down<input id="move-y" type="number" value="0" /></label>
                </div>
                <button
                    id="move-object"
                    ?disabled=${!selection || busy}
                    @click=${guard(() => editor.moveSelectionBy(moveBy('x'), moveBy('y')))}
                >
                    Move selected
                </button>
            </div>
            <div class="section">
                <h3>MAP CHECK</h3>
                <div id="validation" class="validation">${validation}</div>
                <div id="draft-info" class="draft-info">
                    ${
                        dirty
                            ? 'Workspace has unsaved changes.'
                            : base
                              ? 'Loaded published revision.'
                              : 'Local workspace.'
                    }
                </div>
            </div>
            <details>
                <summary>Objects & layers</summary>
                <select
                    id="object-layer"
                    aria-label="Object layer"
                    @change=${(e: Event) =>
                        (this.layer = (e.target as HTMLSelectElement).value as Layer)}
                >
                    ${listedLayers.map(([key, label]) => html`<option value=${key} ?selected=${key === this.layer}>${label}</option>`)}
                </select>
                <div id="object-list" class="object-list">
                    ${this.#objects().map(
                        (_value, index) =>
                            html`<button
                                @click=${() => editor.selectObject({ layer: this.layer, index })}
                            >
                                ${toolLabel(this.layer)} ${index + 1}
                            </button>`,
                    )}
                </div>
            </details>`;
    }
}
customElements.define('bs-inspector', BsInspector);