mirror of
https://github.com/open-webui/open-webui
synced 2025-01-09 20:44:30 +00:00
283 lines
6.7 KiB
Svelte
283 lines
6.7 KiB
Svelte
<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>
|