mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-25 04:40:15 +01:00
feat: global state for current artifact Id and set on artifact preview click
This commit is contained in:
parent
f2a516db02
commit
48ddf4039e
5 changed files with 47 additions and 13 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useMemo, useState, useEffect, useRef } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import * as Tabs from '@radix-ui/react-tabs';
|
||||
import { Sandpack } from '@codesandbox/sandpack-react';
|
||||
import { useRecoilValue, useRecoilState } from 'recoil';
|
||||
import { removeNullishValues } from 'librechat-data-provider';
|
||||
import { SandpackPreview, SandpackProvider } from '@codesandbox/sandpack-react/unstyled';
|
||||
import type { Artifact } from '~/common';
|
||||
|
|
@ -64,10 +64,10 @@ export default function Artifacts() {
|
|||
const { isSubmitting, latestMessage } = useChatContext();
|
||||
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState('code');
|
||||
const [activeTab, setActiveTab] = useState('preview');
|
||||
const artifacts = useRecoilValue(store.artifactsState);
|
||||
const [currentArtifactId, setCurrentArtifactId] = useRecoilState(store.currentArtifactId);
|
||||
|
||||
const [currentArtifactId, setCurrentArtifactId] = useState<string | null>(null);
|
||||
const orderedArtifactIds = useMemo(() => {
|
||||
return Object.keys(artifacts).sort(
|
||||
(a, b) => artifacts[a].lastUpdateTime - artifacts[b].lastUpdateTime,
|
||||
|
|
@ -86,7 +86,7 @@ export default function Artifacts() {
|
|||
const latestArtifactId = orderedArtifactIds[orderedArtifactIds.length - 1];
|
||||
setCurrentArtifactId(latestArtifactId);
|
||||
}
|
||||
}, [orderedArtifactIds]);
|
||||
}, [setCurrentArtifactId, orderedArtifactIds]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSubmitting && orderedArtifactIds.length > 0) {
|
||||
|
|
@ -99,7 +99,7 @@ export default function Artifacts() {
|
|||
lastContentRef.current = latestArtifact.content ?? null;
|
||||
}
|
||||
}
|
||||
}, [isSubmitting, orderedArtifactIds, artifacts]);
|
||||
}, [setCurrentArtifactId, isSubmitting, orderedArtifactIds, artifacts]);
|
||||
|
||||
useEffect(() => {
|
||||
if (latestMessage?.messageId !== lastRunMessageIdRef.current) {
|
||||
|
|
|
|||
|
|
@ -1,27 +1,38 @@
|
|||
import { useSetRecoilState } from 'recoil';
|
||||
import type { Artifact } from '~/common';
|
||||
import FilePreview from '~/components/Chat/Input/Files/FilePreview';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { getFileType } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
const CodePreview = ({ artifact }: { artifact: Artifact | null }) => {
|
||||
if (!artifact) {
|
||||
const localize = useLocalize();
|
||||
const setArtifactId = useSetRecoilState(store.currentArtifactId);
|
||||
if (artifact === null || artifact === undefined) {
|
||||
return null;
|
||||
}
|
||||
const fileType = getFileType('text/x-');
|
||||
const fileType = getFileType('artifact');
|
||||
|
||||
return (
|
||||
<div className="group relative inline-block text-sm text-text-primary">
|
||||
<div className="relative overflow-hidden rounded-xl border border-border-medium">
|
||||
<div className="w-60 bg-surface-active p-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setArtifactId(artifact.id)}
|
||||
className="group relative inline-block rounded-xl text-sm text-text-primary"
|
||||
>
|
||||
<div className="relative overflow-hidden rounded-xl border border-border-medium transition-all duration-300 hover:border-border-xheavy hover:shadow-lg">
|
||||
<div className="w-60 bg-surface-tertiary p-2 ">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<FilePreview fileType={fileType} className="relative" />
|
||||
<div className="overflow-hidden">
|
||||
<div className="overflow-hidden text-left">
|
||||
<div className="truncate font-medium">{artifact.title}</div>
|
||||
<div className="truncate text-text-secondary">{fileType.title}</div>
|
||||
<div className="truncate text-text-secondary">
|
||||
{localize('com_ui_artifact_click')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// file deepcode ignore HardcodedNonCryptoSecret: No hardcoded secrets present in this file
|
||||
|
||||
export default {
|
||||
com_ui_artifact_click: 'Click to open',
|
||||
com_a11y_start: 'The AI is replying.',
|
||||
com_a11y_end: 'The AI has finished their reply.',
|
||||
com_error_moderation:
|
||||
|
|
|
|||
|
|
@ -31,3 +31,18 @@ export const artifactIdsState = atom<string[]>({
|
|||
},
|
||||
] as const,
|
||||
});
|
||||
|
||||
export const currentArtifactId = atom<string | null>({
|
||||
key: 'currentArtifactId',
|
||||
default: null,
|
||||
effects: [
|
||||
({ onSet, node }) => {
|
||||
onSet(async (newValue) => {
|
||||
logger.log('artifacts', 'Recoil Effect: Setting currentArtifactId', {
|
||||
key: node.key,
|
||||
newValue,
|
||||
});
|
||||
});
|
||||
},
|
||||
] as const,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ const codeFile = {
|
|||
title: 'Code',
|
||||
};
|
||||
|
||||
const artifact = {
|
||||
paths: CodePaths,
|
||||
fill: '#2D305C',
|
||||
title: 'Code',
|
||||
};
|
||||
|
||||
export const fileTypes = {
|
||||
/* Category matches */
|
||||
file: {
|
||||
|
|
@ -41,6 +47,7 @@ export const fileTypes = {
|
|||
csv: spreadsheet,
|
||||
pdf: textDocument,
|
||||
'text/x-': codeFile,
|
||||
artifact: artifact,
|
||||
|
||||
/* Exact matches */
|
||||
// 'application/json':,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue