Bring the five-panel hex portal online with a browser 3D/schematic preview, Pi SPI backends, and renamed multi-panel Pico UDP firmware. Co-authored-by: Cursor <cursoragent@cursor.com>
91 lines
2.4 KiB
JavaScript
91 lines
2.4 KiB
JavaScript
import { paintIdentify, paintRgb } from "../panel-paint.js";
|
|
|
|
const PANEL_STYLES = `
|
|
:host {
|
|
display: block;
|
|
background: #000;
|
|
border: 1px solid var(--border, #2a3044);
|
|
border-radius: 4px;
|
|
image-rendering: pixelated;
|
|
}
|
|
canvas {
|
|
display: block;
|
|
width: 100%;
|
|
height: auto;
|
|
}
|
|
.label {
|
|
text-align: center;
|
|
font-size: 0.75rem;
|
|
color: var(--muted, #8b93a8);
|
|
margin: 0.35rem 0;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
`;
|
|
|
|
export class PortalPanel extends HTMLElement {
|
|
static observedAttributes = ["index", "position", "width", "height"];
|
|
|
|
constructor() {
|
|
super();
|
|
this._index = 0;
|
|
this._pixelWidth = 45;
|
|
this._pixelHeight = 9;
|
|
}
|
|
|
|
connectedCallback() {
|
|
if (this.shadowRoot) return;
|
|
const root = this.attachShadow({ mode: "open" });
|
|
root.innerHTML = `
|
|
<style>${PANEL_STYLES}</style>
|
|
<canvas part="canvas"></canvas>
|
|
<div class="label" part="label"></div>
|
|
`;
|
|
this._canvas = /** @type {HTMLCanvasElement} */ (root.querySelector("canvas"));
|
|
this._ctx = /** @type {CanvasRenderingContext2D} */ (this._canvas.getContext("2d"));
|
|
this._label = root.querySelector(".label");
|
|
this._syncFromAttributes();
|
|
}
|
|
|
|
attributeChangedCallback(name) {
|
|
if (!this.shadowRoot) return;
|
|
this._syncFromAttributes();
|
|
}
|
|
|
|
_syncFromAttributes() {
|
|
this._index = Number(this.getAttribute("index") ?? 0);
|
|
this._pixelWidth = Number(this.getAttribute("width") ?? 45);
|
|
this._pixelHeight = Number(this.getAttribute("height") ?? 9);
|
|
const position = this.getAttribute("position") ?? "";
|
|
if (this._label) {
|
|
this._label.textContent = `${this._index} · ${position}`;
|
|
}
|
|
if (this._canvas) {
|
|
this._canvas.width = this._pixelWidth;
|
|
this._canvas.height = this._pixelHeight;
|
|
}
|
|
}
|
|
|
|
/** @returns {HTMLCanvasElement} */
|
|
get canvas() {
|
|
if (!this._canvas) this.connectedCallback();
|
|
return this._canvas;
|
|
}
|
|
|
|
/**
|
|
* @param {number[] | Uint8Array} rgb
|
|
* @param {number} width
|
|
* @param {number} height
|
|
*/
|
|
setFrame(rgb, width, height) {
|
|
if (!this._ctx) this.connectedCallback();
|
|
paintRgb(this._ctx, this._canvas, rgb, width, height);
|
|
}
|
|
|
|
showIdentify() {
|
|
if (!this._ctx) this.connectedCallback();
|
|
paintIdentify(this._ctx, this._canvas, this._index, this._pixelWidth, this._pixelHeight);
|
|
}
|
|
}
|
|
|
|
customElements.define("portal-panel", PortalPanel);
|