fix: pass tab content via URL params instead of IPC
- Pass content, unsavedContent, isEditing via URL query params - PopoutPage reads directly from URL params on mount - Eliminates IPC race condition entirely - Direct store update with loaded:true to prevent auto-reload
This commit is contained in:
@@ -122,21 +122,12 @@ export const NoteBrowser = () => {
|
|||||||
const tabState = tabs.get(file.path)
|
const tabState = tabs.get(file.path)
|
||||||
if (!tabState) return
|
if (!tabState) return
|
||||||
|
|
||||||
const tabData = {
|
const content = tabState.content || ''
|
||||||
file: file,
|
const unsavedContent = tabState.unsavedContent || content
|
||||||
content: tabState.content,
|
const isEditing = tabState.isEditing
|
||||||
unsavedContent: tabState.unsavedContent,
|
|
||||||
isEditing: tabState.isEditing,
|
|
||||||
loading: tabState.loading,
|
|
||||||
loaded: tabState.loaded,
|
|
||||||
}
|
|
||||||
|
|
||||||
const route = `/popout?path=${encodeURIComponent(file.path)}&name=${encodeURIComponent(file.name)}`
|
const route = `/popout?path=${encodeURIComponent(file.path)}&name=${encodeURIComponent(file.name)}&content=${encodeURIComponent(content)}&unsaved=${encodeURIComponent(unsavedContent)}&editing=${isEditing}`
|
||||||
const result = await window.electronAPI?.createWindow({ route, title: file.name })
|
await window.electronAPI?.createWindow({ route, title: file.name })
|
||||||
|
|
||||||
if (result?.success && result.windowId) {
|
|
||||||
await window.electronAPI?.transferTabData(result.windowId!, tabData)
|
|
||||||
}
|
|
||||||
|
|
||||||
closeFile(file)
|
closeFile(file)
|
||||||
}, [tabs, closeFile])
|
}, [tabs, closeFile])
|
||||||
|
|||||||
@@ -6,39 +6,85 @@ import { MarkdownTabPage } from '@/components/tabs/MarkdownTabPage'
|
|||||||
import { RemoteTabPage } from '@/modules/remote/RemoteTabPage'
|
import { RemoteTabPage } from '@/modules/remote/RemoteTabPage'
|
||||||
import { FileTransferPage } from '@/modules/remote/components/file-transfer/FileTransferPage'
|
import { FileTransferPage } from '@/modules/remote/components/file-transfer/FileTransferPage'
|
||||||
import { Minus, Square, X, Maximize2 } from 'lucide-react'
|
import { Minus, Square, X, Maximize2 } from 'lucide-react'
|
||||||
import { usePopOutTab } from '@/hooks/domain/usePopOutTab'
|
import { useTabStore } from '@/stores'
|
||||||
|
|
||||||
export const PopoutPage = () => {
|
export const PopoutPage = () => {
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
const [file, setFile] = useState<FileItemDTO | null>(null)
|
const [file, setFile] = useState<FileItemDTO | null>(null)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [content, setContent] = useState<string>('')
|
||||||
|
const [unsavedContent, setUnsavedContent] = useState<string>('')
|
||||||
|
const [isEditing, setIsEditing] = useState(false)
|
||||||
const [isMaximized, setIsMaximized] = useState(false)
|
const [isMaximized, setIsMaximized] = useState(false)
|
||||||
|
const [ready, setReady] = useState(false)
|
||||||
|
|
||||||
usePopOutTab()
|
const { selectFile } = useTabStore()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const path = searchParams.get('path')
|
const path = searchParams.get('path')
|
||||||
const name = searchParams.get('name')
|
const name = searchParams.get('name')
|
||||||
|
const contentParam = searchParams.get('content')
|
||||||
|
const unsavedParam = searchParams.get('unsaved')
|
||||||
|
const editingParam = searchParams.get('editing')
|
||||||
|
|
||||||
if (!path || !name) {
|
if (!path || !name) {
|
||||||
setError('Missing path or name parameter')
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const decodedPath = decodeURIComponent(path)
|
||||||
|
const decodedName = decodeURIComponent(name)
|
||||||
|
const decodedContent = contentParam ? decodeURIComponent(contentParam) : ''
|
||||||
|
const decodedUnsaved = unsavedParam ? decodeURIComponent(unsavedParam) : decodedContent
|
||||||
|
const decodedEditing = editingParam === 'true'
|
||||||
|
|
||||||
setFile({
|
setFile({
|
||||||
name: decodeURIComponent(name),
|
name: decodedName,
|
||||||
path: decodeURIComponent(path),
|
path: decodedPath,
|
||||||
type: 'file',
|
type: 'file',
|
||||||
size: 0,
|
size: 0,
|
||||||
modified: new Date().toISOString(),
|
modified: new Date().toISOString(),
|
||||||
})
|
})
|
||||||
|
setContent(decodedContent)
|
||||||
|
setUnsavedContent(decodedUnsaved)
|
||||||
|
setIsEditing(decodedEditing)
|
||||||
|
|
||||||
|
useTabStore.setState((state) => {
|
||||||
|
const newTabs = new Map(state.tabs)
|
||||||
|
newTabs.set(decodedPath, {
|
||||||
|
file: {
|
||||||
|
name: decodedName,
|
||||||
|
path: decodedPath,
|
||||||
|
type: 'file' as const,
|
||||||
|
size: 0,
|
||||||
|
modified: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
content: decodedContent,
|
||||||
|
unsavedContent: decodedUnsaved,
|
||||||
|
isEditing: decodedEditing,
|
||||||
|
loading: false,
|
||||||
|
loaded: true,
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
tabs: newTabs,
|
||||||
|
activeTabId: decodedPath,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
selectFile({
|
||||||
|
name: decodedName,
|
||||||
|
path: decodedPath,
|
||||||
|
type: 'file',
|
||||||
|
size: 0,
|
||||||
|
modified: new Date().toISOString(),
|
||||||
|
})
|
||||||
|
|
||||||
|
setReady(true)
|
||||||
|
|
||||||
window.electronAPI?.windowIsMaximized().then((result) => {
|
window.electronAPI?.windowIsMaximized().then((result) => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setIsMaximized(result.isMaximized)
|
setIsMaximized(result.isMaximized)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [searchParams])
|
}, [searchParams, selectFile])
|
||||||
|
|
||||||
const handleMinimize = () => {
|
const handleMinimize = () => {
|
||||||
window.electronAPI?.windowMinimize()
|
window.electronAPI?.windowMinimize()
|
||||||
@@ -55,15 +101,7 @@ export const PopoutPage = () => {
|
|||||||
window.electronAPI?.windowClose()
|
window.electronAPI?.windowClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (!file || !ready) {
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-center h-screen bg-white dark:bg-gray-900">
|
|
||||||
<div className="text-red-500">{error}</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file) {
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-screen bg-white dark:bg-gray-900">
|
<div className="flex items-center justify-center h-screen bg-white dark:bg-gray-900">
|
||||||
<div className="text-gray-500">Loading...</div>
|
<div className="text-gray-500">Loading...</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user