Merge pull request #688 from directus/modal-drawer

New modal design!
This commit is contained in:
Rijk van Zanten
2020-10-16 15:18:46 -04:00
committed by GitHub
133 changed files with 894 additions and 1090 deletions

View File

@@ -48,7 +48,7 @@ export default defineComponent({
const userStore = useUserStore();
const settingsStore = useSettingsStore();
const { hydrating, drawerOpen } = toRefs(appStore.state);
const { hydrating, sidebarOpen } = toRefs(appStore.state);
const brandStyle = computed(() => {
return {
@@ -73,9 +73,9 @@ export default defineComponent({
if (newWidth === oldWidth) return;
if (newWidth >= 1424) {
if (drawerOpen.value === false) drawerOpen.value = true;
if (sidebarOpen.value === false) sidebarOpen.value = true;
} else {
if (drawerOpen.value === true) drawerOpen.value = false;
if (sidebarOpen.value === true) sidebarOpen.value = false;
}
},
{ immediate: true }

View File

@@ -22,8 +22,7 @@ import VInput from './v-input/';
import VItemGroup, { VItem } from './v-item-group';
import VList, { VListGroup, VListItem, VListItemContent, VListItemHint, VListItemIcon, VListItemText } from './v-list/';
import VMenu from './v-menu/';
import VModal from './v-modal/';
import VModalHeading from './v-modal/v-modal-heading.vue';
import VDrawer from './v-drawer/';
import VNotice from './v-notice/';
import VOverlay from './v-overlay/';
import VPagination from './v-pagination/';
@@ -73,8 +72,7 @@ Vue.component('v-list-item-text', VListItemText);
Vue.component('v-list-item', VListItem);
Vue.component('v-list', VList);
Vue.component('v-menu', VMenu);
Vue.component('v-modal', VModal);
Vue.component('v-modal-heading', VModalHeading);
Vue.component('v-drawer', VDrawer);
Vue.component('v-notice', VNotice);
Vue.component('v-overlay', VOverlay);
Vue.component('v-pagination', VPagination);
@@ -104,14 +102,14 @@ Vue.component('transition-expand', TransitionExpand);
import RenderDisplay from '@/views/private/components/render-display';
import RenderTemplate from '@/views/private/components/render-template';
import DrawerDetail from '@/views/private/components/drawer-detail/';
import FilterDrawerDetail from '@/views/private/components/filter-drawer-detail';
import SidebarDetail from '@/views/private/components/sidebar-detail/';
import FilterSidebarDetail from '@/views/private/components/filter-sidebar-detail';
import UserPopover from '@/views/private/components/user-popover';
import ValueNull from '@/views/private/components/value-null';
Vue.component('render-display', RenderDisplay);
Vue.component('render-template', RenderTemplate);
Vue.component('filter-drawer-detail', FilterDrawerDetail);
Vue.component('drawer-detail', DrawerDetail);
Vue.component('filter-sidebar-detail', FilterSidebarDetail);
Vue.component('sidebar-detail', SidebarDetail);
Vue.component('user-popover', UserPopover);
Vue.component('value-null', ValueNull);

View File

@@ -5,24 +5,34 @@
</template>
<style lang="scss">
/** @NOTE this is not scoped on purpose. The children are outsisde of the tree (portal) */
/** @NOTE this is not scoped on purpose. The children are outside of the tree (portal) */
.dialog-enter-active,
.dialog-leave-active {
transition: opacity var(--slow) var(--transition);
& > *:not(.v-overlay) {
&.center > *:not(.v-overlay) {
transform: translateY(0px);
transition: transform var(--slow) var(--transition-in);
}
&.right > *:not(.v-overlay) {
transform: translateX(0px);
transition: transform var(--slow) var(--transition-in);
}
}
.dialog-enter,
.dialog-leave-to {
opacity: 0;
& > *:not(.v-overlay) {
&.center > *:not(.v-overlay) {
transform: translateY(50px);
transition: transform var(--slow) var(--transition-out);
}
&.right > *:not(.v-overlay) {
transform: translateX(50px);
transition: transform var(--slow) var(--transition-out);
}
}
</style>

View File

@@ -3,7 +3,7 @@
<slot name="activator" v-bind="{ on: () => (_active = true) }" />
<portal to="dialog-outlet">
<div v-if="_active" class="container" :class="[className]" :key="id">
<div v-if="_active" class="container" :class="[className, placement]" :key="id">
<v-overlay active absolute @click="emitToggle" />
<slot />
</div>
@@ -30,6 +30,11 @@ export default defineComponent({
type: Boolean,
default: false,
},
placement: {
type: String,
default: 'center',
validator: (val: string) => ['center', 'right'].includes(val),
},
},
setup(props, { emit }) {
const dialog = ref<HTMLElement | null>(null);
@@ -92,11 +97,32 @@ export default defineComponent({
left: 0;
z-index: 500;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
transition: opacity var(--medium) var(--transition);
::v-deep > * {
z-index: 2;
box-shadow: 0px 4px 12px rgba(38, 50, 56, 0.1);
}
&.center {
align-items: center;
justify-content: center;
&.nudge > ::v-deep *:not(:first-child) {
animation: nudge 200ms;
}
}
&.right {
align-items: center;
justify-content: flex-end;
&.nudge > ::v-deep *:not(:first-child) {
transform-origin: right;
animation: shake 200ms;
}
}
::v-deep .v-card {
--v-card-min-width: 540px;
@@ -112,15 +138,6 @@ export default defineComponent({
.v-overlay {
--v-overlay-z-index: 1;
}
&.nudge {
animation: nudge 200ms;
}
::v-deep > * {
z-index: 2;
box-shadow: 0px 4px 12px rgba(38, 50, 56, 0.1);
}
}
@keyframes nudge {
@@ -136,4 +153,18 @@ export default defineComponent({
transform: scale(1);
}
}
@keyframes shake {
0% {
transform: scaleX(1);
}
50% {
transform: scaleX(0.98);
}
100% {
transform: scaleX(1);
}
}
</style>

View File

@@ -0,0 +1,4 @@
import VDrawer from './v-drawer.vue';
export { VDrawer };
export default VDrawer;

View File

@@ -1,20 +1,23 @@
<template>
<v-dialog v-model="_active" @esc="$emit('esc')" :persistent="persistent">
<v-dialog v-model="_active" @esc="$emit('cancel')" :persistent="persistent" placement="right">
<template #activator="{ on }">
<slot name="activator" v-bind="{ on }" />
</template>
<article class="v-modal" :class="{ 'form-width': formWidth }">
<header class="header">
<v-icon class="menu-toggle" name="menu" @click="sidebarActive = !sidebarActive" />
<h2 class="title">{{ title }}</h2>
<slot name="subtitle">
<p v-if="subtitle" class="subtitle">{{ subtitle }}</p>
</slot>
<div class="spacer" />
<slot name="header:append" />
</header>
<div class="content" :class="{ 'no-padding': noPadding }">
<article class="v-drawer">
<v-button
v-if="showCancel"
class="cancel"
@click="$emit('cancel')"
icon
rounded
secondary
v-tooltip.bottom="$t('cancel')"
>
<v-icon name="close" />
</v-button>
<div class="content">
<v-overlay v-if="$slots.sidebar" absolute :active="sidebarActive" @click="sidebarActive = false" />
<nav
v-if="$slots.sidebar"
@@ -25,20 +28,40 @@
<slot name="sidebar" />
</nav>
<main ref="mainEl" class="main">
<header-bar :title="title">
<template #headline>
<slot name="subtitle">
<p v-if="subtitle" class="subtitle">{{ subtitle }}</p>
</slot>
</template>
<template #title-outer:prepend>
<v-button class="header-icon" rounded icon secondary disabled>
<v-icon :name="icon" />
</v-button>
</template>
<template #actions:prepend><slot name="actions:prepend" /></template>
<template #actions><slot name="actions" /></template>
<template #title:append><slot name="header:append" /></template>
</header-bar>
<slot />
</main>
</div>
<footer class="footer" v-if="$slots.footer || $scopedSlots.footer">
<slot name="footer" v-bind="{ close: () => (_active = false) }" />
</footer>
</article>
</v-dialog>
</template>
<script lang="ts">
import { defineComponent, ref, computed, provide } from '@vue/composition-api';
import HeaderBar from '@/views/private/components/header-bar/header-bar.vue';
export default defineComponent({
components: {
HeaderBar,
},
model: {
prop: 'active',
event: 'toggle',
@@ -60,18 +83,12 @@ export default defineComponent({
type: Boolean,
default: false,
},
noPadding: {
type: Boolean,
default: false,
},
formWidth: {
// If the modal is used to just render a form, it needs to be a little smaller to
// allow the form to be rendered in it's correct full size
type: Boolean,
default: false,
icon: {
type: String,
default: 'box',
},
},
setup(props, { emit }) {
setup(props, { emit, listeners }) {
const sidebarActive = ref(false);
const localActive = ref(false);
@@ -89,63 +106,47 @@ export default defineComponent({
},
});
return { sidebarActive, _active, mainEl };
const showCancel = computed(() => {
return listeners.hasOwnProperty('cancel');
});
return { sidebarActive, _active, mainEl, showCancel };
},
});
</script>
<style>
body {
--v-modal-max-width: 916px;
--v-drawer-max-width: 856px;
}
</style>
<style lang="scss" scoped>
@import '@/styles/mixins/breakpoint';
.v-modal {
.v-drawer {
position: relative;
display: flex;
flex-direction: column;
width: calc(100% - 16px);
max-width: var(--v-modal-max-width);
height: calc(100% - 16px);
max-height: 800px;
max-width: var(--v-drawer-max-width);
height: 100%;
background-color: var(--background-page);
border-radius: 4px;
.cancel {
position: absolute;
top: 32px;
left: -76px;
}
.spacer {
flex-grow: 1;
}
.header {
display: flex;
flex-shrink: 0;
align-items: center;
height: 60px;
padding: 0 16px;
border-bottom: 2px solid var(--background-normal);
.title {
margin-right: 12px;
font-size: 16px;
}
.subtitle {
color: var(--foreground-subdued);
font-size: 16px;
}
.menu-toggle {
margin-right: 8px;
@include breakpoint(medium) {
display: none;
}
}
@include breakpoint(medium) {
padding: 0 24px;
}
.header-icon {
--v-button-background-color: var(--background-normal);
--v-button-background-color-activated: var(--background-normal);
--v-button-background-color-hover: var(--background-normal-alt);
--v-button-color-disabled: var(--foreground-normal);
}
.content {
@@ -190,45 +191,20 @@ body {
}
.main {
--content-padding: 16px;
--content-padding-bottom: 32px;
flex-grow: 1;
padding: 16px 16px 32px;
overflow: auto;
@include breakpoint(medium) {
padding: 32px;
--content-padding: 32px;
}
}
&.no-padding .main {
padding: 0px;
}
}
.footer {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: flex-end;
height: 60px;
padding: 0 16px;
border-top: 2px solid var(--background-normal);
::v-deep > *:not(:last-child) {
margin-right: 8px;
}
@include breakpoint(medium) {
padding: 0 24px;
}
}
@include breakpoint(medium) {
width: calc(100% - 64px);
height: calc(100% - 64px);
}
}
.form-width {
--v-modal-max-width: 856px;
}
</style>

View File

@@ -139,10 +139,10 @@ export default defineComponent({
const gridClass = computed<string | null>(() => {
if (el.value === null) return null;
if (width.value > 588 && width.value <= 792) {
return 'grid';
} else {
if (width.value > 792) {
return 'grid with-fill';
} else {
return 'grid';
}
return null;

View File

@@ -1,4 +0,0 @@
import VModal from './v-modal.vue';
export { VModal };
export default VModal;

View File

@@ -1,73 +0,0 @@
# Modal
A modal is basically an elaborate pre-configured dialog. It supports an optional left sidebar that allows for easier tab usage.
## Usage
```html
<v-modal title="My Modal" v-modal="active">
Hello, world!
</v-modal>
```
```html
<v-modal title="My Modal">
<template #activator="{ on }">
<v-button @click="on">Open modal</v-button>
</template>
Hello, world!
</v-modal>
```
```html
<v-modal title="My Modal" v-model="active">
<template #activator="{ on }">
<v-button @click="on">Open modal</v-button>
</template>
<template #sidebar>
<v-tabs vertical>
<v-tab>Hello</v-tab>
<v-tab>Page 2</v-tab>
<v-tab>Page 3</v-tab>
</v-tabs>
</template>
<v-tabs-items>
<v-tab-item>Hello, world!</v-tab-item>
<v-tab-item>I'm page 2!</v-tab-item>
<v-tab-item>I'm page 3!</v-tab-item>
</v-tabs-items>
<template #footer="{ close }">
<v-button @click="close">Close modal</v-button>
</template>
</v-modal>
```
## Props
| Prop | Description | Default |
|--------------|-----------------------------------------------------------------|---------|
| `title`* | Title for the modal | |
| `subtitle` | Optional subtitle for the modal | |
| `active` | If the modal is active. Used in `v-model` | `false` |
| `persistent` | Prevent the user from exiting the modal by clicking the overlay | `false` |
## Events
| Event | Description | Value |
|----------|--------------------------|-----------|
| `toggle` | Sync the `v-model` value | `boolean` |
## Slots
| Slot | Description | Data |
|-------------|--------------------------------------------------------|-------------------------|
| _default_ | Modal content | |
| `activator` | Element to enable the modal | `{ on: () => void }` |
| `sidebar` | Sidebar content for the modal. Often used for `v-tabs` | |
| `footer` | Footer content. Often used for action buttons | `{ close: () => void }` |
## CSS Variables
n/a

View File

@@ -1,34 +0,0 @@
<template>
<div class="v-modal-heading">
<div class="type-title">{{ heading }}</div>
<div v-if="subheading" class="subheading">{{ subheading }}</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from '@vue/composition-api';
export default defineComponent({
props: {
heading: {
type: String,
required: true,
},
subheading: {
type: String,
default: null,
},
},
});
</script>
<style lang="scss" scoped>
.v-modal-heading {
margin-bottom: 48px;
.subheading {
margin-top: 4px;
color: var(--foreground-subdued);
}
}
</style>

View File

@@ -1,84 +0,0 @@
import withPadding from '../../../.storybook/decorators/with-padding';
import readme from './readme.md';
import { defineComponent, ref } from '@vue/composition-api';
export default {
title: 'Components / Modal',
parameters: {
notes: readme,
},
decorators: [withPadding],
};
export const basic = () =>
defineComponent({
setup() {
const active = ref(false);
return { active };
},
template: `
<div>
<v-modal
v-model="active"
title="Creating New Collection"
subtitle="called Customers"
>
<template #activator="{ on }">
<v-button @click="on">Enable modal</v-button>
</template>
<p>Hello world!</p>
<template #footer="{ close }">
<v-button @click="close">Close modal</v-button>
</template>
</v-modal>
<portal-target name="outlet" />
</div>
`,
});
export const withNav = () =>
defineComponent({
setup() {
const active = ref(false);
const current = ref(['hello']);
return { active, current };
},
template: `
<div>
<v-modal
v-model="active"
title="Creating New Collection"
subtitle="called Customers"
>
<template #activator="{ on }">
<v-button @click="on">Enable modal</v-button>
</template>
<template #sidebar>
<v-tabs v-model="current" vertical>
<v-tab value="hello">Hello</v-tab>
<v-tab value="introduce">Modal</v-tab>
</v-tabs>
</template>
<v-tabs-items v-model="current">
<v-tab-item value="hello">
<p>Hello world!</p>
</v-tab-item>
<v-tab-item value="introduce">
<p>I'm a modal with tabs</p>
</v-tab-item>
</v-tabs-items>
<template #footer="{ close }">
<v-button @click="close">Close modal</v-button>
</template>
</v-modal>
<portal-target name="outlet" />
</div>
`,
});

View File

@@ -1,24 +0,0 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueCompositionAPI from '@vue/composition-api';
import VModal from './v-modal.vue';
import VDialog from '@/components/v-dialog/';
import VIcon from '@/components/v-icon/';
const localVue = createLocalVue();
localVue.use(VueCompositionAPI);
localVue.component('v-dialog', VDialog);
localVue.component('v-icon', VIcon);
describe('Components / Modal', () => {
it('Renders', () => {
const component = shallowMount(VModal, {
localVue,
propsData: {
title: 'My Modal',
},
});
expect(component.isVueInstance()).toBe(true);
});
});

View File

@@ -52,7 +52,7 @@
</v-list>
</v-menu>
<modal-collection
<drawer-collection
collection="directus_files"
:active="activeDialog === 'choose'"
@update:active="activeDialog = null"
@@ -88,12 +88,12 @@
<script lang="ts">
import { defineComponent, ref, computed, watch } from '@vue/composition-api';
import uploadFiles from '@/utils/upload-files';
import ModalCollection from '@/views/private/components/modal-collection';
import DrawerCollection from '@/views/private/components/drawer-collection';
import api from '@/api';
import useItem from '@/composables/use-item';
export default defineComponent({
components: { ModalCollection },
components: { DrawerCollection },
props: {
multiple: {
type: Boolean,

View File

@@ -79,7 +79,7 @@
</v-card>
</v-dialog>
<modal-collection
<drawer-collection
collection="directus_files"
:active="activeDialog === 'choose'"
@update:active="activeDialog = null"
@@ -112,7 +112,7 @@
<script lang="ts">
import { defineComponent, ref, watch, computed } from '@vue/composition-api';
import ModalCollection from '@/views/private/components/modal-collection';
import DrawerCollection from '@/views/private/components/drawer-collection';
import api from '@/api';
import readableMimeType from '@/utils/readable-mime-type';
import getRootPath from '@/utils/get-root-path';
@@ -124,7 +124,7 @@ type FileInfo = {
};
export default defineComponent({
components: { ModalCollection },
components: { DrawerCollection },
props: {
value: {
type: String,

View File

@@ -34,7 +34,7 @@
</v-button>
</div>
<modal-item
<drawer-item
v-if="!disabled"
:active="editModalActive"
:collection="relationInfo.junctionCollection"
@@ -46,7 +46,7 @@
@update:active="cancelEdit"
/>
<modal-collection
<drawer-collection
v-if="!disabled"
:active.sync="selectModalActive"
:collection="relationInfo.relationCollection"
@@ -71,8 +71,8 @@
<script lang="ts">
import { defineComponent, ref, computed, toRefs, PropType } from '@vue/composition-api';
import { Header as TableHeader } from '@/components/v-table/types';
import ModalCollection from '@/views/private/components/modal-collection';
import ModalItem from '@/views/private/components/modal-item';
import DrawerCollection from '@/views/private/components/drawer-collection';
import DrawerItem from '@/views/private/components/drawer-item';
import { get } from 'lodash';
import i18n from '@/lang';
@@ -83,7 +83,7 @@ import usePreview from '@/interfaces/many-to-many/use-preview';
import useEdit from '@/interfaces/many-to-many/use-edit';
export default defineComponent({
components: { ModalCollection, ModalItem },
components: { DrawerCollection, DrawerItem },
props: {
primaryKey: {
type: [Number, String],

View File

@@ -38,7 +38,7 @@
</v-button>
</div>
<modal-item
<drawer-item
v-if="!disabled"
:active="editModalActive"
:collection="relationInfo.junctionCollection"
@@ -50,7 +50,7 @@
@update:active="cancelEdit"
/>
<modal-collection
<drawer-collection
v-if="!disabled"
:active.sync="selectModalActive"
:collection="relationCollection.collection"
@@ -64,8 +64,8 @@
<script lang="ts">
import { defineComponent, ref, computed, watch, PropType, toRefs } from '@vue/composition-api';
import ModalItem from '@/views/private/components/modal-item';
import ModalCollection from '@/views/private/components/modal-collection';
import DrawerItem from '@/views/private/components/drawer-item';
import DrawerCollection from '@/views/private/components/drawer-collection';
import { get } from 'lodash';
import useActions from './use-actions';
@@ -75,7 +75,7 @@ import useEdit from './use-edit';
import useSelection from './use-selection';
export default defineComponent({
components: { ModalItem, ModalCollection },
components: { DrawerItem, DrawerCollection },
props: {
value: {
type: Array as PropType<(number | string | Record<string, any>)[] | null>,

View File

@@ -82,7 +82,7 @@
</v-list>
</v-menu>
<modal-item
<drawer-item
v-if="!disabled"
:active.sync="editModalActive"
:collection="relatedCollection.collection"
@@ -91,7 +91,7 @@
@input="stageEdits"
/>
<modal-collection
<drawer-collection
v-if="!disabled"
:active.sync="selectModalActive"
:collection="relatedCollection.collection"
@@ -107,8 +107,8 @@ import { useCollectionsStore, useRelationsStore } from '@/stores/';
import useCollection from '@/composables/use-collection';
import getFieldsFromTemplate from '@/utils/get-fields-from-template';
import api from '@/api';
import ModalItem from '@/views/private/components/modal-item';
import ModalCollection from '@/views/private/components/modal-collection';
import DrawerItem from '@/views/private/components/drawer-item';
import DrawerCollection from '@/views/private/components/drawer-collection';
/**
* @NOTE
@@ -119,7 +119,7 @@ import ModalCollection from '@/views/private/components/modal-collection';
*/
export default defineComponent({
components: { ModalItem, ModalCollection },
components: { DrawerItem, DrawerCollection },
props: {
value: {
type: [Number, String, Object],

View File

@@ -38,7 +38,7 @@
</v-button>
</div>
<modal-item
<drawer-item
v-if="!disabled"
:active="currentlyEditing !== null"
:collection="relatedCollection.collection"
@@ -48,7 +48,7 @@
@update:active="cancelEdit"
/>
<modal-collection
<drawer-collection
v-if="!disabled"
:active.sync="selectModalActive"
:collection="relatedCollection.collection"
@@ -65,14 +65,14 @@ import { defineComponent, ref, computed, watch, PropType } from '@vue/compositio
import api from '@/api';
import useCollection from '@/composables/use-collection';
import { useCollectionsStore, useRelationsStore, useFieldsStore } from '@/stores/';
import ModalItem from '@/views/private/components/modal-item';
import ModalCollection from '@/views/private/components/modal-collection';
import DrawerItem from '@/views/private/components/drawer-item';
import DrawerCollection from '@/views/private/components/drawer-collection';
import { Filter, Field } from '@/types';
import { Header } from '@/components/v-table/types';
import { isEqual } from 'lodash';
export default defineComponent({
components: { ModalItem, ModalCollection },
components: { DrawerItem, DrawerCollection },
props: {
value: {
type: Array as PropType<(number | string | Record<string, any>)[] | null>,

View File

@@ -72,7 +72,7 @@
</v-list>
</v-menu>
<modal-item
<drawer-item
:active.sync="editModalActive"
collection="directus_users"
:primary-key="currentPrimaryKey"
@@ -81,7 +81,7 @@
v-if="!disabled"
/>
<modal-collection
<drawer-collection
:active.sync="selectModalActive"
collection="directus_users"
:selection="selection"
@@ -95,11 +95,11 @@
import { defineComponent, computed, ref, watch, PropType } from '@vue/composition-api';
import useCollection from '@/composables/use-collection';
import api from '@/api';
import ModalItem from '@/views/private/components/modal-item';
import ModalCollection from '@/views/private/components/modal-collection';
import DrawerItem from '@/views/private/components/drawer-item';
import DrawerCollection from '@/views/private/components/drawer-collection';
export default defineComponent({
components: { ModalItem, ModalCollection },
components: { DrawerItem, DrawerCollection },
props: {
value: {
type: String,

View File

@@ -46,8 +46,8 @@
</v-detail>
</portal>
<portal to="drawer">
<filter-drawer-detail v-model="_filters" :collection="collection" :loading="loading" />
<portal to="sidebar">
<filter-sidebar-detail v-model="_filters" :collection="collection" :loading="loading" />
</portal>
<portal to="actions:prepend">

View File

@@ -49,8 +49,8 @@
</div>
</portal>
<portal to="drawer">
<filter-drawer-detail v-model="_filters" :collection="collection" :loading="loading" />
<portal to="sidebar">
<filter-sidebar-detail v-model="_filters" :collection="collection" :loading="loading" />
</portal>
<portal to="actions:prepend">

View File

@@ -31,12 +31,12 @@
<router-view name="detail" :primary-key="primaryKey" />
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_activity_collection'))" />
</drawer-detail>
<layout-drawer-detail @input="layout = $event" :value="layout" />
<portal-target name="drawer" />
</sidebar-detail>
<layout-sidebar-detail @input="layout = $event" :value="layout" />
<portal-target name="sidebar" />
</template>
</private-view>
</template>
@@ -47,8 +47,8 @@ import ActivityNavigation from '../components/navigation.vue';
import { i18n } from '@/lang';
import usePreset from '@/composables/use-preset';
import marked from 'marked';
import FilterDrawerDetail from '@/views/private/components/filter-drawer-detail';
import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail';
import FilterSidebarDetail from '@/views/private/components/filter-sidebar-detail';
import LayoutSidebarDetail from '@/views/private/components/layout-sidebar-detail';
import SearchInput from '@/views/private/components/search-input';
import { nanoid } from 'nanoid';
@@ -58,7 +58,7 @@ type Item = {
export default defineComponent({
name: 'activity-collection',
components: { ActivityNavigation, FilterDrawerDetail, LayoutDrawerDetail, SearchInput },
components: { ActivityNavigation, FilterSidebarDetail, LayoutSidebarDetail, SearchInput },
props: {
primaryKey: {
type: String,

View File

@@ -1,14 +1,14 @@
<template>
<v-modal active title="Activity Item" @toggle="close" @esc="close">
<v-drawer active title="Activity Item" @toggle="close" @cancel="close">
<v-progress-circular indeterminate v-if="loading" />
<template v-else-if="error">
<div class="content" v-else-if="error">
<v-notice type="danger">
{{ error }}
</v-notice>
</template>
</div>
<template v-else>
<div class="content" v-else>
<!-- @TODO add final design -->
<p class="type-label">User:</p>
<user-popover v-if="item.user" :user="item.user.id">
@@ -32,17 +32,18 @@
<p class="type-label">Item:</p>
<p>{{ item.item }}</p>
</template>
</div>
<template #footer>
<v-button v-if="openItemLink" :to="openItemLink">
<v-icon name="launch" left />
{{ $t('open') }}
<template #actions>
<v-button v-if="openItemLink" :to="openItemLink" icon rounded v-tooltip.bottom="$t('open')">
<v-icon name="launch" />
</v-button>
<v-button to="/activity">{{ $t('done') }}</v-button>
<v-button to="/activity" icon rounded v-tooltip.bottom="$t('done')">
<v-icon name="check" />
</v-button>
</template>
</v-modal>
</v-drawer>
</template>
<script lang="ts">
@@ -137,4 +138,10 @@ export default defineComponent({
.type-label:not(:first-child) {
margin-top: 24px;
}
.content {
padding: var(--content-padding);
padding-top: 0;
padding-bottom: var(--content-padding);
}
</style>

View File

@@ -203,8 +203,8 @@
</template>
</component>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div
class="page-description"
v-html="
@@ -215,10 +215,10 @@
)
"
/>
</drawer-detail>
<layout-drawer-detail @input="layout = $event" :value="layout" />
<portal-target name="drawer" />
<export-drawer-detail
</sidebar-detail>
<layout-sidebar-detail @input="layout = $event" :value="layout" />
<portal-target name="sidebar" />
<export-sidebar-detail
:layout-query="layoutQuery"
:search-query="searchQuery"
:collection="currentCollection"
@@ -247,8 +247,8 @@ import { LayoutComponent } from '@/layouts/types';
import CollectionsNotFound from './not-found.vue';
import useCollection from '@/composables/use-collection';
import usePreset from '@/composables/use-preset';
import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail';
import ExportDrawerDetail from '@/views/private/components/export-drawer-detail';
import LayoutSidebarDetail from '@/views/private/components/layout-sidebar-detail';
import ExportSidebarDetail from '@/views/private/components/export-sidebar-detail';
import SearchInput from '@/views/private/components/search-input';
import BookmarkAdd from '@/views/private/components/bookmark-add';
import BookmarkEdit from '@/views/private/components/bookmark-edit';
@@ -265,8 +265,8 @@ export default defineComponent({
components: {
CollectionsNavigation,
CollectionsNotFound,
LayoutDrawerDetail,
ExportDrawerDetail,
LayoutSidebarDetail,
ExportSidebarDetail,
SearchInput,
BookmarkAdd,
BookmarkEdit,
@@ -591,14 +591,14 @@ export default defineComponent({
--v-button-background-color-hover: var(--background-normal-alt);
}
.layout {
--layout-offset-top: 64px;
}
.header-icon {
--v-button-color-disabled: var(--foreground-normal);
}
.layout {
--layout-offset-top: 64px;
}
.bookmark-controls {
.add,
.save,

View File

@@ -176,10 +176,10 @@
</v-card>
</v-dialog>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_collections_item'))" />
</drawer-detail>
</sidebar-detail>
<revisions-drawer-detail
v-if="
collectionInfo.meta &&
@@ -192,7 +192,7 @@
ref="revisionsDrawerDetail"
@revert="refresh"
/>
<comments-drawer-detail
<comments-sidebar-detail
v-if="
collectionInfo.meta &&
collectionInfo.meta.singleton === false &&
@@ -215,7 +215,7 @@ import router from '@/router';
import CollectionsNotFound from './not-found.vue';
import useCollection from '@/composables/use-collection';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import CommentsDrawerDetail from '@/views/private/components/comments-drawer-detail';
import CommentsSidebarDetail from '@/views/private/components/comments-sidebar-detail';
import useItem from '@/composables/use-item';
import SaveOptions from '@/views/private/components/save-options';
import i18n from '@/lang';
@@ -236,7 +236,7 @@ export default defineComponent({
CollectionsNavigation,
CollectionsNotFound,
RevisionsDrawerDetail,
CommentsDrawerDetail,
CommentsSidebarDetail,
SaveOptions,
},
props: {

View File

@@ -28,10 +28,10 @@
</template>
</v-info>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_collections_overview'))" />
</drawer-detail>
</sidebar-detail>
</template>
</private-view>
</template>

View File

@@ -16,10 +16,10 @@
<markdown>{{ markdownWithoutTitle }}</markdown>
</div>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_docs_global'))" />
</drawer-detail>
</sidebar-detail>
</template>
</private-view>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<drawer-detail icon="info_outline" :title="$t('file_details')" close>
<sidebar-detail icon="info_outline" :title="$t('file_details')" close>
<dl v-if="file">
<div v-if="file.type">
<dt>{{ $t('type') }}</dt>
@@ -41,11 +41,11 @@
<dd>{{ file.checksum }}</dd>
</div>
<div v-if="user_created">
<div v-if="userCreated">
<dt>{{ $t('owner') }}</dt>
<dd>
<user-popover :user="user_created.id">
<router-link :to="user_created.link">{{ user_created.name }}</router-link>
<user-popover :user="userCreated.id">
<router-link :to="userCreated.link">{{ userCreated.name }}</router-link>
</user-popover>
</dd>
</div>
@@ -55,11 +55,11 @@
<dd>{{ modificationDate }}</dd>
</div>
<div v-if="user_modified">
<div v-if="userModified">
<dt>{{ $t('edited_by') }}</dt>
<dd>
<user-popover :user="user_modified.id">
<router-link :to="user_modified.link">{{ user_modified.name }}</router-link>
<user-popover :user="userModified.id">
<router-link :to="userModified.link">{{ userModified.name }}</router-link>
</user-popover>
</dd>
</div>
@@ -104,7 +104,7 @@
<v-divider />
<div class="page-description" v-html="marked($t('page_help_files_item'))" />
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">

View File

@@ -126,12 +126,12 @@
<router-view name="addNew" :preset="queryFilters" @upload="refresh" />
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_files_collection'))" />
</drawer-detail>
<layout-drawer-detail @input="layout = $event" :value="layout" />
<portal-target name="drawer" />
</sidebar-detail>
<layout-sidebar-detail @input="layout = $event" :value="layout" />
<portal-target name="sidebar" />
</template>
<template v-if="showDropEffect">
@@ -150,8 +150,8 @@ import { i18n } from '@/lang';
import api from '@/api';
import { LayoutComponent } from '@/layouts/types';
import usePreset from '@/composables/use-preset';
import FilterDrawerDetail from '@/views/private/components/filter-drawer-detail';
import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail';
import FilterSidebarDetail from '@/views/private/components/filter-sidebar-detail';
import LayoutSidebarDetail from '@/views/private/components/layout-sidebar-detail';
import AddFolder from '../components/add-folder.vue';
import SearchInput from '@/views/private/components/search-input';
import marked from 'marked';
@@ -171,7 +171,7 @@ type Item = {
export default defineComponent({
name: 'files-collection',
components: { FilesNavigation, FilterDrawerDetail, LayoutDrawerDetail, AddFolder, SearchInput, FolderPicker },
components: { FilesNavigation, FilterSidebarDetail, LayoutSidebarDetail, AddFolder, SearchInput, FolderPicker },
props: {
queryFilters: {
type: Object as PropType<Record<string, string>>,

View File

@@ -155,15 +155,15 @@
</v-card>
</v-dialog>
<template #drawer>
<file-info-drawer-detail :file="item" @move-folder="moveToDialogActive = true" />
<template #sidebar>
<file-info-sidebar-detail :file="item" @move-folder="moveToDialogActive = true" />
<revisions-drawer-detail
v-if="isBatch === false && isNew === false"
collection="directus_files"
:primary-key="primaryKey"
ref="revisionsDrawerDetail"
/>
<comments-drawer-detail
<comments-sidebar-detail
v-if="isBatch === false && isNew === false"
collection="directus_files"
:primary-key="primaryKey"
@@ -178,7 +178,7 @@ import FilesNavigation from '../components/navigation.vue';
import { i18n } from '@/lang';
import router from '@/router';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import CommentsDrawerDetail from '@/views/private/components/comments-drawer-detail';
import CommentsSidebarDetail from '@/views/private/components/comments-sidebar-detail';
import useItem from '@/composables/use-item';
import SaveOptions from '@/views/private/components/save-options';
import FilePreview from '@/views/private/components/file-preview';
@@ -187,7 +187,7 @@ import { nanoid } from 'nanoid';
import FileLightbox from '@/views/private/components/file-lightbox';
import { useFieldsStore } from '@/stores/';
import { Field } from '@/types';
import FileInfoDrawerDetail from '../components/file-info-drawer-detail.vue';
import FileInfoSidebarDetail from '../components/file-info-sidebar-detail.vue';
import useFormFields from '@/composables/use-form-fields';
import FolderPicker from '../components/folder-picker.vue';
import api from '@/api';
@@ -216,12 +216,12 @@ export default defineComponent({
components: {
FilesNavigation,
RevisionsDrawerDetail,
CommentsDrawerDetail,
CommentsSidebarDetail,
SaveOptions,
FilePreview,
ImageEditor,
FileLightbox,
FileInfoDrawerDetail,
FileInfoSidebarDetail,
FolderPicker,
FilesNotFound,
},

View File

@@ -40,7 +40,7 @@
<v-icon
class="icon"
:class="{
hidden: item.meta && item.meta.hidden || false,
hidden: (item.meta && item.meta.hidden) || false,
system: item.collection.startsWith('directus_'),
unmanaged: item.meta === null && item.collection.startsWith('directus_') === false,
}"
@@ -52,7 +52,7 @@
<span
class="collection"
:class="{
hidden: item.meta && item.meta.hidden || false,
hidden: (item.meta && item.meta.hidden) || false,
system: item.collection.startsWith('directus_'),
unmanaged: item.meta === null && item.collection.startsWith('directus_') === false,
}"
@@ -86,10 +86,10 @@
<router-view name="add" />
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_settings_datamodel_collections'))" />
</drawer-detail>
</sidebar-detail>
<collections-filter v-model="activeTypes" />
</template>
</private-view>

View File

@@ -1,11 +1,11 @@
<template>
<drawer-detail class="collections-filter" icon="filter_list" :title="$tc('collection', 2)">
<sidebar-detail class="collections-filter" icon="filter_list" :title="$tc('collection', 2)">
<div class="type-label label">{{ $t('collections_shown') }}</div>
<v-checkbox value="visible" v-model="_value" :label="$t('visible_collections')" />
<v-checkbox value="unmanaged" v-model="_value" :label="$t('unmanaged_collections')" />
<v-checkbox value="hidden" v-model="_value" :label="$t('hidden_collections')" />
<v-checkbox value="system" v-model="_value" :label="$t('system_collections')" />
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">

View File

@@ -1,14 +1,18 @@
<template>
<div class="actions">
<v-button secondary @click="$emit('cancel')">
{{ $t('cancel') }}
<v-button
v-if="!isExisting && currentTabIndex < tabs.length - 1"
@click="nextTab"
:disabled="nextDisabled"
icon
rounded
v-tooltip.bottom="$t('next')"
>
<v-icon name="arrow_forward" />
</v-button>
<div class="spacer" />
<v-button v-if="!isExisting && currentTabIndex < tabs.length - 1" @click="nextTab" :disabled="nextDisabled">
{{ $t('next') }}
</v-button>
<v-button v-else @click="$emit('save')" :loading="saving">
{{ $t('save') }}
<v-button v-else @click="$emit('save')" :loading="saving" icon rounded v-tooltip.bottom="$t('save')">
<v-icon name="check" />
</v-button>
</div>
</template>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<h2 class="type-title">{{ $t('display_setup_title') }}</h2>
<v-notice type="info">{{ $t('display_setup_title') }}</v-notice>
<v-fancy-select class="select" :items="selectItems" v-model="fieldData.meta.display" />
@@ -130,4 +130,8 @@ export default defineComponent({
text-decoration: underline;
}
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<h2 class="type-title">{{ $t('schema_field_title') }}</h2>
<v-notice type="info">{{ $t('schema_field_title') }}</v-notice>
<div class="form">
<div class="field half-left" v-if="fieldData.meta">
@@ -103,4 +103,8 @@ export default defineComponent({
.required {
--v-icon-color: var(--primary);
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<h2 class="type-title">{{ $t('interface_setup_title') }}</h2>
<v-notice type="info">{{ $t('interface_setup_title') }}</v-notice>
<v-fancy-select class="select" :items="selectItems" v-model="fieldData.meta.interface" />
@@ -139,4 +139,8 @@ export default defineComponent({
text-decoration: underline;
}
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,145 +0,0 @@
<template>
<div>
<h2 class="type-title">{{ $t('configure_languages') }}</h2>
<div class="grid">
<div class="field">
<div class="type-label">{{ $t('translations_collection') }}</div>
<v-input disabled :value="relations[1].many_collection" />
</div>
<div class="field">
<div class="type-label">{{ $t('languages_collection') }}</div>
<v-input :class="{ matches: languagesCollectionExists }" db-safe key="languages-collection" v-model="relations[1].one_collection" :disabled="isExisting" :placeholder="$t('collection') + '...'">
<template #append>
<v-menu show-arrow placement="bottom-end">
<template #activator="{ toggle }">
<v-icon name="list_alt" @click="toggle" v-tooltip="$t('select_existing')" :disabled="isExisting" />
</template>
<v-list class="monospace">
<v-list-item
v-for="item in items"
:key="item.value"
:active="relations[1].one_collection === item.value"
:disabled="item.disabled"
@click="relations[1].one_collection = item.value"
>
<v-list-item-content>
{{ item.text }}
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
</template>
</v-input>
</div>
<v-input :value="relations[1].many_field" :placeholder="$t('foreign_key') + '...'"/>
<v-input db-safe :disabled="languagesCollectionExists" v-model="relations[1].one_primary" :placeholder="$t('primary_key') + '...'" />
<v-icon class="arrow" name="arrow_back" />
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, computed, watch } from '@vue/composition-api';
import { Relation } from '@/types';
import { Field } from '@/types';
import { orderBy } from 'lodash';
import useSync from '@/composables/use-sync';
import { useCollectionsStore, useFieldsStore } from '@/stores';
import i18n from '@/lang';
import { state } from '../store';
export default defineComponent({
props: {
type: {
type: String,
required: true,
},
collection: {
type: String,
required: true,
},
isExisting: {
type: Boolean,
default: false,
},
},
setup(props, { emit }) {
const collectionsStore = useCollectionsStore();
const fieldsStore = useFieldsStore();
const { items } = useRelation();
const languagesCollectionExists = computed(() => {
return !!collectionsStore.getCollection(state.relations[1].one_collection);
});
return {
relations: state.relations,
items,
fieldData: state.fieldData,
languagesCollectionExists,
};
function useRelation() {
const availableCollections = computed(() => {
return orderBy(
collectionsStore.state.collections.filter((collection) => {
return collection.collection.startsWith('directus_') === false;
}),
['collection'],
['asc']
);
});
const items = computed(() =>
availableCollections.value.map((collection) => ({
text: collection.collection,
value: collection.collection,
}))
);
return { items };
}
},
});
</script>
<style lang="scss" scoped>
.grid {
--v-select-font-family: var(--family-monospace);
--v-input-font-family: var(--family-monospace);
position: relative;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px 32px;
margin-top: 48px;
.v-input.matches {
--v-input-color: var(--primary);
}
.arrow {
--v-icon-color: var(--primary);
position: absolute;
bottom: 14px;
left: 50%;
transform: translateX(-50%);
}
}
.v-list {
--v-list-item-content-font-family: var(--family-monospace);
}
.v-divider {
margin: 48px 0;
}
.type-label {
margin-bottom: 8px;
}
</style>

View File

@@ -1,6 +1,7 @@
<template>
<div>
<h2 class="type-title">{{ $t('configure_m2m') }}</h2>
<v-notice type="info">{{ $t('configure_m2m') }}</v-notice>
<div class="grid">
<div class="field">
<div class="type-label">{{ $t('this_collection') }}</div>
@@ -452,4 +453,8 @@ export default defineComponent({
transform: translateX(-50%);
}
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,6 +1,7 @@
<template>
<div>
<h2 class="type-title">{{ $t('configure_m2o') }}</h2>
<v-notice type="info">{{ $t('configure_m2o') }}</v-notice>
<div class="grid">
<div class="field">
<div class="type-label">{{ $t('this_collection') }}</div>
@@ -255,4 +256,8 @@ export default defineComponent({
.type-label {
margin-bottom: 8px;
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,6 +1,7 @@
<template>
<div>
<h2 class="type-title">{{ $t('configure_o2m') }}</h2>
<v-notice type="info">{{ $t('configure_o2m') }}</v-notice>
<div class="grid">
<div class="field">
<div class="type-label">{{ $t('this_collection') }}</div>
@@ -380,4 +381,8 @@ export default defineComponent({
transform: translateX(-50%);
}
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,6 +1,8 @@
<template>
<div>
<h2 class="type-title">{{ $t('schema_setup_title') }}</h2>
<v-notice type="info">
{{ $t('schema_setup_title') }}
</v-notice>
<div class="form">
<div class="field">
@@ -392,10 +394,6 @@ export default defineComponent({
@import '@/styles/mixins/breakpoint';
@import '@/styles/mixins/form-grid';
.type-title {
margin-bottom: 32px;
}
.form {
--v-form-vertical-gap: 32px;
--v-form-horizontal-gap: 32px;
@@ -416,4 +414,8 @@ export default defineComponent({
grid-gap: 12px;
grid-template-columns: 1fr 1fr;
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,6 +1,7 @@
<template>
<div>
<h2 class="type-title">{{ $t('configure_m2m') }}</h2>
<v-notice type="info">{{ $t('configure_m2m') }}</v-notice>
<div class="grid">
<div class="field">
<div class="type-label">{{ $t('this_collection') }}</div>
@@ -349,4 +350,8 @@ export default defineComponent({
.v-list {
--v-list-item-content-font-family: var(--family-monospace);
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -28,11 +28,11 @@
</v-card>
</v-dialog>
<v-modal
<v-drawer
v-else
:active="true"
@toggle="cancelField"
@esc="cancelField"
@cancel="cancelField"
:title="
field === '+'
? $t('creating_new_field', { collection: collectionInfo.name })
@@ -45,49 +45,51 @@
<setup-tabs :current.sync="currentTab" :tabs="tabs" :type="localType" />
</template>
<setup-schema
v-if="currentTab[0] === 'schema'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<div class="content">
<setup-schema
v-if="currentTab[0] === 'schema'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-field
v-if="currentTab[0] === 'field'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-field
v-if="currentTab[0] === 'field'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-relationship
v-if="currentTab[0] === 'relationship'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-relationship
v-if="currentTab[0] === 'relationship'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-translations
v-if="currentTab[0] === 'translations'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-translations
v-if="currentTab[0] === 'translations'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-interface
v-if="currentTab[0] === 'interface'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-interface
v-if="currentTab[0] === 'interface'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-display
v-if="currentTab[0] === 'display'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
<setup-display
v-if="currentTab[0] === 'display'"
:is-existing="field !== '+'"
:collection="collection"
:type="localType"
/>
</div>
<template #footer>
<template #actions>
<setup-actions
:saving="saving"
:collection="collection"
@@ -98,7 +100,7 @@
@cancel="cancelField"
/>
</template>
</v-modal>
</v-drawer>
</template>
<script lang="ts">
@@ -404,4 +406,10 @@ export default defineComponent({
color: var(--primary);
}
}
.content {
padding: var(--content-padding);
padding-top: 0;
padding-bottom: var(--content-padding);
}
</style>

View File

@@ -474,7 +474,7 @@ function initLocalStore(collection: string, field: string, type: typeof localTyp
name: 'German',
},
{
code: 'fr-Fr',
code: 'fr-FR',
name: 'French',
},
{

View File

@@ -73,10 +73,10 @@
/>
</div>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_settings_datamodel_fields'))" />
</drawer-detail>
</sidebar-detail>
</template>
</private-view>
</template>

View File

@@ -1,10 +1,10 @@
<template>
<v-modal
<v-drawer
:title="$t('creating_new_collection')"
:active="true"
class="new-collection"
persistent
@esc="$router.push('/settings/data-model')"
@cancel="$router.push('/settings/data-model')"
>
<v-dialog :active="saveError !== null" @toggle="saveError = null" @esc="saveError = null">
<v-card class="selectable">
@@ -29,9 +29,10 @@
</v-tabs>
</template>
<v-tabs-items v-model="currentTab">
<v-tabs-items class="content" v-model="currentTab">
<v-tab-item value="collection">
<h2 class="type-title">{{ $t('creating_collection_info') }}</h2>
<v-notice type="info">{{ $t('creating_collection_info') }}</v-notice>
<div class="grid">
<div>
<div class="type-label">
@@ -83,7 +84,8 @@
</div>
</v-tab-item>
<v-tab-item value="system">
<h2 class="type-title">{{ $t('creating_collection_system') }}</h2>
<v-notice type="info">{{ $t('creating_collection_system') }}</v-notice>
<div class="grid system">
<div v-for="(info, field) in systemFields" :key="field">
<div class="type-label">{{ $t(info.label) }}</div>
@@ -106,23 +108,29 @@
</v-tab-item>
</v-tabs-items>
<template #footer>
<v-button secondary to="/settings/data-model">
{{ $t('cancel') }}
</v-button>
<div class="spacer" />
<template #actions>
<v-button
:disabled="!collectionName || collectionName.length === 0"
v-if="currentTab[0] === 'collection'"
@click="currentTab = ['system']"
v-tooltip.bottom="$t('next')"
icon
rounded
>
{{ $t('next') }}
<v-icon name="arrow_forward" />
</v-button>
<v-button v-if="currentTab[0] === 'system'" @click="save" :loading="saving">
{{ $t('finish_setup') }}
<v-button
v-if="currentTab[0] === 'system'"
@click="save"
:loading="saving"
v-tooltip.bottom="$t('finish_setup')"
icon
rounded
>
<v-icon name="check" />
</v-button>
</template>
</v-modal>
</v-drawer>
</template>
<script lang="ts">
@@ -469,4 +477,14 @@ export default defineComponent({
.required {
color: var(--primary);
}
.content {
padding: var(--content-padding);
padding-top: 0;
padding-bottom: var(--content-padding);
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -84,8 +84,8 @@
</v-table>
</div>
<template #drawer>
<presets-info-drawer-detail />
<template #sidebar>
<presets-info-sidebar-detail />
</template>
</private-view>
</template>
@@ -102,7 +102,7 @@ import { getLayouts } from '@/layouts';
import { TranslateResult } from 'vue-i18n';
import router from '@/router';
import ValueNull from '@/views/private/components/value-null';
import PresetsInfoDrawerDetail from './components/presets-info-drawer-detail.vue';
import PresetsInfoSidebarDetail from './components/presets-info-sidebar-detail.vue';
type PresetRaw = {
id: number;
@@ -122,7 +122,7 @@ type Preset = {
};
export default defineComponent({
components: { SettingsNavigation, ValueNull, PresetsInfoDrawerDetail },
components: { SettingsNavigation, ValueNull, PresetsInfoSidebarDetail },
setup() {
const layouts = getLayouts();
const collectionsStore = useCollectionsStore();

View File

@@ -1,5 +1,5 @@
<template>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<dl>
<div>
<dt>{{ $t('bookmarks') }}</dt>
@@ -14,7 +14,7 @@
<v-divider />
<div class="page-description" v-html="marked($t('page_help_settings_presets_collection'))" />
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">

View File

@@ -75,18 +75,18 @@
</div>
</div>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_settings_presets_item'))" />
</drawer-detail>
</sidebar-detail>
<portal-target class="layout-drawer" name="drawer" />
<portal-target class="layout-sidebar" name="sidebar" />
<drawer-detail class="layout-drawer" icon="layers" :title="$t('layout_options')">
<sidebar-detail class="layout-sidebar" icon="layers" :title="$t('layout_options')">
<div class="layout-options">
<portal-target name="layout-options" class="portal-contents" />
</div>
</drawer-detail>
</sidebar-detail>
</template>
</private-view>
</template>
@@ -547,10 +547,10 @@ export default defineComponent({
overflow: auto;
}
.layout-drawer {
--drawer-detail-icon-color: var(--warning);
--drawer-detail-color: var(--warning);
--drawer-detail-color-active: var(--warning);
.layout-sidebar {
--sidebar-detail-icon-color: var(--warning);
--sidebar-detail-color: var(--warning);
--sidebar-detail-color-active: var(--warning);
--v-form-vertical-gap: 24px;
}

View File

@@ -1,5 +1,5 @@
<template>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<dl v-if="parsedInfo">
<div>
<dt>{{ $t('directus_version') }}</dt>
@@ -34,7 +34,7 @@
<v-divider />
<div class="page-description" v-html="marked($t('page_help_settings_project'))" />
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">

View File

@@ -21,8 +21,8 @@
<v-form :initial-values="initialValues" v-model="edits" :fields="fields" :primary-key="1" />
</div>
<template #drawer>
<project-info-drawer-detail />
<template #sidebar>
<project-info-sidebar-detail />
</template>
</private-view>
</template>
@@ -32,11 +32,11 @@ import { defineComponent, ref, computed } from '@vue/composition-api';
import SettingsNavigation from '../../components/navigation.vue';
import useCollection from '@/composables/use-collection';
import { useSettingsStore } from '@/stores';
import ProjectInfoDrawerDetail from './components/project-info-drawer-detail.vue';
import ProjectInfoSidebarDetail from './components/project-info-sidebar-detail.vue';
import { clone } from 'lodash';
export default defineComponent({
components: { SettingsNavigation, ProjectInfoDrawerDetail },
components: { SettingsNavigation, ProjectInfoSidebarDetail },
setup() {
const settingsStore = useSettingsStore();

View File

@@ -18,10 +18,10 @@
<settings-navigation />
</template>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_settings_roles_collection'))" />
</drawer-detail>
</sidebar-detail>
</template>
<div class="roles">

View File

@@ -136,15 +136,15 @@ export default defineComponent({
loading.value = true;
try {
const response = await api.get('/permissions', {
params: {
filter: {
role: {
_eq: props.role,
},
},
},
});
const params: any = { filter: { role: {} } };
if (props.role === null) {
params.filter.role = { _null: true };
} else {
params.filter.role = { _eq: props.role };
}
const response = await api.get('/permissions', params);
permissions.value = response.data.data;
} catch (err) {

View File

@@ -1,5 +1,5 @@
<template>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<dl v-if="!isNew && role">
<div>
<dt>{{ $t('primary_key') }}</dt>
@@ -10,7 +10,7 @@
<v-divider />
<div class="page-description" v-html="marked($t('page_help_settings_roles_item'))" />
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">

View File

@@ -71,8 +71,8 @@
/>
</div>
<template #drawer>
<role-info-drawer-detail :role="item" />
<template #sidebar>
<role-info-sidebar-detail :role="item" />
<revisions-drawer-detail collection="directus_roles" :primary-key="primaryKey" />
</template>
</private-view>
@@ -86,7 +86,7 @@ import router from '@/router';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import useItem from '@/composables/use-item';
import { useUserStore } from '@/stores/';
import RoleInfoDrawerDetail from './components/role-info-drawer-detail.vue';
import RoleInfoSidebarDetail from './components/role-info-sidebar-detail.vue';
import PermissionsOverview from './components/permissions-overview.vue';
type Values = {
@@ -95,7 +95,7 @@ type Values = {
export default defineComponent({
name: 'roles-item',
components: { SettingsNavigation, RevisionsDrawerDetail, RoleInfoDrawerDetail, PermissionsOverview },
components: { SettingsNavigation, RevisionsDrawerDetail, RoleInfoSidebarDetail, PermissionsOverview },
props: {
primaryKey: {
type: String,

View File

@@ -1,6 +1,8 @@
<template>
<div class="actions">
<v-button @click="save" :loading="loading">{{ $t('save') }}</v-button>
<v-button @click="save" :loading="loading" icon rounded v-tooltip.bottom="$t('save')">
<v-icon name="check" />
</v-button>
</div>
</template>

View File

@@ -1,13 +1,14 @@
<template>
<div>
<v-modal-heading
:heading="
<v-notice type="info">
{{
$t('fields_for_role', {
role: role ? role.name : $t('public'),
action: $t(permission.action).toLowerCase(),
})
"
/>
}}
</v-notice>
<p class="type-label">{{ $tc('field', 0) }}</p>
<interface-checkboxes v-model="fields" type="json" :choices="fieldsInCollection" />
</div>
@@ -83,4 +84,8 @@ export default defineComponent({
.type-label {
margin-bottom: 8px;
}
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,13 +1,14 @@
<template>
<div>
<v-modal-heading
:heading="
<v-notice type="info">
{{
$t('permissions_for_role', {
action: $t(permission.action).toLowerCase(),
role: role ? role.name : $t('public'),
})
"
/>
}}
</v-notice>
<interface-code v-model="permissions" language="json" type="json" />
</div>
</template>
@@ -47,3 +48,9 @@ export default defineComponent({
},
});
</script>
<style lang="scss" scoped>
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,13 +1,13 @@
<template>
<div>
<v-modal-heading
:heading="
<v-notice type="info">
{{
$t('presets_for_role', {
action: $t(permission.action).toLowerCase(),
role: role ? role.name : $t('public'),
})
"
/>
}}
</v-notice>
<interface-code v-model="presets" language="json" type="json" />
</div>
</template>
@@ -47,3 +47,9 @@ export default defineComponent({
},
});
</script>
<style lang="scss" scoped>
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,13 +1,14 @@
<template>
<div>
<v-modal-heading
:heading="
<v-notice type="info">
{{
$t('validation_for_role', {
action: $t(permission.action).toLowerCase(),
role: role ? role.name : $t('public'),
})
"
/>
}}
</v-notice>
<interface-code v-model="validation" language="json" type="json" />
</div>
</template>
@@ -47,3 +48,9 @@ export default defineComponent({
},
});
</script>
<style lang="scss" scoped>
.v-notice {
margin-bottom: 36px;
}
</style>

View File

@@ -1,20 +1,20 @@
<template>
<v-modal :title="modalTitle" :active="true" class="new-collection" persistent>
<v-drawer :title="modalTitle" :active="true" class="new-collection" persistent>
<template #sidebar v-if="!loading">
<tabs :current-tab.sync="currentTab" :tabs="tabs" />
</template>
<template v-if="!loading">
<div class="content" v-if="!loading">
<permissions v-if="currentTab[0] === 'permissions'" :permission.sync="permission" :role="role" />
<fields v-if="currentTab[0] === 'fields'" :permission.sync="permission" :role="role" />
<validation v-if="currentTab[0] === 'validation'" :permission.sync="permission" :role="role" />
<presets v-if="currentTab[0] === 'presets'" :permission.sync="permission" :role="role" />
</template>
</div>
<template #footer v-if="!loading">
<template #actions v-if="!loading">
<actions :role-key="roleKey" :permission="permission" @refresh="$emit('refresh', +permissionKey)" />
</template>
</v-modal>
</v-drawer>
</template>
<script lang="ts">
@@ -149,3 +149,11 @@ export default defineComponent({
},
});
</script>
<style lang="scss" scoped>
.content {
padding: var(--content-padding);
padding-top: 0;
padding-bottom: var(--content-padding);
}
</style>

View File

@@ -85,12 +85,12 @@
</template>
</component>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_settings_webhooks_collection'))" />
</drawer-detail>
<layout-drawer-detail />
<portal-target name="drawer" />
</sidebar-detail>
<layout-sidebar-detail />
<portal-target name="sidebar" />
</template>
</private-view>
</template>
@@ -98,7 +98,7 @@
<script lang="ts">
import { defineComponent, computed, ref } from '@vue/composition-api';
import SettingsNavigation from '../../components/navigation.vue';
import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail';
import LayoutSidebarDetail from '@/views/private/components/layout-sidebar-detail';
import marked from 'marked';
import { LayoutComponent } from '@/layouts/types';
import { usePreset } from '@/composables/use-preset';
@@ -112,7 +112,7 @@ type Item = {
export default defineComponent({
name: 'webhooks-collection',
components: { SettingsNavigation, LayoutDrawerDetail, SearchInput },
components: { SettingsNavigation, LayoutSidebarDetail, SearchInput },
setup(props) {
const layoutRef = ref<LayoutComponent | null>(null);

View File

@@ -58,10 +58,10 @@
v-model="edits"
/>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_settings_webhooks_item'))" />
</drawer-detail>
</sidebar-detail>
<revisions-drawer-detail v-if="isNew === false" collection="directus_webhooks" :primary-key="primaryKey" />
</template>
</private-view>

View File

@@ -1,5 +1,5 @@
<template>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<dl v-if="isNew === false && user">
<div v-if="user.id">
<dt>{{ $t('key') }}</dt>
@@ -32,7 +32,7 @@
<v-divider />
<div class="page-description" v-html="marked($t('page_help_users_item'))" />
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">

View File

@@ -91,12 +91,12 @@
</template>
</component>
<template #drawer>
<drawer-detail icon="info_outline" :title="$t('information')" close>
<template #sidebar>
<sidebar-detail icon="info_outline" :title="$t('information')" close>
<div class="page-description" v-html="marked($t('page_help_users_collection'))" />
</drawer-detail>
<layout-drawer-detail @input="layout = $event" :value="layout" />
<portal-target name="drawer" />
</sidebar-detail>
<layout-sidebar-detail @input="layout = $event" :value="layout" />
<portal-target name="sidebar" />
</template>
</private-view>
</template>
@@ -109,7 +109,7 @@ import { i18n } from '@/lang';
import api from '@/api';
import { LayoutComponent } from '@/layouts/types';
import usePreset from '@/composables/use-preset';
import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail';
import LayoutSidebarDetail from '@/views/private/components/layout-sidebar-detail';
import SearchInput from '@/views/private/components/search-input';
import marked from 'marked';
import useNavigation from '../composables/use-navigation';
@@ -120,7 +120,7 @@ type Item = {
export default defineComponent({
name: 'users-collection',
components: { UsersNavigation, LayoutDrawerDetail, SearchInput },
components: { UsersNavigation, LayoutSidebarDetail, SearchInput },
props: {
queryFilters: {
type: Object as PropType<Record<string, string>>,

View File

@@ -143,15 +143,15 @@
</v-card>
</v-dialog>
<template #drawer>
<user-info-drawer-detail :is-new="isNew" :user="item" />
<template #sidebar>
<user-info-sidebar-detail :is-new="isNew" :user="item" />
<revisions-drawer-detail
v-if="isBatch === false && isNew === false"
collection="directus_users"
:primary-key="primaryKey"
ref="revisionsDrawerDetail"
/>
<comments-drawer-detail
<comments-sidebar-detail
v-if="isBatch === false && isNew === false"
collection="directus_users"
:primary-key="primaryKey"
@@ -167,14 +167,14 @@ import UsersNavigation from '../components/navigation.vue';
import { i18n } from '@/lang';
import router from '@/router';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import CommentsDrawerDetail from '@/views/private/components/comments-drawer-detail';
import CommentsSidebarDetail from '@/views/private/components/comments-sidebar-detail';
import useItem from '@/composables/use-item';
import SaveOptions from '@/views/private/components/save-options';
import api from '@/api';
import { useFieldsStore, useUserStore } from '@/stores/';
import useFormFields from '@/composables/use-form-fields';
import { Field } from '@/types';
import UserInfoDrawerDetail from '../components/user-info-drawer-detail.vue';
import UserInfoSidebarDetail from '../components/user-info-sidebar-detail.vue';
import { getRootPath } from '@/utils/get-root-path';
import useShortcut from '@/composables/use-shortcut';
import { isAllowed } from '@/utils/is-allowed';
@@ -198,7 +198,7 @@ export default defineComponent({
return next();
},
components: { UsersNavigation, RevisionsDrawerDetail, SaveOptions, CommentsDrawerDetail, UserInfoDrawerDetail },
components: { UsersNavigation, RevisionsDrawerDetail, SaveOptions, CommentsSidebarDetail, UserInfoSidebarDetail },
props: {
primaryKey: {
type: String,

View File

@@ -3,7 +3,7 @@ import { createStore } from 'pinia';
export const useAppStore = createStore({
id: 'appStore',
state: () => ({
drawerOpen: false,
sidebarOpen: false,
hydrated: false,
hydrating: false,
error: null,

View File

@@ -1,4 +0,0 @@
import CommentsDrawerDetail from './comments-drawer-detail.vue';
export { CommentsDrawerDetail };
export default CommentsDrawerDetail;

View File

@@ -1,9 +0,0 @@
# Comments Drawer
Renders an comment timeline in a drawer section meant to be used in the drawer sidebar.
## Usage
```html
<comments-drawer-detail collection="authors" primary-key="15" />
```

View File

@@ -1,5 +1,5 @@
<template>
<drawer-detail :title="$t('comments')" icon="chat_bubble_outline" :badge="count || null">
<sidebar-detail :title="$t('comments')" icon="chat_bubble_outline" :badge="count || null">
<comment-input :refresh="refresh" :collection="collection" :primary-key="primaryKey" />
<v-progress-linear indeterminate v-if="loading" />
@@ -15,7 +15,7 @@
<comment-item :refresh="refresh" :activity="item" :key="item.id" />
</template>
</template>
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">
@@ -138,7 +138,7 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
.drawer-detail {
.sidebar-detail {
--v-badge-background-color: var(--foreground-normal);
}

View File

@@ -0,0 +1,4 @@
import CommentsSidebarDetail from './comments-sidebar-detail.vue';
export { CommentsSidebarDetail };
export default CommentsSidebarDetail;

View File

@@ -0,0 +1,9 @@
# Comments Sidebar
Renders an comment timeline in a sidebar section meant to be used in the sidebar sidebar.
## Usage
```html
<comments-sidebar-detail collection="authors" primary-key="15" />
```

View File

@@ -1,4 +0,0 @@
import DrawerButton from './drawer-button.vue';
export { DrawerButton };
export default DrawerButton;

View File

@@ -1,5 +1,5 @@
<template>
<v-modal v-model="_active" :title="$t('select_item')" no-padding @esc="cancel">
<v-drawer v-model="_active" :title="$t('select_item')" @cancel="cancel">
<component
:is="`layout-${localLayout}`"
:collection="collection"
@@ -20,11 +20,12 @@
</template>
</component>
<template #footer>
<v-button @click="cancel" secondary>{{ $t('cancel') }}</v-button>
<v-button @click="save">{{ $t('save') }}</v-button>
<template #actions>
<v-button @click="save" icon rounded v-tooltip.bottom="$t('save')">
<v-icon name="check" />
</v-button>
</template>
</v-modal>
</v-drawer>
</template>
<script lang="ts">

View File

@@ -0,0 +1,4 @@
import DrawerCollection from './drawer-collection.vue';
export { DrawerCollection };
export default DrawerCollection;

View File

@@ -1,4 +0,0 @@
import DrawerDetailGroup from './drawer-detail-group.vue';
export { DrawerDetailGroup };
export default DrawerDetailGroup;

View File

@@ -1,39 +0,0 @@
# Drawer Detail Group
Used in the private view to manage the active state of [the nested `drawer-detail` components](../drawer-detail/).
## Usage
```html
<drawer-detail-group :drawer-open="drawerOpen">
<drawer-detail icon="person" title="Users" >
<!-- section content -->
</drawer-detail>
<drawer-detail icon="settings" title="Settings" >
<!-- section content -->
</drawer-detail>
<drawer-detail icon="map" title="Routes" >
<!-- section content -->
</drawer-detail>
</drawer-detail-group>
```
## Drawer open state
Once the drawer closes, all open drawer details should be closed. By watching the `drawer-open` prop, we can dynamically close all details.
## Props
| Prop | Description | Default |
|---------------|----------------------------------------------------------|---------|
| `drawer-open` | If the drawer sidebar in the private view is open or not | `false` |
## Slots
| Slot | Description |
|-----------|-------------|
| _default_ | |
## Events
n/a
## CSS Variables
n/a

View File

@@ -1,4 +0,0 @@
import DrawerDetail from './drawer-detail.vue';
export { DrawerDetail };
export default DrawerDetail;

View File

@@ -1,31 +1,34 @@
<template>
<v-modal v-model="_active" :title="title" persistent form-width @esc="cancel">
<template v-if="junctionField">
<v-drawer v-model="_active" :title="title" persistent @cancel="cancel">
<template #actions>
<v-button @click="save" icon rounded v-tooltip.bottom="$t('save')">
<v-icon name="check" />
</v-button>
</template>
<div class="drawer-item-content">
<template v-if="junctionField">
<v-form
:loading="loading"
:initial-values="item && item[junctionField]"
:collection="junctionRelatedCollection"
:primary-key="relatedPrimaryKey"
:edits="_edits[junctionField]"
@input="setJunctionEdits"
/>
<v-divider v-if="showDivider" />
</template>
<v-form
:loading="loading"
:initial-values="item && item[junctionField]"
:collection="junctionRelatedCollection"
:primary-key="relatedPrimaryKey"
:edits="_edits[junctionField]"
@input="setJunctionEdits"
:initial-values="item"
:collection="collection"
:primary-key="primaryKey"
v-model="_edits"
/>
<v-divider v-if="showDivider" />
</template>
<v-form
:loading="loading"
:initial-values="item"
:collection="collection"
:primary-key="primaryKey"
v-model="_edits"
/>
<template #footer>
<v-button @click="cancel" secondary>{{ $t('cancel') }}</v-button>
<v-button @click="save">{{ $t('save') }}</v-button>
</template>
</v-modal>
</div>
</v-drawer>
</template>
<script lang="ts">
@@ -288,4 +291,9 @@ export default defineComponent({
.v-divider {
margin: 52px 0;
}
.drawer-item-content {
padding: var(--content-padding);
padding-bottom: var(--content-padding-bottom);
}
</style>

View File

@@ -0,0 +1,4 @@
import DrawerItem from './drawer-item.vue';
export { DrawerItem };
export default DrawerItem;

View File

@@ -1,4 +0,0 @@
import ExportDrawerDetail from './export-drawer-detail.vue';
export { ExportDrawerDetail };
export default ExportDrawerDetail;

View File

@@ -1,5 +1,5 @@
<template>
<drawer-detail icon="save_alt" :title="$t('export_data')">
<sidebar-detail icon="save_alt" :title="$t('export_data')">
<div class="fields">
<div class="field full">
<p class="type-label">{{ $t('format') }}</p>
@@ -20,10 +20,12 @@
</div>
<div class="field full">
<v-button full-width @click="exportData">{{ $t('export_collection', { collection: collection.name }) }}</v-button>
<v-button full-width @click="exportData">
{{ $t('export_collection', { collection: collection.name }) }}
</v-button>
</div>
</div>
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">
@@ -35,7 +37,7 @@ export default defineComponent({
props: {
layoutQuery: {
type: Object,
default: () => ({})
default: () => ({}),
},
searchQuery: {
type: String,
@@ -44,7 +46,7 @@ export default defineComponent({
collection: {
type: Object as PropType<Collection>,
required: true,
}
},
},
setup(props, { emit }) {
const format = ref('csv');
@@ -56,7 +58,7 @@ export default defineComponent({
const url = `/items/${props.collection.collection}`;
let params: Record<string, any> = {
access_token: api.defaults.headers.Authorization.substring(7)
access_token: api.defaults.headers.Authorization.substring(7),
};
if (format.value === 'csv') {
@@ -69,14 +71,16 @@ export default defineComponent({
params = {
...params,
...props.layoutQuery,
}
};
if (props.searchQuery) {
params.search = props.searchQuery;
}
}
const qs = Object.keys(params).map(key => `${key}=${params[key]}`).join('&');
const qs = Object.keys(params)
.map((key) => `${key}=${params[key]}`)
.join('&');
window.open(`${url}?${qs}`);
}
},

View File

@@ -0,0 +1,4 @@
import ExportSidebarDetail from './export-sidebar-detail.vue';
export { ExportSidebarDetail };
export default ExportSidebarDetail;

View File

@@ -1,4 +0,0 @@
import FilterDrawerDetail from './filter-drawer-detail.vue';
export { FilterDrawerDetail };
export default FilterDrawerDetail;

View File

@@ -1,5 +1,5 @@
<template>
<drawer-detail
<sidebar-detail
:badge="filters.length > 0 ? filters.length : null"
icon="filter_list"
:title="$t('advanced_filter')"
@@ -39,7 +39,7 @@
<v-checkbox v-model="archived" :label="$t('show_archived_items')" />
</template>
</drawer-detail>
</sidebar-detail>
</template>
<script lang="ts">

View File

@@ -0,0 +1,4 @@
import FilterSidebarDetail from './filter-sidebar-detail.vue';
export { FilterSidebarDetail };
export default FilterSidebarDetail;

View File

@@ -5,7 +5,7 @@
</v-button>
<div class="action-buttons">
<v-button class="drawer-toggle" icon rounded secondary outlined @click="$emit('toggle:drawer')">
<v-button class="sidebar-toggle" icon rounded secondary outlined @click="$emit('toggle:sidebar')">
<v-icon name="info" outline />
</v-button>
@@ -40,6 +40,7 @@ export default defineComponent({
.expand {
--v-icon-color: var(--foreground-normal);
flex-shrink: 0;
margin-right: 8px;
@@ -61,7 +62,7 @@ export default defineComponent({
margin-right: 8px;
}
.drawer-toggle {
.sidebar-toggle {
flex-shrink: 0;
@include breakpoint(medium) {
@@ -94,7 +95,7 @@ export default defineComponent({
@include breakpoint(medium) {
.action-buttons ::v-deep {
> *:not(.drawer-toggle) {
> *:not(.sidebar-toggle) {
display: inherit !important;
}
}

View File

@@ -33,7 +33,7 @@ n/a
## Events
| Event | Description | Value |
|-----------------|-------------------------------------------------------|-------|
| `toggle:drawer` | Emitted when the user clicks the toggle drawer button | -- |
| `toggle:sidebar` | Emitted when the user clicks the toggle sidebar button | -- |
## CSS Variables
n/a

View File

@@ -22,8 +22,8 @@ export const basic = () =>
title: {
default: text('Title', 'Hello World'),
},
showDrawerToggle: {
default: boolean('Show Drawer Toggle', false),
showSidebarToggle: {
default: boolean('Show Sidebar Toggle', false),
},
dense: {
default: boolean('Dense', false),
@@ -31,19 +31,19 @@ export const basic = () =>
},
setup() {
const navToggle = action('update:nav-open');
const drawerToggle = action('update:drawer-open');
const sidebarToggle = action('update:sidebar-open');
return { navToggle, drawerToggle };
return { navToggle, sidebarToggle };
},
template: `
<header-bar
:title="title"
:nav-open="false"
:drawer-open="false"
:show-drawer-toggle="showDrawerToggle"
:sidebar-open="false"
:show-sidebar-toggle="showSidebarToggle"
:dense="dense"
@update:nav-open="navToggle"
@update:drawer-open="drawerToggle"
@update:sidebar-open="sidebarToggle"
/>
`,
});
@@ -56,8 +56,8 @@ export const withBreadcrumb = () =>
title: {
default: text('Title', 'Hello World'),
},
showDrawerToggle: {
default: boolean('Show Drawer Toggle', false),
showSidebarToggle: {
default: boolean('Show Sidebar Toggle', false),
},
dense: {
default: boolean('Dense', false),
@@ -65,19 +65,19 @@ export const withBreadcrumb = () =>
},
setup() {
const navToggle = action('update:nav-open');
const drawerToggle = action('update:drawer-open');
const sidebarToggle = action('update:sidebar-open');
return { navToggle, drawerToggle };
return { navToggle, sidebarToggle };
},
template: `
<header-bar
:title="title"
:nav-open="false"
:drawer-open="false"
:show-drawer-toggle="showDrawerToggle"
:sidebar-open="false"
:show-sidebar-toggle="showSidebarToggle"
:dense="dense"
@update:nav-open="navToggle"
@update:drawer-open="drawerToggle"
@update:sidebar-open="sidebarToggle"
>
<template #headline>
<v-breadcrumb :items="[
@@ -103,8 +103,8 @@ export const withBackButton = () =>
title: {
default: text('Title', 'Hello World'),
},
showDrawerToggle: {
default: boolean('Show Drawer Toggle', false),
showSidebarToggle: {
default: boolean('Show Sidebar Toggle', false),
},
dense: {
default: boolean('Dense', false),
@@ -112,19 +112,19 @@ export const withBackButton = () =>
},
setup() {
const navToggle = action('update:nav-open');
const drawerToggle = action('update:drawer-open');
const sidebarToggle = action('update:sidebar-open');
return { navToggle, drawerToggle };
return { navToggle, sidebarToggle };
},
template: `
<header-bar
:title="title"
:nav-open="false"
:drawer-open="false"
:show-drawer-toggle="showDrawerToggle"
:sidebar-open="false"
:show-sidebar-toggle="showSidebarToggle"
:dense="dense"
@update:nav-open="navToggle"
@update:drawer-open="drawerToggle"
@update:sidebar-open="sidebarToggle"
>
<template #title-outer:prepend>
<v-button icon rounded secondary>
@@ -146,8 +146,8 @@ export const slots = () => {
title: {
default: text('Title', 'Hello World'),
},
showDrawerToggle: {
default: boolean('Show Drawer Toggle', false),
showSidebarToggle: {
default: boolean('Show Sidebar Toggle', false),
},
dense: {
default: boolean('Dense', false),
@@ -155,19 +155,19 @@ export const slots = () => {
},
setup() {
const navToggle = action('update:nav-open');
const drawerToggle = action('update:drawer-open');
const sidebarToggle = action('update:sidebar-open');
return { navToggle, drawerToggle };
return { navToggle, sidebarToggle };
},
template: `
<header-bar
:title="title"
:nav-open="false"
:drawer-open="false"
:show-drawer-toggle="showDrawerToggle"
:sidebar-open="false"
:show-sidebar-toggle="showSidebarToggle"
:dense="dense"
@update:nav-open="navToggle"
@update:drawer-open="drawerToggle"
@update:sidebar-open="sidebarToggle"
>
<template #title-outer:prepend>
<slot-label>title-outer:prepend</slot-label>
@@ -205,8 +205,8 @@ export const withActions = () =>
title: {
default: text('Title', 'Hello World'),
},
showDrawerToggle: {
default: boolean('Show Drawer Toggle', false),
showSidebarToggle: {
default: boolean('Show Sidebar Toggle', false),
},
dense: {
default: boolean('Dense', false),
@@ -214,19 +214,19 @@ export const withActions = () =>
},
setup() {
const navToggle = action('update:nav-open');
const drawerToggle = action('update:drawer-open');
const sidebarToggle = action('update:sidebar-open');
return { navToggle, drawerToggle };
return { navToggle, sidebarToggle };
},
template: `
<header-bar
:title="title"
:nav-open="false"
:drawer-open="false"
:show-drawer-toggle="showDrawerToggle"
:sidebar-open="false"
:show-sidebar-toggle="showSidebarToggle"
:dense="dense"
@update:nav-open="navToggle"
@update:drawer-open="drawerToggle"
@update:sidebar-open="sidebarToggle"
>
<template #actions>
<v-button rounded icon style="--v-button-background-color: var(--success);">

View File

@@ -35,9 +35,9 @@ describe('Views / Private / Header Bar', () => {
expect(component.emitted('toggle:nav')?.[0]).toBeTruthy();
const drawerToggle = component.find('.drawer-toggle > .button');
drawerToggle.trigger('click');
const sidebarToggle = component.find('.sidebar-toggle > .button');
sidebarToggle.trigger('click');
expect(component.emitted('toggle:drawer')?.[0]).toBeTruthy();
expect(component.emitted('toggle:sidebar')?.[0]).toBeTruthy();
});
});

View File

@@ -26,7 +26,7 @@
<div class="spacer" />
<slot name="actions:prepend" />
<header-bar-actions @toggle:drawer="$emit('toggle:drawer')">
<header-bar-actions @toggle:sidebar="$emit('toggle:sidebar')">
<slot name="actions" />
</header-bar-actions>
<slot name="actions:append" />
@@ -169,7 +169,7 @@ export default defineComponent({
flex-grow: 1;
}
.drawer-toggle {
.sidebar-toggle {
flex-shrink: 0;
margin-left: 8px;

Some files were not shown because too many files have changed in this diff Show More