98 lines
2.2 KiB
JavaScript
98 lines
2.2 KiB
JavaScript
|
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<string, AceSession>} 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);
|