ChatControls.svelte 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <script lang="ts">
  2. import { SvelteFlowProvider } from '@xyflow/svelte';
  3. import { slide } from 'svelte/transition';
  4. import { onDestroy, onMount } from 'svelte';
  5. import { mobile, showControls, showCallOverlay, showOverview } from '$lib/stores';
  6. import Modal from '../common/Modal.svelte';
  7. import Controls from './Controls/Controls.svelte';
  8. import CallOverlay from './MessageInput/CallOverlay.svelte';
  9. import Drawer from '../common/Drawer.svelte';
  10. import Overview from './Overview.svelte';
  11. import { Pane, PaneResizer } from 'paneforge';
  12. import EllipsisVertical from '../icons/EllipsisVertical.svelte';
  13. import { get } from 'svelte/store';
  14. export let history;
  15. export let models = [];
  16. export let chatId = null;
  17. export let chatFiles = [];
  18. export let params = {};
  19. export let eventTarget: EventTarget;
  20. export let submitPrompt: Function;
  21. export let stopResponse: Function;
  22. export let showMessage: Function;
  23. export let files;
  24. export let modelId;
  25. export let pane;
  26. let largeScreen = false;
  27. onMount(() => {
  28. // listen to resize 1024px
  29. const mediaQuery = window.matchMedia('(min-width: 1024px)');
  30. const handleMediaQuery = (e) => {
  31. if (e.matches) {
  32. largeScreen = true;
  33. } else {
  34. largeScreen = false;
  35. pane = null;
  36. }
  37. };
  38. mediaQuery.addEventListener('change', handleMediaQuery);
  39. handleMediaQuery(mediaQuery);
  40. return () => {
  41. mediaQuery.removeEventListener('change', handleMediaQuery);
  42. };
  43. });
  44. onDestroy(() => {
  45. showControls.set(false);
  46. });
  47. $: if (!chatId) {
  48. showOverview.set(false);
  49. }
  50. </script>
  51. <SvelteFlowProvider>
  52. {#if !largeScreen}
  53. {#if $showControls}
  54. <Drawer
  55. show={$showControls}
  56. on:close={() => {
  57. showControls.set(false);
  58. }}
  59. >
  60. <div
  61. class=" {$showCallOverlay || $showOverview ? ' h-screen w-screen' : 'px-6 py-4'} h-full"
  62. >
  63. {#if $showCallOverlay}
  64. <div
  65. class=" h-full max-h-[100dvh] bg-white text-gray-700 dark:bg-black dark:text-gray-300 flex justify-center"
  66. >
  67. <CallOverlay
  68. bind:files
  69. {submitPrompt}
  70. {stopResponse}
  71. {modelId}
  72. {chatId}
  73. {eventTarget}
  74. on:close={() => {
  75. showControls.set(false);
  76. }}
  77. />
  78. </div>
  79. {:else if $showOverview}
  80. <Overview
  81. {history}
  82. on:nodeclick={(e) => {
  83. showMessage(e.detail.node.data.message);
  84. }}
  85. on:close={() => {
  86. showControls.set(false);
  87. }}
  88. />
  89. {:else}
  90. <Controls
  91. on:close={() => {
  92. showControls.set(false);
  93. }}
  94. {models}
  95. bind:chatFiles
  96. bind:params
  97. />
  98. {/if}
  99. </div>
  100. </Drawer>
  101. {/if}
  102. {:else}
  103. <!-- if $showControls -->
  104. <PaneResizer class="relative flex w-2 items-center justify-center bg-background group">
  105. <div class="z-10 flex h-7 w-5 items-center justify-center rounded-sm">
  106. <EllipsisVertical className="size-4 invisible group-hover:visible" />
  107. </div>
  108. </PaneResizer>
  109. <Pane
  110. bind:pane
  111. defaultSize={$showControls
  112. ? parseInt(localStorage?.chatControlsSize ?? '30')
  113. ? parseInt(localStorage?.chatControlsSize ?? '30')
  114. : 30
  115. : 0}
  116. onResize={(size) => {
  117. console.log(size);
  118. if (size === 0) {
  119. showControls.set(false);
  120. } else {
  121. if (!$showControls) {
  122. showControls.set(true);
  123. }
  124. localStorage.chatControlsSize = size;
  125. }
  126. }}
  127. >
  128. {#if $showControls}
  129. <div class="pr-4 pb-8 flex max-h-full min-h-full">
  130. <div
  131. class="w-full {$showOverview && !$showCallOverlay
  132. ? ' '
  133. : 'px-5 py-4 bg-white dark:shadow-lg dark:bg-gray-850 border border-gray-50 dark:border-gray-800'} rounded-lg z-50 pointer-events-auto overflow-y-auto scrollbar-hidden"
  134. >
  135. {#if $showCallOverlay}
  136. <div class="w-full h-full flex justify-center">
  137. <CallOverlay
  138. bind:files
  139. {submitPrompt}
  140. {stopResponse}
  141. {modelId}
  142. {chatId}
  143. {eventTarget}
  144. on:close={() => {
  145. showControls.set(false);
  146. }}
  147. />
  148. </div>
  149. {:else if $showOverview}
  150. <Overview
  151. {history}
  152. on:nodeclick={(e) => {
  153. if (e.detail.node.data.message.favorite) {
  154. history.messages[e.detail.node.data.message.id].favorite = true;
  155. } else {
  156. history.messages[e.detail.node.data.message.id].favorite = null;
  157. }
  158. showMessage(e.detail.node.data.message);
  159. }}
  160. on:close={() => {
  161. showControls.set(false);
  162. }}
  163. />
  164. {:else}
  165. <Controls
  166. on:close={() => {
  167. showControls.set(false);
  168. }}
  169. {models}
  170. bind:chatFiles
  171. bind:params
  172. />
  173. {/if}
  174. </div>
  175. </div>
  176. {/if}
  177. </Pane>
  178. {/if}
  179. </SvelteFlowProvider>