UNPKG

odious

Version:

Odious fundamentally revolutionizes the software development paradigm by seamlessly integrating deployment considerations into the development process, thus empowering developers of all skill levels to create and deploy applications with unprecedented eas

186 lines (158 loc) 7.39 kB
//NOTE: on start we create a x-instruments web component that contins a bootstrap modal // the modal is shown onContextMenu import Signal from 'signal'; import Forms from 'forms'; import lol from 'lol'; import guid from 'guid'; import transcend from 'transcend'; import ReactiveHTMLElement from '../ReactiveHTMLElement.js'; class Instruments extends ReactiveHTMLElement { selected = new Signal(); // the item selected for user reveiew request; // stores coordinates constructor() { super(); this.status = new Signal('loading'); const localStyle = ` .frosted-glass { background-color: rgba(var(--bs-dark-rgb), 0.1)!important; backdrop-filter: blur(10px)!important; } `; const localCss = new CSSStyleSheet(); localCss.replaceSync(localStyle.trim()); const shadow = this.attachShadow({ mode: 'open' }); shadow.adoptedStyleSheets = [...document.adoptedStyleSheets, localCss]; this.container = document.createElement('div'); this.container.classList.add('modal', 'fade'); this.container.innerHTML = ` <div class="modal-dialog modal-dialog-scrollable modal-lg"> <div class="modal-content" style="background-color: rgba(var(--bs-dark-rgb), 0.1)!important; backdrop-filter: blur(10px)!important;"> <div class="modal-header"> <h5 class="modal-title">Toolbox</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="row"> <div id="module-listing-container" class="col-5"> </div> <div id="module-description" class="col"> </div> </div> </div> <small class="text-secondary p-2"><i class="bi bi-info-circle"></i> Double-click to quickly add to stage.</small> <div class="modal-footer"> <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal"><i class="bi bi-x"></i> Cancel</button> <button id="create-button" type="button" class="btn btn-primary" disabled><i class="bi bi-plus"></i> Use</button> </div> </div> </div> `; shadow.appendChild(this.container); this.modal = new bootstrap.Modal(this.container, {}); const createButton = shadow.getElementById('create-button'); this.selected.subscribe(v=>createButton.disabled=v.path?false:true); //this.selected.subscribe(v=>console.log('TTT createButton.disabled', v.path?false:true)); this.gc = this.listenTo(createButton, 'click', ()=>this.addComponent({path: this.selected.value.path, ...this.request})); const moduleDescription = shadow.getElementById('module-description'); this.gc = this.selected.subscribe(v=>{ moduleDescription.innerHTML = ` <div class="col d-flex flex-column align-items-start gap-2"> <h2 name="name" class="fw-bold text-body-emphasis"></h2> <p name="description" class="text-body-secondary">P</p> <!--<a class="btn btn-primary btn-lg">Primary button</a>--> </div> `; this.assignText(v, moduleDescription); }) } connectedCallback() { // Create Module Listing const instrumentsCategories = document.createElement('ul'); instrumentsCategories.classList.add('list-unstyled', 'ps-0'); // Add Modules // const categories = this.source.root.get('modules'); const categories = this.application.source.get('modules'); for(const parent of categories.children){ const instrumentsCategory = document.createElement('li'); instrumentsCategory.classList.add('mb-1'); const collapseId = guid(); instrumentsCategory.innerHTML = ` <button class="btn btn-toggle d-inline-flex align-items-center rounded border-0 ps-2 fs-5" data-bs-toggle="collapse" data-bs-target="#${collapseId}"> ${parent.settings.get('name')} </button> <div class="collapse show" id="${collapseId}"> <ul class="btn-toggle-nav list-unstyled fw-normal ps-3 pb-1 small"> </ul> </div> `; instrumentsCategories.appendChild(instrumentsCategory) // Add Instruments for(const child of parent.children){ const item = document.createElement('li'); const path = [ parent.id, child.id ].join('/'); const click =()=> this.selected.value = { // select id: child.id, name: child.settings.get('name'), description: child.settings.get('description'), path, parent, child, }; const dblclick =()=> this.addComponent({path, ...this.request}); // add instantly const selector = lol.a({class:'d-inline-flex text-decoration-none rounded fs-6 user-select-none', on:{click, dblclick}, textContent: child.settings.get('name')}, ) item.appendChild(selector); instrumentsCategory.querySelector('ul').appendChild(item) } } // Add Full Module Listing const moduleListingContainer = this.shadowRoot.getElementById('module-listing-container'); moduleListingContainer.appendChild(instrumentsCategories) }; async addComponent(options){ //console.warn('addComponent', options) const application = transcend(this, `x-application`); await application.source.commander.componentCreate(options); this.modal.hide(); } } export default class Constructible { sceneComponent; targetElement; svgMarkerDot; #mouseCoordinates = { x: 0, y: 0 }; constructor(sceneComponent) { this.sceneComponent = sceneComponent; //NOTE: we are adding to shadow root, beneath .content this.targetElement = this.sceneComponent.shadowRoot; //.querySelector(".content"); this.positioningElement = this.sceneComponent.shadowRoot.querySelector(".content"); this.onContextMenu = this.onContextMenu.bind(this); } start() { this.sceneComponent.addEventListener("contextmenu", this.onContextMenu); // NOTE: installing the modal instrumentbox this.instruments = document.createElement('x-instruments'); this.targetElement.appendChild(this.instruments); return () => this.stop(); } stop() { this.sceneComponent.removeEventListener("contextmenu", this.onContextMenu); this.instruments.remove(); } onContextMenu(event) { if(event.target !== this.sceneComponent) return; //console.log(event, this.sceneComponent ); event.preventDefault(); const [x,y] = this.sceneComponent.transform(event.clientX, event.clientY); this.#mouseCoordinates = {x, y}; const svgSurface = this.sceneComponent.drawingSurfaces[1]; if(!this.svgMarkerDot) this.svgMarkerDot = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); this.svgMarkerDot.setAttribute('r', 32); this.svgMarkerDot.setAttribute('fill', 'rgba(255,0,0,0.3)'); this.svgMarkerDot.setAttribute('cx', x); this.svgMarkerDot.setAttribute('cy', y); svgSurface.appendChild(this.svgMarkerDot); setTimeout(()=>{this.svgMarkerDot.remove(); this.svgMarkerDot = null;}, 300) this.instruments.request = { left:x, top:y }; // partion information for command execution; // sent to instrument component that holds modal this.instruments.modal.show(); } } customElements.define(`x-instruments`, Instruments);