Collapsible.svelte 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 id = '';
  30. export let className = '';
  31. export let buttonClassName =
  32. 'w-fit text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition';
  33. export let title = null;
  34. export let attributes = null;
  35. export let grow = false;
  36. export let disabled = false;
  37. export let hide = false;
  38. </script>
  39. <div id={id} class={className}>
  40. {#if title !== null}
  41. <!-- svelte-ignore a11y-no-static-element-interactions -->
  42. <!-- svelte-ignore a11y-click-events-have-key-events -->
  43. <div
  44. class="{buttonClassName} cursor-pointer"
  45. on:pointerup={() => {
  46. if (!disabled) {
  47. open = !open;
  48. }
  49. }}
  50. >
  51. <div
  52. class=" w-full font-medium flex items-center justify-between gap-2 {attributes?.done &&
  53. attributes?.done !== 'true'
  54. ? 'shimmer'
  55. : ''}
  56. "
  57. >
  58. {#if attributes?.done && attributes?.done !== 'true'}
  59. <div>
  60. <Spinner className="size-4" />
  61. </div>
  62. {/if}
  63. <div class="">
  64. {#if attributes?.type === 'reasoning'}
  65. {#if attributes?.done === 'true' && attributes?.duration}
  66. {#if attributes.duration < 60}
  67. {$i18n.t('Thought for {{DURATION}} seconds', {
  68. DURATION: attributes.duration
  69. })}
  70. {:else}
  71. {$i18n.t('Thought for {{DURATION}}', {
  72. DURATION: dayjs.duration(attributes.duration, 'seconds').humanize()
  73. })}
  74. {/if}
  75. {:else}
  76. {$i18n.t('Thinking...')}
  77. {/if}
  78. {:else if attributes?.type === 'code_interpreter'}
  79. {#if attributes?.done === 'true'}
  80. {$i18n.t('Analyzed')}
  81. {:else}
  82. {$i18n.t('Analyzing...')}
  83. {/if}
  84. {:else}
  85. {title}
  86. {/if}
  87. </div>
  88. <div class="flex self-center translate-y-[1px]">
  89. {#if open}
  90. <ChevronUp strokeWidth="3.5" className="size-3.5" />
  91. {:else}
  92. <ChevronDown strokeWidth="3.5" className="size-3.5" />
  93. {/if}
  94. </div>
  95. </div>
  96. </div>
  97. {:else}
  98. <!-- svelte-ignore a11y-no-static-element-interactions -->
  99. <!-- svelte-ignore a11y-click-events-have-key-events -->
  100. <div
  101. class="{buttonClassName} cursor-pointer"
  102. on:pointerup={() => {
  103. if (!disabled) {
  104. open = !open;
  105. }
  106. }}
  107. >
  108. <div>
  109. <slot />
  110. {#if grow}
  111. {#if open && !hide}
  112. <div
  113. transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}
  114. on:pointerup={(e) => {
  115. e.stopPropagation();
  116. }}
  117. >
  118. <slot name="content" />
  119. </div>
  120. {/if}
  121. {/if}
  122. </div>
  123. </div>
  124. {/if}
  125. {#if !grow}
  126. {#if open && !hide}
  127. <div transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}>
  128. <slot name="content" />
  129. </div>
  130. {/if}
  131. {/if}
  132. </div>