From 5668eb1cb40ea52f11820460f714d975f2a72f5e Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Thu, 14 Dec 2023 18:13:40 +0100 Subject: [PATCH] refactored and tidied ui --- dist/utils.js | 321 -------------- example/aframe/sandbox/index.html | 103 ++--- example/assets/css/style.css | 317 ------------- example/assets/js/utils.js | 321 -------------- make | 4 - src/3rd/js/aframe/meeting.js | 20 +- src/3rd/js/aframe/xrf-menu.js | 48 ++ src/3rd/js/menu.js | 713 ++++++++++++++++++++++++++++++ 8 files changed, 804 insertions(+), 1043 deletions(-) delete mode 100644 dist/utils.js delete mode 100644 example/assets/css/style.css delete mode 100644 example/assets/js/utils.js create mode 100644 src/3rd/js/aframe/xrf-menu.js create mode 100644 src/3rd/js/menu.js diff --git a/dist/utils.js b/dist/utils.js deleted file mode 100644 index 4f27546..0000000 --- a/dist/utils.js +++ /dev/null @@ -1,321 +0,0 @@ - -// contentLoaders = {".gltf" : () => .....} and so on - -function loadFile(contentLoaders, multiple){ - return () => { - window.notify("if you're on Meta browser, file-uploads might be disabled") - let input = document.createElement('input'); - input.type = 'file'; - input.multiple = multiple; - input.accept = Object.keys(contentLoaders).join(","); - input.onchange = () => { - let files = Array.from(input.files); - let file = files.slice ? files[0] : files - for( var i in contentLoaders ){ - let r = new RegExp('\\'+i+'$') - if( file.name.match(r) ) return contentLoaders[i](file) - } - alert(file.name+" is not supported") - }; - input.click(); - } -} - -function setupConsole(el){ - if( !el ) return setTimeout( () => setupConsole( $('.lil-gui') ),200 ) - let $console = document.createElement('textarea') - $console.style.position = 'absolute' - $console.style.display = 'block' - $console.style.zIndex = 2000; - $console.style.background = "transparent !important" - $console.style.pointerEvents = 'none' - $console.style.top = '70px' - $console.style.padding = '10px' - $console.style.margin = '10px' - $console.style.background = '#000' - $console.style.left = $console.style.right = $console.style.bottom = 0; - $console.style.color = '#A6F'; - $console.style.fontSize = '10px'; - $console.style.fontFamily = 'Courier' - $console.style.border = '0' - $console.innerHTML = "XRFRAGMENT CONSOLE OUTPUT:\n" - - el.appendChild($console) - - console.log = ( (log) => function(){ - let str = ([...arguments]).join(" ") - let s = str; - log(s) - let lines = String($console.innerHTML + "\n"+s).split("\n") - while( lines.length > 200 ) lines.shift() - $console.innerHTML = lines.join("\n") - $console.scrollTop = $console.scrollHeight; - })(console.log.bind(console)) -} - -function setupUrlBar(el,XRF){ - let inIframe = window.location !== window.parent.location - let ids = ['#overlay','a#embed','a#clone','a#model','a#meeting','#qrcode'] - let showButtons = (state) => { - ids.map( (i) => $(i).style.display = state ? 'inline-block' : 'none' ) - $('a#more').style.display = state ? 'none' : 'inline-block' - if( inIframe ) $('#uri').style.display = 'block' - } - $('a#more').addEventListener('click', () => showButtons(true) ) - $('a#meeting').addEventListener('click', () => { - document.querySelector('a-scene').setAttribute('meeting', 'id: xrfragments') - showButtons(false) - }) - - XRF.addEventListener('hash', () => reflectUrl() ) - const reflectUrl = window.reflectUrl = (url) => { - el.value = url || document.location.search.substr(1) + document.location.hash - let QR = window.QR - QR.canvas = document.getElementById('qrcode') - QR.draw( document.location.href, QR.canvas ) - } - reflectUrl() -} - -function SnackBar(userOptions) { - var snackbar = this || (window.snackbar = {}); - var _Interval; - var _Message; - var _Element; - var _Container; - - var _OptionDefaults = { - message: "Operation performed successfully.", - dismissible: true, - timeout: 7000, - status: "" - } - var _Options = _OptionDefaults; - - function _Create() { - let _Containers = [ ...document.querySelectorAll(".js-snackbar-container") ] - _Containers.map( (c) => c.remove() ) - _Container = null - - if (!_Container) { - // need to create a new container for notifications - _Container = document.createElement("div"); - _Container.classList.add("js-snackbar-container"); - - document.body.appendChild(_Container); - } - _Container.innerHTML = '' - _Element = document.createElement("div"); - _Element.classList.add("js-snackbar__wrapper"); - - let innerSnack = document.createElement("div"); - innerSnack.classList.add("js-snackbar", "js-snackbar--show"); - - if (_Options.status) { - _Options.status = _Options.status.toLowerCase().trim(); - - let status = document.createElement("span"); - status.classList.add("js-snackbar__status"); - - - if (_Options.status === "success" || _Options.status === "green") { - status.classList.add("js-snackbar--success"); - } - else if (_Options.status === "warning" || _Options.status === "alert" || _Options.status === "orange") { - status.classList.add("js-snackbar--warning"); - } - else if (_Options.status === "danger" || _Options.status === "error" || _Options.status === "red") { - status.classList.add("js-snackbar--danger"); - } - else { - status.classList.add("js-snackbar--info"); - } - - innerSnack.appendChild(status); - } - - _Message = document.createElement("span"); - _Message.classList.add("js-snackbar__message"); - _Message.innerHTML = _Options.message; - - innerSnack.appendChild(_Message); - - if (_Options.dismissible) { - let closeBtn = document.createElement("span"); - closeBtn.classList.add("js-snackbar__close"); - closeBtn.innerText = "\u00D7"; - - closeBtn.onclick = snackbar.Close; - - innerSnack.appendChild(closeBtn); - } - - _Element.style.height = "0px"; - _Element.style.opacity = "0"; - _Element.style.marginTop = "0px"; - _Element.style.marginBottom = "0px"; - - _Element.appendChild(innerSnack); - _Container.appendChild(_Element); - - if (_Options.timeout !== false) { - _Interval = setTimeout(snackbar.Close, _Options.timeout); - } - } - - var _ConfigureDefaults = function() { - // if no options given, revert to default - if (userOptions === undefined) { - return; - } - - if (userOptions.message !== undefined) { - _Options.message = userOptions.message; - } - - if (userOptions.dismissible !== undefined) { - if (typeof (userOptions.dismissible) === "string") { - _Options.dismissible = (userOptions.dismissible === "true"); - } - else if (typeof (userOptions.dismissible) === "boolean") { - _Options.dismissible = userOptions.dismissible; - } - else { - console.debug("Invalid option provided for 'dismissable' [" + userOptions.dismissible + "] is of type " + (typeof userOptions.dismissible)); - } - } - - - if (userOptions.timeout !== undefined) { - if (typeof (userOptions.timeout) === "boolean" && userOptions.timeout === false) { - _Options.timeout = false; - } - else if (typeof (userOptions.timeout) === "string") { - _Options.timeout = parseInt(userOptions.timeout); - } - - - if (typeof (userOptions.timeout) === "number") { - if (userOptions.timeout === Infinity) { - _Options.timeout = false; - } - else if (userOptions.timeout >= 0) { - _Options.timeout = userOptions.timeout; - } - else { - console.debug("Invalid timeout entered. Must be greater than or equal to 0."); - } - - _Options.timeout = userOptions.timeout; - } - - - } - - if (userOptions.status !== undefined) { - _Options.status = userOptions.status; - } - } - - snackbar.Open = function() { - let contentHeight = _Element.firstElementChild.scrollHeight; // get the height of the content - - _Element.style.height = contentHeight + "px"; - _Element.style.opacity = 1; - _Element.style.marginTop = "5px"; - _Element.style.marginBottom = "5px"; - - _Element.addEventListener("transitioned", function() { - _Element.removeEventListener("transitioned", arguments.callee); - _Element.style.height = null; - }) - } - - snackbar.Close = function () { - if (_Interval) - clearInterval(_Interval); - - let snackbarHeight = _Element.scrollHeight; // get the auto height as a px value - let snackbarTransitions = _Element.style.transition; - _Element.style.transition = ""; - - requestAnimationFrame(function() { - _Element.style.height = snackbarHeight + "px"; // set the auto height to the px height - _Element.style.opacity = 1; - _Element.style.marginTop = "0px"; - _Element.style.marginBottom = "0px"; - _Element.style.transition = snackbarTransitions - - requestAnimationFrame(function() { - _Element.style.height = "0px"; - _Element.style.opacity = 0; - }) - }); - - setTimeout(function() { - try { _Container.removeChild(_Element); } catch (e) { } - }, 1000); - }; - - _ConfigureDefaults(); - _Create(); - snackbar.Open(); -} - -function notify(scope){ - return function notify(str,opts){ - str = String(str) - opts = opts || {} - if( !opts.status ){ - opts.status = "info" - if( str.match(/error/g) ) opts.status = "danger" - if( str.match(/warning/g) ) opts.status = "warning" - } - opts = Object.assign({ message: str , status, timeout:4000 },opts) - SnackBar( opts ) - } -} - -function download(){ - function fetchAndDownload(dataurl, filename) { - var a = document.createElement("a"); - a.href = dataurl; - a.setAttribute("download", filename); - a.click(); - return false; - } - let file = document.location.search.replace(/\?/,'') - fetchAndDownload( file, file ) -} - -function embed(){ - // *TODO* this should be part of the XRF Threejs framework - if( typeof THREE == 'undefined' ) THREE = xrf.THREE - let radToDeg = THREE.MathUtils.radToDeg - let toDeg = (x) => x / (Math.PI / 180) - let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs - - // *TODO* add camera direction - let direction = new xrf.THREE.Vector3() - camera.getWorldDirection(direction) - const pitch = Math.asin(direction.y); - const yaw = Math.atan2(direction.x, direction.z); - const pitchInDegrees = pitch * 180 / Math.PI; - const yawInDegrees = yaw * 180 / Math.PI; - - let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}` - let newHash = document.location.hash.replace(/[&]?(pos|rot)=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'') - newHash += `&${lastPos}` - document.location.hash = newHash.replace(/&&/,'&') - .replace(/#&/,'') - // copy url to clipboard - var dummy = document.createElement('input'), - text = window.location.href; - document.body.appendChild(dummy); - dummy.value = text; - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); - // End of *TODO* - window.notify(`Link copied to clipboard! ❤️
ps. to embed this experience in your website,
copy/paste the following into your HTML:
`,{timeout:10000}) -} diff --git a/example/aframe/sandbox/index.html b/example/aframe/sandbox/index.html index b739f37..609b76d 100644 --- a/example/aframe/sandbox/index.html +++ b/example/aframe/sandbox/index.html @@ -9,18 +9,8 @@ - - - - @@ -34,71 +24,42 @@ - + - - diff --git a/example/assets/css/style.css b/example/assets/css/style.css deleted file mode 100644 index 4f4c709..0000000 --- a/example/assets/css/style.css +++ /dev/null @@ -1,317 +0,0 @@ -:root { - --primary: #6839dc; - --light-primary: #ea23cf; - --secondary: #872eff; - --light-secondary: #ce7df2; - --red: red; - --black: #424280; - --white: #fdfdfd; - --dark-gray: #343334; - --gray: #ecf7ff47; - --light-gray: #efefef; - --lighter-gray: #e4e2fb96; - --font-sans-serif: system-ui, -apple-system, segoe ui, roboto, ubuntu, helvetica, cantarell, noto sans, sans-serif; - --font-monospace: menlo, monaco, lucida console, liberation mono, dejavu sans mono, bitstream vera sans mono, courier new, monospace, serif; - --border-radius: 0.2rem; - --font-size-1: -} - -button,input[type="submit"] { - background: var(--primary); - border: 0; - border-radius: 7px; - padding: 2px 10px; - font-weight: bold; -} - -body{ - font-family: var(--font-sans-serif); -} - -.small{ - font-size:12px; -} - -textarea, select, input[type="text"] { - background: transparent; /* linear-gradient( var(--lighter-gray), var(--gray) ) !important; */ -} - -input[type="submit"] { - color: var(--light-gray); -} - -.title { - border-bottom: 2px solid var(--secondary); - padding-bottom: 20px; -} - -#overlay{ - background: #FFFb; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 48px; - box-shadow: 0px 0px 10px #0004; - opacity: 0.9; - z-index:2000; -} - -#overlay .logo{ - width: 92px; - position: absolute; - top: 9px; - left: 93px; -} - -#overlay > input[type="submit"] { - height: 32px; - font-size: 14px; - position: absolute; - right: 9px; - top: 8px; -} -#overlay > button#navback, -#overlay > button#navforward { - height: 32px; - font-size: 14px; - position: absolute; - left: 9px; - padding: 2px 13px; - top: 8px; - color: var(--light-gray); -} -#overlay > button#navforward { - left:49px; -} - -#overlay > #uri { - height: 18px; - font-size: 21px; - 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; -} - -.btn-foot{ - background: white; - border-radius: 10px; - border: 5px solid #1c1c3299; - padding: 0px 6px; - position: absolute; - font-weight: 1000; - font-family: sans-serif; - font-size:17px; - color: #888; - height:33px; - z-index:2000; - cursor:pointer; - right: 10px; - text-transform:uppercase; - min-width:107px; - text-decoration:none; -} - -a.btn-foot#clone{ - color: #888; - bottom: 129px; -} - -a.btn-foot#model{ - bottom:72px; -} - -a.btn-foot#more{ - bottom:72px; - width: 37px; - min-width: 37px; - font-size:23px; - text-align: center; -} - -a.btn-foot#embed{ - bottom:186px; -} - -a.btn-foot#meeting{ - bottom:246px; -} - -a#meeting, -a#clone, -a#embed, -a#model{ - display:none -} - -html.a-fullscreen a.btn-foot { - line-height:36px; - margin-right:10px; -} - -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; - } -} - - -/* notifications */ -.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: #EEE; -} - - -.js-snackbar__wrapper { - overflow: hidden; - height: auto; - margin: 5px 0; - transition: all ease .5s; - border-radius: 3px; - box-shadow: 0 0 4px 0 #0007; - right: 20px; - position: fixed; - top: 55px; -} - -.js-snackbar { - display: inline-flex; - box-sizing: border-box; - border-radius: 3px; - color: var(--color-c); - font-size: 16px; - background-color: var(--color-a); - vertical-align: bottom; -} - -.js-snackbar__close, -.js-snackbar__status, -.js-snackbar__message { - position: relative; -} - -.js-snackbar__message { - padding: 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{ - z-index: 2000; - width: 111px; - border-radius: 20px; - background: #fff; - border-radius: 15px; - overflow: hidden; - -webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC); - bottom: 306px; - height: 121px; - right: 19px; -} - -input#share{ - font-size:14px; - font-family: monospace; - border:2px solid #AAA; - width:50vw; - max-width:500px; -} diff --git a/example/assets/js/utils.js b/example/assets/js/utils.js deleted file mode 100644 index 65516a5..0000000 --- a/example/assets/js/utils.js +++ /dev/null @@ -1,321 +0,0 @@ - -// contentLoaders = {".gltf" : () => .....} and so on - -export function loadFile(contentLoaders, multiple){ - return () => { - window.notify("if you're on Meta browser, file-uploads might be disabled") - let input = document.createElement('input'); - input.type = 'file'; - input.multiple = multiple; - input.accept = Object.keys(contentLoaders).join(","); - input.onchange = () => { - let files = Array.from(input.files); - let file = files.slice ? files[0] : files - for( var i in contentLoaders ){ - let r = new RegExp('\\'+i+'$') - if( file.name.match(r) ) return contentLoaders[i](file) - } - alert(file.name+" is not supported") - }; - input.click(); - } -} - -export function setupConsole(el){ - if( !el ) return setTimeout( () => setupConsole( $('.lil-gui') ),200 ) - let $console = document.createElement('textarea') - $console.style.position = 'absolute' - $console.style.display = 'block' - $console.style.zIndex = 2000; - $console.style.background = "transparent !important" - $console.style.pointerEvents = 'none' - $console.style.top = '70px' - $console.style.padding = '10px' - $console.style.margin = '10px' - $console.style.background = '#000' - $console.style.left = $console.style.right = $console.style.bottom = 0; - $console.style.color = '#A6F'; - $console.style.fontSize = '10px'; - $console.style.fontFamily = 'Courier' - $console.style.border = '0' - $console.innerHTML = "XRFRAGMENT CONSOLE OUTPUT:\n" - - el.appendChild($console) - - console.log = ( (log) => function(){ - let str = ([...arguments]).join(" ") - let s = str; - log(s) - let lines = String($console.innerHTML + "\n"+s).split("\n") - while( lines.length > 200 ) lines.shift() - $console.innerHTML = lines.join("\n") - $console.scrollTop = $console.scrollHeight; - })(console.log.bind(console)) -} - -export function setupUrlBar(el,XRF){ - let inIframe = window.location !== window.parent.location - let ids = ['#overlay','a#embed','a#clone','a#model','a#meeting','#qrcode'] - let showButtons = (state) => { - ids.map( (i) => $(i).style.display = state ? 'inline-block' : 'none' ) - $('a#more').style.display = state ? 'none' : 'inline-block' - if( inIframe ) $('#uri').style.display = 'block' - } - $('a#more').addEventListener('click', () => showButtons(true) ) - $('a#meeting').addEventListener('click', () => { - document.querySelector('a-scene').setAttribute('meeting', 'id: xrfragments') - showButtons(false) - }) - - XRF.addEventListener('hash', () => reflectUrl() ) - const reflectUrl = window.reflectUrl = (url) => { - el.value = url || document.location.search.substr(1) + document.location.hash - let QR = window.QR - QR.canvas = document.getElementById('qrcode') - QR.draw( document.location.href, QR.canvas ) - } - reflectUrl() -} - -function SnackBar(userOptions) { - var snackbar = this || (window.snackbar = {}); - var _Interval; - var _Message; - var _Element; - var _Container; - - var _OptionDefaults = { - message: "Operation performed successfully.", - dismissible: true, - timeout: 7000, - status: "" - } - var _Options = _OptionDefaults; - - function _Create() { - let _Containers = [ ...document.querySelectorAll(".js-snackbar-container") ] - _Containers.map( (c) => c.remove() ) - _Container = null - - if (!_Container) { - // need to create a new container for notifications - _Container = document.createElement("div"); - _Container.classList.add("js-snackbar-container"); - - document.body.appendChild(_Container); - } - _Container.innerHTML = '' - _Element = document.createElement("div"); - _Element.classList.add("js-snackbar__wrapper"); - - let innerSnack = document.createElement("div"); - innerSnack.classList.add("js-snackbar", "js-snackbar--show"); - - if (_Options.status) { - _Options.status = _Options.status.toLowerCase().trim(); - - let status = document.createElement("span"); - status.classList.add("js-snackbar__status"); - - - if (_Options.status === "success" || _Options.status === "green") { - status.classList.add("js-snackbar--success"); - } - else if (_Options.status === "warning" || _Options.status === "alert" || _Options.status === "orange") { - status.classList.add("js-snackbar--warning"); - } - else if (_Options.status === "danger" || _Options.status === "error" || _Options.status === "red") { - status.classList.add("js-snackbar--danger"); - } - else { - status.classList.add("js-snackbar--info"); - } - - innerSnack.appendChild(status); - } - - _Message = document.createElement("span"); - _Message.classList.add("js-snackbar__message"); - _Message.innerHTML = _Options.message; - - innerSnack.appendChild(_Message); - - if (_Options.dismissible) { - let closeBtn = document.createElement("span"); - closeBtn.classList.add("js-snackbar__close"); - closeBtn.innerText = "\u00D7"; - - closeBtn.onclick = snackbar.Close; - - innerSnack.appendChild(closeBtn); - } - - _Element.style.height = "0px"; - _Element.style.opacity = "0"; - _Element.style.marginTop = "0px"; - _Element.style.marginBottom = "0px"; - - _Element.appendChild(innerSnack); - _Container.appendChild(_Element); - - if (_Options.timeout !== false) { - _Interval = setTimeout(snackbar.Close, _Options.timeout); - } - } - - var _ConfigureDefaults = function() { - // if no options given, revert to default - if (userOptions === undefined) { - return; - } - - if (userOptions.message !== undefined) { - _Options.message = userOptions.message; - } - - if (userOptions.dismissible !== undefined) { - if (typeof (userOptions.dismissible) === "string") { - _Options.dismissible = (userOptions.dismissible === "true"); - } - else if (typeof (userOptions.dismissible) === "boolean") { - _Options.dismissible = userOptions.dismissible; - } - else { - console.debug("Invalid option provided for 'dismissable' [" + userOptions.dismissible + "] is of type " + (typeof userOptions.dismissible)); - } - } - - - if (userOptions.timeout !== undefined) { - if (typeof (userOptions.timeout) === "boolean" && userOptions.timeout === false) { - _Options.timeout = false; - } - else if (typeof (userOptions.timeout) === "string") { - _Options.timeout = parseInt(userOptions.timeout); - } - - - if (typeof (userOptions.timeout) === "number") { - if (userOptions.timeout === Infinity) { - _Options.timeout = false; - } - else if (userOptions.timeout >= 0) { - _Options.timeout = userOptions.timeout; - } - else { - console.debug("Invalid timeout entered. Must be greater than or equal to 0."); - } - - _Options.timeout = userOptions.timeout; - } - - - } - - if (userOptions.status !== undefined) { - _Options.status = userOptions.status; - } - } - - snackbar.Open = function() { - let contentHeight = _Element.firstElementChild.scrollHeight; // get the height of the content - - _Element.style.height = contentHeight + "px"; - _Element.style.opacity = 1; - _Element.style.marginTop = "5px"; - _Element.style.marginBottom = "5px"; - - _Element.addEventListener("transitioned", function() { - _Element.removeEventListener("transitioned", arguments.callee); - _Element.style.height = null; - }) - } - - snackbar.Close = function () { - if (_Interval) - clearInterval(_Interval); - - let snackbarHeight = _Element.scrollHeight; // get the auto height as a px value - let snackbarTransitions = _Element.style.transition; - _Element.style.transition = ""; - - requestAnimationFrame(function() { - _Element.style.height = snackbarHeight + "px"; // set the auto height to the px height - _Element.style.opacity = 1; - _Element.style.marginTop = "0px"; - _Element.style.marginBottom = "0px"; - _Element.style.transition = snackbarTransitions - - requestAnimationFrame(function() { - _Element.style.height = "0px"; - _Element.style.opacity = 0; - }) - }); - - setTimeout(function() { - try { _Container.removeChild(_Element); } catch (e) { } - }, 1000); - }; - - _ConfigureDefaults(); - _Create(); - snackbar.Open(); -} - -export function notify(scope){ - return function notify(str,opts){ - str = String(str) - opts = opts || {} - if( !opts.status ){ - opts.status = "info" - if( str.match(/error/g) ) opts.status = "danger" - if( str.match(/warning/g) ) opts.status = "warning" - } - opts = Object.assign({ message: str , status, timeout:4000 },opts) - SnackBar( opts ) - } -} - -export function download(){ - function fetchAndDownload(dataurl, filename) { - var a = document.createElement("a"); - a.href = dataurl; - a.setAttribute("download", filename); - a.click(); - return false; - } - let file = document.location.search.replace(/\?/,'') - fetchAndDownload( file, file ) -} - -export function embed(){ - // *TODO* this should be part of the XRF Threejs framework - if( typeof THREE == 'undefined' ) THREE = xrf.THREE - let radToDeg = THREE.MathUtils.radToDeg - let toDeg = (x) => x / (Math.PI / 180) - let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs - - // *TODO* add camera direction - let direction = new xrf.THREE.Vector3() - camera.getWorldDirection(direction) - const pitch = Math.asin(direction.y); - const yaw = Math.atan2(direction.x, direction.z); - const pitchInDegrees = pitch * 180 / Math.PI; - const yawInDegrees = yaw * 180 / Math.PI; - - let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}` - let newHash = document.location.hash.replace(/[&]?(pos|rot)=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'') - newHash += `&${lastPos}` - document.location.hash = newHash.replace(/&&/,'&') - .replace(/#&/,'') - // copy url to clipboard - var dummy = document.createElement('input'), - text = window.location.href; - document.body.appendChild(dummy); - dummy.value = text; - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); - // End of *TODO* - window.notify(`Link copied to clipboard! ❤️
ps. to embed this experience in your website,
copy/paste the following into your HTML:
`,{timeout:10000}) -} diff --git a/make b/make index 9b8a8ba..d1e98ba 100755 --- a/make +++ b/make @@ -80,12 +80,8 @@ build(){ cat dist/xrfragment.three.js > dist/xrfragment.three.module.js echo "export default xrf;" >> dist/xrfragment.three.module.js - # convert ESM to normal browser js - sed 's/export //g' example/assets/js/utils.js > dist/utils.js - # add AFRAME cat dist/xrfragment.three.js \ - dist/utils.js \ src/3rd/js/aframe/*.js \ example/assets/js/qr.js > dist/xrfragment.aframe.js diff --git a/src/3rd/js/aframe/meeting.js b/src/3rd/js/aframe/meeting.js index b1636d7..3c15556 100644 --- a/src/3rd/js/aframe/meeting.js +++ b/src/3rd/js/aframe/meeting.js @@ -42,7 +42,7 @@ AFRAME.registerComponent('meeting', { left: 20px; width: 48%; background: white; - padding: 7px 0px 7px 15px; + padding: 0px 0px 0px 15px; border-radius: 30px; max-width: 500px; box-sizing: border-box; @@ -50,7 +50,8 @@ AFRAME.registerComponent('meeting', { } #chatbar input{ border:none; - width:93%; + width:90%; + box-sizing:border-box; } #chat{ position: absolute; @@ -71,15 +72,11 @@ AFRAME.registerComponent('meeting', { } #chat,#chatbar,#chatbar *, #chat *{ font-family:monospace; - font-size:16px; + font-size:15px; } - #chatbar * { - font-size:20px; - } -}
-
+
` @@ -104,7 +101,7 @@ AFRAME.registerComponent('meeting', { this.getName = getName // tell other peers currently in the room our name - let name = prompt('enter your name:') + let name = this.name = prompt('enter your name:') idsToNames[ room.selfId ] = name.substr(0,15) sendName( name ) @@ -231,6 +228,8 @@ AFRAME.registerComponent('meeting', { if( e.key !== "Enter" ) return send() chatline.value = '' + event.preventDefault(); + event.target.blur() }) // listen for chatmsg @@ -244,6 +243,9 @@ AFRAME.registerComponent('meeting', { chat.append(data.content) // send to screen }) + // notify join in chat + this.send( this.name+": joined") + return this }, diff --git a/src/3rd/js/aframe/xrf-menu.js b/src/3rd/js/aframe/xrf-menu.js new file mode 100644 index 0000000..aa1e1d6 --- /dev/null +++ b/src/3rd/js/aframe/xrf-menu.js @@ -0,0 +1,48 @@ +AFRAME.registerComponent('xrf-menu', { + schema:{ + id:{ required:true, type:'string'} + }, + init: function(){ + // add css+html + window.XRFMENU.addHTML() + + $('a-scene').addEventListener('XRF', this.onXRFready ) + + if( document.location.search.length > 2 ){ + $('[xrf]').setAttribute('xrf', document.location.search.substr(1)+document.location.hash ) + } + + }, + + onXRFready: function(){ + + let XRF = window.AFRAME.XRF + XRFMENU.setupMenu( XRF ) + + // on localhost enable debugging mode for developer convenience + let loc = document.location + if( loc.host.match(/^localhost/) ){ + $('a-scene').setAttribute('stats') + XRF.debug = 1 + } + + // add screenshot component with camera to capture bigger size equirects + // document.querySelector('a-scene').components.screenshot.capture('perspective') + $('a-scene').setAttribute("screenshot",{camera: "[camera]",width: 4096*2, height:2048*2}) + + if( window.outerWidth > 800 ) + setTimeout( () => window.notify("use WASD-keys and mouse-drag to move around",{timeout:false}),2000 ) + + window.AFRAME.XRF.addEventListener('href', (data) => data.selected ? window.notify(`href: ${data.xrf.string}`) : false ) + + // enable user-uploaded asset files + let fileLoaders = XRFMENU.loadFile({ + ".gltf": (file) => file.arrayBuffer().then( (data) => xrf.navigator.to(file.name,null, (new xrf.loaders.gltf()), data) ), + ".glb": (file) => file.arrayBuffer().then( (data) => xrf.navigator.to(file.name,null, (new xrf.loaders.gltf()), data) ) + }) + $("#overlay > input[type=submit]").addEventListener("click", fileLoaders ) + + } + + +}); diff --git a/src/3rd/js/menu.js b/src/3rd/js/menu.js new file mode 100644 index 0000000..468dc82 --- /dev/null +++ b/src/3rd/js/menu.js @@ -0,0 +1,713 @@ +// handy shortcuts +if( !window.$ ) window.$ = (s) => s ? document.querySelector(s) : false +if( !window.$$ ) window.$$ = (s) => s ? [ ...document.querySelectorAll(s) ] : false + +window.XRFMENU = { + + logo: './../../assets/logo.png', + + html: [ + `🧑‍🤝‍🧑 meeting
`, + `🔗 share
` + ], + + loadFile(contentLoaders, multiple){ + return () => { + window.notify("if you're on Meta browser, file-uploads might be disabled") + let input = document.createElement('input'); + input.type = 'file'; + input.multiple = multiple; + input.accept = Object.keys(contentLoaders).join(","); + input.onchange = () => { + let files = Array.from(input.files); + let file = files.slice ? files[0] : files + for( var i in contentLoaders ){ + let r = new RegExp('\\'+i+'$') + if( file.name.match(r) ) return contentLoaders[i](file) + } + alert(file.name+" is not supported") + }; + input.click(); + } + }, + + setupMenu(XRF){ + let urlbar = $('input#uri') + let inIframe = window.location !== window.parent.location + let els = [ ...document.querySelectorAll('.footer .btn') ] + els = els.filter( (el) => el.id != "more" ? el : false ) + + let showMenu = (state) => { + els.map( (el) => el.style.display = state ? 'inline-block' : 'none' ) + $('a#more').style.display = state ? 'none' : 'inline-block' + $('#overlay').style.display = state ? 'inline-block' : 'none' + if( inIframe ) $('#uri').style.display = 'block' + } + + els.map( (el) => el.addEventListener('click', () => showMenu(false) ) ) + $('a#more').addEventListener('click', () => showMenu(true) ) + $('.a-canvas').addEventListener('click', () => showMenu(false) ) + $('a#meeting').addEventListener('click', () => document.querySelector('a-scene').setAttribute('meeting', 'id: xrfragments') ) + + XRF.addEventListener('hash', () => reflectUrl() ) + const reflectUrl = window.reflectUrl = (url) => { + urlbar.value = url || document.location.search.substr(1) + document.location.hash + } + reflectUrl() + }, + + SnackBar(userOptions) { + var snackbar = this || (window.snackbar = {}); + var _Interval; + var _Message; + var _Element; + var _Container; + + var _OptionDefaults = { + message: "Operation performed successfully.", + dismissible: true, + timeout: 7000, + status: "" + } + var _Options = _OptionDefaults; + + function _Create() { + let _Containers = [ ...document.querySelectorAll(".js-snackbar-container") ] + _Containers.map( (c) => c.remove() ) + _Container = null + + if (!_Container) { + // need to create a new container for notifications + _Container = document.createElement("div"); + _Container.classList.add("js-snackbar-container"); + + document.body.appendChild(_Container); + } + _Container.innerHTML = '' + _Element = document.createElement("div"); + _Element.classList.add("js-snackbar__wrapper","xrf"); + + let innerSnack = document.createElement("div"); + innerSnack.classList.add("js-snackbar", "js-snackbar--show"); + + if (_Options.status) { + _Options.status = _Options.status.toLowerCase().trim(); + + let status = document.createElement("span"); + status.classList.add("js-snackbar__status"); + + + if (_Options.status === "success" || _Options.status === "green") { + status.classList.add("js-snackbar--success"); + } + else if (_Options.status === "warning" || _Options.status === "alert" || _Options.status === "orange") { + status.classList.add("js-snackbar--warning"); + } + else if (_Options.status === "danger" || _Options.status === "error" || _Options.status === "red") { + status.classList.add("js-snackbar--danger"); + } + else { + status.classList.add("js-snackbar--info"); + } + + innerSnack.appendChild(status); + } + + _Message = document.createElement("span"); + _Message.classList.add("js-snackbar__message"); + _Message.innerHTML = _Options.message; + + innerSnack.appendChild(_Message); + + if (_Options.dismissible) { + let closeBtn = document.createElement("span"); + closeBtn.classList.add("js-snackbar__close"); + closeBtn.innerText = "\u00D7"; + + closeBtn.onclick = snackbar.Close; + + innerSnack.appendChild(closeBtn); + } + + _Element.style.height = "0px"; + _Element.style.opacity = "0"; + _Element.style.marginTop = "0px"; + _Element.style.marginBottom = "0px"; + + _Element.appendChild(innerSnack); + _Container.appendChild(_Element); + + if (_Options.timeout !== false) { + _Interval = setTimeout(snackbar.Close, _Options.timeout); + } + } + + var _ConfigureDefaults = function() { + // if no options given, revert to default + if (userOptions === undefined) { + return; + } + + if (userOptions.message !== undefined) { + _Options.message = userOptions.message; + } + + if (userOptions.dismissible !== undefined) { + if (typeof (userOptions.dismissible) === "string") { + _Options.dismissible = (userOptions.dismissible === "true"); + } + else if (typeof (userOptions.dismissible) === "boolean") { + _Options.dismissible = userOptions.dismissible; + } + else { + console.debug("Invalid option provided for 'dismissable' [" + userOptions.dismissible + "] is of type " + (typeof userOptions.dismissible)); + } + } + + + if (userOptions.timeout !== undefined) { + if (typeof (userOptions.timeout) === "boolean" && userOptions.timeout === false) { + _Options.timeout = false; + } + else if (typeof (userOptions.timeout) === "string") { + _Options.timeout = parseInt(userOptions.timeout); + } + + + if (typeof (userOptions.timeout) === "number") { + if (userOptions.timeout === Infinity) { + _Options.timeout = false; + } + else if (userOptions.timeout >= 0) { + _Options.timeout = userOptions.timeout; + } + else { + console.debug("Invalid timeout entered. Must be greater than or equal to 0."); + } + + _Options.timeout = userOptions.timeout; + } + + + } + + if (userOptions.status !== undefined) { + _Options.status = userOptions.status; + } + } + + snackbar.Open = function() { + let contentHeight = _Element.firstElementChild.scrollHeight; // get the height of the content + + _Element.style.height = contentHeight + "px"; + _Element.style.opacity = 1; + _Element.style.marginTop = "5px"; + _Element.style.marginBottom = "5px"; + + _Element.addEventListener("transitioned", function() { + _Element.removeEventListener("transitioned", arguments.callee); + _Element.style.height = null; + }) + } + + snackbar.Close = function () { + if (_Interval) + clearInterval(_Interval); + + let snackbarHeight = _Element.scrollHeight; // get the auto height as a px value + let snackbarTransitions = _Element.style.transition; + _Element.style.transition = ""; + + requestAnimationFrame(function() { + _Element.style.height = snackbarHeight + "px"; // set the auto height to the px height + _Element.style.opacity = 1; + _Element.style.marginTop = "0px"; + _Element.style.marginBottom = "0px"; + _Element.style.transition = snackbarTransitions + + requestAnimationFrame(function() { + _Element.style.height = "0px"; + _Element.style.opacity = 0; + }) + }); + + setTimeout(function() { + try { _Container.removeChild(_Element); } catch (e) { } + }, 1000); + }; + + _ConfigureDefaults(); + _Create(); + snackbar.Open(); + }, + + notify(scope){ + return function notify(str,opts){ + str = String(str) + opts = opts || {} + if( !opts.status ){ + opts.status = "info" + if( str.match(/error/g) ) opts.status = "danger" + if( str.match(/warning/g) ) opts.status = "warning" + } + opts = Object.assign({ message: str , status, timeout:4000 },opts) + window.XRFMENU.SnackBar( opts ) + } + }, + + download(){ + function fetchAndDownload(dataurl, filename) { + var a = document.createElement("a"); + a.href = dataurl; + a.setAttribute("download", filename); + a.click(); + return false; + } + let file = document.location.search.replace(/\?/,'') + fetchAndDownload( file, file ) + }, + + embed(){ + // *TODO* this should be part of the XRF Threejs framework + if( typeof THREE == 'undefined' ) THREE = xrf.THREE + let radToDeg = THREE.MathUtils.radToDeg + let toDeg = (x) => x / (Math.PI / 180) + let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs + + // *TODO* add camera direction + let direction = new xrf.THREE.Vector3() + camera.getWorldDirection(direction) + const pitch = Math.asin(direction.y); + const yaw = Math.atan2(direction.x, direction.z); + const pitchInDegrees = pitch * 180 / Math.PI; + const yawInDegrees = yaw * 180 / Math.PI; + + let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}` + let newHash = document.location.hash.replace(/[&]?(pos|rot)=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'') + newHash += `&${lastPos}` + document.location.hash = newHash.replace(/&&/,'&') + .replace(/#&/,'') + // copy url to clipboard + var dummy = document.createElement('input'), + text = window.location.href; + document.body.appendChild(dummy); + dummy.value = text; + dummy.select(); + document.execCommand('copy'); + document.body.removeChild(dummy); + // End of *TODO* + window.notify(`Link copied to clipboard! ❤️

+
+
+
+ 🖥 clone & selfhost this experience
+
+ To embed this experience in your blog,
+ copy/paste the following into your HTML:
+
+ `,{timeout:2000000}) + // draw QR code + setTimeout( () => { + let QR = window.QR + QR.canvas = document.getElementById('qrcode') + QR.draw( document.location.href, QR.canvas ) + },0) + } +} + +window.XRFMENU.addHTML = () => { + + let el = document.createElement("div") + el.innerHTML += ` + + + + ` + document.body.appendChild(el) + + if( XRFMENU.logo ) $('.logo').style['background-image'] = `url(${XRFMENU.logo})` + + window.notify = XRFMENU.notify(window) + window.embed = XRFMENU.embed + 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'); + } + }); + +}