mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-07 11:08:52 +01:00
✨ feat: Improve mobile layout and responsiveness in Artifacts component
This commit is contained in:
parent
0ee5712df1
commit
2a5a3fe508
1 changed files with 85 additions and 40 deletions
|
|
@ -1,8 +1,8 @@
|
|||
import { useRef, useState, useEffect } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import * as Tabs from '@radix-ui/react-tabs';
|
||||
import { Button, Spinner } from '@librechat/client';
|
||||
import { Code, Play, RefreshCw, X } from 'lucide-react';
|
||||
import { Button, Spinner, useMediaQuery } from '@librechat/client';
|
||||
import type { SandpackPreviewRef, CodeEditorRef } from '@codesandbox/sandpack-react';
|
||||
import useArtifacts from '~/hooks/Artifacts/useArtifacts';
|
||||
import DownloadArtifact from './DownloadArtifact';
|
||||
|
|
@ -17,6 +17,7 @@ import store from '~/store';
|
|||
export default function Artifacts() {
|
||||
const localize = useLocalize();
|
||||
const { isMutating } = useEditorContext();
|
||||
const isMobile = useMediaQuery('(max-width: 868px)'); // DO NOT change this value, it is used to determine the layout of the artifacts panel ONLY
|
||||
const editorRef = useRef<CodeEditorRef>();
|
||||
const previewRef = useRef<SandpackPreviewRef>();
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
|
@ -59,43 +60,48 @@ export default function Artifacts() {
|
|||
<div className="flex h-full w-full items-center justify-center">
|
||||
<div
|
||||
className={cn(
|
||||
`flex h-full w-full flex-col overflow-hidden bg-surface-primary text-xl text-text-primary shadow-xl transition-all duration-500 ease-in-out`,
|
||||
isVisible ? 'opacity-100 blur-0' : 'opacity-0 blur-sm'
|
||||
`flex flex-col overflow-hidden bg-surface-primary text-xl text-text-primary shadow-xl transition-all duration-500 ease-in-out`,
|
||||
isVisible ? 'opacity-100 blur-0' : 'opacity-0 blur-sm',
|
||||
isMobile ? 'fixed inset-x-0 bottom-0 z-[100] h-[90vh] rounded-t-xl' : 'h-full w-full',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between bg-surface-primary-alt p-2">
|
||||
<div className="flex items-center">
|
||||
<Tabs.List className="relative inline-flex h-9 gap-2 rounded-xl bg-surface-tertiary p-0.5">
|
||||
<div
|
||||
className={`absolute top-0.5 h-8 rounded-xl bg-surface-primary-alt transition-transform duration-200 ease-out ${
|
||||
activeTab === 'code'
|
||||
? 'w-[42%] translate-x-0'
|
||||
: 'w-[50%] translate-x-[calc(100%-0.250rem)]'
|
||||
}`}
|
||||
/>
|
||||
<Tabs.Trigger
|
||||
value="code"
|
||||
className="relative z-10 flex items-center gap-1.5 rounded-xl border-transparent py-1 pl-2.5 pr-2.5 text-xs font-medium transition-all duration-200 ease-out hover:text-text-primary data-[state=active]:text-text-primary data-[state=inactive]:text-text-secondary"
|
||||
>
|
||||
<Code className="size-3" />
|
||||
<span className="transition-all duration-200 ease-out">
|
||||
{localize('com_ui_code')}
|
||||
</span>
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger
|
||||
value="preview"
|
||||
disabled={isMutating}
|
||||
className="relative z-10 flex items-center gap-2 rounded-xl border-transparent py-1 pl-2.5 pr-2.5 text-xs font-medium transition-all duration-200 ease-out hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-50 data-[state=active]:text-text-primary data-[state=inactive]:text-text-secondary"
|
||||
>
|
||||
<Play className="size-3" />
|
||||
<span className="transition-all duration-200 ease-out">
|
||||
{localize('com_ui_preview')}
|
||||
</span>
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center ${isMobile ? 'justify-center' : 'justify-between'} overflow-x-auto bg-surface-primary-alt ${activeTab === 'code' ? 'p-3' : 'p-2'}`}
|
||||
>
|
||||
{!isMobile && (
|
||||
<div className="flex items-center">
|
||||
<Tabs.List className="relative inline-flex h-9 gap-2 rounded-xl bg-surface-tertiary p-0.5">
|
||||
<div
|
||||
className={`absolute top-0.5 h-8 rounded-xl bg-surface-primary-alt transition-transform duration-200 ease-out ${
|
||||
activeTab === 'code'
|
||||
? 'w-[42%] translate-x-0'
|
||||
: 'w-[50%] translate-x-[calc(100%-0.250rem)]'
|
||||
}`}
|
||||
/>
|
||||
<Tabs.Trigger
|
||||
value="code"
|
||||
className="relative z-10 flex items-center gap-1.5 rounded-xl border-transparent py-1 pl-2.5 pr-2.5 text-xs font-medium transition-all duration-200 ease-out hover:text-text-primary data-[state=active]:text-text-primary data-[state=inactive]:text-text-secondary"
|
||||
>
|
||||
<Code className="size-3" />
|
||||
<span className="transition-all duration-200 ease-out">
|
||||
{localize('com_ui_code')}
|
||||
</span>
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger
|
||||
value="preview"
|
||||
disabled={isMutating}
|
||||
className="relative z-10 flex items-center gap-2 rounded-xl border-transparent py-1 pl-2.5 pr-2.5 text-xs font-medium transition-all duration-200 ease-out hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-50 data-[state=active]:text-text-primary data-[state=inactive]:text-text-secondary"
|
||||
>
|
||||
<Play className="size-3" />
|
||||
<span className="transition-all duration-200 ease-out">
|
||||
{localize('com_ui_preview')}
|
||||
</span>
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex min-w-max items-center gap-3">
|
||||
{activeTab === 'preview' && (
|
||||
<Button
|
||||
size="icon"
|
||||
|
|
@ -141,11 +147,50 @@ export default function Artifacts() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<ArtifactTabs
|
||||
artifact={currentArtifact}
|
||||
editorRef={editorRef as React.MutableRefObject<CodeEditorRef>}
|
||||
previewRef={previewRef as React.MutableRefObject<SandpackPreviewRef>}
|
||||
/>
|
||||
<div className={isMobile ? 'flex-grow overflow-auto' : ''}>
|
||||
<ArtifactTabs
|
||||
isMermaid={isMermaid}
|
||||
artifact={currentArtifact}
|
||||
editorRef={editorRef as React.MutableRefObject<CodeEditorRef>}
|
||||
previewRef={previewRef as React.MutableRefObject<SandpackPreviewRef>}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isMobile && (
|
||||
<div className="flex w-full items-center justify-center bg-surface-primary-alt px-3 pb-2 pt-2">
|
||||
<Tabs.List className="relative flex h-9 w-full rounded-xl bg-surface-tertiary px-1 py-0.5">
|
||||
{/* sliding background: exactly half-width, moves 0% or 100% */}
|
||||
<div
|
||||
className={`absolute left-0 top-0.5 h-8 w-1/2 rounded-xl bg-surface-primary-alt transition-transform duration-200 ease-out ${activeTab === 'code' ? 'translate-x-0' : 'translate-x-full'} `}
|
||||
/>
|
||||
|
||||
<Tabs.Trigger
|
||||
value="code"
|
||||
className="relative z-10 flex w-1/2 items-center justify-center rounded-xl border-transparent py-1 text-center text-xs font-medium transition-all duration-200 ease-out hover:text-text-primary data-[state=active]:text-text-primary data-[state=inactive]:text-text-secondary"
|
||||
>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Code className="size-3" />
|
||||
<span className="transition-all duration-200 ease-out">
|
||||
{localize('com_ui_code')}
|
||||
</span>
|
||||
</div>
|
||||
</Tabs.Trigger>
|
||||
|
||||
<Tabs.Trigger
|
||||
value="preview"
|
||||
disabled={isMutating}
|
||||
className="relative z-10 flex w-1/2 items-center justify-center rounded-xl border-transparent py-1 text-center text-xs font-medium transition-all duration-200 ease-out hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-50 data-[state=active]:text-text-primary data-[state=inactive]:text-text-secondary"
|
||||
>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Play className="size-3" />
|
||||
<span className="transition-all duration-200 ease-out">
|
||||
{localize('com_ui_preview')}
|
||||
</span>
|
||||
</div>
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Root>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue