103 lines
3.0 KiB
JavaScript
103 lines
3.0 KiB
JavaScript
// Side menu component logic
|
||
|
||
class SideMenu extends HTMLElement {
|
||
constructor() {
|
||
super();
|
||
|
||
// Attach a shadow root and clone the template defined in side-menu.html
|
||
this.attachShadow({ mode: "open" });
|
||
const tmpl = document.getElementById("side-menu-template");
|
||
if (!tmpl) {
|
||
console.error("SideMenu: template not found");
|
||
return;
|
||
}
|
||
this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
|
||
|
||
// Reference the toggle button and the menu container
|
||
this._toggleBtn = this.shadowRoot.querySelector(".toggle");
|
||
this._menu = this.shadowRoot.querySelector(".menu");
|
||
this._colorPicker = this.shadowRoot.querySelector("color-picker");
|
||
this._gridToggle = this.shadowRoot.querySelector("#grid-toggle");
|
||
|
||
// Bind event handlers
|
||
this._onToggle = this._onToggle.bind(this);
|
||
this._onColorChange = this._onColorChange.bind(this);
|
||
this._onGridToggle = this._onGridToggle.bind(this);
|
||
}
|
||
|
||
static get observedAttributes() {
|
||
return ["collapsed"];
|
||
}
|
||
|
||
connectedCallback() {
|
||
// Register click listener for the toggle button
|
||
this._toggleBtn?.addEventListener("click", this._onToggle);
|
||
this._colorPicker?.addEventListener("colorchange", this._onColorChange);
|
||
this._gridToggle?.addEventListener("change", this._onGridToggle);
|
||
|
||
// Initialise collapsed state from the attribute (if present)
|
||
if (this.hasAttribute("collapsed")) {
|
||
this._applyCollapsed(true);
|
||
}
|
||
}
|
||
|
||
disconnectedCallback() {
|
||
// Clean up listeners when the element is removed
|
||
this._toggleBtn?.removeEventListener("click", this._onToggle);
|
||
this._colorPicker?.removeEventListener("colorchange", this._onColorChange);
|
||
this._gridToggle?.removeEventListener("change", this._onGridToggle);
|
||
}
|
||
|
||
attributeChangedCallback(name, oldVal, newVal) {
|
||
if (name === "collapsed") {
|
||
const isCollapsed = this.hasAttribute("collapsed");
|
||
this._applyCollapsed(isCollapsed);
|
||
}
|
||
}
|
||
|
||
// Apply or remove the CSS class that slides the menu
|
||
_applyCollapsed(collapsed) {
|
||
const host = this.shadowRoot.host;
|
||
if (collapsed) {
|
||
host.classList.add("collapsed");
|
||
} else {
|
||
host.classList.remove("collapsed");
|
||
}
|
||
}
|
||
// Forward color picker change as bgcolorchange event
|
||
_onColorChange(e) {
|
||
const { color } = e.detail;
|
||
this.dispatchEvent(
|
||
new CustomEvent("bgcolorchange", {
|
||
detail: { color },
|
||
bubbles: true,
|
||
composed: true,
|
||
}),
|
||
);
|
||
}
|
||
|
||
// Forward grid toggle change as gridtoggle event
|
||
_onGridToggle(e) {
|
||
const enabled = e.target.checked;
|
||
this.dispatchEvent(
|
||
new CustomEvent("gridtoggle", {
|
||
detail: { enabled },
|
||
bubbles: true,
|
||
composed: true,
|
||
}),
|
||
);
|
||
}
|
||
|
||
// Toggle the collapsed attribute when the button is clicked
|
||
_onToggle() {
|
||
if (this.hasAttribute("collapsed")) {
|
||
this.removeAttribute("collapsed");
|
||
} else {
|
||
this.setAttribute("collapsed", "");
|
||
}
|
||
}
|
||
}
|
||
|
||
// Register the custom element; we follow the kebab‑case convention used elsewhere
|
||
customElements.define("side-menu-component", SideMenu);
|