wip
This commit is contained in:
parent
f6132a29f4
commit
d3b767b665
7 changed files with 961 additions and 810 deletions
|
|
@ -6,11 +6,11 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||||
|
|
||||||
<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
|
<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
|
||||||
<script src="./../../../dist/xrfragment.aframe.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/aframe-blink-controls/dist/aframe-blink-controls.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/aframe-blink-controls/dist/aframe-blink-controls.min.js"></script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<script src="./../../../dist/xrfragment.aframe.js"></script>
|
||||||
|
|
||||||
<a-scene xr-mode-ui="XRMode: xr" renderer="colorManagement: true; highRefreshRate:true" light="defaultLightsEnabled: false">
|
<a-scene xr-mode-ui="XRMode: xr" renderer="colorManagement: true; highRefreshRate:true" light="defaultLightsEnabled: false">
|
||||||
<a-entity id="player" wasd-controls look-controls>
|
<a-entity id="player" wasd-controls look-controls>
|
||||||
|
|
@ -28,15 +28,15 @@
|
||||||
</a-scene>
|
</a-scene>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// add your logo
|
// the xrf-menu is totally optional but can be handy
|
||||||
|
// to quickly add your logo & buttons etc
|
||||||
XRFMENU.logo = './../../assets/logo.png'
|
XRFMENU.logo = './../../assets/logo.png'
|
||||||
XRFMENU.morelabel = '⚡'
|
XRFMENU.morelabel = '⚡'
|
||||||
// add your menubuttons:
|
// add your menubuttons:
|
||||||
XRFMENU.html.push(`<a class="btn" aria-label="button" aria-description="about menu" onclick="window.showAbout()">💁 about</a><br>`)
|
XRFMENU.buttons = XRFMENU.buttons.concat([`<a class="btn" aria-label="button" aria-description="about menu" onclick="XRFMENU.showAbout()">💁 about</a><br>`])
|
||||||
showAbout = () => window.notify(`
|
XRFMENU.showAbout = () => window.notify(`
|
||||||
<h1>💁 Hi there!</h1>
|
<h1>💁 Hi there!</h1>
|
||||||
|
|
||||||
|
|
||||||
This XR fragments experience works almost anywhere.<br>
|
This XR fragments experience works almost anywhere.<br>
|
||||||
Allowing rich audiovisual events with(out)<br>
|
Allowing rich audiovisual events with(out)<br>
|
||||||
VR/AR headsets (it's awesome though ♥️)<br>
|
VR/AR headsets (it's awesome though ♥️)<br>
|
||||||
|
|
|
||||||
39
src/3rd/js/$.js
Normal file
39
src/3rd/js/$.js
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
// this project uses #vanillajs #proxies #clean #noframework
|
||||||
|
//
|
||||||
|
// menu = $proxy({
|
||||||
|
// attach: 'body',
|
||||||
|
// html: (el) => `<ul><li>${el.items.join('</li><li>')}</li></lu>`,
|
||||||
|
// items: [1,2],
|
||||||
|
// on: (el,k,v) => {
|
||||||
|
// switch(k){
|
||||||
|
// default: return el.outerHTML = el.html(el)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// menu.items = menu.items.concat([3,4])
|
||||||
|
// $('#foo')
|
||||||
|
// $$('.someclass').map( (el) => el.classList.toggle() )
|
||||||
|
//
|
||||||
|
$proxy = (opts) => {
|
||||||
|
let el = document.createElement('div')
|
||||||
|
el.innerHTML = opts.html(opts)
|
||||||
|
el.querySelector = el.querySelector.bind(el)
|
||||||
|
el.appendChild = el.appendChild.bind(el)
|
||||||
|
let parent = typeof opts.attach == 'string' ? document.querySelector(opts.attach) : opts.attach
|
||||||
|
parent.appendChild( el )
|
||||||
|
el.on = el.addEventListener.bind(el)
|
||||||
|
for( let i in opts ) el[i] = opts[i]
|
||||||
|
return new Proxy( el, {
|
||||||
|
get: (el,k,receiver) => el[k] || '',
|
||||||
|
set: (el,k,v) => { el[k] = v; el.on(el,k,v) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$ = typeof $ != 'undefined' ? $ : (s) => document.querySelector(s) // respect jquery
|
||||||
|
$$ = typeof $$ != 'undefined' ? $$ : (s) => [...document.querySelectorAll(s)] // zepto etc.
|
||||||
|
|
||||||
|
$el = (html) => {
|
||||||
|
let el = document.createElement('div')
|
||||||
|
el.innerHTML = html
|
||||||
|
return el.children[0]
|
||||||
|
}
|
||||||
|
|
@ -62,8 +62,6 @@ window.AFRAME.registerComponent('xrf', {
|
||||||
let url = opts.xrf.string
|
let url = opts.xrf.string
|
||||||
let isLocal = url.match(/^#/)
|
let isLocal = url.match(/^#/)
|
||||||
let hasPos = url.match(/pos=/)
|
let hasPos = url.match(/pos=/)
|
||||||
let meeting = $('[meeting]') ? $('[meeting]').components['meeting'] : false
|
|
||||||
if(meeting) meeting.notifyTeleport(url)
|
|
||||||
if( isLocal && hasPos ){
|
if( isLocal && hasPos ){
|
||||||
// local teleports only
|
// local teleports only
|
||||||
let fastFadeMs = 200
|
let fastFadeMs = 200
|
||||||
|
|
|
||||||
|
|
@ -1,391 +1,391 @@
|
||||||
AFRAME.registerComponent('meeting', {
|
//
|
||||||
schema:{
|
//AFRAME.registerComponent('meeting', {
|
||||||
id:{ required:true, type:'string'},
|
// schema:{
|
||||||
visitorname:{required:false,type:'string'},
|
// id:{ required:true, type:'string'},
|
||||||
parentRoom:{required:false,type:'string'},
|
// visitorname:{required:false,type:'string'},
|
||||||
link:{required:false,type:'string'}
|
// parentRoom:{required:false,type:'string'},
|
||||||
},
|
// link:{required:false,type:'string'},
|
||||||
remove: function(){
|
// },
|
||||||
if( this.room ) this.room.leave()
|
//
|
||||||
this.meeting.remove()
|
// // reactive HTML elements
|
||||||
},
|
// $: document.createElement('div'),
|
||||||
update: function(){
|
// cameras: {},
|
||||||
setTimeout( () => {
|
// audios: {},
|
||||||
this.remove()
|
// messages: [],
|
||||||
this.init()
|
// placeholderInput: 'enter name here',
|
||||||
},100)
|
// hideChat: false,
|
||||||
},
|
// log: [],
|
||||||
init: function(){
|
// selfStream: null,
|
||||||
// embed https://github.com/dmotz/trystero (trystero-torrent.min.js build)
|
//
|
||||||
|
// events:{
|
||||||
// add css+html
|
// connect: function(e){
|
||||||
let el = this.meeting = document.createElement("div")
|
// if( !this.data.visitorname ){
|
||||||
el.id = 'meeting'
|
// this.data.appendHTMLMessage("Please enter your name below",["info"])
|
||||||
el.innerHTML += `<style type="text/css">
|
// }else{
|
||||||
#videos{
|
// if( this.data.parentRoom ) this.data.$chat.add(`leaving ${this.data.parentRoom}`,["info"]);
|
||||||
display:grid-auto-columns;
|
// }
|
||||||
grid-column-gap:5px;
|
// },
|
||||||
margin-bottom:15px;
|
// },
|
||||||
position: fixed;
|
//
|
||||||
top: 0;
|
// remove: function(){
|
||||||
left: 0;
|
// this.el.emit("remove",{})
|
||||||
bottom: 0;
|
// this.data.$.remove()
|
||||||
right: 0;
|
// },
|
||||||
margin: 15px;
|
//
|
||||||
z-index:1500;
|
// update: function(){
|
||||||
}
|
// setTimeout( () => {
|
||||||
#videos > video{
|
// this.remove()
|
||||||
border-radius:7px;
|
// this.initMeeting()
|
||||||
display:inline-block;
|
// },100)
|
||||||
background:black;
|
// },
|
||||||
width:80px;
|
//
|
||||||
height:60px;
|
// init: function(){
|
||||||
margin-right:5px;
|
//
|
||||||
margin-bottom:5px;
|
// //// when teleport is clicked
|
||||||
vertical-align:top;
|
// //AFRAME.XRF.addEventListener('href', (opts) => {
|
||||||
pointer-events:all;
|
// // if( !opts.click ) return // ignore mouseovers etc
|
||||||
}
|
// // let url = opts.xrf.string
|
||||||
#videos > video:hover{
|
// // let isTeleport = url.match(/(:\/\/|pos=)/)
|
||||||
filter: brightness(1.8);
|
// // if( isTeleport ){
|
||||||
cursor:pointer;
|
// // url = url[0] == '#' ? document.location.href.replace(/#.*/, opts.xrf.string ) : '?'+opts.xrf.string
|
||||||
}
|
// // this.notifyTeleport( url )
|
||||||
|
// // }
|
||||||
#chatbar,
|
// //})
|
||||||
button#showchat{
|
// this.initMeeting()
|
||||||
z-index: 1500;
|
//
|
||||||
position: fixed;
|
// },
|
||||||
bottom: 20px;
|
//
|
||||||
left: 20px;
|
// initMeeting: function(){
|
||||||
width: 48%;
|
// this.data.link = document.location.href
|
||||||
background: white;
|
// this.initHTML()
|
||||||
padding: 0px 0px 0px 15px;
|
//
|
||||||
border-radius: 30px;
|
// // load plugins
|
||||||
max-width: 500px;
|
// if( window.meeting.trystero ) new window.meeting.trystero(this.el,this,this.data)
|
||||||
box-sizing: border-box;
|
//
|
||||||
box-shadow: 0px 0px 5px 5px #0002;
|
// this.getMedia()
|
||||||
}
|
// this.emit("connect",{})
|
||||||
button#showchat{
|
// },
|
||||||
z-index:1550;
|
//
|
||||||
color:white;
|
// getMedia: async function(){
|
||||||
border:0;
|
// this.data.selfStream = await navigator.mediaDevices.getUserMedia({
|
||||||
display:none;
|
// audio: true,
|
||||||
height: 44px;
|
// video: {
|
||||||
background:#07F;
|
// width: 320,
|
||||||
font-weight:bold;
|
// height: 240,
|
||||||
}
|
// frameRate: {
|
||||||
#chatbar input{
|
// ideal: 30,
|
||||||
border:none;
|
// min: 10
|
||||||
width:90%;
|
// }
|
||||||
box-sizing:border-box;
|
// }
|
||||||
}
|
// })
|
||||||
#chat{
|
// let meVideo = this.createVideoElement(this.data.selfStream)
|
||||||
position: absolute;
|
// meVideo.muted = true
|
||||||
top: 100px;
|
// },
|
||||||
left: 0;
|
//
|
||||||
right: 0;
|
// // central function to broadcast stuff to chat
|
||||||
bottom: 88px;
|
// send: function(opts){
|
||||||
padding: 15px;
|
// opts = { sendLocal: true, sendNetwork:true, ...opts }
|
||||||
pointer-events: none;
|
// if( opts.sendNetwork ){
|
||||||
overflow-y:auto;
|
// if( !this.sendChat ) return
|
||||||
}
|
// this.sendChat({opts}) // send to network
|
||||||
#chat .msg{
|
// }
|
||||||
background: #fff;
|
// if( opts.sendLocal ){
|
||||||
display: inline-block;
|
// this.data.$chat.add( opts ) // send to HTML screen
|
||||||
padding: 6px 17px;
|
// }
|
||||||
border-radius: 20px;
|
// },
|
||||||
color: #000c;
|
//
|
||||||
margin-bottom: 10px;
|
// createVideoElement: function(stream,id){
|
||||||
line-height:23px;
|
// let video = this.data.videos[peerId]
|
||||||
pointer-events:visible;
|
// const videoContainer = document.getElementById('videos')
|
||||||
border: 1px solid #ccc;
|
// // if this peer hasn't sent a stream before, create a video element
|
||||||
}
|
// if (!video) {
|
||||||
#chat .msg.info{
|
// video = document.createElement('video')
|
||||||
background: #333;
|
// video.autoplay = true
|
||||||
color: #FFF;
|
//
|
||||||
font-size: 14px;
|
// // add video element to the DOM
|
||||||
padding: 0px 16px;
|
// videoContainer.appendChild(video)
|
||||||
}
|
// }
|
||||||
#chat .msg.info a,
|
//
|
||||||
#chat .msg.info a:visited{
|
// video.srcObject = stream
|
||||||
color: #aaf;
|
// video.resize = (state) => {
|
||||||
text-decoration: none;
|
// if( video.resize.state == undefined ) video.resize.state = false
|
||||||
transition:0.3s;
|
// if( state == undefined ) state = (video.resize.state = !video.resize.state )
|
||||||
}
|
// video.style.width = state ? '320px' : '80px'
|
||||||
#chat .msg.info a:hover,
|
// video.style.height = state ? '200px' : '60px'
|
||||||
#chat button:hover{
|
// }
|
||||||
filter: brightness(1.8);
|
// this.data.videos[ id || 'me' ] = video
|
||||||
text-decoration: underline;
|
// return video
|
||||||
}
|
// },
|
||||||
#chat button {
|
//
|
||||||
margin: 0px 15px 10px 0px;
|
// initHTML: function(){
|
||||||
background: #07F;
|
//
|
||||||
color: #FFF;
|
// // add css
|
||||||
border-radius: 7px;
|
// this.data.$.innerHTML += `<style type="text/css">
|
||||||
padding: 11px 15px;
|
// #videos{
|
||||||
border: 0;
|
// display:grid-auto-columns;
|
||||||
font-weight: bold;
|
// grid-column-gap:5px;
|
||||||
box-shadow: 0px 0px 5px 5px #0002;
|
// margin-bottom:15px;
|
||||||
pointer-events:all;
|
// position: fixed;
|
||||||
}
|
// top: 0;
|
||||||
#chat,#chatbar,#chatbar *, #chat *{
|
// left: 0;
|
||||||
font-family:monospace;
|
// bottom: 0;
|
||||||
font-size:15px;
|
// right: 0;
|
||||||
}
|
// margin: 15px;
|
||||||
</style>
|
// z-index:1500;
|
||||||
<div id="videos" style="pointer-events:none"></div>
|
// }
|
||||||
<div id="chat" aria-live="assertive" aria-relevant></div>
|
// #videos > video{
|
||||||
<button id="showchat" class="btn">show chat</button>
|
// border-radius:7px;
|
||||||
<div id="chatbar">
|
// display:inline-block;
|
||||||
<input id="chatline" type="text" placeholder="enter name"></input>
|
// background:black;
|
||||||
</div>`
|
// width:80px;
|
||||||
document.body.appendChild(el)
|
// height:60px;
|
||||||
|
// margin-right:5px;
|
||||||
let chatline = this.chatline = document.querySelector("#chatline")
|
// margin-bottom:5px;
|
||||||
let chat = this.chat = document.querySelector("#chat")
|
// vertical-align:top;
|
||||||
chat.log = [] // save raw chatlog to prime new visitors
|
// pointer-events:all;
|
||||||
chat.append = (str,classes,buttons) => this.chatAppend(str,classes,buttons)
|
// }
|
||||||
|
// #videos > video:hover{
|
||||||
this.initChatLine()
|
// filter: brightness(1.8);
|
||||||
|
// cursor:pointer;
|
||||||
if( !this.data.visitorname ) this.chat.append("Please enter your name below",["info"])
|
// }
|
||||||
else{
|
//
|
||||||
if( this.data.parentRoom ) this.chat.append(`leaving ${this.data.parentRoom}`,["info"]);
|
// #chatbar,
|
||||||
this.trysteroInit()
|
// button#showchat{
|
||||||
}
|
// z-index: 1500;
|
||||||
},
|
// position: fixed;
|
||||||
|
// bottom: 20px;
|
||||||
chatAppend: function(str,classes,buttons){
|
// left: 20px;
|
||||||
if( str ){
|
// width: 48%;
|
||||||
str = str.replace('\n', "<br>")
|
// background: white;
|
||||||
.replace(/^[a-zA-Z-0-9]+?[:\.]/,'<b>$&</b>')
|
// padding: 0px 0px 0px 15px;
|
||||||
let el = this.createMsg(str)
|
// border-radius: 30px;
|
||||||
if( classes ) classes.map( (c) => el.classList.add(c) )
|
// max-width: 500px;
|
||||||
this.chat.appendChild(el) // send to screen
|
// box-sizing: border-box;
|
||||||
this.chat.innerHTML += '<br>'
|
// box-shadow: 0px 0px 5px 5px #0002;
|
||||||
if( !classes ) this.chat.log.push(str)
|
// }
|
||||||
}
|
// button#showchat{
|
||||||
if( buttons ){
|
// z-index:1550;
|
||||||
for( let i in buttons ){
|
// color:white;
|
||||||
let btn = document.createElement("button")
|
// border:0;
|
||||||
btn.innerText = i
|
// display:none;
|
||||||
btn.addEventListener('click', () => buttons[i]() )
|
// height: 44px;
|
||||||
this.chat.appendChild(btn)
|
// background:#07F;
|
||||||
}
|
// font-weight:bold;
|
||||||
this.chat.innerHTML += '<br>'
|
// }
|
||||||
}
|
// #chatbar input{
|
||||||
this.chat.scrollTop = this.chat.scrollHeight; // scroll to bottom
|
// border:none;
|
||||||
},
|
// width:90%;
|
||||||
|
// box-sizing:border-box;
|
||||||
trysteroInit: async function(){
|
// }
|
||||||
const { joinRoom } = await import("./../../../dist/trystero-torrent.min.js");
|
// #chat{
|
||||||
|
// position: absolute;
|
||||||
if( !document.location.hash.match(/meet/) ){
|
// top: 100px;
|
||||||
document.location.hash += document.location.hash.match(/#/) ? '&meet' : '#meet'
|
// left: 0;
|
||||||
}
|
// right: 0;
|
||||||
let roomname = this.roomname = this.data.link = document.location.href
|
// bottom: 88px;
|
||||||
const config = this.config = {appId: this.data.id }
|
// padding: 15px;
|
||||||
const room = this.room = joinRoom(config, roomname )
|
// pointer-events: none;
|
||||||
this.chat.append("joined meeting at "+roomname,["info"]);
|
// overflow-y:auto;
|
||||||
this.chat.append("copied meeting link to clipboard",["info"]);
|
// }
|
||||||
|
// #chat .msg{
|
||||||
const idsToNames = this.idsToNames = {}
|
// background: #fff;
|
||||||
const [sendName, getName] = room.makeAction('name')
|
// display: inline-block;
|
||||||
const [sendChat, getChat] = this.room.makeAction('chat')
|
// padding: 6px 17px;
|
||||||
this.sendChat = sendChat
|
// border-radius: 20px;
|
||||||
this.sendName = sendName
|
// color: #000c;
|
||||||
this.getChat = getChat
|
// margin-bottom: 10px;
|
||||||
this.getName = getName
|
// line-height:23px;
|
||||||
|
// pointer-events:visible;
|
||||||
// tell other peers currently in the room our name
|
// border: 1px solid #ccc;
|
||||||
idsToNames[ room.selfId ] = this.data.visitorname.substr(0,15)
|
// }
|
||||||
sendName( this.data.visitorname )
|
// #chat .msg.info{
|
||||||
|
// background: #333;
|
||||||
// listen for peers naming themselves
|
// color: #FFF;
|
||||||
getName((name, peerId) => (idsToNames[peerId] = name))
|
// font-size: 14px;
|
||||||
|
// padding: 0px 16px;
|
||||||
this.initChat()
|
// }
|
||||||
|
// #chat .msg.info a,
|
||||||
// this object can store audio instances for later
|
// #chat .msg.info a:visited{
|
||||||
const peerAudios = this.peerAudios = {}
|
// color: #aaf;
|
||||||
const peerVideos = this.peerVideos = {}
|
// text-decoration: none;
|
||||||
// get a local audio stream from the microphone
|
// transition:0.3s;
|
||||||
const selfStream = await navigator.mediaDevices.getUserMedia({
|
// }
|
||||||
audio: true,
|
// #chat .msg.info a:hover,
|
||||||
video: {
|
// #chat button:hover{
|
||||||
width: 320,
|
// filter: brightness(1.8);
|
||||||
height: 240,
|
// text-decoration: underline;
|
||||||
frameRate: {
|
// }
|
||||||
ideal: 30,
|
// #chat button {
|
||||||
min: 10
|
// margin: 0px 15px 10px 0px;
|
||||||
}
|
// background: #07F;
|
||||||
}
|
// color: #FFF;
|
||||||
})
|
// border-radius: 7px;
|
||||||
let meVideo = this.addVideo(selfStream, room.selfId)
|
// padding: 11px 15px;
|
||||||
meVideo.muted = true
|
// border: 0;
|
||||||
|
// font-weight: bold;
|
||||||
// send stream to peers currently in the room
|
// box-shadow: 0px 0px 5px 5px #0002;
|
||||||
room.addStream(selfStream)
|
// pointer-events:all;
|
||||||
|
// }
|
||||||
// send stream + chatlog to peers who join later
|
// #chat,#chatbar,#chatbar *, #chat *{
|
||||||
room.onPeerJoin( (peerId) => {
|
// font-family:monospace;
|
||||||
room.addStream(selfStream, peerId)
|
// font-size:15px;
|
||||||
sendName( name, peerId)
|
// }
|
||||||
this.sendChat({prime: this.chat.log}, peerId )
|
// </style>
|
||||||
})
|
// <div id="videos" style="pointer-events:none"></div>
|
||||||
|
// <div id="chat" aria-live="assertive" aria-relevant></div>
|
||||||
room.onPeerLeave( (peerId) => {
|
// <div id="chatfooter"></div>
|
||||||
console.log(`${idsToNames[peerId] || 'a visitor'} left`)
|
// `
|
||||||
if( peerVideos[peerId] ){
|
// document.body.appendChild(this.data.$)
|
||||||
peerVideos[peerId].remove()
|
//
|
||||||
delete peerVideos[peerId]
|
// // reactive logic
|
||||||
}
|
// this.data = new Proxy(this.data, {
|
||||||
delete idsToNames[peerId]
|
// html: {
|
||||||
})
|
// chatbar: (data) => data.showChat
|
||||||
|
// ? `<div id="chatbar">
|
||||||
// handle streams from other peers
|
// <input id="chatline" type="text" placeholder="${data.placeholderInput}"></input>
|
||||||
room.onPeerStream((stream, peerId) => {
|
// </div>`
|
||||||
// create an audio instance and set the incoming stream
|
// : `<button id="showchat" class="btn">show chat</button>`
|
||||||
const audio = new Audio()
|
// },
|
||||||
audio.srcObject = stream
|
// get(data,k ){ return data[k] },
|
||||||
audio.autoplay = true
|
// set(data,k,v){
|
||||||
|
// data[k] = v
|
||||||
// add the audio to peerAudio object if you want to address it for something
|
// switch( k ){
|
||||||
// later (volume, etc.)
|
//
|
||||||
peerAudios[peerId] = audio
|
// case 'cameras':{
|
||||||
})
|
// data.$videos.innerHTML = ''
|
||||||
|
// for( let k in data.cameras ) el.appendChild( data.cameras[k] ) )
|
||||||
room.onPeerStream((stream, peerId) => {
|
// return
|
||||||
this.addVideo(stream,peerId)
|
// }
|
||||||
})
|
//
|
||||||
|
// case 'audios':{
|
||||||
// show hide chat on small screens
|
// data.$videos.innerHTML = ''
|
||||||
},
|
// for( let k in data.cameras ) el.appendChild( data.cameras[k] ) )
|
||||||
|
// return
|
||||||
addVideo: function(stream,peerId){
|
// }
|
||||||
let video = this.peerVideos[peerId]
|
//
|
||||||
const videoContainer = document.getElementById('videos')
|
// case 'showChat':{
|
||||||
// if this peer hasn't sent a stream before, create a video element
|
// data.$chatfooter.innerHTML = this.html.chatbar(data)
|
||||||
if (!video) {
|
// data.$chatline.addEventListener("keydown", this.onChatInput )
|
||||||
video = document.createElement('video')
|
// if( v ){
|
||||||
video.autoplay = true
|
// data.$chatfooter.querySelector('#chatline').focus()
|
||||||
|
// }
|
||||||
// add video element to the DOM
|
// return
|
||||||
videoContainer.appendChild(video)
|
// }
|
||||||
}
|
//
|
||||||
|
// }
|
||||||
video.srcObject = stream
|
// },
|
||||||
video.resize = (state) => {
|
// })
|
||||||
if( video.resize.state == undefined ) video.resize.state = false
|
//
|
||||||
if( state == undefined ) state = (video.resize.state = !video.resize.state )
|
// // trigger 1st render
|
||||||
video.style.width = state ? '320px' : '80px'
|
// this.data.showChat = true
|
||||||
video.style.height = state ? '200px' : '60px'
|
//
|
||||||
}
|
// // setup handles
|
||||||
|
// this.data.$videos = this.data.$.querySelector('#meeting #videos')
|
||||||
video.addEventListener('click', () => video.resize() )
|
// this.data.$chatfooter = this.data.$.querySelector('#meeting #chatfooter')
|
||||||
|
// this.data.$chatline = this.data.$chatfooter.querySelector('#chatline')
|
||||||
this.peerVideos[peerId] = video
|
// this.data.$chat = this.data.$.querySelector('#meeting #chat')
|
||||||
return video
|
// this.data.$chat.add = this.addMessage
|
||||||
},
|
//
|
||||||
|
// },
|
||||||
createMsg: function(str){
|
//
|
||||||
let el = document.createElement("div")
|
// addMessage: function(opts){
|
||||||
el.className = "msg"
|
// let {str,classes,buttons) = opts
|
||||||
el.innerHTML = this.linkify(str)
|
// let el = this.data.$chat
|
||||||
return el
|
//
|
||||||
},
|
// const createMsg = (str) => {
|
||||||
|
// let el = document.createElement("div")
|
||||||
// central function to broadcast stuff to chat
|
// el.className = "msg"
|
||||||
send: function(str,classes,buttons){
|
// el.innerHTML = this.linkify(str)
|
||||||
if( !this.sendChat ) return
|
// return el
|
||||||
this.sendChat({content:str}) // send to network
|
// }
|
||||||
this.chat.append(str,classes,buttons) // send to screen
|
//
|
||||||
},
|
// if( str ){
|
||||||
|
// str = str.replace('\n', "<br>")
|
||||||
initChatLine: function(){
|
// .replace(/^[a-zA-Z-0-9]+?[:\.]/,'<b>$&</b>')
|
||||||
let chatline = this.chatline = document.querySelector("#chatline")
|
// let msg = this.createMsg(str)
|
||||||
chatline.addEventListener("keydown", (e) => {
|
// if( classes ) classes.map( (c) => msg.classList.add(c) )
|
||||||
if( e.key !== "Enter" ) return
|
// el.appendChild(msg) // send to screen
|
||||||
if( !this.data.visitorname ){
|
// el.innerHTML += '<br>'
|
||||||
this.data.visitorname = chatline.value.toLowerCase()
|
// if( !classes ) this.data.log.push(str)
|
||||||
this.data.visitorname = this.data.visitorname.replace(/[^a-z]+/g,'-')
|
// }
|
||||||
this.chat.append("note: camera/mic access is totally optional ♥️",["info"])
|
// if( buttons ){
|
||||||
this.chatline.setAttribute("placeholder","chat here")
|
// for( let i in buttons ){
|
||||||
this.trysteroInit()
|
// let btn = document.createElement("button")
|
||||||
}else{
|
// btn.innerText = i
|
||||||
let str = `${this.idsToNames[ this.room.selfId ]}: ${chatline.value.substr(0,65515).trim()}`
|
// btn.addEventListener('click', () => buttons[i]() )
|
||||||
this.send(str)
|
// el.appendChild(btn)
|
||||||
}
|
// }
|
||||||
chatline.value = ''
|
// el.innerHTML += '<br>'
|
||||||
event.preventDefault();
|
// }
|
||||||
event.target.blur()
|
// el.scrollTop = el.scrollHeight; // scroll to bottom
|
||||||
})
|
// }
|
||||||
|
// },
|
||||||
// on small screens/mobile make chat toggle-able
|
//
|
||||||
if( window.outerWidth < 1024 ){
|
// onChatInput: function(e){
|
||||||
let show = (state) => () => {
|
// if( e.key !== "Enter" ) return
|
||||||
$('#chat').style.display = state ? '' : 'none'
|
// let $chatline = this.data.$chatline
|
||||||
$('#chatline').style.display = state ? '' : 'none'
|
// if( !this.data.visitorname ){
|
||||||
$('button#showchat').style.display = state ? 'none' : 'block'
|
// this.data.visitorname = chatline.value.toLowerCase()
|
||||||
}
|
// this.data.visitorname = this.data.visitorname.replace(/[^a-z]+/g,'-')
|
||||||
$('.a-canvas').addEventListener('click', show(false) )
|
// this.send({message:"note: camera/mic access is totally optional ♥️", classes:["info"], isLocal:false})
|
||||||
$('.a-canvas').addEventListener('touchstart', show(false) )
|
// $chatline.setAttribute("placeholder","chat here")
|
||||||
$('#showchat').addEventListener('touchstart', show(true) )
|
// }else{
|
||||||
$('#showchat').addEventListener('click', show(true) )
|
// let str = `${this.data.visitorname}: ${$chatline.value.substr(0,65515).trim()}`
|
||||||
}
|
// this.send({message:str})
|
||||||
},
|
// }
|
||||||
|
// $chatline.value = ''
|
||||||
initChat: function(){
|
// event.preventDefault();
|
||||||
// listen for chatmsg
|
// event.target.blur()
|
||||||
this.getChat((data, peerId) => {
|
// },
|
||||||
if( data.prime ){
|
//
|
||||||
if( this.chat.primed ) return // only prime once
|
// enableSmallScreen: function(){
|
||||||
console.log("receiving prime")
|
// // on small screens/mobile make chat toggle-able
|
||||||
data.prime.map( (l) => chat.append(l) ) // send log to screen
|
// if( window.outerWidth < 1024 ){
|
||||||
this.chat.primed = true
|
// let show = (state) => () => this.data.showChat = state
|
||||||
}
|
// $('.a-canvas').addEventListener('click', () => show(false) )
|
||||||
chat.append(data.content,data.classes,data.buttons) // send to screen
|
// $('.a-canvas').addEventListener('touchstart', () => show(false) )
|
||||||
})
|
// $('#showchat').addEventListener('touchstart', () => show(true) )
|
||||||
|
// $('#showchat').addEventListener('click', () => show(true) )
|
||||||
this.notifyTeleport()
|
// }
|
||||||
return this
|
// }
|
||||||
},
|
//
|
||||||
|
// //notifyTeleport: function(url){
|
||||||
notifyTeleport: function(url,buttons){
|
// // url = url || this.roomname
|
||||||
// send to network
|
// // url = url.replace(/(#|&)meet/,'')
|
||||||
this.sendChat({
|
// // let message = `${this.data.visitorname} teleported to ${url}`
|
||||||
content: `${this.data.visitorname} teleported to ${this.roomname}`,
|
// // this.send({
|
||||||
classes: ["info"],
|
// // message,
|
||||||
buttons
|
// // classes: ["info"]
|
||||||
})
|
// // })
|
||||||
},
|
// //},
|
||||||
|
//
|
||||||
linkify: function(t){
|
// //linkify: function(t){
|
||||||
const m = t.match(/(?<=\s|^)[a-zA-Z0-9-:/]+[?\.][a-zA-Z0-9-].+?(?=[.,;:?!-]?(?:\s|$))/g)
|
// // const m = t.match(/(?<=\s|^)[a-zA-Z0-9-:/]+[?\.][a-zA-Z0-9-].+?(?=[.,;:?!-]?(?:\s|$))/g)
|
||||||
if (!m) return t
|
// // if (!m) return t
|
||||||
const a = []
|
// // const a = []
|
||||||
m.forEach(x => {
|
// // m.forEach(x => {
|
||||||
const [t1, ...t2] = t.split(x)
|
// // const [t1, ...t2] = t.split(x)
|
||||||
a.push(t1)
|
// // a.push(t1)
|
||||||
t = t2.join(x)
|
// // t = t2.join(x)
|
||||||
let y = (!(x.match(/:\/\//)) ? 'https://' : '') + x
|
// // let url = (!(x.match(/:\/\//)) ? 'https://' : '') + x
|
||||||
let attr = 'target="_blank"'
|
// // let attr = `href="${url}" target="_blank"`
|
||||||
if (isNaN(x) ){
|
// // if (isNaN(x) ){
|
||||||
let url_human = y.split('/')[2]
|
// // let url_human = url.split('/')[2]
|
||||||
let isXRFragment = y.match(/\.(glb|gltf|obj|usdz|fbx|col)/)
|
// // let isXRFragment = url.match(/\.(glb|gltf|obj|usdz|fbx|col)/)
|
||||||
if( isXRFragment ){ // detect xr fragments
|
// // if( isXRFragment ){ // detect xr fragments
|
||||||
isMeeting = y.match(/(#|&)meet/)
|
// // isMeeting = url.match(/(#|&)meet/)
|
||||||
url_human = y.replace(/.*[?\?]/,'') // shorten xr fragment links
|
// // url_human = url.replace(/.*[?\?]/,'') // shorten xr fragment links
|
||||||
.replace(/[?\&]meet/,'')
|
// // .replace(/[?\&]meet/,'')
|
||||||
y = y.replace(/.*[\?]/, '?') // start from search (to prevent page-refresh)
|
// // let onclick = [ `xrf.navigator.to('${url}')` ]
|
||||||
attr = ''
|
// // if( isMeeting ) onclick.push(`$('[meeting]').coms['meeting'].update()`)
|
||||||
if( isMeeting ) attr = `onclick="$('[meeting]').components['meeting'].update()"`
|
// // attr = `onclick="${onclick.join(';')}"`
|
||||||
}
|
// // }
|
||||||
a.push(`<a href="${y}" ${attr} style="pointer-events:all">${url_human}</a>`)
|
// // a.push(`<a ${attr} style="pointer-events:all">${url_human}</a>`)
|
||||||
}else
|
// // }else
|
||||||
a.push(x)
|
// // a.push(x)
|
||||||
})
|
// // })
|
||||||
a.push(t)
|
// // a.push(t)
|
||||||
return a.join('')
|
// // return a.join('')
|
||||||
}
|
// //}
|
||||||
|
//
|
||||||
});
|
//})
|
||||||
|
|
|
||||||
109
src/3rd/js/aframe/meeting.trystero.js
Normal file
109
src/3rd/js/aframe/meeting.trystero.js
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
//window.meeting = window.meeting||{}
|
||||||
|
//window.meeting.trystero = async function(el,com,data){
|
||||||
|
//
|
||||||
|
// // embed https://github.com/dmotz/trystero (trystero-torrent.min.js build)
|
||||||
|
// const { joinRoom } = await import("./../../../dist/trystero-torrent.min.js");
|
||||||
|
// this.room = {
|
||||||
|
// handle: null,
|
||||||
|
// link: null,
|
||||||
|
// selfId: null,
|
||||||
|
// names: {},
|
||||||
|
// chat: { send: null, get: null },
|
||||||
|
// name: { send: null, get: null },
|
||||||
|
// config: {appId: this.data.id }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// this.sendName = null
|
||||||
|
//
|
||||||
|
// this.send = (opts) => com.send({...opts, source: 'trystero'})
|
||||||
|
//
|
||||||
|
// el.addEventListener('remove', () => {
|
||||||
|
// if( this.room.handle ) this.room.handle.leave()
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// el.addEventListener('connect', async () => {
|
||||||
|
// let room = this.room
|
||||||
|
//
|
||||||
|
// room.link = this.data.link
|
||||||
|
// if( !room.linkmatch(/(#|&)meet/) ){
|
||||||
|
// room.link = room.link.match(/#/) ? '&meet' : '#meet'
|
||||||
|
// }
|
||||||
|
// room.handle = joinRoom( room.config, room.link )
|
||||||
|
// room.selfId = room.handle.selfId
|
||||||
|
//
|
||||||
|
// this.send({
|
||||||
|
// message: "joined meeting at "+roomname.replace(/(#|&)meet/,''), // dont trigger init()
|
||||||
|
// classes: ["info"],
|
||||||
|
// sendNetwork:false
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// this.send({
|
||||||
|
// message:"copied meeting link to clipboard",
|
||||||
|
// classes: ["info"],
|
||||||
|
// sendNetwork:false
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // setup trystero events
|
||||||
|
// const [sendName, getName] = room.makeAction('name')
|
||||||
|
// const [sendChat, getChat] = room.makeAction('chat')
|
||||||
|
// room.chat.send = sendChat
|
||||||
|
// room.chat.get = getChat
|
||||||
|
// room.name.send = sendName
|
||||||
|
// room.name.get = getName
|
||||||
|
//
|
||||||
|
// // tell other peers currently in the room our name
|
||||||
|
// room.names[ room.selfId ] = com.data.visitorname.substr(0,15)
|
||||||
|
// room.name.send( com.data.visitorname )
|
||||||
|
//
|
||||||
|
// // listen for peers naming themselves
|
||||||
|
// this.name.get((name, peerId) => (room.names[peerId] = name))
|
||||||
|
//
|
||||||
|
// // send self stream to peers currently in the room
|
||||||
|
// room.addStream(com.selfStream)
|
||||||
|
//
|
||||||
|
// // send stream + chatlog to peers who join later
|
||||||
|
// room.onPeerJoin( (peerId) => {
|
||||||
|
// room.addStream( com.selfStream, peerId)
|
||||||
|
// room.name.send( com.data.visitorname, peerId)
|
||||||
|
// room.chat.send({prime: com.log}, peerId )
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// room.onPeerLeave( (peerId) => {
|
||||||
|
// console.log(`${room.names[peerId] || 'a visitor'} left`)
|
||||||
|
// if( com.videos[peerId] ){
|
||||||
|
// com.videos[peerId].remove()
|
||||||
|
// delete com.videos[peerId]
|
||||||
|
// }
|
||||||
|
// delete room.names[peerId]
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // handle streams from other peers
|
||||||
|
// room.onPeerStream((stream, peerId) => {
|
||||||
|
// // create an audio instance and set the incoming stream
|
||||||
|
// const audio = new Audio()
|
||||||
|
// audio.srcObject = stream
|
||||||
|
// audio.autoplay = true
|
||||||
|
// // add the audio to peerAudio object if you want to address it for something
|
||||||
|
// // later (volume, etc.)
|
||||||
|
// com.data.audios[peerId] = audio
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// room.onPeerStream((stream, peerId) => {
|
||||||
|
// com.createVideoElement(stream,peerId)
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // listen for chatmsg
|
||||||
|
// room.chat.get((data, peerId) => {
|
||||||
|
// if( data.prime ){
|
||||||
|
// if( com.log.length > 0 ) return // only prime once
|
||||||
|
// console.log("receiving prime")
|
||||||
|
// data.prime.map( (l) => this.send({message:l, sendLocal:false ) ) // send log to screen
|
||||||
|
// this.chat.primed = true
|
||||||
|
// }
|
||||||
|
// this.send({ ...data, sendLocal: false}) // send to screen
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
@ -4,7 +4,7 @@ AFRAME.registerComponent('xrf-menu', {
|
||||||
},
|
},
|
||||||
init: function(){
|
init: function(){
|
||||||
// add css+html
|
// add css+html
|
||||||
window.XRFMENU.addHTML()
|
window.XRFMENU.init()
|
||||||
|
|
||||||
$('a-scene').addEventListener('XRF', this.onXRFready )
|
$('a-scene').addEventListener('XRF', this.onXRFready )
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@ AFRAME.registerComponent('xrf-menu', {
|
||||||
onXRFready: function(){
|
onXRFready: function(){
|
||||||
|
|
||||||
let XRF = window.AFRAME.XRF
|
let XRF = window.AFRAME.XRF
|
||||||
|
return
|
||||||
XRFMENU.setupMenu( XRF )
|
XRFMENU.setupMenu( XRF )
|
||||||
|
|
||||||
// on localhost enable debugging mode for developer convenience
|
// on localhost enable debugging mode for developer convenience
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,426 @@
|
||||||
// handy shortcuts
|
|
||||||
if( !window.$ ) window.$ = (s) => s ? document.querySelector(s) : false
|
$XRFMENU = $el(
|
||||||
if( !window.$$ ) window.$$ = (s) => s ? [ ...document.querySelectorAll(s) ] : false
|
`<div id="menu" x-bind="XRFMENU">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" type="text/javascript"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
:root {
|
||||||
|
--xrf-primary: #6839dc;
|
||||||
|
--xrf-primary-fg: #FFF;
|
||||||
|
--xrf-light-primary: #ea23cf;
|
||||||
|
--xrf-secondary: #872eff;
|
||||||
|
--xrf-light-xrf-secondary: #ce7df2;
|
||||||
|
--xrf-overlay-bg: #fffb;
|
||||||
|
--xrf-box-shadow: #0005;
|
||||||
|
--xrf-red: red;
|
||||||
|
--xrf-black: #424280;
|
||||||
|
--xrf-white: #fdfdfd;
|
||||||
|
--xrf-dark-gray: #343334;
|
||||||
|
--xrf-gray: #ecf7ff47;
|
||||||
|
--xrf-light-gray: #efefef;
|
||||||
|
--xrf-lighter-gray: #e4e2fb96;
|
||||||
|
--xrf-font-sans-serif: system-ui, -apple-system, segoe ui, roboto, ubuntu, helvetica, cantarell, noto sans, sans-serif;
|
||||||
|
--xrf-font-monospace: menlo, monaco, lucida console, liberation mono, dejavu sans mono, bitstream vera sans mono, courier new, monospace, serif;
|
||||||
|
--xrf-font-size-1: 14px;
|
||||||
|
--xrf-font-size-2: 17px;
|
||||||
|
--xrf-font-size-3: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xrf table tr td{
|
||||||
|
vertical-align:top;
|
||||||
|
}
|
||||||
|
.xrf table tr td:nth-child(1){
|
||||||
|
padding-right:35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xrf button,
|
||||||
|
.xrf input[type="submit"],
|
||||||
|
.xrf .btn {
|
||||||
|
text-decoration:none;
|
||||||
|
background: var(--xrf-primary);
|
||||||
|
border: 0;
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 11px 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: 0.3s;
|
||||||
|
height: 32px;
|
||||||
|
font-size: var(--xrf-font-size-1);
|
||||||
|
color: var(--xrf-primary-fg);
|
||||||
|
line-height: var(--xrf-font-size-1);
|
||||||
|
cursor:pointer;
|
||||||
|
white-space:pre;
|
||||||
|
min-width: 45px;
|
||||||
|
box-shadow: 0px 0px 10px var(--xrf-box-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.xrf button:hover,
|
||||||
|
.xrf input[type="submit"]:hover,
|
||||||
|
.xrf .btn:hover {
|
||||||
|
background: var(--xrf-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.xrf, .xrf *{
|
||||||
|
font-family: var(--xrf-font-sans-serif);
|
||||||
|
font-size: var(--xrf-font-size-1);
|
||||||
|
line-height:27px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea, select, input[type="text"] {
|
||||||
|
background: transparent; /* linear-gradient( var(--xrf-lighter-gray), var(--xrf-gray) ) !important; */
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
color: var(--xrf-light-gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text]{
|
||||||
|
padding:7px 15px;
|
||||||
|
}
|
||||||
|
input{
|
||||||
|
border-radius:7px;
|
||||||
|
margin:5px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
border-bottom: 2px solid var(--xrf-secondary);
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay{
|
||||||
|
background: var(--xrf-overlay-bg);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 48px;
|
||||||
|
box-shadow: 0px 0px 10px var(--xrf-box-shadow);
|
||||||
|
opacity: 0.9;
|
||||||
|
z-index:2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay .logo{
|
||||||
|
width: 92px;
|
||||||
|
position: absolute;
|
||||||
|
top: 9px;
|
||||||
|
left: 93px;
|
||||||
|
height: 30px;
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay > input[type="submit"] {
|
||||||
|
height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay > button#navback,
|
||||||
|
#overlay > button#navforward {
|
||||||
|
height: 32px;
|
||||||
|
font-size: var(--xrf-font-size-1);
|
||||||
|
position: absolute;
|
||||||
|
left: 9px;
|
||||||
|
padding: 2px 13px;
|
||||||
|
border-radius:6px;
|
||||||
|
top: 8px;
|
||||||
|
color: var(--xrf-light-gray);
|
||||||
|
width: 36px;
|
||||||
|
min-width: unset;
|
||||||
|
}
|
||||||
|
#overlay > button#navforward {
|
||||||
|
left:49px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay > #uri {
|
||||||
|
height: 18px;
|
||||||
|
font-size: var(--xrf-font-size-3);
|
||||||
|
position: absolute;
|
||||||
|
left: 200px;
|
||||||
|
top: 9px;
|
||||||
|
max-width: 550px;
|
||||||
|
padding: 5px 0px 5px 5px;
|
||||||
|
width: calc( 63% - 200px);
|
||||||
|
background: #f0f0f0;
|
||||||
|
border-color: #Ccc;
|
||||||
|
border: 2px solid #CCC;
|
||||||
|
border-radius: 7px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.menu .btn{
|
||||||
|
background: var(--xrf-primary);
|
||||||
|
border-radius: 25px;
|
||||||
|
border: 0;
|
||||||
|
padding: 5px 19px;
|
||||||
|
font-weight: 1000;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: var(--xrf-font-size-2);
|
||||||
|
color:var(--xrf-primary-fg);
|
||||||
|
height:33px;
|
||||||
|
z-index:2000;
|
||||||
|
cursor:pointer;
|
||||||
|
min-width:107px;
|
||||||
|
text-decoration:none;
|
||||||
|
display:none;
|
||||||
|
margin-top: 15px;
|
||||||
|
line-height:36px;
|
||||||
|
margin-right:10px;
|
||||||
|
text-align:left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xrf a.btn#more{
|
||||||
|
width: 19px;
|
||||||
|
min-width: 19px;
|
||||||
|
font-size:16px;
|
||||||
|
text-align: center;
|
||||||
|
background:white;
|
||||||
|
}
|
||||||
|
|
||||||
|
html{
|
||||||
|
max-width:unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.render {
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
bottom:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lil-gui.autoPlace{
|
||||||
|
right:0px !important;
|
||||||
|
top:48px !important;
|
||||||
|
height:33vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#VRButton {
|
||||||
|
margin-bottom:20vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 450px) {
|
||||||
|
#uri{ display:none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.lil-gui.root{
|
||||||
|
top:auto !important;
|
||||||
|
left:auto !important;
|
||||||
|
}
|
||||||
|
.js-snackbar__message{
|
||||||
|
overflow-y:auto;
|
||||||
|
max-height:600px;
|
||||||
|
}
|
||||||
|
.js-snackbar__message h1,h2,h3{
|
||||||
|
font-size:22px;
|
||||||
|
}
|
||||||
|
.xrf table tr td {
|
||||||
|
|
||||||
|
}
|
||||||
|
:root{
|
||||||
|
--xrf-font-size-1: 13px;
|
||||||
|
--xrf-font-size-2: 17px;
|
||||||
|
--xrf-font-size-3: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* notifications */
|
||||||
|
|
||||||
|
.js-snackbar-container .btn,
|
||||||
|
.js-snackbar-container input[type=submit],
|
||||||
|
.js-snackbar-container button{
|
||||||
|
margin-bottom:15px;
|
||||||
|
}
|
||||||
|
.js-snackbar-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 0px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width:100%;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
z-index:1001;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar-container * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__wrapper {
|
||||||
|
--color-c: #555;
|
||||||
|
--color-a: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.js-snackbar__wrapper {
|
||||||
|
overflow: hidden;
|
||||||
|
height: auto;
|
||||||
|
margin: 5px 0;
|
||||||
|
transition: all ease .5s;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 0 4px 0 var(--xrf-box-shadow);
|
||||||
|
right: 20px;
|
||||||
|
position: fixed;
|
||||||
|
top: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar {
|
||||||
|
display: inline-flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--color-c);
|
||||||
|
background-color: var(--color-a);
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__close,
|
||||||
|
.js-snackbar__status,
|
||||||
|
.js-snackbar__message {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__message {
|
||||||
|
margin: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__status {
|
||||||
|
display: none;
|
||||||
|
width: 15px;
|
||||||
|
margin-right: 5px;
|
||||||
|
border-radius: 3px 0 0 3px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__status.js-snackbar--success,
|
||||||
|
.js-snackbar__status.js-snackbar--warning,
|
||||||
|
.js-snackbar__status.js-snackbar--danger,
|
||||||
|
.js-snackbar__status.js-snackbar--info {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__status.js-snackbar--success {
|
||||||
|
background-color: #4caf50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__status.js-snackbar--warning {
|
||||||
|
background-color: #ff9800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__status.js-snackbar--danger {
|
||||||
|
background-color: #ff6060;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__status.js-snackbar--info {
|
||||||
|
background-color: #CCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__close {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 10px;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-snackbar__close:hover {
|
||||||
|
background-color: #4443;
|
||||||
|
}
|
||||||
|
|
||||||
|
.a-enter-vr-button, .a-enter-ar-button{
|
||||||
|
height:41px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode{
|
||||||
|
background: transparent;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 121px;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
input#share{
|
||||||
|
font-size: var(--xrf-font-size-1);
|
||||||
|
font-family: var(--xrf-font-monospace);
|
||||||
|
border:2px solid #AAA;
|
||||||
|
width:50vw;
|
||||||
|
max-width:400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse; /* This reverses the stacking order of the flex container */
|
||||||
|
align-items: flex-end;
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 71px;
|
||||||
|
right: 11px;
|
||||||
|
bottom: 0;
|
||||||
|
padding-bottom:149px;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
.footer .menu{
|
||||||
|
text-align:right;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<div id="overlay" class="xrf" style="display:none">
|
||||||
|
<div class="logo" :style="'background-image: url('+$store.XRFMENU.logo+')'"></div>
|
||||||
|
<button id="navback" onclick="history.back()"><</button>
|
||||||
|
<button id="navforward" onclick="history.forward()">></button>
|
||||||
|
<input type="submit" value="load 3D file"></input>
|
||||||
|
<input type="text" id="uri" value="" onchange="AFRAME.XRF.navigator.to( $('#uri').value )" style="display:none"/>
|
||||||
|
</div>
|
||||||
|
<div class="xrf footer">
|
||||||
|
<div id="buttons" class="menu">
|
||||||
|
<a class="btn" id="more" style="display:inline-block" x-text="$store.XRFMENU.morelabel"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
)
|
||||||
|
//${window.XRFMENU.html.map( (html) => typeof html == "function" ? html() : html ).join('\n')}
|
||||||
|
|
||||||
window.XRFMENU = {
|
window.XRFMENU = {
|
||||||
|
|
||||||
logo: './../../assets/logo.png',
|
$: $XRFMENU,
|
||||||
|
|
||||||
html: [
|
morelabel: '⚡',
|
||||||
|
enabled: false,
|
||||||
|
logo: './../../assets/logo.png',
|
||||||
|
buttons: [
|
||||||
`<a class="btn" aria-label="button" aria-description="start text/audio/video chat" id="meeting" target="_blank">🧑🤝🧑 meeting</a><br>`,
|
`<a class="btn" aria-label="button" aria-description="start text/audio/video chat" id="meeting" target="_blank">🧑🤝🧑 meeting</a><br>`,
|
||||||
`<a class="btn" aria-label="button" aria-description="share URL/screenshot/embed" id="share" target="_blank" onclick="window.share()">🔗 share</a><br>`
|
`<a class="btn" aria-label="button" aria-description="share URL/screenshot/embed" id="share" target="_blank" onclick="window.share()">🔗 share</a><br>`
|
||||||
],
|
],
|
||||||
|
|
||||||
|
init: () => {
|
||||||
|
|
||||||
|
// bind object as alpine app
|
||||||
|
document.body.appendChild( XRFMENU.$ )
|
||||||
|
document.addEventListener('alpine:init', () => Alpine.bind('XRFMENU', () => XRFMENU ) )
|
||||||
|
|
||||||
|
//if( XRFMENU.logo ) $('.logo').style['background-image'] = `url(${XRFMENU.logo})`
|
||||||
|
window.notify = XRFMENU.notify(window)
|
||||||
|
window.share = XRFMENU.share
|
||||||
|
window.download = XRFMENU.download
|
||||||
|
window.notify('loading '+document.location.search.substr(1))
|
||||||
|
// reroute console messages to snackbar notifications
|
||||||
|
console.log = ( (log) => function(str){
|
||||||
|
if( String(str).match(/(:.*#|note:)/) ) window.notify(str)
|
||||||
|
log(str)
|
||||||
|
})(console.log)
|
||||||
|
// allow iframe to open url
|
||||||
|
window.addEventListener('message', (event) => {
|
||||||
|
if (event.data && event.data.url) {
|
||||||
|
window.open(event.data.url, '_blank');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
loadFile(contentLoaders, multiple){
|
loadFile(contentLoaders, multiple){
|
||||||
return () => {
|
return () => {
|
||||||
window.notify("if you're on Meta browser, file-uploads might be disabled")
|
window.notify("if you're on Meta browser, file-uploads might be disabled")
|
||||||
|
|
@ -299,409 +709,3 @@ window.XRFMENU = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.XRFMENU.addHTML = () => {
|
|
||||||
|
|
||||||
let el = document.createElement("div")
|
|
||||||
el.innerHTML += `<style type="text/css">
|
|
||||||
:root {
|
|
||||||
--xrf-primary: #6839dc;
|
|
||||||
--xrf-primary-fg: #FFF;
|
|
||||||
--xrf-light-primary: #ea23cf;
|
|
||||||
--xrf-secondary: #872eff;
|
|
||||||
--xrf-light-xrf-secondary: #ce7df2;
|
|
||||||
--xrf-overlay-bg: #fffb;
|
|
||||||
--xrf-box-shadow: #0005;
|
|
||||||
--xrf-red: red;
|
|
||||||
--xrf-black: #424280;
|
|
||||||
--xrf-white: #fdfdfd;
|
|
||||||
--xrf-dark-gray: #343334;
|
|
||||||
--xrf-gray: #ecf7ff47;
|
|
||||||
--xrf-light-gray: #efefef;
|
|
||||||
--xrf-lighter-gray: #e4e2fb96;
|
|
||||||
--xrf-font-sans-serif: system-ui, -apple-system, segoe ui, roboto, ubuntu, helvetica, cantarell, noto sans, sans-serif;
|
|
||||||
--xrf-font-monospace: menlo, monaco, lucida console, liberation mono, dejavu sans mono, bitstream vera sans mono, courier new, monospace, serif;
|
|
||||||
--xrf-font-size-1: 14px;
|
|
||||||
--xrf-font-size-2: 17px;
|
|
||||||
--xrf-font-size-3: 21px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xrf table tr td{
|
|
||||||
vertical-align:top;
|
|
||||||
}
|
|
||||||
.xrf table tr td:nth-child(1){
|
|
||||||
padding-right:35px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xrf button,
|
|
||||||
.xrf input[type="submit"],
|
|
||||||
.xrf .btn {
|
|
||||||
text-decoration:none;
|
|
||||||
background: var(--xrf-primary);
|
|
||||||
border: 0;
|
|
||||||
border-radius: 25px;
|
|
||||||
padding: 11px 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
transition: 0.3s;
|
|
||||||
height: 32px;
|
|
||||||
font-size: var(--xrf-font-size-1);
|
|
||||||
color: var(--xrf-primary-fg);
|
|
||||||
line-height: var(--xrf-font-size-1);
|
|
||||||
cursor:pointer;
|
|
||||||
white-space:pre;
|
|
||||||
min-width: 45px;
|
|
||||||
box-shadow: 0px 0px 10px var(--xrf-box-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.xrf button:hover,
|
|
||||||
.xrf input[type="submit"]:hover,
|
|
||||||
.xrf .btn:hover {
|
|
||||||
background: var(--xrf-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.xrf, .xrf *{
|
|
||||||
font-family: var(--xrf-font-sans-serif);
|
|
||||||
font-size: var(--xrf-font-size-1);
|
|
||||||
line-height:27px;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea, select, input[type="text"] {
|
|
||||||
background: transparent; /* linear-gradient( var(--xrf-lighter-gray), var(--xrf-gray) ) !important; */
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="submit"] {
|
|
||||||
color: var(--xrf-light-gray);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text]{
|
|
||||||
padding:7px 15px;
|
|
||||||
}
|
|
||||||
input{
|
|
||||||
border-radius:7px;
|
|
||||||
margin:5px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
border-bottom: 2px solid var(--xrf-secondary);
|
|
||||||
padding-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#overlay{
|
|
||||||
background: var(--xrf-overlay-bg);
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 48px;
|
|
||||||
box-shadow: 0px 0px 10px var(--xrf-box-shadow);
|
|
||||||
opacity: 0.9;
|
|
||||||
z-index:2000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#overlay .logo{
|
|
||||||
width: 92px;
|
|
||||||
position: absolute;
|
|
||||||
top: 9px;
|
|
||||||
left: 93px;
|
|
||||||
height: 30px;
|
|
||||||
background-size: contain;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
#overlay > input[type="submit"] {
|
|
||||||
height: 32px;
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
top: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#overlay > button#navback,
|
|
||||||
#overlay > button#navforward {
|
|
||||||
height: 32px;
|
|
||||||
font-size: var(--xrf-font-size-1);
|
|
||||||
position: absolute;
|
|
||||||
left: 9px;
|
|
||||||
padding: 2px 13px;
|
|
||||||
border-radius:6px;
|
|
||||||
top: 8px;
|
|
||||||
color: var(--xrf-light-gray);
|
|
||||||
width: 36px;
|
|
||||||
min-width: unset;
|
|
||||||
}
|
|
||||||
#overlay > button#navforward {
|
|
||||||
left:49px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#overlay > #uri {
|
|
||||||
height: 18px;
|
|
||||||
font-size: var(--xrf-font-size-3);
|
|
||||||
position: absolute;
|
|
||||||
left: 200px;
|
|
||||||
top: 9px;
|
|
||||||
max-width: 550px;
|
|
||||||
padding: 5px 0px 5px 5px;
|
|
||||||
width: calc( 63% - 200px);
|
|
||||||
background: #f0f0f0;
|
|
||||||
border-color: #Ccc;
|
|
||||||
border: 2px solid #CCC;
|
|
||||||
border-radius: 7px;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.menu .btn{
|
|
||||||
background: var(--xrf-primary);
|
|
||||||
border-radius: 25px;
|
|
||||||
border: 0;
|
|
||||||
padding: 5px 19px;
|
|
||||||
font-weight: 1000;
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: var(--xrf-font-size-2);
|
|
||||||
color:var(--xrf-primary-fg);
|
|
||||||
height:33px;
|
|
||||||
z-index:2000;
|
|
||||||
cursor:pointer;
|
|
||||||
min-width:107px;
|
|
||||||
text-decoration:none;
|
|
||||||
display:none;
|
|
||||||
margin-top: 15px;
|
|
||||||
line-height:36px;
|
|
||||||
margin-right:10px;
|
|
||||||
text-align:left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xrf a.btn#more{
|
|
||||||
width: 19px;
|
|
||||||
min-width: 19px;
|
|
||||||
font-size:16px;
|
|
||||||
text-align: center;
|
|
||||||
background:white;
|
|
||||||
}
|
|
||||||
|
|
||||||
html{
|
|
||||||
max-width:unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.render {
|
|
||||||
position:absolute;
|
|
||||||
top:0;
|
|
||||||
left:0;
|
|
||||||
right:0;
|
|
||||||
bottom:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lil-gui.autoPlace{
|
|
||||||
right:0px !important;
|
|
||||||
top:48px !important;
|
|
||||||
height:33vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
#VRButton {
|
|
||||||
margin-bottom:20vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 450px) {
|
|
||||||
#uri{ display:none; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.lil-gui.root{
|
|
||||||
top:auto !important;
|
|
||||||
left:auto !important;
|
|
||||||
}
|
|
||||||
.js-snackbar__message{
|
|
||||||
overflow-y:auto;
|
|
||||||
max-height:600px;
|
|
||||||
}
|
|
||||||
.js-snackbar__message h1,h2,h3{
|
|
||||||
font-size:22px;
|
|
||||||
}
|
|
||||||
.xrf table tr td {
|
|
||||||
|
|
||||||
}
|
|
||||||
:root{
|
|
||||||
--xrf-font-size-1: 13px;
|
|
||||||
--xrf-font-size-2: 17px;
|
|
||||||
--xrf-font-size-3: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* notifications */
|
|
||||||
|
|
||||||
.js-snackbar-container .btn,
|
|
||||||
.js-snackbar-container input[type=submit],
|
|
||||||
.js-snackbar-container button{
|
|
||||||
margin-bottom:15px;
|
|
||||||
}
|
|
||||||
.js-snackbar-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 0px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
width:100%;
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
z-index:1001;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar-container * {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__wrapper {
|
|
||||||
--color-c: #555;
|
|
||||||
--color-a: #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.js-snackbar__wrapper {
|
|
||||||
overflow: hidden;
|
|
||||||
height: auto;
|
|
||||||
margin: 5px 0;
|
|
||||||
transition: all ease .5s;
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: 0 0 4px 0 var(--xrf-box-shadow);
|
|
||||||
right: 20px;
|
|
||||||
position: fixed;
|
|
||||||
top: 55px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar {
|
|
||||||
display: inline-flex;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 3px;
|
|
||||||
color: var(--color-c);
|
|
||||||
background-color: var(--color-a);
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__close,
|
|
||||||
.js-snackbar__status,
|
|
||||||
.js-snackbar__message {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__message {
|
|
||||||
margin: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__status {
|
|
||||||
display: none;
|
|
||||||
width: 15px;
|
|
||||||
margin-right: 5px;
|
|
||||||
border-radius: 3px 0 0 3px;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__status.js-snackbar--success,
|
|
||||||
.js-snackbar__status.js-snackbar--warning,
|
|
||||||
.js-snackbar__status.js-snackbar--danger,
|
|
||||||
.js-snackbar__status.js-snackbar--info {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__status.js-snackbar--success {
|
|
||||||
background-color: #4caf50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__status.js-snackbar--warning {
|
|
||||||
background-color: #ff9800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__status.js-snackbar--danger {
|
|
||||||
background-color: #ff6060;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__status.js-snackbar--info {
|
|
||||||
background-color: #CCC;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__close {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 10px;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-snackbar__close:hover {
|
|
||||||
background-color: #4443;
|
|
||||||
}
|
|
||||||
|
|
||||||
.a-enter-vr-button, .a-enter-ar-button{
|
|
||||||
height:41px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#qrcode{
|
|
||||||
background: transparent;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 121px;
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
input#share{
|
|
||||||
font-size: var(--xrf-font-size-1);
|
|
||||||
font-family: var(--xrf-font-monospace);
|
|
||||||
border:2px solid #AAA;
|
|
||||||
width:50vw;
|
|
||||||
max-width:400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column-reverse; /* This reverses the stacking order of the flex container */
|
|
||||||
align-items: flex-end;
|
|
||||||
height: 100%;
|
|
||||||
position: fixed;
|
|
||||||
top: 71px;
|
|
||||||
right: 11px;
|
|
||||||
bottom: 0;
|
|
||||||
padding-bottom:149px;
|
|
||||||
box-sizing:border-box;
|
|
||||||
}
|
|
||||||
.footer .menu{
|
|
||||||
text-align:right;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<div id="overlay" class="xrf" style="display:none">
|
|
||||||
<div class="logo"></div>
|
|
||||||
<button id="navback" onclick="history.back()"><</button>
|
|
||||||
<button id="navforward" onclick="history.forward()">></button>
|
|
||||||
<input type="submit" value="load 3D file"></input>
|
|
||||||
<input type="text" id="uri" value="" onchange="AFRAME.XRF.navigator.to( $('#uri').value )" style="display:none"/>
|
|
||||||
</div>
|
|
||||||
<!-- open AFRAME inspector: $('a-scene').components.inspector.openInspector() -->
|
|
||||||
<div class="xrf footer">
|
|
||||||
<div id="buttons" class="menu">
|
|
||||||
${window.XRFMENU.html.map( (html) => typeof html == "function" ? html() : html ).join('\n')}
|
|
||||||
<a class="btn" id="more" style="display:inline-block">${window.XRFMENU.morelabel}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
document.body.appendChild(el)
|
|
||||||
|
|
||||||
if( XRFMENU.logo ) $('.logo').style['background-image'] = `url(${XRFMENU.logo})`
|
|
||||||
|
|
||||||
window.notify = XRFMENU.notify(window)
|
|
||||||
window.share = XRFMENU.share
|
|
||||||
window.download = XRFMENU.download
|
|
||||||
window.notify('loading '+document.location.search.substr(1))
|
|
||||||
// reroute console messages to snackbar notifications
|
|
||||||
console.log = ( (log) => function(str){
|
|
||||||
if( String(str).match(/(:.*#|note:)/) ) window.notify(str)
|
|
||||||
log(str)
|
|
||||||
})(console.log)
|
|
||||||
// allow iframe to open url
|
|
||||||
window.addEventListener('message', (event) => {
|
|
||||||
if (event.data && event.data.url) {
|
|
||||||
window.open(event.data.url, '_blank');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue