ChatMenu.svelte 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <script lang="ts">
  2. import { DropdownMenu } from 'bits-ui';
  3. import { flyAndScale } from '$lib/utils/transitions';
  4. import { getContext, createEventDispatcher } from 'svelte';
  5. const dispatch = createEventDispatcher();
  6. import Dropdown from '$lib/components/common/Dropdown.svelte';
  7. import GarbageBin from '$lib/components/icons/GarbageBin.svelte';
  8. import Pencil from '$lib/components/icons/Pencil.svelte';
  9. import Tooltip from '$lib/components/common/Tooltip.svelte';
  10. import Tags from '$lib/components/chat/Tags.svelte';
  11. import Share from '$lib/components/icons/Share.svelte';
  12. import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
  13. import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte';
  14. import Bookmark from '$lib/components/icons/Bookmark.svelte';
  15. import BookmarkSlash from '$lib/components/icons/BookmarkSlash.svelte';
  16. import { getChatPinnedStatusById, toggleChatPinnedStatusById } from '$lib/apis/chats';
  17. import { chats } from '$lib/stores';
  18. const i18n = getContext('i18n');
  19. export let shareHandler: Function;
  20. export let cloneChatHandler: Function;
  21. export let archiveChatHandler: Function;
  22. export let renameHandler: Function;
  23. export let deleteHandler: Function;
  24. export let onClose: Function;
  25. export let chatId = '';
  26. let show = false;
  27. let pinned = false;
  28. const pinHandler = async () => {
  29. await toggleChatPinnedStatusById(localStorage.token, chatId);
  30. dispatch('change');
  31. };
  32. const checkPinned = async () => {
  33. pinned = await getChatPinnedStatusById(localStorage.token, chatId);
  34. };
  35. $: if (show) {
  36. checkPinned();
  37. }
  38. </script>
  39. <Dropdown
  40. bind:show
  41. on:change={(e) => {
  42. if (e.detail === false) {
  43. onClose();
  44. }
  45. }}
  46. >
  47. <Tooltip content={$i18n.t('More')}>
  48. <slot />
  49. </Tooltip>
  50. <div slot="content">
  51. <DropdownMenu.Content
  52. class="w-full max-w-[180px] rounded-xl 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"
  53. sideOffset={-2}
  54. side="bottom"
  55. align="start"
  56. transition={flyAndScale}
  57. >
  58. <DropdownMenu.Item
  59. class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
  60. on:click={() => {
  61. pinHandler();
  62. }}
  63. >
  64. {#if pinned}
  65. <BookmarkSlash strokeWidth="2" />
  66. <div class="flex items-center">{$i18n.t('Unpin')}</div>
  67. {:else}
  68. <Bookmark strokeWidth="2" />
  69. <div class="flex items-center">{$i18n.t('Pin')}</div>
  70. {/if}
  71. </DropdownMenu.Item>
  72. <DropdownMenu.Item
  73. class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
  74. on:click={() => {
  75. renameHandler();
  76. }}
  77. >
  78. <Pencil strokeWidth="2" />
  79. <div class="flex items-center">{$i18n.t('Rename')}</div>
  80. </DropdownMenu.Item>
  81. <DropdownMenu.Item
  82. class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
  83. on:click={() => {
  84. cloneChatHandler();
  85. }}
  86. >
  87. <DocumentDuplicate strokeWidth="2" />
  88. <div class="flex items-center">{$i18n.t('Clone')}</div>
  89. </DropdownMenu.Item>
  90. <DropdownMenu.Item
  91. class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
  92. on:click={() => {
  93. archiveChatHandler();
  94. }}
  95. >
  96. <ArchiveBox strokeWidth="2" />
  97. <div class="flex items-center">{$i18n.t('Archive')}</div>
  98. </DropdownMenu.Item>
  99. <DropdownMenu.Item
  100. class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
  101. on:click={() => {
  102. shareHandler();
  103. }}
  104. >
  105. <Share />
  106. <div class="flex items-center">{$i18n.t('Share')}</div>
  107. </DropdownMenu.Item>
  108. <DropdownMenu.Item
  109. class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
  110. on:click={() => {
  111. deleteHandler();
  112. }}
  113. >
  114. <GarbageBin strokeWidth="2" />
  115. <div class="flex items-center">{$i18n.t('Delete')}</div>
  116. </DropdownMenu.Item>
  117. <hr class="border-gray-100 dark:border-gray-800 mt-2.5 mb-1.5" />
  118. <div class="flex p-1">
  119. <Tags
  120. {chatId}
  121. on:add={(e) => {
  122. dispatch('tag', {
  123. type: 'add',
  124. name: e.detail.name
  125. });
  126. show = false;
  127. }}
  128. on:delete={(e) => {
  129. dispatch('tag', {
  130. type: 'delete',
  131. name: e.detail.name
  132. });
  133. show = false;
  134. }}
  135. on:close={() => {
  136. show = false;
  137. onClose();
  138. }}
  139. />
  140. </div>
  141. </DropdownMenu.Content>
  142. </div>
  143. </Dropdown>