import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { ResizableHandle, ResizablePanel, ResizablePanelGroup, } from "~/components/ui/resizable"; import Tabs, { Tab } from "~/components/ui/tabs"; import FileViewer from "./file-viewer"; import trpc from "~/lib/trpc"; import EditorContext from "../context/editor"; import type { FileSchema } from "~/server/db/schema/file"; import Panel from "~/components/ui/panel"; import { previewStore } from "../stores/web-preview"; import { useProjectContext } from "../context/project"; import { ImperativePanelHandle } from "react-resizable-panels"; import Sidebar from "./sidebar"; import useCommandKey from "~/hooks/useCommandKey"; import { Button } from "~/components/ui/button"; import { FaCompress, FaCompressArrowsAlt } from "react-icons/fa"; import ConsoleLogger from "./console-logger"; import { useData } from "~/renderer/hooks"; import { Data } from "../+data"; import { useBreakpoint } from "~/hooks/useBreakpoint"; const Editor = () => { const { project, pinnedFiles } = useData(); const trpcUtils = trpc.useUtils(); const projectCtx = useProjectContext(); const sidebarPanel = useRef(null); const [breakpoint] = useBreakpoint(); const [sidebarExpanded, setSidebarExpanded] = useState(false); const [curTabIdx, setCurTabIdx] = useState(0); const [curOpenFiles, setOpenFiles] = useState( pinnedFiles.map((i) => i.id) ); const openedFilesData = trpc.file.getAll.useQuery( { projectId: project.id, id: curOpenFiles }, { enabled: curOpenFiles.length > 0, initialData: pinnedFiles } ); const [openedFiles, setOpenedFiles] = useState(pinnedFiles); const deleteFile = trpc.file.delete.useMutation({ onSuccess: (file) => { trpcUtils.file.getAll.invalidate(); onFileChanged(file); const openFileIdx = curOpenFiles.indexOf(file.id); if (openFileIdx >= 0) { onCloseFile(openFileIdx); } }, }); const toggleSidebar = useCallback(() => { const sidebar = sidebarPanel.current; if (!sidebar) { return; } if (sidebar.isExpanded()) { sidebar.collapse(); } else { sidebar.expand(); sidebar.resize(25); } }, [sidebarPanel]); useCommandKey("b", toggleSidebar); useEffect(() => { if (!pinnedFiles?.length || curOpenFiles.length > 0) { return; } pinnedFiles.forEach((file) => { onOpenFile(file.id, false); }); return () => { setOpenFiles([]); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [pinnedFiles]); useEffect(() => { if (openedFilesData.data) { setOpenedFiles(openedFilesData.data); } }, [openedFilesData.data]); const onOpenFile = useCallback( (fileId: number, autoSwitchTab = true) => { const idx = curOpenFiles.indexOf(fileId); if (idx >= 0) { return setCurTabIdx(idx); } setOpenFiles((state) => { if (autoSwitchTab) { setCurTabIdx(state.length); } return [...state, fileId]; }); }, [curOpenFiles] ); const onDeleteFile = useCallback( (fileId: number) => { if ( window.confirm("Are you sure want to delete this files?") && !deleteFile.isPending ) { deleteFile.mutate(fileId); } }, [deleteFile] ); const onCloseFile = useCallback( (idx: number) => { const _f = [...curOpenFiles]; _f.splice(idx, 1); setOpenFiles(_f); if (curTabIdx === idx) { setCurTabIdx(Math.max(0, idx - 1)); } }, [curOpenFiles, curTabIdx] ); const onFileChanged = useCallback( (_file: Omit) => { openedFilesData.refetch(); }, [openedFilesData] ); const refreshPreview = useCallback(() => { previewStore.getState().refresh(); }, []); const openFileList = useMemo(() => { return curOpenFiles.map((fileId) => { const fileData = openedFiles?.find((i) => i.id === fileId); return { title: fileData?.filename || "...", render: () => ( ), }; }) satisfies Tab[]; }, [curOpenFiles, openedFiles, refreshPreview]); const PanelComponent = !projectCtx.isCompact ? Panel : "div"; return ( setSidebarExpanded(true)} onCollapse={() => setSidebarExpanded(false)} > {breakpoint >= 2 ? ( <> ) : null} ); }; export default Editor;