Use Vue’s transition element to transition between menu panels

This commit is contained in:
Samuel Elliott 2018-08-09 22:50:14 +01:00
parent b33aff51c1
commit 387227cc1f
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
7 changed files with 63 additions and 99 deletions

View File

@ -122,6 +122,9 @@
} }
} }
&.bd-stop .bd-sidebar-region {
z-index: 3004;
}
&.bd-stop .bd-content-region { &.bd-stop .bd-content-region {
z-index: 3003; z-index: 3003;
} }

View File

@ -5,27 +5,28 @@
flex-grow: 1; flex-grow: 1;
backface-visibility: hidden; backface-visibility: hidden;
> div { > * {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1; flex-grow: 1;
&.bd-contentcolumn-enter-active,
&.bd-contentcolumn-leave-active {
transition: opacity 0.4s ease;
} }
> div:not(.active) { &.bd-contentcolumn-enter-to {
opacity: 1;
}
&.bd-contentcolumn-leave-to {
opacity: 0; opacity: 0;
}
&.bd-contentcolumn-leave-active {
position: absolute; position: absolute;
left: 310px; width: 590px;
right: 0;
// width: 100%;
height: 100%;
pointer-events: none; pointer-events: none;
} }
} }
.bd-content {
animation: bd-fade-in .4s forwards;
.animating {
animation: bd-fade-out .4s forwards;
}
} }

View File

