Parcourir la source

feat/enh: embed citation

Timothy Jaeryang Baek il y a 1 semaine
Parent
commit
f58fc753e3

+ 3 - 1
src/lib/components/chat/Chat.svelte

@@ -38,7 +38,8 @@
 		toolServers,
 		functions,
 		selectedFolder,
-		pinnedChats
+		pinnedChats,
+		showEmbeds
 	} from '$lib/stores';
 	import {
 		convertMessagesToHistory,
@@ -564,6 +565,7 @@
 				showCallOverlay.set(false);
 				showOverview.set(false);
 				showArtifacts.set(false);
+				showEmbeds.set(false);
 			}
 		});
 

+ 18 - 5
src/lib/components/chat/ChatControls.svelte

@@ -4,7 +4,14 @@
 	import { Pane, PaneResizer } from 'paneforge';
 
 	import { onDestroy, onMount, tick } from 'svelte';
-	import { mobile, showControls, showCallOverlay, showOverview, showArtifacts } from '$lib/stores';
+	import {
+		mobile,
+		showControls,
+		showCallOverlay,
+		showOverview,
+		showArtifacts,
+		showEmbeds
+	} from '$lib/stores';
 
 	import Modal from '../common/Modal.svelte';
 	import Controls from './Controls/Controls.svelte';
@@ -13,6 +20,7 @@
 	import Overview from './Overview.svelte';
 	import EllipsisVertical from '../icons/EllipsisVertical.svelte';
 	import Artifacts from './Artifacts.svelte';
+	import Embeds from './ChatControls/Embeds.svelte';
 
 	export let history;
 	export let models = [];
@@ -134,6 +142,7 @@
 		showControls.set(false);
 		showOverview.set(false);
 		showArtifacts.set(false);
+		showEmbeds.set(false);
 
 		if ($showCallOverlay) {
 			showCallOverlay.set(false);
@@ -155,9 +164,9 @@
 				}}
 			>
 				<div
-					class=" {$showCallOverlay || $showOverview || $showArtifacts
+					class=" {$showCallOverlay || $showOverview || $showArtifacts || $showEmbeds
 						? ' h-screen  w-full'
-						: 'px-6 py-4'} h-full"
+						: 'px-4 py-3'} h-full"
 				>
 					{#if $showCallOverlay}
 						<div
@@ -175,6 +184,8 @@
 								}}
 							/>
 						</div>
+					{:else if $showEmbeds}
+						<Embeds />
 					{:else if $showArtifacts}
 						<Artifacts {history} />
 					{:else if $showOverview}
@@ -241,9 +252,9 @@
 			{#if $showControls}
 				<div class="flex max-h-full min-h-full">
 					<div
-						class="w-full {($showOverview || $showArtifacts) && !$showCallOverlay
+						class="w-full {($showOverview || $showArtifacts || $showEmbeds) && !$showCallOverlay
 							? ' '
-							: 'px-4 py-4 bg-white dark:shadow-lg dark:bg-gray-850 '} z-40 pointer-events-auto overflow-y-auto scrollbar-hidden"
+							: 'px-4 py-3 bg-white dark:shadow-lg dark:bg-gray-850 '} z-40 pointer-events-auto overflow-y-auto scrollbar-hidden"
 						id="controls-container"
 					>
 						{#if $showCallOverlay}
@@ -260,6 +271,8 @@
 									}}
 								/>
 							</div>
+						{:else if $showEmbeds}
+							<Embeds overlay={dragged} />
 						{:else if $showArtifacts}
 							<Artifacts {history} overlay={dragged} />
 						{:else if $showOverview}

+ 42 - 0
src/lib/components/chat/ChatControls/Embeds.svelte

