Banners.svelte 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. <script lang="ts">
  2. import Switch from '$lib/components/common/Switch.svelte';
  3. import Tooltip from '$lib/components/common/Tooltip.svelte';
  4. import EllipsisVertical from '$lib/components/icons/EllipsisVertical.svelte';
  5. import XMark from '$lib/components/icons/XMark.svelte';
  6. import Sortable from 'sortablejs';
  7. import { getContext } from 'svelte';
  8. const i18n = getContext('i18n');
  9. export let banners = [];
  10. let sortable = null;
  11. let bannerListElement = null;
  12. const positionChangeHandler = () => {
  13. const bannerIdOrder = Array.from(bannerListElement.children).map((child) =>
  14. child.id.replace('banner-item-', '')
  15. );
  16. // Sort the banners array based on the new order
  17. banners = bannerIdOrder.map((id) => {
  18. const index = banners.findIndex((banner) => banner.id === id);
  19. return banners[index];
  20. });
  21. };
  22. $: if (banners) {
  23. init();
  24. }
  25. const init = () => {
  26. if (sortable) {
  27. sortable.destroy();
  28. }
  29. if (bannerListElement) {
  30. sortable = Sortable.create(bannerListElement, {
  31. animation: 150,
  32. handle: '.item-handle',
  33. onUpdate: async (event) => {
  34. positionChangeHandler();
  35. }
  36. });
  37. }
  38. };
  39. </script>
  40. <div class=" flex flex-col space-y-0.5" bind:this={bannerListElement}>
  41. {#each banners as banner, bannerIdx (banner.id)}
  42. <div class=" flex justify-between items-center -ml-1" id="banner-item-{banner.id}">
  43. <EllipsisVertical className="size-4 cursor-move item-handle" />
  44. <div class="flex flex-row flex-1 gap-2 items-center">
  45. <select
  46. class="w-fit capitalize rounded-xl text-xs bg-transparent outline-hidden text-left pl-1 pr-2"
  47. bind:value={banner.type}
  48. required
  49. >
  50. {#if banner.type == ''}
  51. <option value="" selected disabled class="text-gray-900">{$i18n.t('Type')}</option>
  52. {/if}
  53. <option value="info" class="text-gray-900">{$i18n.t('Info')}</option>
  54. <option value="warning" class="text-gray-900">{$i18n.t('Warning')}</option>
  55. <option value="error" class="text-gray-900">{$i18n.t('Error')}</option>
  56. <option value="success" class="text-gray-900">{$i18n.t('Success')}</option>
  57. </select>
  58. <input
  59. class="pr-5 py-1.5 text-xs w-full bg-transparent outline-hidden"
  60. placeholder={$i18n.t('Content')}
  61. bind:value={banner.content}
  62. />
  63. <div class="relative -left-2">
  64. <Tooltip content={$i18n.t('Dismissible')} className="flex h-fit items-center">
  65. <Switch bind:state={banner.dismissible} />
  66. </Tooltip>
  67. </div>
  68. </div>
  69. <button
  70. class="pr-3"
  71. type="button"
  72. on:click={() => {
  73. banners.splice(bannerIdx, 1);
  74. banners = banners;
  75. }}
  76. >
  77. <XMark />
  78. </button>
  79. </div>
  80. {/each}
  81. </div>