Collapsible.svelte 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <script lang="ts">
  2. import { getContext, createEventDispatcher } from 'svelte';
  3. const i18n = getContext('i18n');
  4. import dayjs from '$lib/dayjs';
  5. import duration from 'dayjs/plugin/duration';
  6. import relativeTime from 'dayjs/plugin/relativeTime';
  7. dayjs.extend(duration);
  8. dayjs.extend(relativeTime);
  9. async function loadLocale(locales) {
  10. for (const locale of locales) {
  11. try {
  12. dayjs.locale(locale);
  13. break; // Stop after successfully loading the first available locale
  14. } catch (error) {
  15. console.error(`Could not load locale '${locale}':`, error);
  16. }
  17. }
  18. }
  19. // Assuming $i18n.languages is an array of language codes
  20. $: loadLocale($i18n.languages);
  21. const dispatch = createEventDispatcher();
  22. $: dispatch('change', open);
  23. import { slide } from 'svelte/transition';
  24. import { quintOut } from 'svelte/easing';
  25. import ChevronUp from '../icons/ChevronUp.svelte';
  26. import ChevronDown from '../icons/ChevronDown.svelte';
  27. import Spinner from './Spinner.svelte';
  28. export let open = false;
  29. export let className = '';
  30. export let buttonClassName =
  31. 'w-fit text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition';
  32. export let title = null;
  33. export let attributes = null;
  34. export let grow = false;
  35. export let disabled = false;
  36. export let hide = false;
  37. </script>
  38. <div class={className}>
  39. {#if title !== null}
  40. <!-- svelte-ignore a11y-no-static-element-interactions -->
  41. <!-- svelte-ignore a11y-click-events-have-key-events -->
  42. <div
  43. class="{buttonClassName} cursor-pointer"
  44. on:pointerup={() => {
  45. if (!disabled) {
  46. open = !open;
  47. }
  48. }}
  49. >
  50. <div
  51. class=" w-full font-medium flex items-center justify-between gap-2 {attributes?.done &&
  52. attributes?.done !== 'true'
  53. ? 'shimmer'
  54. : ''}
  55. "
  56. >
  57. {#if attributes?.done && attributes?.done !== 'true'}
  58. <div>
  59. <Spinner className="size-4" />
  60. </div>
  61. {/if}
  62. <div class="">
  63. {#if attributes?.type === 'reasoning'}
  64. {#if attributes?.done === 'true' && attributes?.duration}
  65. {$i18n.t('Thought for {{DURATION}}', {
  66. DURATION: dayjs.duration(attributes.duration, 'seconds').humanize()
  67. })}
  68. {:else}
  69. {$i18n.t('Thinking...')}
  70. {/if}
  71. {:else if attributes?.type === 'code_interpreter'}
  72. {#if attributes?.done === 'true'}
  73. {$i18n.t('Analyzed')}
  74. {:else}
  75. {$i18n.t('Analyzing...')}
  76. {/if}
  77. {:else}
  78. {title}
  79. {/if}
  80. </div>
  81. <div class="flex self-center translate-y-[1px]">
  82. {#if open}
  83. <ChevronUp strokeWidth="3.5" className="size-3.5" />
  84. {:else}
  85. <ChevronDown strokeWidth="3.5" className="size-3.5" />
  86. {/if}
  87. </div>
  88. </div>
  89. </div>
  90. {:else}
  91. <!-- svelte-ignore a11y-no-static-element-interactions -->
  92. <!-- svelte-ignore a11y-click-events-have-key-events -->
  93. <div
  94. class="{buttonClassName} cursor-pointer"
  95. on:pointerup={() => {
  96. if (!disabled) {
  97. open = !open;
  98. }
  99. }}
  100. >
  101. <div>
  102. <slot />
  103. {#if grow}
  104. {#if open && !hide}
  105. <div
  106. transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}
  107. on:pointerup={(e) => {
  108. e.stopPropagation();
  109. }}
  110. >
  111. <slot name="content" />
  112. </div>
  113. {/if}
  114. {/if}
  115. </div>
  116. </div>
  117. {/if}
  118. {#if !grow}
  119. {#if open && !hide}
  120. <div transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}>
  121. <slot name="content" />
  122. </div>
  123. {/if}
  124. {/if}
  125. </div>