mirror of
https://github.com/directus/directus.git
synced 2026-02-19 10:14:33 -05:00
Add the cards layout (#430)
* Fix reactivity of currentLayout in drawer detail * Start on cards layout * Use dense list items in v-select * Add cards + size option * Render cards + files based on options * Allow modules to set view defaults * Start on render-template component * Add get fields from template util * Use render template component in cards layout * Render as small icon * Accept options in display handler function * Fix type warnings in format title display * Remove empty styling in render template component * Account for null values in render template * Add loading state to cards layout * Remove type validation in skeleton loader * Only fetch rendered fields * Fix resolving of default values for cards module * Add selection state to cards * Add selection state to cards * Make render template reactive * Implement setup options * Add disabled support to v-select * Add fallback icon option + disable fit input when no source * Add sort header to cards layout * Remove console log * Add selection state to cards header * Fix z-indexing of header menu * Add pagination to cards layout * Fix types in field * Fix type checks in field-setup * Add role presentation to img * Remove code smell * Handle file library gracefully * Add native lazy loading to images in cards layout * Render SVGs inline in card
This commit is contained in:
@@ -16,13 +16,15 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
let currentLayout = layouts.find((layout) => layout.id === props.value);
|
||||
const currentLayout = computed(() => {
|
||||
const layout = layouts.find((layout) => layout.id === props.value);
|
||||
|
||||
// If for whatever reason the current layout doesn't exist, force reset it to tabular
|
||||
if (currentLayout === undefined) {
|
||||
currentLayout = layouts.find((layout) => layout.id === 'tabular');
|
||||
emit('input', 'tabular');
|
||||
}
|
||||
if (layout === undefined) {
|
||||
return layouts.find((layout) => layout.id === 'tabular');
|
||||
}
|
||||
|
||||
return layout;
|
||||
});
|
||||
|
||||
const viewType = computed({
|
||||
get() {
|
||||
|
||||
4
src/views/private/components/render-template/index.ts
Normal file
4
src/views/private/components/render-template/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import RenderTemplate from './render-template.vue';
|
||||
|
||||
export { RenderTemplate };
|
||||
export default RenderTemplate;
|
||||
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div class="render-template">
|
||||
<template v-for="(part, index) in parts">
|
||||
<component
|
||||
v-if="part !== null && typeof part === 'object'"
|
||||
:is="`display-${part.component}`"
|
||||
:key="index"
|
||||
:value="part.value"
|
||||
v-bind="part.options"
|
||||
/>
|
||||
<template v-else>{{ part }}</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from '@vue/composition-api';
|
||||
import useFieldsStore from '@/stores/fields';
|
||||
import { get } from 'lodash';
|
||||
import { Field } from '@/stores/fields/types';
|
||||
import displays from '@/displays';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
collection: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
item: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type: Object as PropType<Record<string, any>>,
|
||||
required: true,
|
||||
},
|
||||
template: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
const regex = /({{.*?}})/g;
|
||||
|
||||
const parts = computed(() =>
|
||||
props.template.split(regex).map((part) => {
|
||||
if (part.startsWith('{{') === false) return part;
|
||||
|
||||
const fieldKey = part.replace(/{{/g, '').replace(/}}/g, '').trim();
|
||||
const field: Field | null = fieldsStore.getField(props.collection, fieldKey);
|
||||
|
||||
// Instead of crashing when the field doesn't exist, we'll render a couple question
|
||||
// marks to indicate it's absence
|
||||
if (!field) return '???';
|
||||
|
||||
// Try getting the value from the item, return some question marks if it doesn't exist
|
||||
const value = get(props.item, fieldKey);
|
||||
if (value === undefined) return '???';
|
||||
|
||||
// If no display is configured, we can render the raw value
|
||||
if (field.display === null) return value;
|
||||
|
||||
const displayInfo = displays.find((display) => display.id === field.display);
|
||||
|
||||
// If used display doesn't exist in the current project, return raw value
|
||||
if (!displayInfo) return value;
|
||||
|
||||
// If the display handler is a function, we parse the value and return the result
|
||||
if (typeof displayInfo.handler === 'function') {
|
||||
const handler = displayInfo.handler as Function;
|
||||
return handler(value, field.display_options);
|
||||
}
|
||||
|
||||
return {
|
||||
component: field.display,
|
||||
options: field.display_options,
|
||||
value: value,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return { parts };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.render-template {
|
||||
display: contents;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user