mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
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>
This commit is contained in:
@@ -5,6 +5,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { useParams } from 'next/navigation'
|
||||
import {
|
||||
Button,
|
||||
Columns2,
|
||||
Download,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -48,6 +49,7 @@ import {
|
||||
ResourceHeader,
|
||||
timeCell,
|
||||
} from '@/app/workspace/[workspaceId]/components'
|
||||
import type { PreviewMode } from '@/app/workspace/[workspaceId]/files/components/file-viewer'
|
||||
import {
|
||||
FileViewer,
|
||||
isPreviewable,
|
||||
@@ -157,7 +159,7 @@ export function Files() {
|
||||
const [creatingFile, setCreatingFile] = useState(false)
|
||||
const [isDirty, setIsDirty] = useState(false)
|
||||
const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle')
|
||||
const [showPreview, setShowPreview] = useState(true)
|
||||
const [previewMode, setPreviewMode] = useState<PreviewMode>('preview')
|
||||
const [showUnsavedChangesAlert, setShowUnsavedChangesAlert] = useState(false)
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
|
||||
const [contextMenuFile, setContextMenuFile] = useState<WorkspaceFileRecord | null>(null)
|
||||
@@ -312,7 +314,7 @@ export function Files() {
|
||||
if (isDirty) {
|
||||
setShowUnsavedChangesAlert(true)
|
||||
} else {
|
||||
setShowPreview(false)
|
||||
setPreviewMode('editor')
|
||||
setSelectedFileId(null)
|
||||
}
|
||||
}, [isDirty])
|
||||
@@ -382,13 +384,11 @@ export function Files() {
|
||||
]
|
||||
)
|
||||
|
||||
const handleTogglePreview = useCallback(() => setShowPreview((prev) => !prev), [])
|
||||
|
||||
const handleDiscardChanges = useCallback(() => {
|
||||
setShowUnsavedChangesAlert(false)
|
||||
setIsDirty(false)
|
||||
setSaveStatus('idle')
|
||||
setShowPreview(false)
|
||||
setPreviewMode('editor')
|
||||
setSelectedFileId(null)
|
||||
}, [])
|
||||
|
||||
@@ -480,8 +480,14 @@ export function Files() {
|
||||
if (justCreatedFileIdRef.current && !isJustCreated) {
|
||||
justCreatedFileIdRef.current = null
|
||||
}
|
||||
setShowPreview(!isJustCreated)
|
||||
}, [selectedFileId])
|
||||
if (isJustCreated) {
|
||||
setPreviewMode('editor')
|
||||
} else {
|
||||
const file = selectedFileId ? files.find((f) => f.id === selectedFileId) : null
|
||||
const canPreview = file ? isPreviewable(file) : false
|
||||
setPreviewMode(canPreview ? 'preview' : 'editor')
|
||||
}
|
||||
}, [selectedFileId, files])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedFile) return
|
||||
@@ -504,10 +510,23 @@ export function Files() {
|
||||
return () => window.removeEventListener('beforeunload', handler)
|
||||
}, [isDirty])
|
||||
|
||||
const handleCyclePreviewMode = useCallback(() => {
|
||||
setPreviewMode((prev) => {
|
||||
if (prev === 'editor') return 'split'
|
||||
if (prev === 'split') return 'preview'
|
||||
return 'editor'
|
||||
})
|
||||
}, [])
|
||||
|
||||
const handleTogglePreview = useCallback(() => {
|
||||
setPreviewMode((prev) => (prev === 'preview' ? 'editor' : 'preview'))
|
||||
}, [])
|
||||
|
||||
const fileActions = useMemo<HeaderAction[]>(() => {
|
||||
if (!selectedFile) return []
|
||||
const canEditText = isTextEditable(selectedFile)
|
||||
const canPreview = isPreviewable(selectedFile)
|
||||
const hasSplitView = canEditText && canPreview
|
||||
|
||||
const saveLabel =
|
||||
saveStatus === 'saving'
|
||||
@@ -518,16 +537,12 @@ export function Files() {
|
||||
? 'Save failed'
|
||||
: 'Save'
|
||||
|
||||
const nextModeLabel =
|
||||
previewMode === 'editor' ? 'Split' : previewMode === 'split' ? 'Preview' : 'Edit'
|
||||
const nextModeIcon =
|
||||
previewMode === 'editor' ? Columns2 : previewMode === 'split' ? Eye : Pencil
|
||||
|
||||
return [
|
||||
...(canPreview
|
||||
? [
|
||||
{
|
||||
label: showPreview ? 'Edit' : 'Preview',
|
||||
icon: showPreview ? Pencil : Eye,
|
||||
onClick: handleTogglePreview,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(canEditText
|
||||
? [
|
||||
{
|
||||
@@ -540,6 +555,23 @@ export function Files() {
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(hasSplitView
|
||||
? [
|
||||
{
|
||||
label: nextModeLabel,
|
||||
icon: nextModeIcon,
|
||||
onClick: handleCyclePreviewMode,
|
||||
},
|
||||
]
|
||||
: canPreview
|
||||
? [
|
||||
{
|
||||
label: previewMode === 'preview' ? 'Edit' : 'Preview',
|
||||
icon: previewMode === 'preview' ? Pencil : Eye,
|
||||
onClick: handleTogglePreview,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
label: 'Download',
|
||||
icon: Download,
|
||||
@@ -554,7 +586,8 @@ export function Files() {
|
||||
}, [
|
||||
selectedFile,
|
||||
saveStatus,
|
||||
showPreview,
|
||||
previewMode,
|
||||
handleCyclePreviewMode,
|
||||
handleTogglePreview,
|
||||
handleSave,
|
||||
isDirty,
|
||||
@@ -580,8 +613,6 @@ export function Files() {
|
||||
}
|
||||
|
||||
if (selectedFile) {
|
||||
const canPreview = isPreviewable(selectedFile)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='flex h-full flex-1 flex-col overflow-hidden bg-[var(--bg)]'>
|
||||
@@ -595,7 +626,7 @@ export function Files() {
|
||||
file={selectedFile}
|
||||
workspaceId={workspaceId}
|
||||
canEdit={userPermissions.canEdit === true}
|
||||
showPreview={showPreview && canPreview}
|
||||
previewMode={previewMode}
|
||||
autoFocus={justCreatedFileIdRef.current === selectedFile.id}
|
||||
onDirtyChange={setIsDirty}
|
||||
onSaveStatusChange={setSaveStatus}
|
||||
|
||||
25
apps/sim/components/emcn/icons/columns2.tsx
Normal file
25
apps/sim/components/emcn/icons/columns2.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import type { SVGProps } from 'react'
|
||||
|
||||
/**
|
||||
* Columns2 icon component - displays two vertical columns in a rounded container
|
||||
* @param props - SVG properties including className, fill, etc.
|
||||
*/
|
||||
export function Columns2(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
width='24'
|
||||
height='24'
|
||||
viewBox='-1 -2 24 24'
|
||||
fill='none'
|
||||
stroke='currentColor'
|
||||
strokeWidth='1.75'
|
||||
strokeLinecap='round'
|
||||
strokeLinejoin='round'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
{...props}
|
||||
>
|
||||
<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' />
|
||||
<path d='M10.25 0.75V18.75' />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -15,6 +15,7 @@ export { Card } from './card'
|
||||
export { Check } from './check'
|
||||
export { ChevronDown } from './chevron-down'
|
||||
export { ClipboardList } from './clipboard-list'
|
||||
export { Columns2 } from './columns2'
|
||||
export { Columns3 } from './columns3'
|
||||
export { Connections } from './connections'
|
||||
export { Copy } from './copy'
|
||||
|
||||
Reference in New Issue
Block a user