work in progress [might break]

This commit is contained in:
Leon van Kammen 2024-01-01 18:53:10 +00:00
parent 774317793b
commit 094a78570b
2 changed files with 171 additions and 55 deletions

View File

@ -11,9 +11,13 @@ AFRAME.registerComponent('helloworld', {
dom: { dom: {
scale: 3.5, scale: 3.5,
events: ['click','input'], events: ['click','input'],
html: `<div id="hello" class="modal"> html: (me) => `
<button class="close"></button> <div id="${me.el.uid}" class="modal hello">
<b>Hello world</b> <div class="top">
<div class="title">Hello world</div>
<button class="close"></button>
<button class="fold">_</button>
</div>
<br><br> <br><br>
<fieldset> <fieldset>
<legend>Colour</legend> <legend>Colour</legend>
@ -25,35 +29,36 @@ AFRAME.registerComponent('helloworld', {
<input id="material-wireframe" type="checkbox" name="wireframe"><label for="material-wireframe"> Wireframe</label><br> <input id="material-wireframe" type="checkbox" name="wireframe"><label for="material-wireframe"> Wireframe</label><br>
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Size:</legend> <legend>Size: <span id="value"></span></legend>
<input type="range" min="0.1" max="2" value="1" step="0.01" id="myRange" style="background-color: transparent;"> <input type="range" min="0.1" max="2" value="1" step="0.01" id="myRange" style="background-color: transparent;">
</fieldset> </fieldset>
<button onclick="AFRAME.scenes[0].exitVR()" style="display: block;">Exit Immersive</button> <button>hello</button>
</div>`, </div>`,
css: `div{ #hello {position:relative;top:0;width:300px} }` css: `.modal.hello {
position:relative;top:0;width:200px
foo { /* modern css supported via stylis */ }
}`
}, },
events:{ events:{
html: function( ){ console.log("htmlmesh component mounted!") }, // html-component was added to this AFRAME entity html: function( ){ console.log("htmlmesh component mounted!") }, // html-component was added to this AFRAME entity
title: function(e){ this.dom.el.querySelector("b").innerHTML = e.detail.v }, // this.data.title was changed click: function(e){ // a click was detected on this.el.dom or AFRAME entity
click: function(e){ // a click was detected on this.dom.el or AFRAME entity let el = e.detail.target || e.detail.srcElement
if( !e.detail.target ) return if( !el ) return
if( e.detail.target.className == 'close' ){ if( el.className.match("fold") ) this.el.toggleFold()
this.dom.el.remove() if( el.className.match("close") ) this.el.close()
this.el.removeAttribute("html")
}
}, },
input: function(e){ input: function(e){
if( !e.detail.target ) return if( !e.detail.target ) return
if( e.detail.target.id == 'myRange' ) this.data.title = e.detail.target.value // reactive demonstration if( e.detail.target.id == 'myRange' ) this.data.value = e.detail.target.value // reactive demonstration
} },
value: function(e){ this.el.dom.querySelector("#value").innerHTML = e.detail.v }, // this.data.title was changed
}, },
init: function () { init: function () {
this.require( this.dependencies ) this.require( this.dependencies )
.then( () => { .then( () => {
document.body.appendChild(this.dom.el) this.el.setAttribute("html",`html:#${this.el.uid}; cursor:#cursor`)
this.el.setAttribute("html",'html:#hello; cursor:#cursor')
}) })
}, },

View File

@ -5,13 +5,14 @@ AFRAME.registerComponent('app', {
"uri":{ type:"string"} "uri":{ type:"string"}
}, },
init: function() { init: function() {
this.require([ this.data.uri ]) let id = this.data.uri.split("/").pop() // 'a/b/c/mycom.js' => 'mycom.js'
.then( () => { let component = id.split(".js").shift() // 'mycom.js' => 'mycom'
let id = this.data.uri.split("/").pop() // 'a/b/c/mycom.js' => 'mycom.js' let mount = () => {
let component = id.split(".js").shift() // 'mycom.js' => 'mycom'
let entity = document.createElement("a-entity") let entity = document.createElement("a-entity")
this.el.setAttribute(component,this.data) this.el.setAttribute(component,this.data)
}) }
if( AFRAME.components[component] || document.head.querySelector(`script#${id}`) ) mount()
else this.require([ this.data.uri ]).then( mount ).catch(console.error)
}, },
@ -68,24 +69,75 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){
return function(){ return function(){
updateProperties.apply(this,arguments) updateProperties.apply(this,arguments)
if( this.dom && this.data){ if( this.dom && this.data){
let reactify = (el,aframe) => new Proxy(this.data,{
get(me,k,v) { return me[k] }, tasks = {
set(me,k,v){
me[k] = v generateUniqueId: () => {
aframe.emit(k,{el,k,v}) this.el.uid = String(Math.random()).substr(2)
} return tasks
}) },
let el = document.createElement('div')
el.innerHTML = this.dom.html ensureOverlay: () => {
this.data = reactify( el, this.el ) let overlay = document.querySelector('#overlay')
this.dom.el = el.childNodes[0] if( !overlay ){
this.dom.events.map( (e) => this.dom.el.addEventListener(e, (ev) => this.el.emit(e,ev) ) ) overlay = document.createElement('div')
// add css if any overlay.id = "#overlay"
if( this.dom.css && !document.head.querySelector(`style#${this.attrName}`) ){ document.body.appendChild(overlay)
document.head.innerHTML += `<style id="${this.attrName}">${this.dom.css}</style>` document.querySelector("a-scene").setAttribute("webxr","overlayElement:#overlay")
}
tasks.overlay = overlay
return tasks
},
createReactiveDOMElement: () => {
const reactify = (el,aframe) => new Proxy(this.data,{
get(me,k,v) { return me[k] },
set(me,k,v){
me[k] = v
aframe.emit(k,{el,k,v})
}
})
this.el.dom = document.createElement('div')
this.el.dom.innerHTML = this.dom.html(this)
this.data = reactify( this.dom.el, this.el )
this.dom.events.map( (e) => this.el.dom.addEventListener(e, (ev) => this.el.emit(e,ev) ) )
return tasks
},
addCSS: () => {
if( this.dom.css && !document.head.querySelector(`style#${this.attrName}`) ){
document.head.innerHTML += `<style id="${this.attrName}">${this.dom.css}</style>`
}
return tasks
},
scaleDOMvsXR: () => {
if( this.dom.scale ) this.el.setAttribute('scale',`${this.dom.scale} ${this.dom.scale} ${this.dom.scale}`)
return tasks
},
addModalFunctions: () => {
this.el.close = () => {
this.el.dom.remove()
this.el.removeAttribute("html")
}
this.el.toggleFold = () => {
this.el.dom.querySelector(".modal").classList.toggle('fold')
this.el.dom.querySelector('.top .fold').innerText = this.el.dom.querySelector('.modal').className.match(/fold/) ? '▢' : '_'
}
return tasks
},
} }
if( this.dom.scale ) this.el.setAttribute('scale',`${this.dom.scale} ${this.dom.scale} ${this.dom.scale}`)
//('[helloworld]').object3D.children[0].material.map.magFilter = THREE.NearestFilter tasks
.generateUniqueId()
.ensureOverlay()
.addCSS()
.createReactiveDOMElement()
.scaleDOMvsXR()
.addModalFunctions()
// finally lets add the bad boy to the DOM
tasks.overlay.appendChild(this.el.dom)
} }
} }
}( AFRAME.AComponent.prototype.updateProperties) }( AFRAME.AComponent.prototype.updateProperties)
@ -93,6 +145,10 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){
// //
// base CSS for XRSH apps // base CSS for XRSH apps
// //
// limitations / some guidelines for html-mesh compatibility:
// * no icon libraries (favicon e.g.)
// * 'border-radius: 2px 3px 4px 5px' (applies 2px to all corners)
//
document.head.innerHTML += ` document.head.innerHTML += `
<style type="text/css"> <style type="text/css">
/* CSS reset */ /* CSS reset */
@ -116,6 +172,8 @@ document.head.innerHTML += `
--xrsh-font-size-1: 14px; --xrsh-font-size-1: 14px;
--xrsh-font-size-2: 17px; --xrsh-font-size-2: 17px;
--xrsh-font-size-3: 21px; --xrsh-font-size-3: 21px;
--xrsh-modal-button-bg: #CCC;
--xrsh-modal-button-fg: #FFF;
} }
a-scene{ a-scene{
@ -138,21 +196,16 @@ document.head.innerHTML += `
accent-color: var(--xrsh-light-primary); accent-color: var(--xrsh-light-primary);
} }
#overlay{
display: flex; /* tile modals */
}
h1,h2,h3,h4,h5{ h1,h2,h3,h4,h5{
color: var(--xrsh-gray); color: var(--xrsh-gray);
} }
h1 { font-size: var(--xrsh-font-size-3); } h1 { font-size: var(--xrsh-font-size-3); }
h2,h3,h4{ font-size: var(--xrsh-font-size-2); } h2,h3,h4{ font-size: var(--xrsh-font-size-2); }
.modal{
background: #f0f0f0;
padding: 20px 20px 10px 20px;
border-radius: 15px;
display: inline-block;
position:relative;
z-index:50;
}
button,.btn,input[type=submit]{ button,.btn,input[type=submit]{
border-radius:7px; border-radius:7px;
background: var(--xrsh-primary); background: var(--xrsh-primary);
@ -160,7 +213,6 @@ document.head.innerHTML += `
transition:0.3s; transition:0.3s;
padding: 10px; padding: 10px;
font-weight: bold; font-weight: bold;
border-block: none;
border: none; border: none;
cursor:pointer; cursor:pointer;
} }
@ -168,15 +220,74 @@ document.head.innerHTML += `
filter: brightness(1.5); filter: brightness(1.5);
} }
button.close{ .modal{
background: transparent; background: #f0f0f0;
color: #000; padding: 20px 20px 10px 20px;
border-radius: 15px;
display: inline-block; display: inline-block;
float: right; position:relative;
z-index:50;
height:unset;
overflow:hidden;
margin-left:10px;
}
.modal.fold {
height:22px;
overflow:hidden;
}
.modal .top{
background: var(--xrsh-light-primary);
border-radius:15px;
position: absolute;
z-index:1;
left: 0;
right: 0;
top: 0;
height: 25px;
padding: 13px 10px 1px 14px;
color: #FFF;
}
/* remove this to see why this is a workaround for border-radius bug */
.modal .top .title{
position: absolute;
background: var(--xrsh-light-primary);
display: block;
left: 0;
right: 0;
height: 27px;
padding: 0px 0px 0px 20px;
font-weight: bold;
}
.modal .top button{
padding: 5px 7px;
background: var(--xrsh-modal-button-bg);
color: var(--xrsh-modal-button-fg);
font-weight: bold;
float:right;
}
.modal .top button:hover{
filter: brightness(1.1);
}
.modal .top button.close{
background: transparent;
display: block;
font-size: 20px; font-size: 20px;
padding: 0; padding: 0;
transform: translate(-4px,-3px) scale(1.3,1); transform: translate(-4px,-3px) scale(1.5,1);
margin-left: 20px; margin-left: 6px;
}
.modal .top button.fold{
background: transparent;
border: none;
margin: 0;
margin-left: 30px;
transform: scale(1.2) translate(0px,-6px);
} }
legend{ legend{