diff --git a/frontend/src/app/(main)/chat/layout.tsx b/frontend/src/app/(main)/chat/layout.tsx deleted file mode 100644 index c465337d..00000000 --- a/frontend/src/app/(main)/chat/layout.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import MainLayout from './main-layout'; - -export default function Layout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return {children}; -} diff --git a/frontend/src/app/(main)/chat/page.tsx b/frontend/src/app/(main)/chat/page.tsx deleted file mode 100644 index 1ca9146d..00000000 --- a/frontend/src/app/(main)/chat/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import Home from './Home'; - -export default function Page() { - return ; -} diff --git a/frontend/src/app/(main)/layout.tsx b/frontend/src/app/(main)/layout.tsx deleted file mode 100644 index 71cddd19..00000000 --- a/frontend/src/app/(main)/layout.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Metadata, Viewport } from 'next'; -import React from 'react'; -export const metadata: Metadata = { - title: 'Codefox - The best dev project generator', - description: 'The best dev project generator', -}; - -export const viewport: Viewport = { - width: 'device-width', - initialScale: 1, - maximumScale: 1, - userScalable: false, -}; -export default function HomeLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( -
-
{children}
-
- ); -} diff --git a/frontend/src/app/chat/layout.tsx b/frontend/src/app/chat/layout.tsx new file mode 100644 index 00000000..5fbe73a2 --- /dev/null +++ b/frontend/src/app/chat/layout.tsx @@ -0,0 +1,9 @@ +import ChatLayout from '../../components/chat/chat-layout'; + +export default function Layout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return {children}; +} diff --git a/frontend/src/app/chat/page.tsx b/frontend/src/app/chat/page.tsx new file mode 100644 index 00000000..508a47e6 --- /dev/null +++ b/frontend/src/app/chat/page.tsx @@ -0,0 +1,5 @@ +import Chat from '@/components/chat'; + +export default function Page() { + return ; +} diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 35de5094..59c3d2cd 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,4 +1,4 @@ -import type { Metadata } from 'next'; +import type { Metadata, Viewport } from 'next'; import { Inter } from 'next/font/google'; import './globals.css'; import { BaseProviders } from '@/providers/BaseProvider'; @@ -6,10 +6,16 @@ import { BaseProviders } from '@/providers/BaseProvider'; const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { - title: 'Codefox', + title: 'Codefox - The best dev project generator', description: 'The best dev project generator', }; +export const viewport: Viewport = { + width: 'device-width', + initialScale: 1, + maximumScale: 1, + userScalable: false, +}; export default function RootLayout({ children, }: { @@ -18,7 +24,11 @@ export default function RootLayout({ return ( - {children} + +
+ {children} +
+
); diff --git a/frontend/src/app/(main)/page.tsx b/frontend/src/app/page.tsx similarity index 100% rename from frontend/src/app/(main)/page.tsx rename to frontend/src/app/page.tsx diff --git a/frontend/src/components/chat/chat-bottombar.tsx b/frontend/src/components/chat/chat-bottombar.tsx index 98e26d10..501782d2 100644 --- a/frontend/src/components/chat/chat-bottombar.tsx +++ b/frontend/src/components/chat/chat-bottombar.tsx @@ -1,7 +1,7 @@ 'use client'; import React, { useEffect } from 'react'; -import { ChatProps } from './chat'; +import { ChatProps } from './chat-panel'; import Link from 'next/link'; import { cn } from '@/lib/utils'; import { Button, buttonVariants } from '../ui/button'; diff --git a/frontend/src/components/chat/chat-layout.tsx b/frontend/src/components/chat/chat-layout.tsx new file mode 100644 index 00000000..92e1bb3c --- /dev/null +++ b/frontend/src/components/chat/chat-layout.tsx @@ -0,0 +1,129 @@ +'use client'; +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'; +import { SidebarProvider } from '@/components/ui/sidebar'; +import { ChatSideBar } from '@/components/sidebar'; + +import ProjectModal from '@/components/chat/project-modal'; +import { useQuery } from '@apollo/client'; +import { useChatList } from '@/hooks/useChatList'; +import { GET_USER_PROJECTS } from '@/graphql/request'; +import { useAuthContext } from '@/providers/AuthProvider'; +import { ProjectProvider } from './code-engine/project-context'; + +export default function ChatLayout({ + children, +}: { + children: React.ReactNode; +}) { + const { isAuthorized, isChecking } = useAuthContext(); + const [isModalOpen, setIsModalOpen] = useState(false); + const [isCollapsed, setIsCollapsed] = useState(false); + const [isMobile, setIsMobile] = useState(false); + + const defaultLayout = [25, 75]; // [sidebar, main] + const navCollapsedSize = 5; + + const { refetch } = useQuery(GET_USER_PROJECTS); + const { + chats, + loading, + error, + chatListUpdated, + setChatListUpdated, + refetchChats, + } = useChatList(); + + const router = useRouter(); + + useEffect(() => { + if (isChecking || !isAuthorized) { + router.push('/'); + } + }, [isChecking, isAuthorized, router]); + + useEffect(() => { + document.cookie = `react-resizable-panels:collapsed=${JSON.stringify( + isCollapsed + )}; path=/; max-age=604800`; + }, [isCollapsed]); + + useEffect(() => { + const checkScreenWidth = () => { + setIsMobile(window.innerWidth <= 1023); + }; + checkScreenWidth(); + window.addEventListener('resize', checkScreenWidth); + return () => window.removeEventListener('resize', checkScreenWidth); + }, []); + + if (isChecking) { + return ( +
+ Loading... +
+ ); + } + + if (!isAuthorized) { + return null; + } + + return ( +
+ { + const sidebarSize = sizes[0]; + const isNowCollapsed = sidebarSize < 10; + setIsCollapsed(isNowCollapsed); + + if (isNowCollapsed && sizes.length > 1) { + const newSizes = [navCollapsedSize, 100 - navCollapsedSize]; + document.cookie = `react-resizable-panels:layout=${JSON.stringify( + newSizes + )}; path=/; max-age=604800`; + return newSizes; + } + + document.cookie = `react-resizable-panels:layout=${JSON.stringify( + sizes + )}; path=/; max-age=604800`; + return sizes; + }} + className="h-screen items-stretch w-full" + > + + + setIsModalOpen(false)} + refetchProjects={refetch} + /> + + + + {children} + + + + +
+ ); +} diff --git a/frontend/src/components/chat/chat-list.tsx b/frontend/src/components/chat/chat-list.tsx index fd65ed41..e329cad8 100644 --- a/frontend/src/components/chat/chat-list.tsx +++ b/frontend/src/components/chat/chat-list.tsx @@ -7,7 +7,7 @@ import { Avatar, AvatarFallback, AvatarImage, SmallAvatar } from '../ui/avatar'; import Markdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import CodeDisplayBlock from '../code-display-block'; -import { Message } from '../types'; +import { Message } from '../../const/MessageType'; import { Button } from '../ui/button'; import { Pencil } from 'lucide-react'; import { useAuth } from '@/hooks/useAuth'; diff --git a/frontend/src/components/chat/chat.tsx b/frontend/src/components/chat/chat-panel.tsx similarity index 96% rename from frontend/src/components/chat/chat.tsx rename to frontend/src/components/chat/chat-panel.tsx index ec703de7..6d713513 100644 --- a/frontend/src/components/chat/chat.tsx +++ b/frontend/src/components/chat/chat-panel.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ChatBottombar from './chat-bottombar'; import ChatTopbar from './chat-topbar'; -import { ChatRequestOptions, Message } from '../types'; +import { ChatRequestOptions, Message } from '../../const/MessageType'; import ChatList from './chat-list'; export interface ChatProps { diff --git a/frontend/src/components/code-engine/code-engine.tsx b/frontend/src/components/chat/code-engine/code-engine.tsx similarity index 100% rename from frontend/src/components/code-engine/code-engine.tsx rename to frontend/src/components/chat/code-engine/code-engine.tsx diff --git a/frontend/src/components/code-engine/file-explorer-button.tsx b/frontend/src/components/chat/code-engine/file-explorer-button.tsx similarity index 100% rename from frontend/src/components/code-engine/file-explorer-button.tsx rename to frontend/src/components/chat/code-engine/file-explorer-button.tsx diff --git a/frontend/src/components/code-engine/file-structure.tsx b/frontend/src/components/chat/code-engine/file-structure.tsx similarity index 100% rename from frontend/src/components/code-engine/file-structure.tsx rename to frontend/src/components/chat/code-engine/file-structure.tsx diff --git a/frontend/src/components/code-engine/project-context.tsx b/frontend/src/components/chat/code-engine/project-context.tsx similarity index 100% rename from frontend/src/components/code-engine/project-context.tsx rename to frontend/src/components/chat/code-engine/project-context.tsx index 4e3a7cdb..8f019490 100644 --- a/frontend/src/components/code-engine/project-context.tsx +++ b/frontend/src/components/chat/code-engine/project-context.tsx @@ -8,13 +8,13 @@ import React, { useEffect, } from 'react'; import { useLazyQuery, useMutation, useQuery } from '@apollo/client'; -import { Project } from '../project-modal'; import { useAuth } from '@/hooks/useAuth'; import { CREATE_PROJECT, GET_CHAT_DETAILS, GET_USER_PROJECTS, } from '@/graphql/request'; +import { Project } from '../project-modal'; export interface ProjectContextType { projects: Project[]; diff --git a/frontend/src/components/code-engine/web-view.tsx b/frontend/src/components/chat/code-engine/web-view.tsx similarity index 100% rename from frontend/src/components/code-engine/web-view.tsx rename to frontend/src/components/chat/code-engine/web-view.tsx diff --git a/frontend/src/app/(main)/chat/Home.tsx b/frontend/src/components/chat/index.tsx similarity index 92% rename from frontend/src/app/(main)/chat/Home.tsx rename to frontend/src/components/chat/index.tsx index 2d8b9466..16a12389 100644 --- a/frontend/src/app/(main)/chat/Home.tsx +++ b/frontend/src/components/chat/index.tsx @@ -6,18 +6,18 @@ import { ResizablePanel, ResizableHandle, } from '@/components/ui/resizable'; -import { CodeEngine } from '@/components/code-engine/code-engine'; import { GET_CHAT_HISTORY } from '@/graphql/request'; import { useQuery } from '@apollo/client'; import { toast } from 'sonner'; -import { EventEnum } from '@/components/enum'; -import { useModels } from '../../../hooks/useModels'; -import { useChatList } from '../../../hooks/useChatList'; -import { useChatStream } from '../../../hooks/useChatStream'; +import { EventEnum } from '@/const/EventEnum'; import EditUsernameForm from '@/components/edit-username-form'; -import ChatContent from '@/components/chat/chat'; +import ChatContent from '@/components/chat/chat-panel'; +import { useModels } from '@/hooks/useModels'; +import { useChatList } from '@/hooks/useChatList'; +import { useChatStream } from '@/hooks/useChatStream'; +import { CodeEngine } from './code-engine/code-engine'; -export default function Home() { +export default function Chat() { // Initialize state, refs, and custom hooks const urlParams = new URLSearchParams(window.location.search); const [chatId, setChatId] = useState(''); diff --git a/frontend/src/app/(main)/chat/main-layout.tsx b/frontend/src/components/chat/main-layout.tsx similarity index 95% rename from frontend/src/app/(main)/chat/main-layout.tsx rename to frontend/src/components/chat/main-layout.tsx index 4f4bb701..342fa98e 100644 --- a/frontend/src/app/(main)/chat/main-layout.tsx +++ b/frontend/src/components/chat/main-layout.tsx @@ -5,14 +5,15 @@ import { ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'; import { SidebarProvider } from '@/components/ui/sidebar'; import { ChatSideBar } from '@/components/sidebar'; -import ProjectModal from '@/components/project-modal'; +import ProjectModal from '@/components/chat/project-modal'; import { useQuery } from '@apollo/client'; -import { ProjectProvider } from '@/components/code-engine/project-context'; + import { useChatList } from '@/hooks/useChatList'; import { GET_USER_PROJECTS } from '@/graphql/request'; import { useAuthContext } from '@/providers/AuthProvider'; +import { ProjectProvider } from './code-engine/project-context'; -export default function MainLayout({ +export default function ChatLayout({ children, }: { children: React.ReactNode; diff --git a/frontend/src/components/project-modal.tsx b/frontend/src/components/chat/project-modal.tsx similarity index 100% rename from frontend/src/components/project-modal.tsx rename to frontend/src/components/chat/project-modal.tsx diff --git a/frontend/src/components/file-sidebar.tsx b/frontend/src/components/file-sidebar.tsx index fe3a1ada..a9d9ada9 100644 --- a/frontend/src/components/file-sidebar.tsx +++ b/frontend/src/components/file-sidebar.tsx @@ -8,7 +8,7 @@ import SidebarSkeleton from './sidebar-skeleton'; import UserSettings from './user-settings'; import { SideBarItem } from './sidebar-item'; import { Chat } from '@/graphql/type'; -import { EventEnum } from './enum'; +import { EventEnum } from '../const/EventEnum'; import { SidebarContent, SidebarGroup, diff --git a/frontend/src/components/sidebar-item.tsx b/frontend/src/components/sidebar-item.tsx index fc2a477c..00ae80fb 100644 --- a/frontend/src/components/sidebar-item.tsx +++ b/frontend/src/components/sidebar-item.tsx @@ -22,7 +22,7 @@ import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { toast } from 'sonner'; -import { EventEnum } from './enum'; +import { EventEnum } from '../const/EventEnum'; interface SideBarItemProps { id: string; diff --git a/frontend/src/components/sidebar.tsx b/frontend/src/components/sidebar.tsx index cc7c1167..5a3b1123 100644 --- a/frontend/src/components/sidebar.tsx +++ b/frontend/src/components/sidebar.tsx @@ -7,7 +7,7 @@ import SidebarSkeleton from './sidebar-skeleton'; import UserSettings from './user-settings'; import { SideBarItem } from './sidebar-item'; import { Chat } from '@/graphql/type'; -import { EventEnum } from './enum'; +import { EventEnum } from '../const/EventEnum'; import { SidebarContent, SidebarGroup, @@ -18,7 +18,7 @@ import { SidebarFooter, } from './ui/sidebar'; import { cn } from '@/lib/utils'; -import { ProjectContext } from './code-engine/project-context'; +import { ProjectContext } from './chat/code-engine/project-context'; interface SidebarProps { setIsModalOpen: (value: boolean) => void; // Parent setter to update collapse state diff --git a/frontend/src/components/user-settings.tsx b/frontend/src/components/user-settings.tsx index f32d6b2e..9553cfa7 100644 --- a/frontend/src/components/user-settings.tsx +++ b/frontend/src/components/user-settings.tsx @@ -18,7 +18,7 @@ import { Button } from '@/components/ui/button'; import { useAuth } from '@/hooks/useAuth'; import { useRouter } from 'next/navigation'; import { useMemo, useState, memo } from 'react'; -import { EventEnum } from './enum'; +import { EventEnum } from '../const/EventEnum'; interface UserSettingsProps { isSimple: boolean; diff --git a/frontend/src/components/enum.ts b/frontend/src/const/EventEnum.ts similarity index 100% rename from frontend/src/components/enum.ts rename to frontend/src/const/EventEnum.ts diff --git a/frontend/src/components/types.ts b/frontend/src/const/MessageType.ts similarity index 100% rename from frontend/src/components/types.ts rename to frontend/src/const/MessageType.ts diff --git a/frontend/src/hooks/useChatStream.ts b/frontend/src/hooks/useChatStream.ts index b7bd3f0a..6273e481 100644 --- a/frontend/src/hooks/useChatStream.ts +++ b/frontend/src/hooks/useChatStream.ts @@ -1,7 +1,7 @@ import { useState, useCallback } from 'react'; import { useMutation, useSubscription } from '@apollo/client'; import { CHAT_STREAM, CREATE_CHAT, TRIGGER_CHAT } from '@/graphql/request'; -import { Message } from '@/components/types'; +import { Message } from '@/const/MessageType'; import { toast } from 'sonner'; import { useRouter } from 'next/navigation'; enum StreamStatus {