feat(layout): allow to minimize chat (#35)

This commit is contained in:
Dominic Elm
2024-08-14 11:08:52 +02:00
committed by GitHub
parent 8fd9d4477e
commit d5a29c2427
18 changed files with 262 additions and 114 deletions

View File

@@ -17,9 +17,10 @@ import type { FileMap } from '~/lib/stores/files';
import { themeStore } from '~/lib/stores/theme';
import { workbenchStore } from '~/lib/stores/workbench';
import { classNames } from '~/utils/classNames';
import { WORK_DIR } from '~/utils/constants';
import { renderLogger } from '~/utils/logger';
import { isMobile } from '~/utils/mobile';
import { FileTreePanel } from './FileTreePanel';
import { FileTree } from './FileTree';
import { Terminal, type TerminalRef } from './terminal/Terminal';
interface EditorPanelProps {
@@ -124,22 +125,24 @@ export const EditorPanel = memo(
<PanelGroup direction="vertical">
<Panel defaultSize={showTerminal ? DEFAULT_EDITOR_SIZE : 100} minSize={20}>
<PanelGroup direction="horizontal">
<Panel defaultSize={25} minSize={10} collapsible>
<Panel defaultSize={20} minSize={10} collapsible>
<div className="flex flex-col border-r border-bolt-elements-borderColor h-full">
<PanelHeader>
<div className="i-ph:tree-structure-duotone shrink-0" />
Files
</PanelHeader>
<FileTreePanel
<FileTree
className="h-full"
files={files}
unsavedFiles={unsavedFiles}
rootFolder={WORK_DIR}
selectedFile={selectedFile}
onFileSelect={onFileSelect}
/>
</div>
</Panel>
<PanelResizeHandle />
<Panel className="flex flex-col" defaultSize={75} minSize={20}>
<Panel className="flex flex-col" defaultSize={80} minSize={20}>
<PanelHeader>
{activeFile && (
<div className="flex items-center flex-1 text-sm">

View File

@@ -1,29 +0,0 @@
import { memo } from 'react';
import type { FileMap } from '~/lib/stores/files';
import { WORK_DIR } from '~/utils/constants';
import { renderLogger } from '~/utils/logger';
import { FileTree } from './FileTree';
interface FileTreePanelProps {
files?: FileMap;
selectedFile?: string;
unsavedFiles?: Set<string>;
onFileSelect?: (value?: string) => void;
}
export const FileTreePanel = memo(({ files, unsavedFiles, selectedFile, onFileSelect }: FileTreePanelProps) => {
renderLogger.trace('FileTreePanel');
return (
<div className="flex-1 overflow-y-scroll">
<FileTree
className="h-full"
files={files}
unsavedFiles={unsavedFiles}
rootFolder={WORK_DIR}
selectedFile={selectedFile}
onFileSelect={onFileSelect}
/>
</div>
);
});

View File

@@ -82,11 +82,11 @@ export const Preview = memo(() => {
/>
</div>
</div>
<div className="flex-1 bg-white border-t">
<div className="flex-1 border-t border-bolt-elements-borderColor">
{activePreview ? (
<iframe ref={iframeRef} className="border-none w-full h-full" src={iframeUrl} />
<iframe ref={iframeRef} className="border-none w-full h-full bg-white" src={iframeUrl} />
) : (
<div className="flex w-full h-full justify-center items-center">No preview available</div>
<div className="flex w-full h-full justify-center items-center bg-white">No preview available</div>
)}
</div>
</div>

View File

@@ -11,6 +11,7 @@ import { IconButton } from '~/components/ui/IconButton';
import { PanelHeaderButton } from '~/components/ui/PanelHeaderButton';
import { Slider, type SliderOptions } from '~/components/ui/Slider';
import { workbenchStore, type WorkbenchViewType } from '~/lib/stores/workbench';
import { classNames } from '~/utils/classNames';
import { cubicEasingFn } from '~/utils/easings';
import { renderLogger } from '~/utils/logger';
import { EditorPanel } from './EditorPanel';
@@ -43,7 +44,7 @@ const workbenchVariants = {
},
},
open: {
width: '100%',
width: 'var(--workbench-width)',
transition: {
duration: 0.2,
ease: cubicEasingFn,
@@ -100,53 +101,71 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
return (
chatStarted && (
<motion.div initial="closed" animate={showWorkbench ? 'open' : 'closed'} variants={workbenchVariants}>
<div className="fixed top-[calc(var(--header-height)+1.5rem)] bottom-[calc(1.5rem-1px)] w-[50vw] mr-4 z-0">
<div className="flex flex-col bg-bolt-elements-background-depth-2 border border-bolt-elements-borderColor shadow-sm rounded-lg overflow-hidden absolute inset-0 right-8">
<div className="flex items-center px-3 py-2 border-b border-bolt-elements-borderColor">
<Slider selected={selectedView} options={sliderOptions} setSelected={setSelectedView} />
<PanelHeaderButton
className="ml-auto mr-1 text-sm"
onClick={() => {
workbenchStore.toggleTerminal(!workbenchStore.showTerminal.get());
}}
>
<div className="i-ph:terminal" />
Toggle Terminal
</PanelHeaderButton>
<IconButton
icon="i-ph:x-circle"
className="-mr-1"
size="xl"
onClick={() => {
workbenchStore.showWorkbench.set(false);
}}
/>
</div>
<div className="relative flex-1 overflow-hidden">
<View
initial={{ x: selectedView === 'code' ? 0 : '-100%' }}
animate={{ x: selectedView === 'code' ? 0 : '-100%' }}
>
<EditorPanel
editorDocument={currentDocument}
isStreaming={isStreaming}
selectedFile={selectedFile}
files={files}
unsavedFiles={unsavedFiles}
onFileSelect={onFileSelect}
onEditorScroll={onEditorScroll}
onEditorChange={onEditorChange}
onFileSave={onFileSave}
onFileReset={onFileReset}
<motion.div
initial="closed"
animate={showWorkbench ? 'open' : 'closed'}
variants={workbenchVariants}
className="z-workbench"
>
<div
className={classNames(
'fixed top-[calc(var(--header-height)+1.5rem)] bottom-6 w-[var(--workbench-inner-width)] mr-4 z-0 transition-[left,width] duration-200 bolt-ease-cubic-bezier',
{
'left-[var(--workbench-left)]': showWorkbench,
'left-[100%]': !showWorkbench,
},
)}
>
<div className="absolute inset-0 px-6">
<div className="h-full flex flex-col bg-bolt-elements-background-depth-2 border border-bolt-elements-borderColor shadow-sm rounded-lg overflow-hidden">
<div className="flex items-center px-3 py-2 border-b border-bolt-elements-borderColor">
<Slider selected={selectedView} options={sliderOptions} setSelected={setSelectedView} />
<div className="ml-auto" />
{selectedView === 'code' && (
<PanelHeaderButton
className="mr-1 text-sm"
onClick={() => {
workbenchStore.toggleTerminal(!workbenchStore.showTerminal.get());
}}
>
<div className="i-ph:terminal" />
Toggle Terminal
</PanelHeaderButton>
)}
<IconButton
icon="i-ph:x-circle"
className="-mr-1"
size="xl"
onClick={() => {
workbenchStore.showWorkbench.set(false);
}}
/>
</View>
<View
initial={{ x: selectedView === 'preview' ? 0 : '100%' }}
animate={{ x: selectedView === 'preview' ? 0 : '100%' }}
>
<Preview />
</View>
</div>
<div className="relative flex-1 overflow-hidden">
<View
initial={{ x: selectedView === 'code' ? 0 : '-100%' }}
animate={{ x: selectedView === 'code' ? 0 : '-100%' }}
>
<EditorPanel
editorDocument={currentDocument}
isStreaming={isStreaming}
selectedFile={selectedFile}
files={files}
unsavedFiles={unsavedFiles}
onFileSelect={onFileSelect}
onEditorScroll={onEditorScroll}
onEditorChange={onEditorChange}
onFileSave={onFileSave}
onFileReset={onFileReset}
/>
</View>
<View
initial={{ x: selectedView === 'preview' ? 0 : '100%' }}
animate={{ x: selectedView === 'preview' ? 0 : '100%' }}
>
<Preview />
</View>
</div>
</div>
</div>
</div>