Improve drawer on mobile

Fixes #859
This commit is contained in:
rijkvanzanten
2020-11-11 18:01:24 -05:00
parent 7ce4f10d6d
commit 0457509e9e
8 changed files with 118 additions and 56 deletions

View File

@@ -18,17 +18,12 @@
</v-button>
<div class="content">
<v-overlay v-if="$slots.sidebar" absolute :active="sidebarActive" @click="sidebarActive = false" />
<nav
v-if="$slots.sidebar"
class="sidebar"
:class="{ active: sidebarActive }"
@click="sidebarActive = false"
>
<v-overlay v-if="$slots.sidebar" absolute @click="sidebarActive = false" />
<nav v-if="$slots.sidebar" class="sidebar">
<slot name="sidebar" />
</nav>
<main ref="mainEl" class="main">
<header-bar :title="title">
<header-bar :title="title" @primary="$emit('cancel')" primary-action-icon="close">
<template #headline>
<slot name="subtitle">
<p v-if="subtitle" class="subtitle">{{ subtitle }}</p>
@@ -47,6 +42,12 @@
<template #title:append><slot name="header:append" /></template>
</header-bar>
<v-detail class="mobile-sidebar" :label="sidebarLabel">
<nav v-if="$slots.sidebar">
<slot name="sidebar" />
</nav>
</v-detail>
<slot />
</main>
</div>
@@ -57,6 +58,7 @@
<script lang="ts">
import { defineComponent, ref, computed, provide } from '@vue/composition-api';
import HeaderBar from '@/views/private/components/header-bar/header-bar.vue';
import i18n from '../../lang';
export default defineComponent({
components: {
@@ -87,9 +89,12 @@ export default defineComponent({
type: String,
default: 'box',
},
sidebarLabel: {
type: String,
default: i18n.t('sidebar'),
},
},
setup(props, { emit, listeners }) {
const sidebarActive = ref(false);
const localActive = ref(false);
const mainEl = ref<Element>();
@@ -110,7 +115,7 @@ export default defineComponent({
return listeners.hasOwnProperty('cancel');
});
return { sidebarActive, _active, mainEl, showCancel };
return { _active, mainEl, showCancel };
},
});
</script>
@@ -128,6 +133,7 @@ body {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
max-width: var(--v-drawer-max-width);
height: 100%;
background-color: var(--background-page);
@@ -156,27 +162,18 @@ body {
overflow: hidden;
.sidebar {
position: absolute;
top: 0;
left: 0;
z-index: 2;
flex-basis: 220px;
flex-shrink: 0;
width: 220px;
height: 100%;
background-color: var(--background-normal);
transform: translateX(-100%);
transition: transform var(--slow) var(--transition-out);
&.active {
transform: translateX(0);
transition-timing-function: var(--transition-in);
}
display: none;
@include breakpoint(medium) {
position: relative;
z-index: 2;
display: block;
flex-basis: 220px;
flex-shrink: 0;
width: 220px;
height: 100%;
height: auto;
transform: translateX(0);
background-color: var(--background-normal);
}
}
@@ -208,4 +205,13 @@ body {
width: calc(100% - 64px);
}
}
.mobile-sidebar {
margin: var(--content-padding);
nav {
background-color: var(--background-subdued);
border-radius: var(--border-radius);
}
}
</style>

View File

@@ -40,6 +40,7 @@
"
:subtitle="localType ? $t(`field_${localType}`) : null"
persistent
:sidebar-label="currentTabInfo.text"
>
<template #sidebar>
<setup-tabs :current.sync="currentTab" :tabs="tabs" :type="localType" />
@@ -183,7 +184,7 @@ export default defineComponent({
initLocalStore(props.collection, props.field, localType.value);
const { tabs, currentTab } = useTabs();
const { tabs, currentTab, currentTabInfo } = useTabs();
const saving = ref(false);
@@ -200,6 +201,7 @@ export default defineComponent({
existingField,
collectionInfo,
translationsManual,
currentTabInfo,
};
function useTabs() {
@@ -257,7 +259,12 @@ export default defineComponent({
const currentTab = ref(['schema']);
return { tabs, currentTab };
const currentTabInfo = computed(() => {
const tabKey = currentTab.value[0];
return tabs.value.find((tab) => tab.value === tabKey);
});
return { tabs, currentTab, currentTabInfo };
function relationshipDisabled() {
return isEmpty(state.fieldData.field);

View File

@@ -5,16 +5,19 @@
class="new-collection"
persistent
@cancel="$router.push('/settings/data-model')"
:sidebar-label="$t(currentTab)"
>
<template #sidebar>
<v-tabs vertical v-model="currentTab">
<v-tab value="collection">{{ $t('collection_setup') }}</v-tab>
<v-tab value="system" :disabled="!collectionName">{{ $t('optional_system_fields') }}</v-tab>
<v-tab value="collection_setup">{{ $t('collection_setup') }}</v-tab>
<v-tab value="optional_system_fields" :disabled="!collectionName">
{{ $t('optional_system_fields') }}
</v-tab>
</v-tabs>
</template>
<v-tabs-items class="content" v-model="currentTab">
<v-tab-item value="collection">
<v-tab-item value="collection_setup">
<v-notice type="info">{{ $t('creating_collection_info') }}</v-notice>
<div class="grid">
@@ -67,7 +70,7 @@
</div>
</div>
</v-tab-item>
<v-tab-item value="system">
<v-tab-item value="optional_system_fields">
<v-notice type="info">{{ $t('creating_collection_system') }}</v-notice>
<div class="grid system">
@@ -95,8 +98,8 @@
<template #actions>
<v-button
:disabled="!collectionName || collectionName.length === 0"
v-if="currentTab[0] === 'collection'"
@click="currentTab = ['system']"
v-if="currentTab[0] === 'collection_setup'"
@click="currentTab = ['optional_system_fields']"
v-tooltip.bottom="$t('next')"
icon
rounded
@@ -104,7 +107,7 @@
<v-icon name="arrow_forward" />
</v-button>
<v-button
v-if="currentTab[0] === 'system'"
v-if="currentTab[0] === 'optional_system_fields'"
@click="save"
:loading="saving"
v-tooltip.bottom="$t('finish_setup')"
@@ -133,7 +136,7 @@ export default defineComponent({
const fieldsStore = useFieldsStore();
const relationsStore = useRelationsStore();
const currentTab = ref(['collection']);
const currentTab = ref(['collection_setup']);
const collectionName = ref(null);
const singleton = ref(false);
@@ -225,7 +228,7 @@ export default defineComponent({
await fieldsStore.hydrate();
notify({
title: 'Collection Created',
title: i18n.t('collection_created'),
type: 'success',
});

View File

@@ -1,5 +1,11 @@
<template>
<v-drawer :title="modalTitle" :active="true" class="new-collection" persistent>
<v-drawer
:title="modalTitle"
:active="true"
class="new-collection"
persistent
:sidebar-label="currentTabInfo && currentTabInfo.text"
>
<template #sidebar v-if="!loading">
<tabs :current-tab.sync="currentTab" :tabs="tabs" />
</template>
@@ -117,6 +123,12 @@ export default defineComponent({
const currentTab = ref<string[]>([]);
const currentTabInfo = computed(() => {
const tabKey = currentTab.value?.[0];
if (!tabKey) return null;
return tabs.value.find((tab) => tab.value === tabKey);
});
watch(
tabs,
(newTabs, oldTabs) => {
@@ -126,7 +138,7 @@ export default defineComponent({
{ immediate: true }
);
return { permission, role, loading, modalTitle, tabs, currentTab };
return { permission, role, loading, modalTitle, tabs, currentTab, currentTabInfo };
async function load() {
loading.value = true;

View File

@@ -5,7 +5,15 @@
</v-button>
<div class="action-buttons">
<v-button class="sidebar-toggle" icon rounded secondary outlined @click="$emit('toggle:sidebar')">
<v-button
class="sidebar-toggle"
icon
rounded
secondary
outlined
@click="$emit('toggle:sidebar')"
v-if="showSidebarToggle"
>
<v-icon name="info" outline />
</v-button>
@@ -18,7 +26,12 @@
import { defineComponent, ref } from '@vue/composition-api';
export default defineComponent({
props: {},
props: {
showSidebarToggle: {
type: Boolean,
default: false,
},
},
setup() {
const active = ref(false);
return { active };

View File

@@ -1,7 +1,7 @@
<template>
<header class="header-bar" ref="headerEl" :class="{ collapsed: collapsed }">
<v-button secondary class="nav-toggle" icon rounded @click="$emit('toggle:nav')">
<v-icon name="menu" />
<v-button secondary class="nav-toggle" icon rounded @click="$emit('primary')" v-if="$listeners.primary">
<v-icon :name="primaryActionIcon" />
</v-button>
<div class="title-outer-prepend" v-if="$scopedSlots['title-outer:prepend']">
@@ -12,6 +12,7 @@
<div class="headline">
<slot name="headline" />
</div>
<div class="title">
<slot name="title">
<slot name="title:prepend" />
@@ -26,9 +27,11 @@
<div class="spacer" />
<slot name="actions:prepend" />
<header-bar-actions @toggle:sidebar="$emit('toggle:sidebar')">
<header-bar-actions :show-sidebar-toggle="showSidebarToggle" @toggle:sidebar="$emit('toggle:sidebar')">
<slot name="actions" />
</header-bar-actions>
<slot name="actions:append" />
</header>
</template>
@@ -44,6 +47,14 @@ export default defineComponent({
type: String,
default: null,
},
showSidebarToggle: {
type: Boolean,
default: false,
},
primaryActionIcon: {
type: String,
default: 'menu',
},
},
setup() {
const headerEl = ref<Element>();

View File

@@ -1,6 +1,11 @@
<template>
<div>
<v-drawer v-model="_active" :title="$t('item_revision')" @cancel="_active = false">
<v-drawer
v-model="_active"
:title="$t('item_revision')"
@cancel="_active = false"
:sidebar-label="$t(currentTab[0])"
>
<template #subtitle>
<revisions-drawer-picker :revisions="revisions" :current.sync="_current" />
</template>
@@ -14,9 +19,9 @@
</template>
<div class="content">
<revisions-drawer-preview v-if="currentTab[0] === 'preview'" :revision="currentRevision" />
<revisions-drawer-preview v-if="currentTab[0] === 'revision_preview'" :revision="currentRevision" />
<revisions-drawer-updates
v-if="currentTab[0] === 'updates'"
v-if="currentTab[0] === 'updates_made'"
:revision="currentRevision"
:revisions="revisions"
/>
@@ -80,7 +85,7 @@ export default defineComponent({
const _active = useSync(props, 'active', emit);
const _current = useSync(props, 'current', emit);
const currentTab = ref(['preview']);
const currentTab = ref(['revision_preview']);
const currentRevision = computed(() => {
return props.revisions.find((revision) => revision.id === props.current);
@@ -89,11 +94,11 @@ export default defineComponent({
const tabs = [
{
text: i18n.t('revision_preview'),
value: 'preview',
value: 'revision_preview',
},
{
text: i18n.t('updates_made'),
value: 'updates',
value: 'updates_made',
},
];

View File

@@ -19,7 +19,12 @@
</div>
</aside>
<div class="content" ref="contentEl">
<header-bar :title="title" @toggle:sidebar="sidebarOpen = !sidebarOpen" @toggle:nav="navOpen = !navOpen">
<header-bar
show-sidebar-toggle
:title="title"
@toggle:sidebar="sidebarOpen = !sidebarOpen"
@primary="navOpen = !navOpen"
>
<template v-for="(_, scopedSlotName) in $scopedSlots" v-slot:[scopedSlotName]="slotData">
<slot :name="scopedSlotName" v-bind="slotData" />
</template>
@@ -65,9 +70,9 @@ import SidebarButton from './components/sidebar-button/';
import NotificationsGroup from './components/notifications-group/';
import NotificationsPreview from './components/notifications-preview/';
import NotificationDialogs from './components/notification-dialogs/';
import { useUserStore, useAppStore } from '@/stores';
import i18n from '@/lang';
import emitter, { Events } from '@/events';
import { useUserStore, useAppStore } from '../../stores';
import i18n from '../../lang';
import emitter, { Events } from '../../events';
export default defineComponent({
components: {
@@ -127,7 +132,7 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
@import '@/styles/mixins/breakpoint';
@import '../../styles/mixins/breakpoint';
.private-view {
--content-padding: 12px;