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.
import { html } from 'lit';
import { editor } from '../editor-controller';
import { mountPaneResizers } from '../pane-resizer';
import type { WorkspaceTab } from '../state/editor-state';
import { LightElement } from './light-element';
import './bs-tool-palette';
import './bs-map-canvas';
import './bs-inspector';
const tabs: [WorkspaceTab, string][] = [
['map', 'Map'],
['tools', 'Tools'],
['details', 'Details'],
];
/** Mobile tabs plus the three-column workspace with resizable side panes. */
export class BsWorkspace extends LightElement {
constructor() {
super();
this.watch((s) => [s.workspaceTab, s.busy]);
}
render() {
const { workspaceTab, busy } = editor.state;
return html`<nav class="tabs" aria-label="Workspace">
${tabs.map(
([tab, label]) =>
html`<button
data-tab=${tab}
class=${tab === workspaceTab ? 'active' : ''}
@click=${() => editor.setWorkspaceTab(tab)}
>
${label}
</button>`,
)}
</nav>
<div class="workspace" data-tab=${workspaceTab} ?inert=${busy}>
<aside id="tool-panel" class="pane left"><bs-tool-palette></bs-tool-palette></aside>
<section class="canvas-pane" aria-label="Map workspace">
<bs-map-canvas></bs-map-canvas>
<div
id="resizer-left"
class="pane-resizer left"
role="separator"
aria-orientation="vertical"
tabindex="0"
aria-label="Resize map tools panel"
></div>
<div
id="resizer-right"
class="pane-resizer right"
role="separator"
aria-orientation="vertical"
tabindex="0"
aria-label="Resize details panel"
></div>
</section>
<aside id="inspector" class="pane right"><bs-inspector></bs-inspector></aside>
</div>`;
}
firstUpdated() {
// Side panes resize by dragging their handles on the canvas edges, arrow keys on a
// focused handle, or a double-click reset. The canvas ResizeObserver refits the map.
const $ = (selector: string) => this.querySelector<HTMLElement>(selector)!;
mountPaneResizers($('.workspace'), {
left: {
handle: $('#resizer-left'),
pane: $('#tool-panel'),
defaultWidth: 174,
min: 120,
max: 420,
},
right: {
handle: $('#resizer-right'),
pane: $('#inspector'),
defaultWidth: 260,
min: 200,
max: 560,
},
});
}
updated() {
// Switching mobile tabs reveals the canvas; redraw once layout settles.
requestAnimationFrame(() => editor.ui.canvas?.draw());
}
}
customElements.define('bs-workspace', BsWorkspace);
