ui fixes + build fixes
This commit is contained in:
parent
a5f65fdf03
commit
2a9b97e7bb
|
@ -0,0 +1,296 @@
|
|||
|
||||
// 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#source','a#model','#qrcode']
|
||||
let showButtons = () => {
|
||||
ids.map( (i) => $(i).style.display = 'block' )
|
||||
$('a#more').style.display = 'none'
|
||||
if( inIframe ) $('#uri').style.display = 'block'
|
||||
}
|
||||
$('a#more').addEventListener('click', () => showButtons() )
|
||||
|
||||
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:2000 },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 framework
|
||||
let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs
|
||||
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=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'')
|
||||
newHash += `&${lastPos}`
|
||||
document.location.hash = newHash.replace(/&&/,'&')
|
||||
// End of *TODO*
|
||||
window.notify(`<b>Link copied to clipboard!</b> ❤️<br>ps. to embed this experience in your website,<br>copy/paste the following into your HTML:<br><input type="text" value="<iframe src='${document.location.href}'><br></iframe>" id="share"/>`,{timeout:10000})
|
||||
}
|
|
@ -1060,8 +1060,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
|
||||
return new Promise( (resolve,reject) => {
|
||||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||
|
||||
if( !file || xrf.model.file == file ){ // we're already loaded
|
||||
if( !file || (!data && xrf.model.file == file) ){ // we're already loaded
|
||||
hashbus.pub( url, xrf.model, flags ) // and eval local URI XR fragments
|
||||
xrf.navigator.updateHash(hash)
|
||||
return resolve(xrf.model)
|
||||
|
|
|
@ -1060,8 +1060,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
|
||||
return new Promise( (resolve,reject) => {
|
||||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||
|
||||
if( !file || xrf.model.file == file ){ // we're already loaded
|
||||
if( !file || (!data && xrf.model.file == file) ){ // we're already loaded
|
||||
hashbus.pub( url, xrf.model, flags ) // and eval local URI XR fragments
|
||||
xrf.navigator.updateHash(hash)
|
||||
return resolve(xrf.model)
|
||||
|
|
|
@ -1060,8 +1060,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
|
||||
return new Promise( (resolve,reject) => {
|
||||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||
|
||||
if( !file || xrf.model.file == file ){ // we're already loaded
|
||||
if( !file || (!data && xrf.model.file == file) ){ // we're already loaded
|
||||
hashbus.pub( url, xrf.model, flags ) // and eval local URI XR fragments
|
||||
xrf.navigator.updateHash(hash)
|
||||
return resolve(xrf.model)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<script src="https://cdn.jsdelivr.net/npm/aframe-blink-controls/dist/aframe-blink-controls.min.js"></script>
|
||||
<script src="./../../../dist/xrfragment.aframe.js"></script>
|
||||
<script src="./../../assets/js/qr.js"></script>
|
||||
<script src="./../../../dist/utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="overlay" style="display:none">
|
||||
|
@ -18,13 +19,13 @@
|
|||
<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 )"/>
|
||||
<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() -->
|
||||
<a class="btn-foot" id="source" target="_blank" href="https://github.com/coderofsalvation/xrfragment-helloworld">➕ clone project</a>
|
||||
<a class="btn-foot" id="embed" target="_blank" onclick="embed()">🔗 share</a>
|
||||
<a class="btn-foot" id="model" target="_blank" href="index.gltf">⬇️ scene</a>
|
||||
<a class="btn-foot" id="source" target="_blank" href="https://github.com/coderofsalvation/xrfragment-helloworld">➕ host</a>
|
||||
<a class="btn-foot" id="embed" target="_blank" onclick="window.embed()">🔗 share</a>
|
||||
<a class="btn-foot" id="model" target="_blank" onclick="window.download()">⬇️ scene</a>
|
||||
<a class="btn-foot" id="more" target="_blank">XRF</a>
|
||||
<textarea style="display:none"></textarea>
|
||||
<canvas id="qrcode" style="display:none" width="300" height="300"></canvas>
|
||||
|
@ -32,7 +33,7 @@
|
|||
<a-scene light="defaultLightsEnabled: false">
|
||||
<a-entity id="player" wasd-controls look-controls>
|
||||
<a-entity id="left-hand" laser-controls="hand: left" raycaster="objects:.ray" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor">
|
||||
<a-entity rotation="-90 0 0" position="0 0.1 0">
|
||||
<a-entity rotation="-90 0 0" position="0 0.1 0" id="navigator">
|
||||
<a-entity id="back" xrf-button="label: <; width:0.05; action: history.back()" position="-0.025 0 0" class="ray"></a-entity>
|
||||
<a-entity id="next" xrf-button="label: >; width:0.05; action: history.forward()" position=" 0.025 0 0" class="ray"></a-entity>
|
||||
</a-entity>
|
||||
|
@ -45,8 +46,7 @@
|
|||
<a-plane id="floor" position="0 0 0" rotation="-90 0 0" width="100" height="100" material="visible:false"></a-plane>
|
||||
</a-scene>
|
||||
|
||||
<script type="module">
|
||||
import { loadFile, setupConsole, setupUrlBar, notify, embed } from './../../assets/js/utils.js';
|
||||
<script>
|
||||
window.$ = (s) => document.querySelector(s)
|
||||
window.notify = notify(window)
|
||||
window.embed = embed
|
||||
|
|
|
@ -100,6 +100,7 @@ input[type="submit"] {
|
|||
cursor:pointer;
|
||||
right: 10px;
|
||||
text-transform:uppercase;
|
||||
min-width:107px;
|
||||
}
|
||||
|
||||
a.btn-foot#embed{
|
||||
|
@ -114,6 +115,7 @@ a.btn-foot#model{
|
|||
a.btn-foot#more{
|
||||
bottom:72px;
|
||||
width: 60px;
|
||||
min-width:60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -273,9 +275,9 @@ html{
|
|||
z-index: 2000;
|
||||
position: absolute;
|
||||
border: 5px solid #1c1c3299;
|
||||
bottom: 247px;
|
||||
top: 66px;
|
||||
right: 20px;
|
||||
width: 193px;
|
||||
width: 175px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,10 +54,12 @@ export function setupConsole(el){
|
|||
}
|
||||
|
||||
export function setupUrlBar(el,XRF){
|
||||
let inIframe = window.location !== window.parent.location
|
||||
let ids = ['#overlay','a#embed','a#source','a#model','#qrcode']
|
||||
let showButtons = () => {
|
||||
ids.map( (i) => $(i).style.display = 'block' )
|
||||
$('a#more').style.display = 'none'
|
||||
if( inIframe ) $('#uri').style.display = 'block'
|
||||
}
|
||||
$('a#more').addEventListener('click', () => showButtons() )
|
||||
|
||||
|
@ -270,6 +272,18 @@ export function notify(scope){
|
|||
}
|
||||
}
|
||||
|
||||
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 framework
|
||||
let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<div id="overlay" x-data="{ urls: ['#pos=0,1.6,15','#pos=0,1.6,15&rot=0,360,0'] }">
|
||||
<img src="./../../assets/logo.png" class="logo"/>
|
||||
<input type="submit" value="load 3D file"></input>
|
||||
<input type="text" id="uri" value="" onchange="XRF.navigator.to( $('#uri').value )"/>
|
||||
<input type="text" id="uri" value="" onchange="XRF.navigator.to( $('#uri').value )" style="display:none"/>
|
||||
</div>
|
||||
|
||||
<!-- open AFRAME inspector: $('a-scene').components.inspector.openInspector() -->
|
||||
|
|
2
make
2
make
|
@ -77,6 +77,8 @@ build_js(){
|
|||
# add AFRAME
|
||||
cat dist/xrfragment.three.js \
|
||||
src/3rd/js/aframe/*.js > dist/xrfragment.aframe.js
|
||||
# convert ESM to normal browser js
|
||||
sed 's/export //g' example/assets/js/utils.js > dist/utils.js
|
||||
ls -la dist | grep js
|
||||
exit $ok
|
||||
}
|
||||
|
|
|
@ -7,8 +7,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
|
||||
return new Promise( (resolve,reject) => {
|
||||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||
|
||||
if( !file || xrf.model.file == file ){ // we're already loaded
|
||||
if( !file || (!data && xrf.model.file == file) ){ // we're already loaded
|
||||
hashbus.pub( url, xrf.model, flags ) // and eval local URI XR fragments
|
||||
xrf.navigator.updateHash(hash)
|
||||
return resolve(xrf.model)
|
||||
|
|
Loading…
Reference in New Issue