@@ -5,6 +5,7 @@ import { createLogger } from '@sim/logger'
55import { useParams } from 'next/navigation'
66import {
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'
5153import {
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,7 +480,7 @@ export function Files() {
480480 if ( justCreatedFileIdRef . current && ! isJustCreated ) {
481481 justCreatedFileIdRef . current = null
482482 }
483- setShowPreview ( ! isJustCreated )
483+ setPreviewMode ( isJustCreated ? 'editor' : 'preview' )
484484 } , [ selectedFileId ] )
485485
486486 useEffect ( ( ) => {
@@ -504,10 +504,23 @@ export function Files() {
504504 return ( ) => window . removeEventListener ( 'beforeunload' , handler )
505505 } , [ isDirty ] )
506506
507+ const handleCyclePreviewMode = useCallback ( ( ) => {
508+ setPreviewMode ( ( prev ) => {
509+ if ( prev === 'editor' ) return 'split'
510+ if ( prev === 'split' ) return 'preview'
511+ return 'editor'
512+ } )
513+ } , [ ] )
514+
515+ const handleTogglePreview = useCallback ( ( ) => {
516+ setPreviewMode ( ( prev ) => ( prev === 'preview' ? 'editor' : 'preview' ) )
517+ } , [ ] )
518+
507519 const fileActions = useMemo < HeaderAction [ ] > ( ( ) => {
508520 if ( ! selectedFile ) return [ ]
509521 const canEditText = isTextEditable ( selectedFile )
510522 const canPreview = isPreviewable ( selectedFile )
523+ const hasSplitView = canEditText && canPreview
511524
512525 const saveLabel =
513526 saveStatus === 'saving'
@@ -518,16 +531,10 @@ export function Files() {
518531 ? 'Save failed'
519532 : 'Save'
520533
534+ const nextModeLabel = previewMode === 'editor' ? 'Split' : previewMode === 'split' ? 'Preview' : 'Edit'
535+ const nextModeIcon = previewMode === 'editor' ? Columns2 : previewMode === 'split' ? Eye : Pencil
536+
521537 return [
522- ...( canPreview
523- ? [
524- {
525- label : showPreview ? 'Edit' : 'Preview' ,
526- icon : showPreview ? Pencil : Eye ,
527- onClick : handleTogglePreview ,
528- } ,
529- ]
530- : [ ] ) ,
531538 ...( canEditText
532539 ? [
533540 {
@@ -540,6 +547,23 @@ export function Files() {
540547 } ,
541548 ]
542549 : [ ] ) ,
550+ ...( hasSplitView
551+ ? [
552+ {
553+ label : nextModeLabel ,
554+ icon : nextModeIcon ,
555+ onClick : handleCyclePreviewMode ,
556+ } ,
557+ ]
558+ : canPreview
559+ ? [
560+ {
561+ label : previewMode === 'preview' ? 'Edit' : 'Preview' ,
562+ icon : previewMode === 'preview' ? Pencil : Eye ,
563+ onClick : handleTogglePreview ,
564+ } ,
565+ ]
566+ : [ ] ) ,
543567 {
544568 label : 'Download' ,
545569 icon : Download ,
@@ -554,7 +578,8 @@ export function Files() {
554578 } , [
555579 selectedFile ,
556580 saveStatus ,
557- showPreview ,
581+ previewMode ,
582+ handleCyclePreviewMode ,
558583 handleTogglePreview ,
559584 handleSave ,
560585 isDirty ,
@@ -580,8 +605,6 @@ export function Files() {
580605 }
581606
582607 if ( selectedFile ) {
583- const canPreview = isPreviewable ( selectedFile )
584-
585608 return (
586609 < >
587610 < div className = 'flex h-full flex-1 flex-col overflow-hidden bg-[var(--bg)]' >
@@ -595,7 +618,7 @@ export function Files() {
595618 file = { selectedFile }
596619 workspaceId = { workspaceId }
597620 canEdit = { userPermissions . canEdit === true }
598- showPreview = { showPreview && canPreview }
621+ previewMode = { previewMode }
599622 autoFocus = { justCreatedFileIdRef . current === selectedFile . id }
600623 onDirtyChange = { setIsDirty }
601624 onSaveStatusChange = { setSaveStatus }
0 commit comments