From ad2fa285a0dbf27c7d9992d03c29ebeab41bb2d3 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Mon, 22 Jan 2024 11:13:41 +0000 Subject: [PATCH] wip: iconmenu is now an app too --- app/{ => example}/helloworld-html.js | 0 app/{ => example}/helloworld-htmlform.js | 0 app/{ => example}/helloworld-window.js | 0 app/{ => example}/helloworld.js | 0 app/{ => example}/helloworld.old.js | 0 app/launcher.js | 21 ++-- app/spatialize.js | 19 +++- com/app.js | 130 +++++++++-------------- 8 files changed, 73 insertions(+), 97 deletions(-) rename app/{ => example}/helloworld-html.js (100%) rename app/{ => example}/helloworld-htmlform.js (100%) rename app/{ => example}/helloworld-window.js (100%) rename app/{ => example}/helloworld.js (100%) rename app/{ => example}/helloworld.old.js (100%) diff --git a/app/helloworld-html.js b/app/example/helloworld-html.js similarity index 100% rename from app/helloworld-html.js rename to app/example/helloworld-html.js diff --git a/app/helloworld-htmlform.js b/app/example/helloworld-htmlform.js similarity index 100% rename from app/helloworld-htmlform.js rename to app/example/helloworld-htmlform.js diff --git a/app/helloworld-window.js b/app/example/helloworld-window.js similarity index 100% rename from app/helloworld-window.js rename to app/example/helloworld-window.js diff --git a/app/helloworld.js b/app/example/helloworld.js similarity index 100% rename from app/helloworld.js rename to app/example/helloworld.js diff --git a/app/helloworld.old.js b/app/example/helloworld.old.js similarity index 100% rename from app/helloworld.old.js rename to app/example/helloworld.old.js diff --git a/app/launcher.js b/app/launcher.js index dcae6d2..acd034f 100644 --- a/app/launcher.js +++ b/app/launcher.js @@ -37,7 +37,7 @@ AFRAME.registerComponent('launcher', { scale: 3, events: ['click'], html: (me) => `
-
+
`, css: `#iconmenu { @@ -53,6 +53,7 @@ AFRAME.registerComponent('launcher', { padding-bottom: 72px; box-sizing: border-box; pointer-events: none; + visibility: visible !important; } #iconmenu > button { pointer-events:all; @@ -84,9 +85,8 @@ AFRAME.registerComponent('launcher', { padding: 5px; border-radius: 0px; } - #iconmenu > button > img:hover, - #iconmenu > button.enable > img { - border:2px solid #444; + #iconmenu > button > img:hover{ + background: #AAA; transition:0.gg3s; border-radius: 50%; }` @@ -110,24 +110,21 @@ AFRAME.registerComponent('launcher', { clearTimeout(this.timeout) this.timeout = setTimeout( () => { AFRAME.app.foreach( (app) => { - console.dir(app) if( !app.manifest ) return - console.log("--rendering button") - return + console.log(app.data.uri+" "+app.data.order) + let btn = app.btn = document.createElement('button') if( app.manifest.icons?.length > 0){ let img = document.createElement('img') img.src = app.manifest.icons[0].src - img.alt = app.manifest.name + img.title = app.manifest.name + ": " + app.manifest.description btn.appendChild(img) }else btn.innerText = app.manifest.short_name - btn.addEventListener('click', () => { - app.el.emit('launcher',app) - }) + btn.addEventListener('click', () => app.el.emit('launcher',app) ) this.el.dom.querySelector('#iconmenu').appendChild(btn) }) - },200) + },100) }, manifest: { // HTML5 manifest to identify app to xrsh diff --git a/app/spatialize.js b/app/spatialize.js index a574eae..18bc533 100644 --- a/app/spatialize.js +++ b/app/spatialize.js @@ -9,6 +9,17 @@ AFRAME.registerComponent('spatialize', { document.querySelector('a-scene').addEventListener('exit-vr', () => this.toggle(false) ) // toggle immersive with ESCAPE document.body.addEventListener('keydown', (e) => e.key == 'Escape' && this.toggle() ) + + document.head.innerHTML += `` }, requires:{ @@ -31,7 +42,8 @@ AFRAME.registerComponent('spatialize', { state = state || !document.body.className.match(/XR/) document.body.classList[ state ? 'add' : 'remove'](['XR']) AFRAME.scenes[0].emit( state ? 'apps:XR' : 'apps:2D') - this.btn.classList.toggle('enable') + this.btn.querySelector('img').src = state ? this.manifest.icons[0].src_2D + : this.manifest.icons[0].src }, manifest: { // HTML5 manifest to identify app to xrsh @@ -39,7 +51,8 @@ AFRAME.registerComponent('spatialize', { "name": "spatialize", "icons": [ { - "src": "https://css.gg/stack.svg", + "src": "https://css.gg/display-grid.svg", + "src_2D": "https://css.gg/stack.svg", "type": "image/svg+xml", "sizes": "512x512" } @@ -66,7 +79,7 @@ AFRAME.registerComponent('spatialize', { "icons": [{ "src": "/images/today.png", "sizes": "192x192" }] } ], - "description": "Hello world information", + "description": "use ESC-key to toggle between 2D / 3D", "screenshots": [ { "src": "/images/screenshot1.png", diff --git a/com/app.js b/com/app.js index d15952d..111fd92 100644 --- a/com/app.js +++ b/com/app.js @@ -3,20 +3,37 @@ AFRAME.required = {} AFRAME.app = new Proxy({ + order:0, + add(component, entity){ + // categorize by component to prevent similar apps loading duplicate dependencies simultaniously this[component] = this[component] || [] this[component].push(entity) + entity.data.order = entity.data.order || this.count() + }, + count(){ + let n = 0 + this.foreach( () => n++ ) + return n }, foreach(cb){ + const isArray = (e) => e.push + let arr = [] for( let i in this ){ - if( typeof this[i] != 'function' ) this[i].map( (app) => cb({app,component:i}) ) + if( isArray(this[i]) ) this[i].map( (app) => arr.push(app.el.app) ) } + arr.sort( (a,b) => a.data.order > b.data.order ) + .map( cb ) } },{ get(me,k) { return me[k] }, set(me,k,v){ me[k] = v } }) +/* + * This is the abstract 'app' component + */ + AFRAME.registerComponent('app', { schema:{ "uri":{ type:"string"} @@ -57,7 +74,6 @@ AFRAME.registerComponent('app', { type: String(uri).split(".").pop() // 'mycom.js' => 'js' } }, - // usage: require(["./app/foo.js"]) // require({foo: "https://foo.com/foo.js"}) require: AFRAME.AComponent.prototype.require = function(packages,readyEvent){ @@ -101,13 +117,17 @@ AFRAME.registerComponent('app', { }) -// monkeypatching initComponent will trigger events when components -// are initialized (that way apps can react to attached components) -// basically, in both situations: -// -// -// -// event 'foo' will be triggered as both entities (in)directly require component 'foo' +/* + * Here are monkeypatched AFRAME component prototype functions + * + * monkeypatching initComponent will trigger events when components + * are initialized (that way apps can react to attached components) + * basically, in both situations: + * + * + * + * event 'foo' will be triggered as both entities (in)directly require component 'foo' + */ AFRAME.AComponent.prototype.initComponent = function(initComponent){ return function(){ @@ -122,7 +142,7 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){ return function(){ updateProperties.apply(this,arguments) - if( !this.data || !this.data.uri ) return // only deal with apps + if( !this.data || !this.data.uri || this.isApp ) return // only deal with apps (once) // ensure overlay let overlay = document.querySelector('#overlay') @@ -131,22 +151,22 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){ overlay.id = "overlay" document.body.appendChild(overlay) document.querySelector("a-scene").setAttribute("webxr","overlayElement:#overlay") - let menu = document.createElement('div') - menu.id = 'iconmenu' - document.body.appendChild(menu) +// let menu = document.createElement('div') +// menu.id = 'iconmenu' +// document.body.appendChild(menu) } - // add menu button - if( this.manifest && this.manifest.icons ){ - let btn = document.createElement('button') - btn.app = this - if( this.manifest.icons.length ){ - btn.innerHTML = `` - }else btn.innerText = this.manifest.short_name - btn.setAttribute("alt", this.manifest.name ) - btn.addEventListener('click', (e) => this.el.emit('launcher',{}) ) - document.querySelector("#iconmenu").appendChild(btn) - } +// // add menu button +// if( this.manifest && this.manifest.icons ){ +// let btn = document.createElement('button') +// btn.app = this +// if( this.manifest.icons.length ){ +// btn.innerHTML = `` +// }else btn.innerText = this.manifest.short_name +// btn.setAttribute("alt", this.manifest.name ) +// btn.addEventListener('click', (e) => this.el.emit('launcher',{}) ) +// document.querySelector("#iconmenu").appendChild(btn) +// } // reactify components with dom-definition if( this.data.uri && this.dom && !this.el.dom ){ @@ -220,9 +240,12 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){ // assign unique app id if( !this.el.uid ) this.el.uid = '_'+String(Math.random()).substr(10) - // fetch requires if( this.requires ) this.require( this.requires, 'requires:ready' ) else this.el.emit('requires:ready') + + // mark app as being initialized + this.isApp = true + this.el.app = this } }( AFRAME.AComponent.prototype.updateProperties) @@ -249,62 +272,5 @@ document.head.innerHTML += ` #overlay.hide{ z-index:-10; } - - #toggle_overlay{ - display:none; - position: fixed; - right: 20px; - bottom: 73px; - width: 58px; - text-align: center; - height: 40px; - padding: 0; - z-index: 100; - border: 3px solid #3aacff; - border-radius:11px; - transition:0.3s; - padding: 0px; - font-weight: bold; - cursor:pointer; - font-family:sans-serif; - font-size:15px; - color: #FFF; - background: #3aacff; - transition:0.5s; - } - .XR #toggle_overlay{ - background: transparent; - color: #3aacff; - } - - .XR #overlay{ - visibility: hidden; - } ` - -// draw a button so we can toggle apps between 2D / XR -let toggle = (state) => { - state = state || !document.body.className.match(/XR/) - document.body.classList[ state ? 'add' : 'remove'](['XR']) - AFRAME.scenes[0].emit( state ? 'apps:XR' : 'apps:2D') -} - -document.addEventListener("DOMContentLoaded", (event) => { - let btn = document.createElement("button") - btn.id = "toggle_overlay" - btn.innerHTML = "" - btn.addEventListener('click', (e) => toggle() ) - document.body.appendChild(btn) - - document.querySelector('a-scene').addEventListener('enter-vr',() => toggle(true) ) - document.querySelector('a-scene').addEventListener('exit-vr', () => toggle(false) ) - document.querySelector('a-scene').addEventListener('loaded', () => { - let VRbtn = document.querySelector('a-scene .a-enter-vr') - let ARbtn = document.querySelector('a-scene .a-enter-ar') - if( VRbtn ) document.body.appendChild(VRbtn) // move to body - if( ARbtn ) document.body.appendChild(ARbtn) // so they will always be visible - }) - // toggle immersive with ESCAPE - document.body.addEventListener('keydown', (e) => e.key == 'Escape' && toggle() ) -})