Skip to content

Commit 70d8df5

Browse files
TheodoreSpeaksTheodore Li
andauthored
fix(ui): add back file split view (#3632)
* fix(ui): add back file split view * Open md in split view * Fix lint * Default to preview --------- Co-authored-by: Theodore Li <theo@sim.ai>
1 parent 101fcec commit 70d8df5

File tree

3 files changed

+77
-20
lines changed

3 files changed

+77
-20
lines changed

apps/sim/app/workspace/[workspaceId]/files/files.tsx

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { createLogger } from '@sim/logger'
55
import { useParams } from 'next/navigation'
66
import {
77
Button,
8+
Columns2,
89
Download,
910
DropdownMenu,
1011
DropdownMenuContent,
@@ -48,6 +49,7 @@ import {
4849
ResourceHeader,
4950
timeCell,
5051
} from '@/app/workspace/[workspaceId]/components'
52+
import type { PreviewMode } from '@/app/workspace/[workspaceId]/files/components/file-viewer'
5153
import {
5254
FileViewer,
5355
isPreviewable,
@@ -157,7 +159,7 @@ export function Files() {
157159
const [creatingFile, setCreatingFile] = useState(false)
158160
const [isDirty, setIsDirty] = useState(false)
159161
const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle')
160-
const [showPreview, setShowPreview] = useState(true)
162+
const [previewMode, setPreviewMode] = useState<PreviewMode>('preview')
161163
const [showUnsavedChangesAlert, setShowUnsavedChangesAlert] = useState(false)
162164
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
163165
const [contextMenuFile, setContextMenuFile] = useState<WorkspaceFileRecord | null>(null)
@@ -312,7 +314,7 @@ export function Files() {
312314
if (isDirty) {
313315
setShowUnsavedChangesAlert(true)
314316
} else {
315-
setShowPreview(false)
317+
setPreviewMode('editor')
316318
setSelectedFileId(null)
317319
}
318320
}, [isDirty])
@@ -382,13 +384,11 @@ export function Files() {
382384
]
383385
)
384386

385-
const handleTogglePreview = useCallback(() => setShowPreview((prev) => !prev), [])
386-
387387
const handleDiscardChanges = useCallback(() => {
388388
setShowUnsavedChangesAlert(false)
389389
setIsDirty(false)
390390
setSaveStatus('idle')
391-
setShowPreview(false)
391+
setPreviewMode('editor')
392392
setSelectedFileId(null)
393393
}, [])
394394

@@ -480,8 +480,14 @@ export function Files() {
480480
if (justCreatedFileIdRef.current && !isJustCreated) {
481481
justCreatedFileIdRef.current = null
482482
}
483-
setShowPreview(!isJustCreated)
484-
}, [selectedFileId])
483+
if (isJustCreated) {
484+
setPreviewMode('editor')
485+
} else {
486+
const file = selectedFileId ? files.find((f) => f.id === selectedFileId) : null
487+
const canPreview = file ? isPreviewable(file) : false
488+
setPreviewMode(canPreview ? 'preview' : 'editor')
489+
}
490+
}, [selectedFileId, files])
485491

