Got basic dialog working, no morph animation yet

This commit is contained in:
Stefan Zermatten
2018-10-09 16:24:43 +02:00
parent 89820780b5
commit dc8185df98
18 changed files with 318 additions and 101 deletions

View File

@@ -0,0 +1,13 @@
<template>
<v-card>
<v-toolbar color="primary" dark>
<slot name="toolbar"></slot>
</v-toolbar>
<v-layout>
<slot></slot>
</v-layout>
<v-card-actions>
<slot name="actions"></slot>
</v-card-actions>
</v-card>
</template>

View File

@@ -0,0 +1,98 @@
<template>
<v-layout class="dialog-stack" align-center justify-center>
<div
class="backdrop"
@click="backdropClicked"
:class="dialogs.length ? '' : 'hidden' "
></div>
<transition-group name="dialog-list" class="dialog-sizer" tag="div">
<div
v-for="(dialog, index) in dialogs"
:key="dialog._id"
class="dialog"
:style="getDialogStyle(index)"
>
<component :is="dialog.component" :data="dialog.data"></component>
</div>
</transition-group>
</v-layout>
</template>
<script>
import "/imports/ui/dialogStack/dialogStackWindowEvents.js";
import store from "/imports/ui/vuexStore.js";
import anime from "animejs";
const offset = 16;
export default {
computed: {
dialogs(){
return store.state.dialogStack.dialogs;
},
},
methods: {
popDialogStack(){
store.dispatch("popDialogStack");
},
backdropClicked(event){
if (event.target === event.currentTarget) this.popDialogStack();
},
getDialogStyle(index){
const length = store.state.dialogStack.dialogs.length;
if (index >= length) return;
const num = length - 1;
const left = (num - index) * -offset;
const top = (num - index) * -offset;
return `left:${left}px; top:${top}px;`;
},
},
};
</script>
<style scoped>
.dialog-stack {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
}
.dialog-sizer {
position: relative;
height: 500px;
width: 500px;
z-index: 5;
flex: initial;
}
.backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
z-index: 4;
pointer-events: initial;
}
.backdrop.hidden {
display: none
}
.dialog-list-move {
transition: transform 400ms;
}
.dialog-list-leave-active {
}
.dialog {
position: absolute;
height: 100%;
width: 100%;
pointer-events: initial;
}
.dialog > * {
height: 100%;
width: 100%;
}
</style>

View File

@@ -0,0 +1,28 @@
<template>
<dialog-base>
<div slot="toolbar">
Test Dialog
</div>
<div>
<v-btn @click="openDialog">Open Dialog</v-btn>
</div>
</dialog-base>
</template>
<script>
import store from "/imports/ui/vuexStore.js";
import DialogBase from "/imports/ui/dialogStack/DialogBase.vue";
const component = {
methods: {
openDialog(event){
store.commit("pushDialogStack", {
component,
});
}
},
components: {
DialogBase,
},
};
export default component;
</script>

View File

@@ -0,0 +1,87 @@
import store from "/imports/ui/vuexStore.js";
const offset = 16;
const duration = 400;
let dialogStack = {};
dialogStack.dialogs = [];
const dialogStackStore = {
state: {
dialogs: [],
},
mutations: {
pushDialogStack(state, {component, data, element, returnElement, callback}){
// Generate a new _id so that Vue knows how to shuffle the array
const _id = Random.id();
state.dialogs.push({
_id,
component,
data,
element,
returnElement,
callback,
});
updateHistory();
},
popDialogStackMutation (state, result){
const dialog = state.dialogs.pop();
updateHistory();
if (!dialog) return;
dialog.callback && dialog.callback(result);
},
},
actions: {
popDialogStack(context, result){
if (history && history.state && history.state.openDialogs){
history.back();
} else {
context.commit("popDialogStackMutation", result)
}
}
}
};
export default dialogStackStore;
const updateHistory = function(){
// history should looks like: [{openDialogs: 0}, {openDialogs: n}] where
// n is the number of open dialogs
// If we can't access the history object, give up
if (!history) return;
// Make sure that there is a state tracking open dialogs
// replace the state without bashing it in the process
if (!history.state || !_.isFinite(history.state.openDialogs)){
let newState = _.clone(history.state) || {};
newState.openDialogs = 0;
history.replaceState(newState, "");
}
const numDialogs = dialogStackStore.state.dialogs.length;
const stateDialogs = history.state.openDialogs;
// If the number of dialogs and state dialogs are equal, we don't need to do
// anything
if (numDialogs === stateDialogs) return;
if (stateDialogs > 0){
// On a dialog count
if (numDialogs === 0){
// but shouldn't be
history.back();
} else {
// but should replace with correct count
let newState = _.clone(history.state) || {};
newState.openDialogs = dialogStackStore.state.dialogs.length;
history.replaceState(newState, "");
}
} else if (numDialogs > 0 && stateDialogs === 0){
// On the zero state, push a dialog count
history.pushState({openDialogs: numDialogs}, "");
} else {
console.warn(
"History could not be updated correctly, unexpected case",
{stateDialogs, numDialogs},
)
}
};

View File

@@ -0,0 +1,11 @@
import store from "/imports/ui/vuexStore.js";
if (window){
window.onpopstate = function(event){
let state = event.state;
let numDialogs = store.state.dialogStack.dialogs.length;
if (_.isFinite(state.openDialogs) && numDialogs > state.openDialogs){
store.commit("popDialogStackMutation");
}
};
}