Compare commits
3 Commits
2.0-beta.1
...
2.0-beta.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27f1f4e720 | ||
|
|
d63b8c835d | ||
|
|
85f3881935 |
@@ -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
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -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%;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user