@@ -0,0 +1,42 @@
+<script>
+	import { embed, showControls, showEmbeds } from '$lib/stores';
+
+	import FullHeightIframe from '$lib/components/common/FullHeightIframe.svelte';
+	import XMark from '$lib/components/icons/XMark.svelte';
+
+	export let overlay = false;
+</script>
+
+{#if $embed}
+	<div class="h-full w-full">
+		<div
+			class="pointer-events-auto z-20 flex justify-between items-center py-3 px-2 font-primar text-gray-900 dark:text-white"
+		>
+			<div class="flex-1 flex items-center justify-between pl-2">
+				<div class="flex items-center space-x-2">
+					{$embed?.title ?? 'Embedded Content'}
+				</div>
+			</div>
+
+			<button
+				class="self-center pointer-events-auto p-1 rounded-full bg-white dark:bg-gray-850"
+				on:click={() => {
+					console.log('hi');
+					showControls.set(false);
+					showEmbeds.set(false);
+					embed.set(null);
+				}}
+			>
+				<XMark className="size-3.5 text-gray-900 dark:text-white" />
+			</button>
+		</div>
+
+		<div class=" w-full h-full relative">
+			{#if overlay}
+				<div class=" absolute top-0 left-0 right-0 bottom-0 z-10"></div>
+			{/if}
+
+			<FullHeightIframe src={$embed?.url} iframeClassName="w-full h-full" />
+		</div>
+	</div>
+{/if}

+ 19 - 2
src/lib/components/chat/Messages/Citations.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 	import { getContext } from 'svelte';
 	import CitationModal from './Citations/CitationModal.svelte';
+	import { embed, showControls, showEmbeds } from '$lib/stores';
 
 	const i18n = getContext('i18n');
 
@@ -21,8 +22,24 @@
 	export const showSourceModal = (sourceIdx) => {
 		if (citations[sourceIdx]) {
 			console.log('Showing citation modal for:', citations[sourceIdx]);
-			selectedCitation = citations[sourceIdx];
-			showCitationModal = true;
+
+			if (citations[sourceIdx]?.source?.embed_url) {
+				const embedUrl = citations[sourceIdx].source.embed_url;
+				if (embedUrl) {
+					showControls.set(true);
+					showEmbeds.set(true);
+					embed.set({
+						title: citations[sourceIdx]?.source?.name || 'Embedded Content',
+						url: embedUrl
+					});
+				} else {
+					selectedCitation = citations[sourceIdx];
+					showCitationModal = true;
+				}
+			} else {
+				selectedCitation = citations[sourceIdx];
+				showCitationModal = true;
+			}
 		}
 	};
 

+ 2 - 0
src/lib/components/chat/Messages/ContentRenderer.svelte

@@ -10,6 +10,7 @@
 		settings,
 		showArtifacts,
 		showControls,
+		showEmbeds,
 		showOverview
 	} from '$lib/stores';
 	import FloatingButtons from '../ContentRenderer/FloatingButtons.svelte';
@@ -194,6 +195,7 @@
 			await showControls.set(true);
 			await showArtifacts.set(true);
 			await showOverview.set(false);
+			await showEmbeds.set(false);
 		}}
 	/>
 </div>

+ 1 - 1
src/lib/components/chat/Overview.svelte

@@ -160,7 +160,7 @@
 </script>
 
 <div class="w-full h-full relative">
-	<div class=" absolute z-50 w-full flex justify-between dark:text-gray-100 px-4 py-3.5">
+	<div class=" absolute z-50 w-full flex justify-between dark:text-gray-100 px-4 py-3">
 		<div class="flex items-center gap-2.5">
 			<button
 				class="self-center p-0.5"

+ 4 - 2
src/lib/components/common/FullHeightIframe.svelte

@@ -6,6 +6,8 @@
 	export let title = 'Embedded Content';
 	export let initialHeight: number | null = null; // initial height in px, null = auto
 
+	export let iframeClassName = 'w-full rounded-2xl';
+
 	export let args = null;
 
 	export let allowScripts = true;
@@ -174,7 +176,7 @@ window.Chart = parent.Chart; // Chart previously assigned on parent
 		bind:this={iframe}
 		srcdoc={iframeDoc}
 		{title}
-		class="w-full rounded-2xl"
+		class={iframeClassName}
 		style={`${initialHeight ? `height:${initialHeight}px;` : ''}`}
 		width="100%"
 		frameborder="0"
@@ -187,7 +189,7 @@ window.Chart = parent.Chart; // Chart previously assigned on parent
 		bind:this={iframe}
 		src={iframeSrc}
 		{title}
-		class="w-full rounded-2xl"
+		class={iframeClassName}
 		style={`${initialHeight ? `height:${initialHeight}px;` : ''}`}
 		width="100%"
 		frameborder="0"

+ 5 - 1
src/lib/components/layout/Navbar/Menu.svelte

@@ -18,7 +18,8 @@
 		theme,
 		user,
 		settings,
-		folders
+		folders,
+		showEmbeds
 	} from '$lib/stores';
 	import { flyAndScale } from '$lib/utils/transitions';
 	import { getChatById } from '$lib/apis/chats';
@@ -319,6 +320,7 @@
 						await showControls.set(true);
 						await showOverview.set(false);
 						await showArtifacts.set(false);
+						await showEmbeds.set(false);
 					}}
 				>
 					<AdjustmentsHorizontal className=" size-4" strokeWidth="1.5" />
@@ -333,6 +335,7 @@
 					await showControls.set(true);
 					await showOverview.set(true);
 					await showArtifacts.set(false);
+					await showEmbeds.set(false);
 				}}
 			>
 				<Map className=" size-4" strokeWidth="1.5" />
@@ -346,6 +349,7 @@
 					await showControls.set(true);
 					await showArtifacts.set(true);
 					await showOverview.set(false);
+					await showEmbeds.set(false);
 				}}
 			>
 				<Cube className=" size-4" strokeWidth="1.5" />

+ 2 - 0
src/lib/stores/index.ts

@@ -75,10 +75,12 @@ export const showArchivedChats = writable(false);
 export const showChangelog = writable(false);
 
 export const showControls = writable(false);
+export const showEmbeds = writable(false);
 export const showOverview = writable(false);
 export const showArtifacts = writable(false);
 export const showCallOverlay = writable(false);
 
+export const embed = writable(null);
 export const artifactCode = writable(null);
 
 export const temporaryChatEnabled = writable(false);