Selector.svelte 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <script lang="ts">
  2. import { DropdownMenu } from 'bits-ui';
  3. import { onMount, getContext, createEventDispatcher } from 'svelte';
  4. import { flyAndScale } from '$lib/utils/transitions';
  5. import { knowledge } from '$lib/stores';
  6. import Dropdown from '$lib/components/common/Dropdown.svelte';
  7. const i18n = getContext('i18n');
  8. const dispatch = createEventDispatcher();
  9. export let onClose: Function = () => {};
  10. let items = [];
  11. onMount(() => {
  12. let legacy_documents = $knowledge.filter((item) => item?.meta?.document);
  13. let legacy_collections =
  14. legacy_documents.length > 0
  15. ? [
  16. {
  17. name: 'All Documents',
  18. legacy: true,
  19. type: 'collection',
  20. description: 'Deprecated (legacy collection), please create a new knowledge base.',
  21. title: $i18n.t('All Documents'),
  22. collection_names: legacy_documents.map((item) => item.id)
  23. },
  24. ...legacy_documents
  25. .reduce((a, item) => {
  26. return [...new Set([...a, ...(item?.meta?.tags ?? []).map((tag) => tag.name)])];
  27. }, [])
  28. .map((tag) => ({
  29. name: tag,
  30. legacy: true,
  31. type: 'collection',
  32. description: 'Deprecated (legacy collection), please create a new knowledge base.',
  33. collection_names: legacy_documents
  34. .filter((item) => (item?.meta?.tags ?? []).map((tag) => tag.name).includes(tag))
  35. .map((item) => item.id)
  36. }))
  37. ]
  38. : [];
  39. items = [...$knowledge, ...legacy_collections].map((item) => {
  40. return {
  41. ...item,
  42. ...(item?.legacy || item?.meta?.legacy || item?.meta?.document ? { legacy: true } : {})
  43. };
  44. });
  45. });
  46. </script>
  47. <Dropdown
  48. on:change={(e) => {
  49. if (e.detail === false) {
  50. onClose();
  51. }
  52. }}
  53. >
  54. <slot />
  55. <div slot="content">
  56. <DropdownMenu.Content
  57. class="w-full max-w-80 rounded-lg px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow-lg"
  58. sideOffset={8}
  59. side="bottom"
  60. align="start"
  61. transition={flyAndScale}
  62. >
  63. <div class="max-h-[10rem] overflow-y-scroll">
  64. {#if items.length === 0}
  65. <div class="text-center text-sm text-gray-500 dark:text-gray-400">
  66. {$i18n.t('No knowledge found')}
  67. </div>
  68. {:else}
  69. {#each items as item}
  70. <DropdownMenu.Item
  71. class="flex gap-2.5 items-center px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
  72. on:click={() => {
  73. dispatch('select', item);
  74. }}
  75. >
  76. <div class="flex items-center">
  77. <div class="flex flex-col">
  78. <div class=" w-fit mb-0.5">
  79. {#if item.legacy}
  80. <div
  81. class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded uppercase text-xs font-bold px-1"
  82. >
  83. Legacy
  84. </div>
  85. {:else if item?.meta?.document}
  86. <div
  87. class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded uppercase text-xs font-bold px-1"
  88. >
  89. Document
  90. </div>
  91. {:else}
  92. <div
  93. class="bg-green-500/20 text-green-700 dark:text-green-200 rounded uppercase text-xs font-bold px-1"
  94. >
  95. Collection
  96. </div>
  97. {/if}
  98. </div>
  99. <div class="line-clamp-1 font-medium pr-0.5">
  100. {item.name}
  101. </div>
  102. </div>
  103. </div>
  104. </DropdownMenu.Item>
  105. {/each}
  106. {/if}
  107. </div>
  108. </DropdownMenu.Content>
  109. </div>
  110. </Dropdown>