Spaces:
Paused
Paused
| <script lang="ts"> | |
| import { SvelteFlowProvider } from '@xyflow/svelte'; | |
| import { slide } from 'svelte/transition'; | |
| import { Pane, PaneResizer } from 'paneforge'; | |
| import { onDestroy, onMount, tick } from 'svelte'; | |
| import { mobile, showControls, showCallOverlay, showOverview, showArtifacts } from '$lib/stores'; | |
| import Modal from '../common/Modal.svelte'; | |
| import Controls from './Controls/Controls.svelte'; | |
| import CallOverlay from './MessageInput/CallOverlay.svelte'; | |
| import Drawer from '../common/Drawer.svelte'; | |
| import Overview from './Overview.svelte'; | |
| import EllipsisVertical from '../icons/EllipsisVertical.svelte'; | |
| import Artifacts from './Artifacts.svelte'; | |
| import { min } from '@floating-ui/utils'; | |
| export let history; | |
| export let models = []; | |
| export let chatId = null; | |
| export let chatFiles = []; | |
| export let params = {}; | |
| export let eventTarget: EventTarget; | |
| export let submitPrompt: Function; | |
| export let stopResponse: Function; | |
| export let showMessage: Function; | |
| export let files; | |
| export let modelId; | |
| export let pane; | |
| let mediaQuery; | |
| let largeScreen = false; | |
| let dragged = false; | |
| let minSize = 0; | |
| export const openPane = () => { | |
| if (parseInt(localStorage?.chatControlsSize)) { | |
| pane.resize(parseInt(localStorage?.chatControlsSize)); | |
| } else { | |
| pane.resize(minSize); | |
| } | |
| }; | |
| const handleMediaQuery = async (e) => { | |
| if (e.matches) { | |
| largeScreen = true; | |
| if ($showCallOverlay) { | |
| showCallOverlay.set(false); | |
| await tick(); | |
| showCallOverlay.set(true); | |
| } | |
| } else { | |
| largeScreen = false; | |
| if ($showCallOverlay) { | |
| showCallOverlay.set(false); | |
| await tick(); | |
| showCallOverlay.set(true); | |
| } | |
| pane = null; | |
| } | |
| }; | |
| const onMouseDown = (event) => { | |
| dragged = true; | |
| }; | |
| const onMouseUp = (event) => { | |
| dragged = false; | |
| }; | |
| onMount(() => { | |
| // listen to resize 1024px | |
| mediaQuery = window.matchMedia('(min-width: 1024px)'); | |
| mediaQuery.addEventListener('change', handleMediaQuery); | |
| handleMediaQuery(mediaQuery); | |
| // Select the container element you want to observe | |
| const container = document.getElementById('chat-container'); | |
| // initialize the minSize based on the container width | |
| minSize = Math.floor((350 / container.clientWidth) * 100); | |
| // Create a new ResizeObserver instance | |
| const resizeObserver = new ResizeObserver((entries) => { | |
| for (let entry of entries) { | |
| const width = entry.contentRect.width; | |
| // calculate the percentage of 200px | |
| const percentage = (350 / width) * 100; | |
| // set the minSize to the percentage, must be an integer | |
| minSize = Math.floor(percentage); | |
| if ($showControls) { | |
| if (pane && pane.isExpanded() && pane.getSize() < minSize) { | |
| pane.resize(minSize); | |
| } | |
| } | |
| } | |
| }); | |
| // Start observing the container's size changes | |
| resizeObserver.observe(container); | |
| document.addEventListener('mousedown', onMouseDown); | |
| document.addEventListener('mouseup', onMouseUp); | |
| }); | |
| onDestroy(() => { | |
| showControls.set(false); | |
| mediaQuery.removeEventListener('change', handleMediaQuery); | |
| document.removeEventListener('mousedown', onMouseDown); | |
| document.removeEventListener('mouseup', onMouseUp); | |
| }); | |
| const closeHandler = () => { | |
| showControls.set(false); | |
| showOverview.set(false); | |
| showArtifacts.set(false); | |
| if ($showCallOverlay) { | |
| showCallOverlay.set(false); | |
| } | |
| }; | |
| $: if (!chatId) { | |
| closeHandler(); | |
| } | |
| </script> | |
| <SvelteFlowProvider> | |
| {#if !largeScreen} | |
| {#if $showControls} | |
| <Drawer | |
| show={$showControls} | |
| on:close={() => { | |
| showControls.set(false); | |
| }} | |
| > | |
| <div | |
| class=" {$showCallOverlay || $showOverview || $showArtifacts | |
| ? ' h-screen w-screen' | |
| : 'px-6 py-4'} h-full" | |
| > | |
| {#if $showCallOverlay} | |
| <div | |
| class=" h-full max-h-[100dvh] bg-white text-gray-700 dark:bg-black dark:text-gray-300 flex justify-center" | |
| > | |
| <CallOverlay | |
| bind:files | |
| {submitPrompt} | |
| {stopResponse} | |
| {modelId} | |
| {chatId} | |
| {eventTarget} | |
| on:close={() => { | |
| showControls.set(false); | |
| }} | |
| /> | |
| </div> | |
| {:else if $showArtifacts} | |
| <Artifacts {history} /> | |
| {:else if $showOverview} | |
| <Overview | |
| {history} | |
| on:nodeclick={(e) => { | |
| showMessage(e.detail.node.data.message); | |
| }} | |
| on:close={() => { | |
| showControls.set(false); | |
| }} | |
| /> | |
| {:else} | |
| <Controls | |
| on:close={() => { | |
| showControls.set(false); | |
| }} | |
| {models} | |
| bind:chatFiles | |
| bind:params | |
| /> | |
| {/if} | |
| </div> | |
| </Drawer> | |
| {/if} | |
| {:else} | |
| <!-- if $showControls --> | |
| {#if $showControls} | |
| <PaneResizer class="relative flex w-2 items-center justify-center bg-background group"> | |
| <div class="z-10 flex h-7 w-5 items-center justify-center rounded-sm"> | |
| <EllipsisVertical className="size-4 invisible group-hover:visible" /> | |
| </div> | |
| </PaneResizer> | |
| {/if} | |
| <Pane | |
| bind:pane | |
| defaultSize={0} | |
| onResize={(size) => { | |
| console.log('size', size, minSize); | |
| if ($showControls && pane.isExpanded()) { | |
| if (size < minSize) { | |
| pane.resize(minSize); | |
| } | |
| if (size < minSize) { | |
| localStorage.chatControlsSize = 0; | |
| } else { | |
| localStorage.chatControlsSize = size; | |
| } | |
| } | |
| }} | |
| onCollapse={() => { | |
| showControls.set(false); | |
| }} | |
| collapsible={true} | |
| class="pt-8" | |
| > | |
| {#if $showControls} | |
| <div class="pr-4 pb-8 flex max-h-full min-h-full"> | |
| <div | |
| class="w-full {($showOverview || $showArtifacts) && !$showCallOverlay | |
| ? ' ' | |
| : 'px-4 py-4 bg-white dark:shadow-lg dark:bg-gray-850 border border-gray-50 dark:border-gray-850'} rounded-xl z-40 pointer-events-auto overflow-y-auto scrollbar-hidden" | |
| > | |
| {#if $showCallOverlay} | |
| <div class="w-full h-full flex justify-center"> | |
| <CallOverlay | |
| bind:files | |
| {submitPrompt} | |
| {stopResponse} | |
| {modelId} | |
| {chatId} | |
| {eventTarget} | |
| on:close={() => { | |
| showControls.set(false); | |
| }} | |
| /> | |
| </div> | |
| {:else if $showArtifacts} | |
| <Artifacts {history} overlay={dragged} /> | |
| {:else if $showOverview} | |
| <Overview | |
| {history} | |
| on:nodeclick={(e) => { | |
| if (e.detail.node.data.message.favorite) { | |
| history.messages[e.detail.node.data.message.id].favorite = true; | |
| } else { | |
| history.messages[e.detail.node.data.message.id].favorite = null; | |
| } | |
| showMessage(e.detail.node.data.message); | |
| }} | |
| on:close={() => { | |
| showControls.set(false); | |
| }} | |
| /> | |
| {:else} | |
| <Controls | |
| on:close={() => { | |
| showControls.set(false); | |
| }} | |
| {models} | |
| bind:chatFiles | |
| bind:params | |
| /> | |
| {/if} | |
| </div> | |
| </div> | |
| {/if} | |
| </Pane> | |
| {/if} | |
| </SvelteFlowProvider> | |