Merge pull request #215 from directus/merge-tags-badge

Merge badge and tags display
This commit is contained in:
Rijk van Zanten
2020-09-08 09:48:08 -04:00
committed by GitHub
9 changed files with 118 additions and 185 deletions

View File

@@ -1,70 +0,0 @@
<template>
<div>
<value-null v-if="value === null" />
<div class="badge" :style="styles">{{ displayValue }}</div>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from '@vue/composition-api';
import formatTitle from '@directus/format-title';
type Choice = {
value: string;
text: string;
foreground: string | null;
background: string | null;
};
export default defineComponent({
props: {
value: {
type: String,
default: null,
},
choices: {
type: Array as PropType<Choice[]>,
default: () => [],
},
defaultBackground: {
type: String,
default: '#eceff1',
},
defaultForeground: {
type: String,
default: '#263238',
},
},
setup(props) {
const currentChoice = computed(() => {
return props.choices.find((choice) => {
return choice.value === props.value;
});
});
const displayValue = computed(() => {
if (!currentChoice.value) return formatTitle(props.value);
return currentChoice.value.text;
});
const styles = computed(() => {
return {
color: currentChoice.value?.foreground || props.defaultForeground,
backgroundColor: currentChoice.value?.background || props.defaultBackground,
};
});
return { displayValue, styles };
},
});
</script>
<style lang="scss" scoped>
.badge {
display: inline-block;
padding: 8px;
line-height: 1;
vertical-align: middle;
border-radius: var(--border-radius);
}
</style>

View File

@@ -1,12 +1,12 @@
import { defineDisplay } from '@/displays/define';
import DisplayBadge from './badge.vue';
import DisplayLabels from './labels.vue';
export default defineDisplay(({ i18n }) => ({
id: 'badge',
name: i18n.t('badge'),
types: ['string'],
id: 'labels',
name: i18n.t('labels'),
types: ['string', 'json'],
icon: 'flag',
handler: DisplayBadge,
handler: DisplayLabels,
options: [
{
field: 'defaultForeground',
@@ -32,6 +32,18 @@ export default defineDisplay(({ i18n }) => ({
default_value: '#eceff1',
},
},
{
field: 'format',
name: i18n.t('format_text'),
type: 'boolean',
meta: {
width: 'half-left',
interface: 'toggle',
},
schema: {
default_value: true,
},
},
{
field: 'choices',
name: i18n.t('choices'),

View File

@@ -0,0 +1,99 @@
<template>
<div class="display-tags">
<v-chip
v-for="item in items"
:key="item.value"
:style="{
'--v-chip-color': item.foreground,
'--v-chip-background-color': item.background,
}"
small
disabled
label
>
{{ item.text }}
</v-chip>
</div>
</template>
<script lang="ts">
import { defineComponent, computed, PropType } from '@vue/composition-api';
import formatTitle from '@directus/format-title';
type Choice = {
value: string;
text: string;
foreground: string | null;
background: string | null;
};
export default defineComponent({
props: {
value: {
type: [String, Array] as PropType<string | string[]>,
required: true,
},
format: {
type: Boolean,
default: true,
},
choices: {
type: Array as PropType<Choice[]>,
default: () => [],
},
defaultBackground: {
type: String,
default: '#eceff1',
},
defaultForeground: {
type: String,
default: '#263238',
},
type: {
type: String,
validator: (val: string) => ['json', 'string'].includes(val),
},
},
setup(props) {
const items = computed(() => {
let items: string[];
if (props.value === null) items = [];
else if (props.type === 'string') items = [props.value as string];
else items = props.value as string[];
return items.map((item) => {
const choice = props.choices.find((choice) => choice.value === item);
if (choice === undefined) {
return {
value: item,
text: props.format ? formatTitle(item) : item,
foreground: props.defaultForeground,
background: props.defaultBackground,
};
} else {
return {
value: item,
text: choice.text || (props.format ? formatTitle(item) : item),
foreground: choice.foreground || props.defaultForeground,
background: choice.background || props.defaultBackground,
};
}
});
});
return { items };
},
});
</script>
<style lang="scss" scoped>
.display-tags {
display: inline-block;
}
.v-chip + .v-chip {
margin-left: 4px;
}
</style>

View File

@@ -1,24 +0,0 @@
import { defineDisplay } from '@/displays/define';
import DisplayTags from './tags.vue';
export default defineDisplay(({ i18n }) => ({
id: 'tags',
name: i18n.t('tags'),
types: ['json'],
icon: 'label',
handler: DisplayTags,
options: [
{
field: 'format',
name: i18n.t('format_text'),
type: 'boolean',
meta: {
width: 'half',
interface: 'toggle',
},
schema: {
default_value: true,
},
},
],
}));

View File

@@ -1,3 +0,0 @@
# Tags
Renders a CSV of strings as individual chips.

View File

@@ -1,24 +0,0 @@
import withPadding from '../../../.storybook/decorators/with-padding';
import { withKnobs, array } from '@storybook/addon-knobs';
import readme from './readme.md';
import { defineComponent } from '@vue/composition-api';
export default {
title: 'Displays / Tags',
decorators: [withPadding, withKnobs],
parameters: {
notes: readme,
},
};
export const basic = () =>
defineComponent({
props: {
value: {
default: array('Value', ['vip', 'executive']),
},
},
template: `
<display-tags :value="value" />
`,
});

View File

@@ -1,21 +0,0 @@
import DisplayTags from './tags.vue';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import VueCompositionAPI from '@vue/composition-api';
import VChip from '@/components/v-chip';
const localVue = createLocalVue();
localVue.use(VueCompositionAPI);
localVue.component('v-chip', VChip);
describe('Displays / Tags', () => {
it('Renders a chip for every value', () => {
const component = shallowMount(DisplayTags, {
localVue,
propsData: {
value: ['tag 1', 'tag 2', 'tag 3'],
},
});
expect(component.findAll(VChip).length).toBe(3);
});
});

View File

@@ -1,38 +0,0 @@
<template>
<div class="display-tags">
<v-chip v-for="val in value" :key="val" small disabled label>
{{ format ? formatTitle(val) : val }}
</v-chip>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from '@vue/composition-api';
import formatTitle from '@directus/format-title';
export default defineComponent({
props: {
value: {
type: Array as PropType<string[]>,
required: true,
},
format: {
type: Boolean,
default: true,
},
},
setup() {
return { formatTitle };
},
});
</script>
<style lang="scss" scoped>
.display-tags {
display: inline-block;
}
.v-chip + .v-chip {
margin-left: 4px;
}
</style>

View File

@@ -103,6 +103,8 @@
"color_dot": "Color Dot",
"default_color": "Default Color",
"labels": "Labels",
"global": "Global",
"admins_have_all_permissions": "Admins have all permissions",