feat/enh: embed citation

This commit is contained in:
Timothy Jaeryang Baek 2025-09-28 22:15:47 -05:00
parent 118549caf3
commit f58fc753e3
9 changed files with 96 additions and 12 deletions

View file

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

View file

@ -4,7 +4,14 @@
import { Pane, PaneResizer } from 'paneforge'; import { Pane, PaneResizer } from 'paneforge';
import { onDestroy, onMount, tick } from 'svelte'; 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 Modal from '../common/Modal.svelte';
import Controls from './Controls/Controls.svelte'; import Controls from './Controls/Controls.svelte';
@ -13,6 +20,7 @@
import Overview from './Overview.svelte'; import Overview from './Overview.svelte';
import EllipsisVertical from '../icons/EllipsisVertical.svelte'; import EllipsisVertical from '../icons/EllipsisVertical.svelte';
import Artifacts from './Artifacts.svelte'; import Artifacts from './Artifacts.svelte';
import Embeds from './ChatControls/Embeds.svelte';
export let history; export let history;
export let models = []; export let models = [];
@ -134,6 +142,7 @@
showControls.set(false); showControls.set(false);
showOverview.set(false); showOverview.set(false);
showArtifacts.set(false); showArtifacts.set(false);
showEmbeds.set(false);
if ($showCallOverlay) { if ($showCallOverlay) {
showCallOverlay.set(false); showCallOverlay.set(false);
@ -155,9 +164,9 @@
}} }}
> >
<div <div
class=" {$showCallOverlay || $showOverview || $showArtifacts class=" {$showCallOverlay || $showOverview || $showArtifacts || $showEmbeds
? ' h-screen w-full' ? ' h-screen w-full'
: 'px-6 py-4'} h-full" : 'px-4 py-3'} h-full"
> >
{#if $showCallOverlay} {#if $showCallOverlay}
<div <div
@ -175,6 +184,8 @@
}} }}
/> />
</div> </div>
{:else if $showEmbeds}
<Embeds />
{:else if $showArtifacts} {:else if $showArtifacts}
<Artifacts {history} /> <Artifacts {history} />
{:else if $showOverview} {:else if $showOverview}
@ -241,9 +252,9 @@
{#if $showControls} {#if $showControls}
<div class="flex max-h-full min-h-full"> <div class="flex max-h-full min-h-full">
<div <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" id="controls-container"
> >
{#if $showCallOverlay} {#if $showCallOverlay}
@ -260,6 +271,8 @@
}} }}
/> />
</div> </div>
{:else if $showEmbeds}
<Embeds overlay={dragged} />
{:else if $showArtifacts} {:else if $showArtifacts}
<Artifacts {history} overlay={dragged} /> <Artifacts {history} overlay={dragged} />
{:else if $showOverview} {:else if $showOverview}

View file

@ -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}

View file

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte'; import { getContext } from 'svelte';
import CitationModal from './Citations/CitationModal.svelte'; import CitationModal from './Citations/CitationModal.svelte';
import { embed, showControls, showEmbeds } from '$lib/stores';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
@ -21,8 +22,24 @@
export const showSourceModal = (sourceIdx) => { export const showSourceModal = (sourceIdx) => {
if (citations[sourceIdx]) { if (citations[sourceIdx]) {
console.log('Showing citation modal for:', 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;
}
} }
}; };

View file

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

View file

@ -160,7 +160,7 @@
</script> </script>
<div class="w-full h-full relative"> <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"> <div class="flex items-center gap-2.5">
<button <button
class="self-center p-0.5" class="self-center p-0.5"

View file

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

View file

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

View file

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