| <script lang="ts"> |
| import { SvelteFlowProvider } from '@xyflow/svelte'; |
| import { slide } from 'svelte/transition'; |
| |
| 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 { Pane, PaneResizer } from 'paneforge'; |
| import EllipsisVertical from '../icons/EllipsisVertical.svelte'; |
| import Artifacts from './Artifacts.svelte'; |
| |
| 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; |
| |
| 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); |
| |
| 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={$showControls |
| ? parseInt(localStorage?.chatControlsSize ?? '30') |
| ? parseInt(localStorage?.chatControlsSize ?? '30') |
| : 30 |
| : 0} |
| onResize={(size) => { |
| if (size === 0) { |
| showControls.set(false); |
| } else { |
| if (!$showControls) { |
| showControls.set(true); |
| } |
| localStorage.chatControlsSize = size; |
| } |
| }} |
| 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-800'} rounded-lg 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> |
|
|