PersonalSettingOverviewOrder.vue 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. <!-- Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { animations, parents } from '@formkit/drag-and-drop'
  4. import { dragAndDrop } from '@formkit/drag-and-drop/vue'
  5. import { cloneDeep, isEqual } from 'lodash-es'
  6. import { ref, watch, useTemplateRef, type Ref } from 'vue'
  7. import { startAndEndEventsDNDPlugin } from '#shared/utils/startAndEndEventsDNDPlugin.ts'
  8. export interface OverviewItem {
  9. id: string
  10. name: string
  11. organizationShared?: boolean | null
  12. outOfOffice?: boolean | null
  13. }
  14. const localValue = defineModel<OverviewItem[]>({
  15. required: true,
  16. })
  17. const dndEndCallback = (parent: HTMLElement) => {
  18. const parentData = parents.get(parent)
  19. if (!parentData) return
  20. localValue.value = cloneDeep(parentData.getValues(parent))
  21. }
  22. const dndParentElement = useTemplateRef('dnd-parent')
  23. const dndLocalValue = ref(localValue.value || [])
  24. watch(localValue, (newValue) => {
  25. if (isEqual(dndLocalValue.value, newValue)) return
  26. dndLocalValue.value = cloneDeep(newValue || [])
  27. })
  28. dragAndDrop({
  29. parent: dndParentElement as Ref<HTMLElement>,
  30. values: dndLocalValue,
  31. plugins: [
  32. startAndEndEventsDNDPlugin(undefined, dndEndCallback),
  33. animations(),
  34. ],
  35. dropZoneClass: 'opacity-0',
  36. touchDropZoneClass: 'opacity-0',
  37. })
  38. </script>
  39. <template>
  40. <div v-if="localValue" class="rounded-lg bg-blue-200 dark:bg-gray-700">
  41. <!-- :TODO if we add proper a11y support -->
  42. <!-- <span class="hidden" aria-live="assertive" >{{assistiveText}}</span>-->
  43. <span id="drag-and-drop-ticket-overviews" class="sr-only">
  44. {{ $t('Drag and drop to reorder ticket overview list items.') }}
  45. </span>
  46. <ul ref="dnd-parent" class="flex flex-col p-1">
  47. <li
  48. v-for="value in dndLocalValue"
  49. :key="value.id"
  50. class="draggable flex min-h-9 cursor-grab items-start gap-2.5 p-2.5 active:cursor-grabbing"
  51. draggable="true"
  52. aria-describedby="drag-and-drop-ticket-overviews"
  53. >
  54. <CommonIcon
  55. class="mt-1 shrink-0 fill-stone-200 dark:fill-neutral-500"
  56. name="grip-vertical"
  57. size="tiny"
  58. decorative
  59. />
  60. <div class="grow">
  61. <CommonLabel class="inline text-black dark:text-white">
  62. {{ $t(value.name) }}
  63. </CommonLabel>
  64. <CommonBadge
  65. v-if="value.organizationShared"
  66. variant="info"
  67. class="ms-1.5"
  68. >{{ $t('Only when shared organization member') }}</CommonBadge
  69. >
  70. <CommonBadge v-if="value.outOfOffice" variant="info" class="ms-1.5">{{
  71. $t('Only when out of office replacement')
  72. }}</CommonBadge>
  73. </div>
  74. </li>
  75. </ul>
  76. </div>
  77. </template>