Compare commits

..

3 Commits

3 changed files with 235 additions and 225 deletions

View File

@@ -131,16 +131,25 @@ export default {
], ],
} }
}).map(slot => { }).map(slot => {
slot.children = CreatureProperties.find({ if (
'parent.id': slot._id, !this.showHiddenSlots &&
removed: {$ne: true}, slot.quantityExpected === 0 &&
}, { slot.hideWhenFull
sort: { order: 1 }, ){
}).fetch(); slot.children = []
} else {
slot.children = CreatureProperties.find({
'parent.id': slot._id,
removed: {$ne: true},
}, {
sort: { order: 1 },
}).fetch();
}
return slot; return slot;
}).filter(slot => !( // Hide full and ignored slots }).filter(slot => !( // Hide full and ignored slots
!this.showHiddenSlots && !this.showHiddenSlots &&
slot.hideWhenFull && slot.hideWhenFull &&
slot.quantityExpected > 0 &&
slot.totalFilled >= slot.quantityExpected || slot.totalFilled >= slot.quantityExpected ||
slot.ignored slot.ignored
)); ));

View File

@@ -1,215 +1,225 @@
<template> <template>
<v-layout class="dialog-stack" align-center justify-center> <v-layout
<transition name="backdrop-fade"> class="dialog-stack"
<div align-center
class="backdrop" justify-center
@click="backdropClicked" >
v-if="dialogs.length" <transition name="backdrop-fade">
></div> <div
</transition> v-if="dialogs.length"
class="backdrop"
@click="backdropClicked"
/>
</transition>
<transition-group <transition-group
name="dialog-list" name="dialog-list"
class="dialog-sizer" class="dialog-sizer"
tag="div" tag="div"
@enter="enter" @enter="enter"
@leave="leave" @leave="leave"
> >
<v-card <v-card
v-for="(dialog, index) in dialogs" v-for="(dialog, index) in dialogs"
:key="dialog._id" :key="dialog._id"
:ref="index"
class="dialog" class="dialog"
:data-element-id="dialog.elementId" :data-element-id="dialog.elementId"
:data-index="index" :data-index="index"
:ref="index" :style="getDialogStyle(index)"
:style="getDialogStyle(index)" :elevation="6"
:elevation="6"
> >
<transition name="slide"> <transition name="slide">
<component :is="dialog.component" v-bind="dialog.data" @pop="popDialogStack($event)" class="dialog-component"></component> <component
</transition> :is="dialog.component"
v-bind="dialog.data"
class="dialog-component"
@pop="popDialogStack($event)"
/>
</transition>
</v-card> </v-card>
</transition-group> </transition-group>
</v-layout> </v-layout>
</template> </template>
<script> <script>
import Vue from "vue"; import Vue from 'vue';
import anime from "animejs"; import anime from 'animejs';
import "/imports/ui/dialogStack/dialogStackWindowEvents.js"; import '/imports/ui/dialogStack/dialogStackWindowEvents.js';
import mockElement from '/imports/ui/dialogStack/mockElement.js'; import mockElement from '/imports/ui/dialogStack/mockElement.js';
import DialogComponentIndex from '/imports/ui/dialogStack/DialogComponentIndex.js'; import DialogComponentIndex from '/imports/ui/dialogStack/DialogComponentIndex.js';
const OFFSET = 16; const OFFSET = 16;
const MOCK_DURATION = 400; // Keep in sync with css transition of .dialog const MOCK_DURATION = 400; // Keep in sync with css transition of .dialog
export default { export default {
components: DialogComponentIndex, components: DialogComponentIndex,
computed: { computed: {
dialogs(){ dialogs(){
return this.$store.state.dialogStack.dialogs; return this.$store.state.dialogStack.dialogs;
}, },
}, },
watch: {
dialogs(newDialogs) {
let el = document.documentElement;
if (newDialogs.length) {
this.top = el.scrollTop;
if (el.scrollHeight > el.clientHeight){
el.style.position = 'fixed';
el.style.top = `${-this.top}px`;
el.style.left = 0;
el.style.right = 0;
el.style.overflowY = 'scroll';
}
} else {
el.style.position = null;
el.style.top = null;
el.style.left = null;
el.style.right = null;
el.style.overflowY = null;
el.scrollTop = this.top;
}
}
},
methods: { methods: {
popDialogStack(result){ popDialogStack(result){
this.$store.dispatch("popDialogStack", result); this.$store.dispatch('popDialogStack', result);
}, },
backdropClicked(event){ backdropClicked(event){
if (event.target === event.currentTarget) this.popDialogStack(); if (event.target === event.currentTarget) this.popDialogStack();
}, },
getDialogStyle(index){ getDialogStyle(index){
const length = this.$store.state.dialogStack.dialogs.length; const length = this.$store.state.dialogStack.dialogs.length;
if (index >= length) return; if (index >= length) return;
const num = length - 1; const num = length - 1;
const left = (num - index) * -OFFSET; const left = (num - index) * -OFFSET;
const top = (num - index) * -OFFSET; const top = (num - index) * -OFFSET;
return `left:${left}px; top:${top}px;`; return `left:${left}px; top:${top}px;`;
}, },
getTopElementByDataId(elementId, offset = 0){ getTopElementByDataId(elementId, offset = 0){
let stackLength = this.$store.state.dialogStack.dialogs.length - offset; let stackLength = this.$store.state.dialogStack.dialogs.length - offset;
if (stackLength){ if (stackLength){
let topDialog = this.$refs[stackLength - 1][0]; let topDialog = this.$refs[stackLength - 1][0];
return topDialog.$el.querySelector(`[data-id='${elementId}']`); return topDialog.$el.querySelector(`[data-id='${elementId}']`);
} else {
return document.querySelector(`[data-id='${elementId}']`);
}
},
enter(target, done){
if (!target || !target.attributes['data-element-id']){
done();
return;
}
let elementId = target.attributes['data-element-id'].value;
let source = this.getTopElementByDataId(elementId, 1);
if (!source){
done();
return;
}
// Get the original styles so we can repair them later
let originalStyle = {
transform: target.style.transform,
backgroundColor: target.style.backgroundColor,
borderRadius: target.style.borderRadius,
transition: target.style.transition,
boxShadow: target.style.boxShadow,
sourceTransition: source.style.transition,
}
// hide the source
source.style.transition = "none";
source.style.opacity = "0";
this.hiddenElement = source;
// Instantly mock the source
target.style.transition = 'none';
mockElement({source, target});
// on the next animation frame, repair the styles
requestAnimationFrame(() => {
target.style.transform = originalStyle.transform;
target.style.backgroundColor = originalStyle.backgroundColor;
target.style.borderRadius = originalStyle.borderRadius;
target.style.transition = originalStyle.transition;
target.style.boxShadow = originalStyle.boxShadow;
source.style.transition = originalStyle.sourceTransition;
setTimeout(done, MOCK_DURATION);
});
},
leave(target, done){
// Give minimongo time to update documents we might need to animate to
setTimeout(() => this.doLeave(target, done));
},
doLeave(target, done){
let elementId;
let returnElementId = this.$store.state.dialogStack.currentReturnElement;
if (returnElementId) {
elementId = returnElementId;
} else {
if (!target || !target.attributes['data-element-id']){
done();
return;
}
elementId = target.attributes['data-element-id'].value;
}
let source = this.getTopElementByDataId(elementId);
if (!source){
console.warn(`Can't find source for ${elementId}`);
done();
return;
}
let index = target.attributes['data-index'].value;
if (index != 0){
// If we aren't the only dialog, we'll need compensate for offset
mockElement({source, target, offset: {x: OFFSET, y: OFFSET}})
} else {
mockElement({source, target});
}
// If the source and the hidden Element are different
// hide the source and reveal the hidden element
let originalSourceTransition = source.style.transition;
if (this.hiddenElement !== source){
source.style.transition = "none";
source.style.opacity = "0";
this.hiddenElement.style.opacity = null;
}
setTimeout(() => {
source.style.opacity = null;
source.style.transition = 'none';
target.style.transition = `opacity ${MOCK_DURATION / 4}ms, pointer-events 0s`
requestAnimationFrame(() => {
source.style.transition = originalSourceTransition;
target.style.opacity = "0";
target.style.pointerEvents = "none";
target.style.setProperty('box-shadow', "none", 'important');
setTimeout(done, MOCK_DURATION / 4);
});
}, MOCK_DURATION);
},
noScroll(e){
e.preventDefault();
}
},
watch: {
dialogs(newDialogs) {
let el = document.documentElement;
if (newDialogs.length) {
this.top = el.scrollTop;
if (el.scrollHeight > el.clientHeight){
el.style.position = 'fixed';
el.style.top = `${-this.top}px`;
el.style.left = 0;
el.style.right = 0;
el.style.overflowY = 'scroll';
}
} else { } else {
el.style.position = null; return document.querySelector(`[data-id='${elementId}']`);
el.style.top = null;
el.style.left = null;
el.style.right = null;
el.style.overflowY = null;
el.scrollTop = this.top;
} }
},
enter(target, done){
if (!target || !target.attributes['data-element-id']){
done();
return;
}
let elementId = target.attributes['data-element-id'].value;
let source = this.getTopElementByDataId(elementId, 1);
if (!source){
done();
return;
}
// Get the original styles so we can repair them later
let originalStyle = {
transform: target.style.transform,
backgroundColor: target.style.backgroundColor,
borderRadius: target.style.borderRadius,
transition: target.style.transition,
boxShadow: target.style.boxShadow,
sourceTransition: source.style.transition,
}
// hide the source
source.style.transition = 'none';
source.style.opacity = '0';
this.hiddenElement = source;
// Instantly mock the source
target.style.transition = 'none';
mockElement({source, target});
// on the next animation frame, repair the styles
requestAnimationFrame(() => {
target.style.transform = originalStyle.transform;
target.style.backgroundColor = originalStyle.backgroundColor;
target.style.borderRadius = originalStyle.borderRadius;
target.style.transition = originalStyle.transition;
target.style.boxShadow = originalStyle.boxShadow;
source.style.transition = originalStyle.sourceTransition;
setTimeout(done, MOCK_DURATION);
});
},
leave(target, done){
// Give minimongo time to update documents we might need to animate to
setTimeout(() => this.doLeave(target, done));
},
doLeave(target, done){
let elementId;
let returnElementId = this.$store.state.dialogStack.currentReturnElement;
if (returnElementId) {
elementId = returnElementId;
} else {
if (!target || !target.attributes['data-element-id']){
done();
return;
}
elementId = target.attributes['data-element-id'].value;
}
let source = this.getTopElementByDataId(elementId);
if (!source){
console.warn(`Can't find source for ${elementId}`);
this.hiddenElement.style.opacity = null;
done();
return;
}
let index = target.attributes['data-index'].value;
if (index != 0){
// If we aren't the only dialog, we'll need compensate for offset
mockElement({source, target, offset: {x: OFFSET, y: OFFSET}})
} else {
mockElement({source, target});
}
// If the source and the hidden Element are different
// hide the source and reveal the hidden element
let originalSourceTransition = source.style.transition;
if (this.hiddenElement !== source){
source.style.transition = 'none';
source.style.opacity = '0';
this.hiddenElement.style.opacity = null;
}
setTimeout(() => {
source.style.opacity = null;
source.style.transition = 'none';
target.style.transition = `opacity ${MOCK_DURATION / 4}ms, pointer-events 0s`
requestAnimationFrame(() => {
source.style.transition = originalSourceTransition;
target.style.opacity = '0';
target.style.pointerEvents = 'none';
target.style.setProperty('box-shadow', 'none', 'important');
setTimeout(done, MOCK_DURATION / 4);
});
}, MOCK_DURATION);
},
noScroll(e){
e.preventDefault();
} }
} }
}; };
</script> </script>
<style scoped> <style scoped>
.backdrop { .backdrop {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: rgba(0, 0, 0, 0.4); background-color: rgba(0, 0, 0, 0.4);
z-index: 4; z-index: 4;
pointer-events: initial; pointer-events: initial;
} }
.backdrop-fade-enter-active, .backdrop-fade-leave-active { .backdrop-fade-enter-active, .backdrop-fade-leave-active {
transition: opacity 0.3s; transition: opacity 0.3s;
} }
.backdrop-fade-enter, .backdrop-fade-leave-to { .backdrop-fade-enter, .backdrop-fade-leave-to {
opacity: 0; opacity: 0;
} }
.dialog-stack { .dialog-stack {
position: fixed; position: fixed;
top: 0; top: 0;
@@ -217,56 +227,56 @@
right: 0; right: 0;
bottom: 0; bottom: 0;
pointer-events: none; pointer-events: none;
z-index: 4; z-index: 4;
} }
.dialog-sizer { .dialog-sizer {
position: relative; position: relative;
width: 80%; width: 80%;
width: calc(100% - 64px); width: calc(100% - 64px);
max-width: 1000px; max-width: 1000px;
height: 80%; height: 80%;
height: calc(100% - 64px); height: calc(100% - 64px);
max-height: 800px; max-height: 800px;
z-index: 5; z-index: 5;
flex: initial; flex: initial;
} }
/* sm */ /* sm */
@media only screen and (max-width: 960px) and (min-width: 601px){ @media only screen and (max-width: 960px) and (min-width: 601px){
.dialog-sizer { .dialog-sizer {
width: calc(100% - 32px); width: calc(100% - 32px);
height: calc(100% - 32px); height: calc(100% - 32px);
} }
} }
/* xs */ /* xs */
@media only screen and (max-width: 600px) { @media only screen and (max-width: 600px) {
.dialog-sizer { .dialog-sizer {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
.dialog-list-enter .dialog-component, .dialog-list-leave-to .dialog-component { .dialog-list-enter .dialog-component, .dialog-list-leave-to .dialog-component {
opacity: 0; opacity: 0;
} }
.dialog-list-enter-active .dialog-component { .dialog-list-enter-active .dialog-component {
transition: opacity 0.3s; transition: opacity 0.3s;
} }
.dialog-list-leave-active .dialog-component { .dialog-list-leave-active .dialog-component {
transition: opacity 0.3s 0.1s; transition: opacity 0.3s 0.1s;
} }
.dialog-list-enter-active { .dialog-list-enter-active {
transition: all 0.4s, box-shadow 0.1s; transition: all 0.4s, box-shadow 0.1s;
} }
.dialog-list-leave-active { .dialog-list-leave-active {
transition: all 0.4s, box-shadow 0.1s 0.3s, opacity 0.1s, pointer-events 0s; transition: all 0.4s, box-shadow 0.1s 0.3s, opacity 0.1s, pointer-events 0s;
} }
.dialog { .dialog {
transform-origin: top left; transform-origin: top left;
position: absolute; position: absolute;
height: 100%; height: 100%;
width: 100%; width: 100%;
pointer-events: initial; pointer-events: initial;
z-index: 1; z-index: 1;
overflow: hidden; overflow: hidden;
} }
.dialog > * { .dialog > * {
height: 100%; height: 100%;

View File

@@ -1,14 +1,5 @@
<template> <template>
<div class="sidebar"> <div class="sidebar">
<v-alert
icon="priority_high"
type="error"
dismissible
:value="true"
>
This version of DiceCloud is in beta. Some data stored here may be destroyed by
future updates.
</v-alert>
<v-layout <v-layout
v-if="!signedIn" v-if="!signedIn"
row row