| | <script lang="ts"> |
| | import { decode } from 'html-entities'; |
| | import { v4 as uuidv4 } from 'uuid'; |
| | |
| | import { getContext } from 'svelte'; |
| | const i18n = getContext('i18n'); |
| | |
| | import dayjs from '$lib/dayjs'; |
| | import duration from 'dayjs/plugin/duration'; |
| | import relativeTime from 'dayjs/plugin/relativeTime'; |
| | |
| | dayjs.extend(duration); |
| | dayjs.extend(relativeTime); |
| | |
| | async function loadLocale(locales) { |
| | if (!locales || !Array.isArray(locales)) { |
| | return; |
| | } |
| | for (const locale of locales) { |
| | try { |
| | dayjs.locale(locale); |
| | break; |
| | } catch (error) { |
| | console.error(`Could not load locale '${locale}':`, error); |
| | } |
| | } |
| | } |
| | |
| | |
| | $: loadLocale($i18n.languages); |
| | |
| | import { slide } from 'svelte/transition'; |
| | import { quintOut } from 'svelte/easing'; |
| | |
| | import ChevronUp from '../icons/ChevronUp.svelte'; |
| | import ChevronDown from '../icons/ChevronDown.svelte'; |
| | import Spinner from './Spinner.svelte'; |
| | |
| | export let open = false; |
| | |
| | export let className = ''; |
| | export let buttonClassName = |
| | 'w-fit text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition'; |
| | |
| | export let id = ''; |
| | export let title = null; |
| | export let attributes = null; |
| | |
| | export let chevron = false; |
| | export let grow = false; |
| | |
| | export let disabled = false; |
| | export let hide = false; |
| | |
| | export let onChange: Function = () => {}; |
| | |
| | $: onChange(open); |
| | |
| | const collapsibleId = uuidv4(); |
| | </script> |
| |
|
| | <div {id} class={className}> |
| | {#if title !== null} |
| | |
| | |
| | <div |
| | class="{buttonClassName} {disabled ? '' : 'cursor-pointer'}" |
| | on:pointerup={() => { |
| | if (!disabled) { |
| | open = !open; |
| | } |
| | }} |
| | > |
| | <div |
| | class=" w-full font-medium flex items-center justify-between gap-2 {attributes?.done && |
| | attributes?.done !== 'true' |
| | ? 'shimmer' |
| | : ''} |
| | " |
| | > |
| | {#if attributes?.done && attributes?.done !== 'true'} |
| | <div> |
| | <Spinner className="size-4" /> |
| | </div> |
| | {/if} |
| |
|
| | <div class=""> |
| | {#if attributes?.type === 'reasoning'} |
| | {#if attributes?.done === 'true' && attributes?.duration} |
| | {#if attributes.duration < 1} |
| | {$i18n.t('Thought for less than a second')} |
| | {:else if attributes.duration < 60} |
| | {$i18n.t('Thought for {{DURATION}} seconds', { |
| | DURATION: attributes.duration |
| | })} |
| | {:else} |
| | {$i18n.t('Thought for {{DURATION}}', { |
| | DURATION: dayjs.duration(attributes.duration, 'seconds').humanize() |
| | })} |
| | {/if} |
| | {:else} |
| | {$i18n.t('Thinking...')} |
| | {/if} |
| | {:else if attributes?.type === 'code_interpreter'} |
| | {#if attributes?.done === 'true'} |
| | {$i18n.t('Analyzed')} |
| | {:else} |
| | {$i18n.t('Analyzing...')} |
| | {/if} |
| | {:else} |
| | {title} |
| | {/if} |
| | </div> |
| |
|
| | {#if !disabled} |
| | <div class="flex self-center translate-y-[1px]"> |
| | {#if open} |
| | <ChevronUp strokeWidth="3.5" className="size-3.5" /> |
| | {:else} |
| | <ChevronDown strokeWidth="3.5" className="size-3.5" /> |
| | {/if} |
| | </div> |
| | {/if} |
| | </div> |
| | </div> |
| | {:else} |
| | |
| | |
| | <div |
| | class="{buttonClassName} cursor-pointer" |
| | on:click={(e) => { |
| | e.stopPropagation(); |
| | }} |
| | on:pointerup={(e) => { |
| | if (!disabled) { |
| | open = !open; |
| | } |
| | }} |
| | > |
| | <div> |
| | <div class="flex items-start justify-between"> |
| | <slot /> |
| |
|
| | {#if chevron} |
| | <div class="flex self-start translate-y-1"> |
| | {#if open} |
| | <ChevronUp strokeWidth="3.5" className="size-3.5" /> |
| | {:else} |
| | <ChevronDown strokeWidth="3.5" className="size-3.5" /> |
| | {/if} |
| | </div> |
| | {/if} |
| | </div> |
| |
|
| | {#if grow} |
| | {#if open && !hide} |
| | <div |
| | transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }} |
| | on:pointerup={(e) => { |
| | e.stopPropagation(); |
| | }} |
| | > |
| | <slot name="content" /> |
| | </div> |
| | {/if} |
| | {/if} |
| | </div> |
| | </div> |
| | {/if} |
| |
|
| | {#if !grow} |
| | {#if open && !hide} |
| | <div transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}> |
| | <slot name="content" /> |
| | </div> |
| | {/if} |
| | {/if} |
| | </div> |
| |
|