mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-04 04:57:51 +00:00 
			
		
		
		
	feat: Add Label Input components (#10480)
This commit is contained in:
		
							
								
								
									
										49
									
								
								app/javascript/dashboard/components-next/Label/AddLabel.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								app/javascript/dashboard/components-next/Label/AddLabel.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
import { ref } from 'vue';
 | 
			
		||||
import { useI18n } from 'vue-i18n';
 | 
			
		||||
 | 
			
		||||
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
 | 
			
		||||
 | 
			
		||||
defineProps({
 | 
			
		||||
  labelMenuItems: {
 | 
			
		||||
    type: Array,
 | 
			
		||||
    default: () => [],
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits(['updateLabel']);
 | 
			
		||||
 | 
			
		||||
const { t } = useI18n();
 | 
			
		||||
 | 
			
		||||
const showDropdown = ref(false);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="relative">
 | 
			
		||||
    <button
 | 
			
		||||
      class="flex items-center gap-1 px-2 py-1 rounded-md outline-dashed h-[26px] outline-1 outline-n-slate-6 hover:bg-n-alpha-2"
 | 
			
		||||
      :class="{ 'bg-n-alpha-2': showDropdown }"
 | 
			
		||||
      @click="showDropdown = !showDropdown"
 | 
			
		||||
    >
 | 
			
		||||
      <span class="i-lucide-plus" />
 | 
			
		||||
      <span class="text-sm text-n-slate-11">
 | 
			
		||||
        {{ t('LABEL.TAG_BUTTON') }}
 | 
			
		||||
      </span>
 | 
			
		||||
    </button>
 | 
			
		||||
    <DropdownMenu
 | 
			
		||||
      v-if="showDropdown"
 | 
			
		||||
      v-on-clickaway="() => (showDropdown = false)"
 | 
			
		||||
      :menu-items="labelMenuItems"
 | 
			
		||||
      show-search
 | 
			
		||||
      class="z-[100] w-48 mt-2 overflow-y-auto ltr:left-0 rtl:right-0 top-full max-h-52"
 | 
			
		||||
      @action="emit('updateLabel', $event)"
 | 
			
		||||
    >
 | 
			
		||||
      <template #thumbnail="{ item }">
 | 
			
		||||
        <div
 | 
			
		||||
          class="rounded-sm size-2"
 | 
			
		||||
          :style="{ backgroundColor: item.thumbnail.color }"
 | 
			
		||||
        />
 | 
			
		||||
      </template>
 | 
			
		||||
    </DropdownMenu>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
							
								
								
									
										22
									
								
								app/javascript/dashboard/components-next/Label/LabelItem.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/javascript/dashboard/components-next/Label/LabelItem.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
defineProps({
 | 
			
		||||
  label: {
 | 
			
		||||
    type: Object,
 | 
			
		||||
    default: null,
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div
 | 
			
		||||
    class="bg-n-alpha-2 rounded-md flex items-center h-7 w-fit py-1 ltr:pl-1 rtl:pr-1 ltr:pr-1.5 rtl:pl-1.5"
 | 
			
		||||
  >
 | 
			
		||||
    <div
 | 
			
		||||
      class="w-2 h-2 m-1 rounded-sm"
 | 
			
		||||
      :style="{ backgroundColor: label.color }"
 | 
			
		||||
    />
 | 
			
		||||
    <span class="text-sm text-n-slate-12">
 | 
			
		||||
      {{ label.title }}
 | 
			
		||||
    </span>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
import AddLabel from '../AddLabel.vue';
 | 
			
		||||
import { labelMenuItems } from './fixtures';
 | 
			
		||||
 | 
			
		||||
function onUpdateLabel(label) {
 | 
			
		||||
  console.log('Label updated:', label);
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <Story title="Components/Label/Add Label">
 | 
			
		||||
    <Variant title="Default (button with label menu items with active state)">
 | 
			
		||||
      <div class="h-[300px] p-4">
 | 
			
		||||
        <AddLabel
 | 
			
		||||
          :label-menu-items="labelMenuItems"
 | 
			
		||||
          @update-label="onUpdateLabel"
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    </Variant>
 | 
			
		||||
 | 
			
		||||
    <Variant title="Empty List (button with empty label menu)">
 | 
			
		||||
      <div class="h-[300px] p-4">
 | 
			
		||||
        <AddLabel :label-menu-items="[]" @update-label="onUpdateLabel" />
 | 
			
		||||
      </div>
 | 
			
		||||
    </Variant>
 | 
			
		||||
  </Story>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
import Label from '../LabelItem.vue';
 | 
			
		||||
import { label } from './fixtures';
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <Story title="Components/Label/Label item">
 | 
			
		||||
    <Variant title="Default">
 | 
			
		||||
      <Label :label="label" />
 | 
			
		||||
    </Variant>
 | 
			
		||||
 | 
			
		||||
    <Variant title="Custom Label">
 | 
			
		||||
      <Label
 | 
			
		||||
        :label="{
 | 
			
		||||
          title: 'Custom Label',
 | 
			
		||||
          color: '#FF5733',
 | 
			
		||||
        }"
 | 
			
		||||
      />
 | 
			
		||||
    </Variant>
 | 
			
		||||
  </Story>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -0,0 +1,62 @@
 | 
			
		||||
export const label = {
 | 
			
		||||
  id: 1,
 | 
			
		||||
  title: 'delivery',
 | 
			
		||||
  color: '#A2FDD5',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const labelMenuItems = [
 | 
			
		||||
  {
 | 
			
		||||
    label: 'delivery',
 | 
			
		||||
    value: 3,
 | 
			
		||||
    thumbnail: {
 | 
			
		||||
      color: '#A2FDD5',
 | 
			
		||||
    },
 | 
			
		||||
    isSelected: true,
 | 
			
		||||
    action: 'addLabel',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'lead',
 | 
			
		||||
    value: 6,
 | 
			
		||||
    thumbnail: {
 | 
			
		||||
      color: '#F161C8',
 | 
			
		||||
    },
 | 
			
		||||
    isSelected: false,
 | 
			
		||||
    action: 'addLabel',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'ops-handover',
 | 
			
		||||
    value: 4,
 | 
			
		||||
    thumbnail: {
 | 
			
		||||
      color: '#A53326',
 | 
			
		||||
    },
 | 
			
		||||
    isSelected: false,
 | 
			
		||||
    action: 'addLabel',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'billing',
 | 
			
		||||
    value: 1,
 | 
			
		||||
    thumbnail: {
 | 
			
		||||
      color: '#28AD21',
 | 
			
		||||
    },
 | 
			
		||||
    isSelected: false,
 | 
			
		||||
    action: 'addLabel',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'premium-customer',
 | 
			
		||||
    value: 5,
 | 
			
		||||
    thumbnail: {
 | 
			
		||||
      color: '#6FD4EF',
 | 
			
		||||
    },
 | 
			
		||||
    isSelected: false,
 | 
			
		||||
    action: 'addLabel',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'software',
 | 
			
		||||
    value: 2,
 | 
			
		||||
    thumbnail: {
 | 
			
		||||
      color: '#8F6EF2',
 | 
			
		||||
    },
 | 
			
		||||
    isSelected: false,
 | 
			
		||||
    action: 'addLabel',
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
@@ -30,5 +30,8 @@
 | 
			
		||||
  },
 | 
			
		||||
  "BREADCRUMB": {
 | 
			
		||||
    "ARIA_LABEL": "Breadcrumb"
 | 
			
		||||
  },
 | 
			
		||||
  "LABEL": {
 | 
			
		||||
    "TAG_BUTTON": "tag"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user