@ -46,22 +46,16 @@ export default class {
DOM.createElement('div', null, 'bd-toasts').appendTo(DOM.bdToasts); DOM.createElement('div', null, 'bd-toasts').appendTo(DOM.bdToasts);
DOM.createElement('bd-tooltips').appendTo(DOM.bdBody); DOM.createElement('bd-tooltips').appendTo(DOM.bdBody);
this.toasts = new Vue({ this.toasts = new (Vue.extend(BdToasts))({
el: '#bd-toasts', el: '#bd-toasts'
components: { BdToasts },
template: '<BdToasts />'
}); });
this.modals = new Vue({ this.modals = new (Vue.extend(BdModals))({
el: '#bd-modals', el: '#bd-modals'
components: { BdModals },
template: '<BdModals />'
}); });
this.vueInstance = new Vue({ this.vueInstance = new (Vue.extend(BdSettingsWrapper))({
el: '#bd-settings', el: '#bd-settings'
components: { BdSettingsWrapper },
template: '<BdSettingsWrapper />'
}); });
return this.vueInstance; return this.vueInstance;

View File

@ -9,8 +9,8 @@
*/ */
<template> <template>
<div class="bd-settings" :class="{active: active, 'bd-settings-out': activeIndex === -1 && lastActiveIndex >= 0}" @keyup="$emit('close')"> <div class="bd-settings" :class="{active, 'bd-settings-out': !item && animating}" @keyup="$emit('close')">
<SidebarView :contentVisible="this.activeIndex >= 0 || this.lastActiveIndex >= 0" :animating="this.animating" :class="{'bd-stop': !first}"> <SidebarView :contentVisible="item" :animating="animating" :class="{'bd-stop': item}">
<Sidebar slot="sidebar"> <Sidebar slot="sidebar">
<div class="bd-settings-x" @click="$emit('close')"> <div class="bd-settings-x" @click="$emit('close')">
<MiClose size="17"/> <MiClose size="17"/>
@ -18,9 +18,10 @@
</div> </div>
<template v-for="(category, text) in sidebar"> <template v-for="(category, text) in sidebar">
<SidebarItem :item="{text, type: 'header'}" /> <SidebarItem :item="{text, type: 'header'}" />
<SidebarItem v-for="item in category" :item="item" :key="item.id" @click="itemOnClick(item.id)" /> <SidebarItem v-for="i in category" :key="i.id" :item="i" :active="item && i.id === item.id" @click="itemOnClick(i.id)" />
</template> </template>
</Sidebar> </Sidebar>
<div slot="sidebarfooter" class="bd-info"> <div slot="sidebarfooter" class="bd-info">
<span class="bd-vtext">v2.0.0a by Jiiks/JsSucks</span> <span class="bd-vtext">v2.0.0a by Jiiks/JsSucks</span>
<div @click="openGithub" v-tooltip="'GitHub'" class="bd-material-button"> <div @click="openGithub" v-tooltip="'GitHub'" class="bd-material-button">
@ -33,25 +34,28 @@
<MiWeb size="16" /> <MiWeb size="16" />
</div> </div>
</div> </div>
<ContentColumn slot="content"> <ContentColumn slot="content">
<div v-for="item in sidebarItems" v-if="activeContent(item.contentid) || animatingContent(item.contentid)" :class="{active: activeContent(item.contentid), animating: animatingContent(item.contentid)}"> <transition name="bd-contentcolumn" @before-enter="animating++" @after-enter="animating--" @enter-cancelled="animating--" @before-leave="animating++" @after-leave="animating--" @leave-cancelled="animating--">
<div v-if="item" :key="item.id">
<template v-if="item.component"> <template v-if="item.component">
<component :is="item.component" :SettingsWrapper="SettingsWrapper" /> <component :is="item.component" :SettingsWrapper="SettingsWrapper" />
</template> </template>
<SettingsWrapper v-if="typeof item.set === 'string'" :headertext="Settings.getSet(item.set).headertext"> <SettingsWrapper v-else-if="typeof item.set === 'string'" :headertext="Settings.getSet(item.set).headertext">
<SettingsPanel :settings="Settings.getSet(item.set)" :schemes="Settings.getSet(item.set).schemes" /> <SettingsPanel :settings="Settings.getSet(item.set)" :schemes="Settings.getSet(item.set).schemes" />
</SettingsWrapper> </SettingsWrapper>
<SettingsWrapper v-else-if="item.set" :headertext="item.set.headertext"> <SettingsWrapper v-else-if="item.set" :headertext="item.set.headertext">
<SettingsPanel :settings="item.set" :schemes="item.set.schemes" /> <SettingsPanel :settings="item.set" :schemes="item.set.schemes" />
</SettingsWrapper> </SettingsWrapper>
<ConnectivityView v-if="item.contentid === 'connectivity'"/> <ConnectivityView v-else-if="item.contentid === 'connectivity'" />
<CssEditorView v-if="item.contentid === 'css'" /> <CssEditorView v-else-if="item.contentid === 'css'" />
<PluginsView v-if="item.contentid === 'plugins'" /> <PluginsView v-else-if="item.contentid === 'plugins'" />
<ThemesView v-if="item.contentid === 'themes'" /> <ThemesView v-else-if="item.contentid === 'themes'" />
<UpdaterView v-if="item.contentid === 'updater'" /> <UpdaterView v-else-if="item.contentid === 'updater'" />
</div> </div>
</transition>
</ContentColumn> </ContentColumn>
</SidebarView> </SidebarView>
</div> </div>
@ -69,13 +73,10 @@
export default { export default {
data() { data() {
return { return {
BdMenuItems, animating: 0,
activeIndex: -1, item: null,
lastActiveIndex: -1, items: BdMenuItems.items,
animating: false,
first: true,
Settings, Settings,
timeout: null,
SettingsWrapper, SettingsWrapper,
openMenuHandler: null openMenuHandler: null
}; };
@ -87,12 +88,9 @@
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle MiGithubCircle, MiWeb, MiClose, MiTwitterCircle
}, },
computed: { computed: {
sidebarItems() {
return this.BdMenuItems.items;
},
sidebar() { sidebar() {
const categories = {}; const categories = {};
for (let item of this.sidebarItems) { for (let item of this.items) {
if (item.hidden) continue; if (item.hidden) continue;
const category = categories[item.category] || (categories[item.category] = []); const category = categories[item.category] || (categories[item.category] = []);
category.push(item); category.push(item);
@ -102,42 +100,10 @@
}, },
methods: { methods: {
itemOnClick(id) { itemOnClick(id) {
if (this.animating || id === this.activeIndex) return; this.item = this.items.find(item => item.id === id);
const activeItem = this.sidebarItems.find(item => item.id === this.activeIndex);
if (activeItem) activeItem.active = false;
this.sidebarItems.find(item => item.id === id).active = true;
this.animating = true;
this.lastActiveIndex = this.activeIndex;
this.activeIndex = id;
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.first = false;
this.animating = false;
this.lastActiveIndex = -1;
this.timeout = null;
}, 400);
},
activeContent(s) {
const item = this.sidebarItems.find(item => item.contentid === s);
return item && item.id === this.activeIndex;
},
animatingContent(s) {
const item = this.sidebarItems.find(item => item.contentid === s);
return item && item.id === this.lastActiveIndex;
}, },
closeContent() { closeContent() {
if (this.activeIndex >= 0) this.sidebarItems.find(item => item.id === this.activeIndex).active = false; this.item = null;
this.first = true;
this.lastActiveIndex = this.activeIndex;
this.activeIndex = -1;
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.animating = false;
this.lastActiveIndex = -1;
this.timeout = null;
}, 400);
}, },
openGithub() { openGithub() {
shell.openExternal('https://github.com/JsSucks/BetterDiscordApp'); shell.openExternal('https://github.com/JsSucks/BetterDiscordApp');
@ -156,7 +122,7 @@
} }
}, },
created() { created() {
Events.on('bd-open-menu', this.openMenuHandler = item => item && this.itemOnClick(this.sidebarItems.find(i => i === item || i.id === item || i.contentid === item || i.set === item).id)); Events.on('bd-open-menu', this.openMenuHandler = item => item && this.itemOnClick(this.items.find(i => i === item || i.id === item || i.contentid === item || i.set === item).id));
}, },
destroyed() { destroyed() {
if (this.openMenuHandler) Events.off('bd-open-menu', this.openMenuHandler); if (this.openMenuHandler) Events.off('bd-open-menu', this.openMenuHandler);

View File

@ -9,13 +9,13 @@
*/ */
<template> <template>
<div class="bd-item" :class="{active: item.active}" @click="$emit('click', item.id)"> <div class="bd-item" :class="{active}" @click="$emit('click', item.id)">
{{item.text}} {{item.text}}
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: ['item'] props: ['item', 'active']
} }
</script> </script>

View File

@ -9,7 +9,7 @@
*/ */
<template> <template>
<SidebarButton v-if="item._type === 'button'" :item="item" @click="$emit('click', $event)" /> <SidebarButton v-if="item._type === 'button'" :item="item" :active="active" @click="$emit('click', $event)" />
<SidebarHeader v-else :item="item" /> <SidebarHeader v-else :item="item" />
</template> </template>
@ -18,7 +18,7 @@
import { SidebarHeader, SidebarButton } from './'; import { SidebarHeader, SidebarButton } from './';
export default { export default {
props: ['item'], props: ['item', 'active'],
components: { components: {
SidebarHeader, SidebarHeader,
SidebarButton SidebarButton