Collapsible.svelte 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. {#if attributes.duration < 60}
  66. {$i18n.t('Thought for {{DURATION}} seconds', {
  67. DURATION: attributes.duration
  68. })}
  69. {:else}
  70. {$i18n.t('Thought for {{DURATION}}', {
  71. DURATION: dayjs.duration(attributes.duration, 'seconds').humanize()
  72. })}
  73. {/if}
  74. {:else}
  75. {$i18n.t('Thinking...')}
  76. {/if}
  77. {:else if attributes?.type === 'code_interpreter'}
  78. {#if attributes?.done === 'true'}
  79. {$i18n.t('Analyzed')}
  80. {:else}
  81. {$i18n.t('Analyzing...')}
  82. {/if}
  83. {:else}
  84. {title}
  85. {/if}
  86. </div>
  87. <div class="flex self-center translate-y-[1px]">
  88. {#if open}
  89. <ChevronUp strokeWidth="3.5" className="size-3.5" />
  90. {:else}
  91. <ChevronDown strokeWidth="3.5" className="size-3.5" />
  92. {/if}
  93. </div>
  94. </div>
  95. </div>
  96. {:else}
  97. <!-- svelte-ignore a11y-no-static-element-interactions -->
  98. <!-- svelte-ignore a11y-click-events-have-key-events -->
  99. <div
  100. class="{buttonClassName} cursor-pointer"
  101. on:pointerup={() => {
  102. if (!disabled) {
  103. open = !open;
  104. }
  105. }}
  106. >
  107. <div>
  108. <slot />
  109. {#if grow}
  110. {#if open && !hide}
  111. <div
  112. transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}
  113. on:pointerup={(e) => {
  114. e.stopPropagation();
  115. }}
  116. >
  117. <slot name="content" />
  118. </div>
  119. {/if}
  120. {/if}
  121. </div>
  122. </div>
  123. {/if}
  124. {#if !grow}
  125. {#if open && !hide}
  126. <div transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}>
  127. <slot name="content" />
  128. </div>
  129. {/if}
  130. {/if}
  131. </div>