import "/static/vendor/ace/ace.js"; import { $el } from "../../vendor/domutil/domutil.js"; class Editor extends HTMLElement { editor; /** @type {HTMLDivElement} Tab container */ tabEl; /** @type {Map} File name to file session */ files; constructor() { super(); this.files = {}; this.attachShadow({ mode: "open" }); } connectedCallback() { this.tabEl = $el("div", { className: "tab-container" }); this.shadowRoot.append(this.tabEl); const style = $el("style"); style.textContent = ` .tab-container { display: flex; & .tab { border: 2px solid var(--table-border-color); padding: 0.5ch 0.8ch; background-color: var(--button-bg); cursor: pointer; &.active { background-color: var(--table-border-color); } &:not(:first-child) { margin-left: -2px; } } } `; const slot = $el("slot", { name: "body" }); this.shadowRoot.append(style, slot); const editorEl = $el("div", { slot: "body" }); this.append(editorEl); // Create editor ace.config.set('basePath', '/static/vendor/ace') this.editor = ace.edit(editorEl); // todo make this stuff customizable?? this.editor.setTheme("ace/theme/dracula"); this.editor.setOptions({ fontFamily: "Iosevka Web", fontSize: "12pt", }); this.editor.getSession().setUseWrapMode(true); this.editor.setKeyboardHandler("ace/keyboard/vim"); } /** * Add a file editing session * @param {string} name File name * @param {string} content File contents */ addFile(name, content) { // Add to session list this.files[name] = ace.createEditSession(content); // TODO replace this with auto-detection this.files[name].setMode("ace/mode/nix"); // Create tab and set as active const tab = this.#addTab(name); tab.click(); } /** * Create a new tab * @param {string} name Tab name * @returns Tab element */ #addTab(name) { const tab = $el("div", { className: "tab", "@click": () => { this.editor.setSession(this.files[name]); this.tabEl.querySelectorAll(".tab").forEach(el => el.classList.remove("active")); tab.classList.add("active"); } }, name); this.tabEl.append(tab); return tab; } } customElements.define("file-editor", Editor);