486492
useEffect(() => {
487493
if (!selectedFile) return
@@ -504,10 +510,23 @@ export function Files() {
504510
return () => window.removeEventListener('beforeunload', handler)
505511
}, [isDirty])
506512

513+
const handleCyclePreviewMode = useCallback(() => {
514+
setPreviewMode((prev) => {
515+
if (prev === 'editor') return 'split'
516+
if (prev === 'split') return 'preview'
517+
return 'editor'
518+
})
519+
}, [])
520+
521+
const handleTogglePreview = useCallback(() => {
522+
setPreviewMode((prev) => (prev === 'preview' ? 'editor' : 'preview'))
523+
}, [])
524+
507525
const fileActions = useMemo<HeaderAction[]>(() => {
508526
if (!selectedFile) return []
509527
const canEditText = isTextEditable(selectedFile)
510528
const canPreview = isPreviewable(selectedFile)
529+
const hasSplitView = canEditText && canPreview
511530

512531
const saveLabel =
513532
saveStatus === 'saving'
@@ -518,16 +537,12 @@ export function Files() {
518537
? 'Save failed'
519538
: 'Save'
520539

540+
const nextModeLabel =
541+
previewMode === 'editor' ? 'Split' : previewMode === 'split' ? 'Preview' : 'Edit'
542+
const nextModeIcon =
543+
previewMode === 'editor' ? Columns2 : previewMode === 'split' ? Eye : Pencil
544+
521545
return [
522-
...(canPreview
523-
? [
524-
{
525-
label: showPreview ? 'Edit' : 'Preview',
526-
icon: showPreview ? Pencil : Eye,
527-
onClick: handleTogglePreview,
528-
},
529-
]
530-
: []),
531546
...(canEditText
532547
? [
533548
{
@@ -540,6 +555,23 @@ export function Files() {
540555
},
541556
]
542557
: []),
558+
...(hasSplitView
559+
? [
560+
{
561+
label: nextModeLabel,
562+
icon: nextModeIcon,
563+
onClick: handleCyclePreviewMode,
564+
},
565+
]
566+
: canPreview
567+
? [
568+
{
569+
label: previewMode === 'preview' ? 'Edit' : 'Preview',
570+
icon: previewMode === 'preview' ? Pencil : Eye,
571+
onClick: handleTogglePreview,
572+
},
573+
]
574+
: []),
543575
{
544576
label: 'Download',
545577
icon: Download,
@@ -554,7 +586,8 @@ export function Files() {
554586
}, [
555587
selectedFile,
556588
saveStatus,
557-
showPreview,
589+
previewMode,
590+
handleCyclePreviewMode,
558591
handleTogglePreview,
559592
handleSave,
560593
isDirty,
@@ -580,8 +613,6 @@ export function Files() {
580613
}
581614

582615
if (selectedFile) {
583-
const canPreview = isPreviewable(selectedFile)
584-
585616
return (
586617
<>
587618
<div className='flex h-full flex-1 flex-col overflow-hidden bg-[var(--bg)]'>
@@ -595,7 +626,7 @@ export function Files() {
595626
file={selectedFile}
596627
workspaceId={workspaceId}
597628
canEdit={userPermissions.canEdit === true}
598-
showPreview={showPreview && canPreview}
629+
previewMode={previewMode}
599630
autoFocus={justCreatedFileIdRef.current === selectedFile.id}
600631
onDirtyChange={setIsDirty}
601632
onSaveStatusChange={setSaveStatus}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { SVGProps } from 'react'
2+
3+
/**
4+
* Columns2 icon component - displays two vertical columns in a rounded container
5+
* @param props - SVG properties including className, fill, etc.
6+
*/
7+
export function Columns2(props: SVGProps<SVGSVGElement>) {
8+
return (
9+
<svg
10+
width='24'
11+
height='24'
12+
viewBox='-1 -2 24 24'
13+
fill='none'
14+
stroke='currentColor'
15+
strokeWidth='1.75'
16+
strokeLinecap='round'
17+
strokeLinejoin='round'
18+
xmlns='http://www.w3.org/2000/svg'
19+
{...props}
20+
>
21+
<path d='M0.75 3.25C0.75 1.86929 1.86929 0.75 3.25 0.75H17.25C18.6307 0.75 19.75 1.86929 19.75 3.25V16.25C19.75 17.6307 18.6307 18.75 17.25 18.75H3.25C1.86929 18.75 0.75 17.6307 0.75 16.25V3.25Z' />
22+
<path d='M10.25 0.75V18.75' />
23+
</svg>
24+
)
25+
}

apps/sim/components/emcn/icons/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export { Card } from './card'
1515
export { Check } from './check'
1616
export { ChevronDown } from './chevron-down'
1717
export { ClipboardList } from './clipboard-list'
18+
export { Columns2 } from './columns2'
1819
export { Columns3 } from './columns3'
1920
export { Connections } from './connections'
2021
export { Copy } from './copy'

0 commit comments

Comments
 (0)