mirror of
https://github.com/directus/directus.git
synced 2026-01-28 06:58:02 -05:00
Small tweaks, large benefits (#404)
* Add 160px bottom padding to all pages * Force header column to have 24px min width * Allow resizing of last column in v-table * Fix table row unwanted spacing + offset 2px * Add divider to end of drawer detail * Add down chevron on project chooser hover * Add support for color accented modules * Use yellow header icon in settings * Add link to collections module browse icon * Dont show all items selected on load v-table * Add prepend / append slot to v-checkbox * Add drag handles to field setup settings in tabular * Fix loading state in table * Show all resize handles on hover * Lose breadcrumb in collections module, show singleton title * Wrap activity icon, render textarea full width * Dont render comments section on batch * Allow input to shrink for slots * Fix cursor on v-selects * Prevent input usage when they have click events * Fix margin on divider in fields-management * Fix drag handles on field selects * Fix button / divider spacing * Remove support for divider inset * Fix test warning * Fix table-row test * Fix codesmell * Fix missing scope attr
This commit is contained in:
@@ -239,6 +239,7 @@ export default defineComponent({
|
||||
|
||||
min-width: 60px;
|
||||
padding: 0 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&.small {
|
||||
|
||||
@@ -95,9 +95,11 @@ If you can't, you should listen to the `update:indeterminate` event and respond
|
||||
| `indeterminate` | Show the indeterminate state | `false` |
|
||||
|
||||
## Slots
|
||||
| Slot | Description |
|
||||
|---------|------------------------------------------------------------------------------------------------|
|
||||
| `label` | Allows custom markup and HTML to be rendered inside the label. Will override the `label` prop. |
|
||||
| Slot | Description |
|
||||
|-----------|------------------------------------------------------------------------------------------------|
|
||||
| `label` | Allows custom markup and HTML to be rendered inside the label. Will override the `label` prop. |
|
||||
| `prepend` | Rendered right before the checkbox |
|
||||
| `append` | Rendered right after the label |
|
||||
|
||||
## Events
|
||||
| Event | Description | Data |
|
||||
|
||||
@@ -112,3 +112,27 @@ export const htmlLabel = () => ({
|
||||
</v-checkbox>
|
||||
`,
|
||||
});
|
||||
|
||||
export const slots = () => ({
|
||||
methods: {
|
||||
onChange: action('change'),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checked: false,
|
||||
};
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<v-checkbox v-model="checked" @change="onChange" label="Checkbox">
|
||||
<template #prepend>
|
||||
<v-sheet style="--v-sheet-min-height: 0; --v-sheet-background-color: var(--primary-alt);">Prepend</v-sheet>
|
||||
</template>
|
||||
|
||||
<template #append>
|
||||
<v-sheet style="--v-sheet-min-height: 0; --v-sheet-background-color: var(--secondary-alt);">Append</v-sheet>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
:disabled="disabled"
|
||||
:class="{ checked: isChecked }"
|
||||
>
|
||||
<v-icon :name="icon" />
|
||||
<div class="prepend" v-if="$scopedSlots.prepend"><slot name="prepend" /></div>
|
||||
<v-icon class="checkbox" :name="icon" />
|
||||
<span class="label type-text">
|
||||
<slot name="label">{{ label }}</slot>
|
||||
</span>
|
||||
<div class="append" v-if="$scopedSlots.append"><slot name="append" /></div>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
@@ -105,7 +107,7 @@ export default defineComponent({
|
||||
@include no-wrap;
|
||||
}
|
||||
|
||||
& .v-icon {
|
||||
& .checkbox {
|
||||
--v-icon-color: var(--foreground-subdued);
|
||||
}
|
||||
|
||||
@@ -116,21 +118,27 @@ export default defineComponent({
|
||||
color: var(--foreground-subdued);
|
||||
}
|
||||
|
||||
.v-icon {
|
||||
.checkbox {
|
||||
--v-icon-color: var(--foreground-subdued);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:disabled):hover {
|
||||
.v-icon {
|
||||
.checkbox {
|
||||
--v-icon-color: var(--foreground-subdued);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:disabled).checked {
|
||||
.v-icon {
|
||||
.checkbox {
|
||||
--v-icon-color: var(--v-checkbox-color);
|
||||
}
|
||||
}
|
||||
|
||||
.prepend,
|
||||
.append {
|
||||
display: contents;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,7 +12,6 @@ Divides content. Made to be used in `v-list` or `v-tabs` components.
|
||||
| Prop | Description | Default |
|
||||
|------------|-----------------------------------------------------|---------|
|
||||
| `vertical` | Render the divider vertically | `false` |
|
||||
| `inset` | Insets the divider to align with the (list) content | `false` |
|
||||
|
||||
## Events
|
||||
n/a
|
||||
|
||||
@@ -26,12 +26,9 @@ export const basic = () =>
|
||||
vertical: {
|
||||
default: boolean('Vertical', false),
|
||||
},
|
||||
inset: {
|
||||
default: boolean('Inset', false),
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<v-divider :vertical="vertical" :inset="inset" />
|
||||
<v-divider :vertical="vertical" />
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -42,12 +39,9 @@ export const withText = () =>
|
||||
vertical: {
|
||||
default: boolean('Vertical', false),
|
||||
},
|
||||
inset: {
|
||||
default: boolean('Inset', false),
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<v-divider :vertical="vertical" :inset="inset">
|
||||
<v-divider :vertical="vertical">
|
||||
This is a divider.
|
||||
</v-divider>
|
||||
`,
|
||||
@@ -64,11 +58,7 @@ export const inList = () =>
|
||||
VListItemTitle,
|
||||
VIcon,
|
||||
},
|
||||
props: {
|
||||
inset: {
|
||||
default: boolean('Inset', false),
|
||||
},
|
||||
},
|
||||
props: {},
|
||||
template: `
|
||||
<v-sheet style="max-width: 200px">
|
||||
<v-list>
|
||||
@@ -79,7 +69,7 @@ export const inList = () =>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider :inset="inset" style="margin-top: 8px; margin-bottom: 8px;" />
|
||||
<v-divider style="margin-top: 8px; margin-bottom: 8px;" />
|
||||
|
||||
<v-list-item v-for="n in 1" @click="() => {}">
|
||||
<v-list-item-icon><v-icon name="box" /></v-list-item-icon />
|
||||
@@ -88,7 +78,7 @@ export const inList = () =>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider :inset="inset" style="margin-top: 8px; margin-bottom: 8px;" />
|
||||
<v-divider style="margin-top: 8px; margin-bottom: 8px;" />
|
||||
|
||||
<v-list-item v-for="n in 3" @click="() => {}">
|
||||
<v-list-item-icon><v-icon name="box" /></v-list-item-icon />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="v-divider" :class="{ vertical, inset }">
|
||||
<div class="v-divider" :class="{ vertical }">
|
||||
<span v-if="!vertical && $slots.default"><slot /></span>
|
||||
<hr role="separator" :aria-orientation="vertical ? 'vertical' : 'horizontal'" />
|
||||
</div>
|
||||
@@ -10,10 +10,6 @@ import { defineComponent } from '@vue/composition-api';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
inset: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
vertical: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -48,11 +44,6 @@ export default defineComponent({
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&.inset:not(.vertical) {
|
||||
max-width: calc(100% - 16px);
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
&.vertical {
|
||||
display: inline-flex;
|
||||
align-self: stretch;
|
||||
@@ -63,14 +54,6 @@ export default defineComponent({
|
||||
height: inherit;
|
||||
border-width: 0 2px 0 0;
|
||||
}
|
||||
|
||||
&.inset {
|
||||
hr {
|
||||
min-height: 0;
|
||||
max-height: calc(100% - 16px);
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div class="v-input" :class="{ 'full-width': fullWidth }">
|
||||
<div
|
||||
class="v-input"
|
||||
@click="$emit('click', $event)"
|
||||
:class="{ 'full-width': fullWidth, 'has-click': hasClick }"
|
||||
>
|
||||
<div v-if="$slots['prepend-outer']" class="prepend-outer">
|
||||
<slot name="prepend-outer" :value="value" :disabled="disabled" />
|
||||
</div>
|
||||
@@ -76,7 +80,11 @@ export default defineComponent({
|
||||
input: emitValue,
|
||||
}));
|
||||
|
||||
return { _listeners };
|
||||
const hasClick = computed(() => {
|
||||
return listeners.click !== undefined;
|
||||
});
|
||||
|
||||
return { _listeners, hasClick };
|
||||
|
||||
function emitValue(event: InputEvent) {
|
||||
let value = (event.target as HTMLInputElement).value;
|
||||
@@ -136,24 +144,6 @@ export default defineComponent({
|
||||
border-color: var(--border-normal);
|
||||
}
|
||||
|
||||
input {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
appearance: none;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--foreground-subdued);
|
||||
}
|
||||
}
|
||||
|
||||
&.monospace {
|
||||
input {
|
||||
font-family: var(--family-monospace);
|
||||
}
|
||||
}
|
||||
|
||||
.prefix,
|
||||
.suffix {
|
||||
color: var(--foreground-subdued);
|
||||
@@ -164,6 +154,38 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
flex-grow: 1;
|
||||
width: 80%; // allows flex to shrink to allow for slots
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
appearance: none;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--foreground-subdued);
|
||||
}
|
||||
}
|
||||
|
||||
&.has-click {
|
||||
cursor: pointer;
|
||||
input {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.active .input {
|
||||
color: var(--foreground-normal);
|
||||
background-color: var(--background-page);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.input.monospace {
|
||||
input {
|
||||
font-family: var(--family-monospace);
|
||||
}
|
||||
}
|
||||
|
||||
.append-outer {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
@@ -128,4 +128,12 @@ export default defineComponent({
|
||||
.monospace {
|
||||
font-family: var(--family-monospace);
|
||||
}
|
||||
|
||||
.v-input {
|
||||
cursor: pointer;
|
||||
|
||||
::v-deep input {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</th>
|
||||
|
||||
<th
|
||||
v-for="(header, index) in headers"
|
||||
v-for="header in headers"
|
||||
:key="header.value"
|
||||
:class="getClassesForHeader(header)"
|
||||
class="cell"
|
||||
@@ -30,11 +30,13 @@
|
||||
</div>
|
||||
<span
|
||||
class="resize-handle"
|
||||
v-if="showResize && index !== headers.length - 1"
|
||||
v-if="showResize"
|
||||
@click.stop
|
||||
@mousedown="onResizeHandleMouseDown(header, $event)"
|
||||
/>
|
||||
</th>
|
||||
|
||||
<th class="spacer cell" scope="col" />
|
||||
</tr>
|
||||
</thead>
|
||||
</template>
|
||||
@@ -314,7 +316,7 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
th:hover .resize-handle {
|
||||
&:hover .resize-handle {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('Table / Row', () => {
|
||||
});
|
||||
|
||||
it('Renders right amount of cells per row', async () => {
|
||||
expect(component.find('.table-row').findAll('td').length).toBe(2);
|
||||
expect(component.find('.table-row').findAll('td').length).toBe(3);
|
||||
});
|
||||
|
||||
it('Renders the provided element in the nested scoped slot', async () => {
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
:class="getClassesForCell(header)"
|
||||
v-for="header in headers"
|
||||
:key="header.value"
|
||||
:style="{ height: height + 'px', lineHeight: height + 'px' }"
|
||||
:style="{ height: height + 'px', lineHeight: height - 2 + 'px' }"
|
||||
>
|
||||
<slot :name="`item.${header.value}`" :item="item">{{ item[header.value] }}</slot>
|
||||
</td>
|
||||
|
||||
<td class="spacer cell" />
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -153,10 +153,18 @@ export default defineComponent({
|
||||
setup(props, { emit, listeners }) {
|
||||
const _headers = computed({
|
||||
get: () => {
|
||||
return props.headers.map((header: HeaderRaw) => ({
|
||||
...HeaderDefaults,
|
||||
...header,
|
||||
}));
|
||||
return props.headers
|
||||
.map((header: HeaderRaw) => ({
|
||||
...HeaderDefaults,
|
||||
...header,
|
||||
}))
|
||||
.map((header) => {
|
||||
if (header.width && header.width < 24) {
|
||||
header.width = 24;
|
||||
}
|
||||
|
||||
return header;
|
||||
});
|
||||
},
|
||||
set: (newHeaders: Header[]) => {
|
||||
emit(
|
||||
@@ -196,7 +204,7 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const loadingColSpan = computed<string>(() => {
|
||||
let length = _headers.value.length;
|
||||
let length = _headers.value.length + 1; // +1 account for spacer
|
||||
if (props.showSelect) length = length + 1;
|
||||
if (props.showManualSort) length = length + 1;
|
||||
return `1 / span ${length}`;
|
||||
@@ -220,7 +228,7 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const allItemsSelected = computed<boolean>(() => {
|
||||
return props.selection.length === props.items.length;
|
||||
return props.loading === false && props.selection.length === props.items.length;
|
||||
});
|
||||
|
||||
const someItemsSelected = computed<boolean>(() => {
|
||||
@@ -231,17 +239,15 @@ export default defineComponent({
|
||||
|
||||
const columnStyle = computed<string>(() => {
|
||||
let gridTemplateColumns = _headers.value
|
||||
.map((header, index, array) => {
|
||||
if (index !== array.length - 1) {
|
||||
return header.width ? `${header.width}px` : 'min-content';
|
||||
} else {
|
||||
return `minmax(min-content, 1fr)`;
|
||||
}
|
||||
.map((header) => {
|
||||
return header.width ? `${header.width}px` : 'min-content';
|
||||
})
|
||||
.reduce((acc, val) => (acc += ' ' + val), '');
|
||||
|
||||
if (props.showSelect) gridTemplateColumns = 'auto ' + gridTemplateColumns;
|
||||
if (props.showManualSort) gridTemplateColumns = 'auto ' + gridTemplateColumns;
|
||||
|
||||
gridTemplateColumns = gridTemplateColumns + ' 1fr';
|
||||
return gridTemplateColumns;
|
||||
});
|
||||
|
||||
@@ -316,6 +322,7 @@ export default defineComponent({
|
||||
display: grid;
|
||||
grid-template-columns: var(--grid-columns);
|
||||
min-width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
|
||||
::v-deep {
|
||||
|
||||
@@ -2,14 +2,19 @@
|
||||
<div class="layout-tabular">
|
||||
<portal to="drawer">
|
||||
<drawer-detail icon="table_chart" :title="$t('layouts.tabular.fields')">
|
||||
<draggable v-model="activeFields">
|
||||
<draggable v-model="activeFields" handle=".drag-handle">
|
||||
<v-checkbox
|
||||
v-for="field in activeFields"
|
||||
v-model="fields"
|
||||
:key="field.field"
|
||||
:value="field.field"
|
||||
:label="field.name"
|
||||
/>
|
||||
>
|
||||
<template #append>
|
||||
<div class="spacer" />
|
||||
<v-icon @click.stop name="drag_handle" class="drag-handle" />
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</draggable>
|
||||
|
||||
<v-checkbox
|
||||
@@ -417,4 +422,22 @@ export default defineComponent({
|
||||
.v-info {
|
||||
margin: 20vh 0;
|
||||
}
|
||||
|
||||
.v-checkbox {
|
||||
width: 100%;
|
||||
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.drag-handle {
|
||||
--v-icon-color: var(--foreground-subdued);
|
||||
|
||||
cursor: ns-resize;
|
||||
|
||||
&:hover {
|
||||
--v-icon-color: var(--foreground-normal);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,15 +2,11 @@
|
||||
<collections-not-found v-if="!currentCollection || collection.startsWith('directus_')" />
|
||||
<private-view v-else :title="currentCollection.name">
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded disabled icon secondary>
|
||||
<v-button rounded icon secondary :to="collectionsLink">
|
||||
<v-icon :name="currentCollection.icon" />
|
||||
</v-button>
|
||||
</template>
|
||||
|
||||
<template #headline>
|
||||
<v-breadcrumb :items="breadcrumb" />
|
||||
</template>
|
||||
|
||||
<template #drawer><portal-target name="drawer" /></template>
|
||||
|
||||
<template #actions>
|
||||
@@ -131,23 +127,22 @@ export default defineComponent({
|
||||
|
||||
const { selection } = useSelection();
|
||||
const { info: currentCollection, primaryKeyField } = useCollection(collection);
|
||||
const { addNewLink, batchLink } = useLinks();
|
||||
const { addNewLink, batchLink, collectionsLink } = useLinks();
|
||||
const { viewOptions, viewQuery } = useCollectionPreset(collection);
|
||||
const { confirmDelete, deleting, batchDelete } = useBatchDelete();
|
||||
const { breadcrumb } = useBreadcrumb();
|
||||
|
||||
return {
|
||||
currentCollection,
|
||||
addNewLink,
|
||||
batchLink,
|
||||
selection,
|
||||
breadcrumb,
|
||||
confirmDelete,
|
||||
batchDelete,
|
||||
deleting,
|
||||
layout,
|
||||
viewOptions,
|
||||
viewQuery,
|
||||
collectionsLink,
|
||||
};
|
||||
|
||||
function useSelection() {
|
||||
@@ -207,22 +202,13 @@ export default defineComponent({
|
||||
return `/${currentProjectKey}/collections/${props.collection}/${batchPrimaryKeys}`;
|
||||
});
|
||||
|
||||
return { addNewLink, batchLink };
|
||||
}
|
||||
|
||||
function useBreadcrumb() {
|
||||
const breadcrumb = computed(() => {
|
||||
const collectionsLink = computed<string>(() => {
|
||||
const currentProjectKey = projectsStore.state.currentProjectKey;
|
||||
|
||||
return [
|
||||
{
|
||||
name: i18n.tc('collection', 2),
|
||||
to: `/${currentProjectKey}/collections`,
|
||||
},
|
||||
];
|
||||
return `/${currentProjectKey}/collections`;
|
||||
});
|
||||
|
||||
return { breadcrumb };
|
||||
return { addNewLink, batchLink, collectionsLink };
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<template>
|
||||
<collections-not-found v-if="error && error.code === 404" />
|
||||
<private-view v-else :title="$t('editing', { collection: collectionInfo.name })">
|
||||
<private-view
|
||||
v-else
|
||||
:title="
|
||||
$t(collectionInfo.single ? 'editing_single' : 'editing', {
|
||||
collection: collectionInfo.name,
|
||||
})
|
||||
"
|
||||
>
|
||||
<template #title-outer:prepend>
|
||||
<v-button v-if="collectionInfo.single" rounded icon secondary disabled>
|
||||
<v-icon :name="collectionInfo.icon" />
|
||||
</v-button>
|
||||
<v-button v-else rounded icon secondary exact :to="breadcrumb[1].to">
|
||||
<v-button v-else rounded icon secondary exact :to="backLink">
|
||||
<v-icon name="arrow_back" />
|
||||
</v-button>
|
||||
</template>
|
||||
|
||||
<template #headline>
|
||||
<v-breadcrumb :items="breadcrumb" />
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
<v-dialog v-model="confirmDelete">
|
||||
<template #activator="{ on }">
|
||||
@@ -110,7 +113,7 @@
|
||||
|
||||
<template #drawer>
|
||||
<activity-drawer-detail
|
||||
v-if="isNew === false"
|
||||
v-if="isBatch === false && isNew === false"
|
||||
:collection="collection"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
@@ -122,7 +125,6 @@
|
||||
import { defineComponent, computed, toRefs, ref } from '@vue/composition-api';
|
||||
import useProjectsStore from '@/stores/projects';
|
||||
import CollectionsNavigation from '../../components/navigation/';
|
||||
import { i18n } from '@/lang';
|
||||
import router from '@/router';
|
||||
import CollectionsNotFound from '../not-found/';
|
||||
import useCollection from '@/compositions/use-collection';
|
||||
@@ -154,7 +156,6 @@ export default defineComponent({
|
||||
const { collection, primaryKey } = toRefs(props);
|
||||
|
||||
const { info: collectionInfo, softDeleteStatus } = useCollection(collection);
|
||||
const { breadcrumb } = useBreadcrumb();
|
||||
|
||||
const {
|
||||
isNew,
|
||||
@@ -176,12 +177,16 @@ export default defineComponent({
|
||||
const confirmDelete = ref(false);
|
||||
const confirmSoftDelete = ref(false);
|
||||
|
||||
const backLink = computed(
|
||||
() => `/${currentProjectKey.value}/collections/${collection.value}/`
|
||||
);
|
||||
|
||||
return {
|
||||
item,
|
||||
loading,
|
||||
backLink,
|
||||
error,
|
||||
isNew,
|
||||
breadcrumb,
|
||||
edits,
|
||||
hasEdits,
|
||||
saving,
|
||||
@@ -199,21 +204,6 @@ export default defineComponent({
|
||||
softDeleteStatus,
|
||||
};
|
||||
|
||||
function useBreadcrumb() {
|
||||
const breadcrumb = computed(() => [
|
||||
{
|
||||
name: i18n.tc('collection', 2),
|
||||
to: `/${currentProjectKey.value}/collections/`,
|
||||
},
|
||||
{
|
||||
name: collectionInfo.value?.name,
|
||||
to: `/${currentProjectKey.value}/collections/${props.collection}/`,
|
||||
},
|
||||
]);
|
||||
|
||||
return { breadcrumb };
|
||||
}
|
||||
|
||||
async function saveAndQuit() {
|
||||
await save();
|
||||
router.push(`/${currentProjectKey.value}/collections/${props.collection}`);
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
<template #drawer>
|
||||
<activity-drawer-detail
|
||||
v-if="isNew === false"
|
||||
v-if="isBatch === false && isNew === false"
|
||||
collection="directus_files"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
|
||||
@@ -9,6 +9,7 @@ export default defineModule(({ i18n }) => ({
|
||||
id: 'settings',
|
||||
name: i18n.t('settings'),
|
||||
icon: 'settings',
|
||||
color: 'var(--warning)',
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('settings_data_model')">
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded disabled icon secondary>
|
||||
<v-button class="header-icon" rounded disabled icon secondary>
|
||||
<v-icon name="account_tree" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -104,4 +104,9 @@ export default defineComponent({
|
||||
.v-table {
|
||||
padding: var(--content-padding);
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
--v-button-color-disabled: var(--warning);
|
||||
--v-button-background-color-disabled: var(--warning-alt);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<v-menu attached :class="hidden ? 'full' : field.width" close-on-content-click>
|
||||
<template #activator="{ toggle }">
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-input
|
||||
class="field"
|
||||
:class="{ hidden }"
|
||||
:class="{ hidden, active }"
|
||||
readonly
|
||||
@click="toggle"
|
||||
:value="field.name"
|
||||
@@ -234,7 +234,9 @@ export default defineComponent({
|
||||
|
||||
.v-icon {
|
||||
--v-icon-color: var(--foreground-subdued);
|
||||
}
|
||||
|
||||
pointer-events: none;
|
||||
.drag-handle {
|
||||
cursor: grab !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
large
|
||||
@click="openFieldSetup()"
|
||||
>
|
||||
<v-icon name="add" left />
|
||||
<v-icon name="add" />
|
||||
{{ $t('add_field') }}
|
||||
</v-button>
|
||||
|
||||
@@ -243,7 +243,7 @@ export default defineComponent({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-divider {
|
||||
margin: var(--content-padding) 0;
|
||||
margin: 32px 0;
|
||||
}
|
||||
|
||||
.add-field {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="collectionInfo.name">
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded disabled icon secondary>
|
||||
<v-button class="header-icon" rounded disabled icon secondary>
|
||||
<v-icon name="account_tree" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -65,4 +65,9 @@ export default defineComponent({
|
||||
max-width: 800px;
|
||||
padding: var(--content-padding);
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
--v-button-color-disabled: var(--warning);
|
||||
--v-button-background-color-disabled: var(--warning-alt);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('settings_global')">
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded disabled icon secondary>
|
||||
<v-button class="header-icon" rounded disabled icon secondary>
|
||||
<v-icon name="public" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -62,4 +62,9 @@ export default defineComponent({
|
||||
.settings {
|
||||
padding: var(--content-padding);
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
--v-button-color-disabled: var(--warning);
|
||||
--v-button-background-color-disabled: var(--warning-alt);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('roles')">
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded disabled icon secondary>
|
||||
<v-button class="header-icon" rounded disabled icon secondary>
|
||||
<v-icon name="people" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -175,4 +175,9 @@ export default defineComponent({
|
||||
.layout {
|
||||
--layout-offset-top: 64px;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
--v-button-color-disabled: var(--warning);
|
||||
--v-button-background-color-disabled: var(--warning-alt);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('editing', { collection: $t('roles') })">
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded icon secondary exact :to="breadcrumb[0].to">
|
||||
<v-button class="header-icon" rounded icon secondary exact :to="breadcrumb[0].to">
|
||||
<v-icon name="arrow_back" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -194,4 +194,9 @@ export default defineComponent({
|
||||
.v-form {
|
||||
padding: var(--content-padding);
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
--v-button-color-disabled: var(--warning);
|
||||
--v-button-background-color-disabled: var(--warning-alt);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('webhooks')">
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded disabled icon secondary>
|
||||
<v-button class="header-icon" rounded disabled icon secondary>
|
||||
<v-icon name="send" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -175,4 +175,9 @@ export default defineComponent({
|
||||
.layout {
|
||||
--layout-offset-top: 64px;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
--v-button-color-disabled: var(--warning);
|
||||
--v-button-background-color-disabled: var(--warning-alt);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('editing', { collection: $t('webhooks') })">
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded icon secondary exact :to="breadcrumb[0].to">
|
||||
<v-button class="header-icon" rounded icon secondary exact :to="breadcrumb[0].to">
|
||||
<v-icon name="arrow_back" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -194,4 +194,9 @@ export default defineComponent({
|
||||
.v-form {
|
||||
padding: var(--content-padding);
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
--v-button-color-disabled: var(--warning);
|
||||
--v-button-background-color-disabled: var(--warning-alt);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,6 +9,7 @@ export type ModuleConfig = {
|
||||
name: string | VueI18n.TranslateResult;
|
||||
routes?: RouteConfig[];
|
||||
link?: string;
|
||||
color?: string;
|
||||
};
|
||||
|
||||
export type ModuleContext = { i18n: VueI18n };
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
<template #drawer>
|
||||
<activity-drawer-detail
|
||||
v-if="isNew === false"
|
||||
v-if="isBatch === false && isNew === false"
|
||||
collection="directus_users"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
:placeholder="$t('leave_comment')"
|
||||
v-model="newCommentContent"
|
||||
expand-on-focus
|
||||
full-width
|
||||
>
|
||||
<template #append>
|
||||
<v-button
|
||||
@@ -25,19 +26,21 @@
|
||||
<v-avatar small>
|
||||
<v-icon name="person_outline" />
|
||||
</v-avatar>
|
||||
<div class="name">
|
||||
<template v-if="act.action_by && act.action_by">
|
||||
{{ act.action_by.first_name }} {{ act.action_by.last_name }}
|
||||
</template>
|
||||
<template v-else-if="act.action.by && action.action_by">
|
||||
{{ $t('private_user') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('external') }}
|
||||
</template>
|
||||
</div>
|
||||
<div class="date" v-tooltip.start="new Date(act.action_on)">
|
||||
{{ act.date_relative }}
|
||||
<div class="header-content">
|
||||
<div class="name">
|
||||
<template v-if="act.action_by && act.action_by">
|
||||
{{ act.action_by.first_name }} {{ act.action_by.last_name }}
|
||||
</template>
|
||||
<template v-else-if="act.action.by && action.action_by">
|
||||
{{ $t('private_user') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('external') }}
|
||||
</template>
|
||||
</div>
|
||||
<div class="date" v-tooltip.start="new Date(act.action_on)">
|
||||
{{ act.date_relative }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -152,7 +155,10 @@ export default defineComponent({
|
||||
...record,
|
||||
date_relative: await localizedFormatDistance(
|
||||
new Date(record.action_on),
|
||||
new Date()
|
||||
new Date(),
|
||||
{
|
||||
addSuffix: true,
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
@@ -237,6 +243,11 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
.name,
|
||||
.date {
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ import VueCompositionAPI, { ref } from '@vue/composition-api';
|
||||
import DrawerDetail from './drawer-detail.vue';
|
||||
import * as GroupableComposition from '@/compositions/groupable/groupable';
|
||||
import VIcon from '@/components/v-icon';
|
||||
import VDivider from '@/components/v-divider';
|
||||
import TransitionExpand from '@/components/transition/expand';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(VueCompositionAPI);
|
||||
localVue.component('v-icon', VIcon);
|
||||
localVue.component('transition-expand', TransitionExpand);
|
||||
localVue.component('v-divider', VDivider);
|
||||
|
||||
describe('Drawer Detail', () => {
|
||||
it('Uses the useGroupable composition', () => {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<div class="content">
|
||||
<slot />
|
||||
</div>
|
||||
<v-divider />
|
||||
</div>
|
||||
</transition-expand>
|
||||
</div>
|
||||
@@ -88,4 +89,10 @@ export default defineComponent({
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.v-divider {
|
||||
--v-divider-color: var(--border-normal);
|
||||
|
||||
margin: 0 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
:to="module.to"
|
||||
:href="module.href"
|
||||
tile
|
||||
:style="
|
||||
module.color
|
||||
? {
|
||||
'--v-button-background-color-activated': module.color,
|
||||
}
|
||||
: null
|
||||
"
|
||||
>
|
||||
<v-icon :name="module.icon" />
|
||||
</v-button>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="project-chooser">
|
||||
<div class="project-chooser" :class="{ active }">
|
||||
<button class="toggle" :disabled="projects.length === 1" @click="active = !active">
|
||||
<latency-indicator />
|
||||
{{ currentProject.name }}
|
||||
<span class="name">{{ currentProject.name }}</span>
|
||||
<v-icon class="icon" name="expand_more" />
|
||||
</button>
|
||||
<transition-expand>
|
||||
<div v-if="active" class="options-wrapper">
|
||||
@@ -85,6 +86,24 @@ export default defineComponent({
|
||||
.latency-indicator {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.name {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: var(--foreground-subdued);
|
||||
opacity: 0;
|
||||
transition: opacity var(--fast) var(--transition);
|
||||
}
|
||||
|
||||
&:hover .icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.active .toggle .icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.options-wrapper {
|
||||
|
||||
@@ -244,7 +244,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
@include breakpoint(small) {
|
||||
--content-padding: 32px;
|
||||
--content-padding: 32px 32px 160px 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user