import { useCallback, useEffect, useMemo, useState } from "react"; import { ResizableHandle, ResizablePanel, ResizablePanelGroup, } from "~/components/ui/resizable"; import Tabs, { Tab, TabView } 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 { useProjectContext } from "../context/project"; import Sidebar from "./sidebar"; import ConsoleLogger from "./console-logger"; import { useData } from "~/renderer/hooks"; import { Data } from "../+data"; import { useBreakpoint } from "~/hooks/useBreakpoint"; import StatusBar from "./status-bar"; import { FiTerminal } from "react-icons/fi"; import SettingsDialog from "./settings-dialog"; import FileIcon from "~/components/ui/file-icon"; import { api } from "~/lib/api"; import { useMutation } from "@tanstack/react-query"; import { Button } from "~/components/ui/button"; import { FaExternalLinkAlt } from "react-icons/fa"; import { BASE_URL } from "~/lib/consts"; const Editor = () => { const { project, initialFiles } = useData(); const trpcUtils = trpc.useUtils(); const { isEmbed } = useProjectContext(); const [breakpoint] = useBreakpoint(); const [curTabIdx, setCurTabIdx] = useState(0); const [curOpenFiles, setOpenFiles] = useState( initialFiles.map((i) => i.id) ); const openedFilesData = trpc.file.getAll.useQuery( { projectId: project.id!, id: curOpenFiles }, { enabled: curOpenFiles.length > 0, initialData: initialFiles } ); const [openedFiles, setOpenedFiles] = useState(initialFiles); const generateThumbnail = useMutation({ mutationFn: () => { return api(`/thumbnail/${project.slug!}`, { method: "PATCH" }); }, }); 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); } }, }); useEffect(() => { if (!initialFiles?.length || curOpenFiles.length > 0) { return; } initialFiles.forEach((file) => { onOpenFile(file.id, false); }); return () => { setOpenFiles([]); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [initialFiles]); useEffect(() => { if (openedFilesData.data) { setOpenedFiles(openedFilesData.data); } }, [openedFilesData.data]); // useEffect(() => { // // start API sandbox // api(`/sandbox/${project.slug}/start`, { method: "POST" }).catch(() => {}); // }, [project]); useEffect(() => { const itv = setInterval(() => generateThumbnail.mutate(), 60000); const generate = setTimeout(() => generateThumbnail.mutate(), 1000); return () => { clearInterval(itv); clearTimeout(generate); }; }, []); 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 tabs = useMemo(() => { let tabs: Tab[] = []; // opened files tabs = tabs.concat( curOpenFiles.map((fileId) => { const fileData = openedFiles?.find((i) => i.id === fileId); const filename = fileData?.filename || "..."; return { title: filename, icon: , render: () => , }; }) ); // show console tab on mobile if (breakpoint < 2) { tabs.push({ title: "Console", icon: , render: () => , locked: true, }); } // tabs.push({ // title: "API", // icon: , // render: () => , // locked: true, // }); return tabs; }, [curOpenFiles, openedFiles, breakpoint]); const currentTab = Math.min(Math.max(curTabIdx, 0), tabs.length - 1); return (
{breakpoint >= 2 ? ( <> ) : null}
); }; export default Editor;