From 35329882f90136e2bec8882d2e8096197036449e Mon Sep 17 00:00:00 2001 From: d-kimsuon Date: Wed, 3 Sep 2025 18:16:08 +0900 Subject: [PATCH] feat: responsive design --- .../[projectId]/components/ProjectPage.tsx | 83 +++++++--- .../components/SessionPageContent.tsx | 50 ++++-- .../AssistantConversationContent.tsx | 6 +- .../conversationList/ConversationList.tsx | 2 +- .../conversationList/UserTextContent.tsx | 4 +- .../sessionSidebar/SessionSidebar.tsx | 149 ++++++++++-------- 6 files changed, 191 insertions(+), 103 deletions(-) diff --git a/src/app/projects/[projectId]/components/ProjectPage.tsx b/src/app/projects/[projectId]/components/ProjectPage.tsx index 796f1cc..3cfa5ac 100644 --- a/src/app/projects/[projectId]/components/ProjectPage.tsx +++ b/src/app/projects/[projectId]/components/ProjectPage.tsx @@ -3,12 +3,14 @@ import { useQueryClient } from "@tanstack/react-query"; import { ArrowLeftIcon, + ChevronDownIcon, FolderIcon, MessageSquareIcon, PlusIcon, + SettingsIcon, } from "lucide-react"; import Link from "next/link"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { SettingsControls } from "@/components/SettingsControls"; import { Button } from "@/components/ui/button"; import { @@ -18,6 +20,11 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible"; import { useConfig } from "../../../hooks/useConfig"; import { projectQueryConfig, useProject } from "../hooks/useProject"; import { firstCommandToTitle } from "../services/firstCommandToTitle"; @@ -29,6 +36,7 @@ export const ProjectPageContent = ({ projectId }: { projectId: string }) => { } = useProject(projectId); const { config } = useConfig(); const queryClient = useQueryClient(); + const [isSettingsOpen, setIsSettingsOpen] = useState(false); // biome-ignore lint/correctness/useExhaustiveDependencies: invalidate when config changed useEffect(() => { @@ -44,48 +52,77 @@ export const ProjectPageContent = ({ projectId }: { projectId: string }) => { }; return ( -
-
+
+
-
-
- -

+
+
+ +

{project.meta.projectPath ?? project.claudeProjectPath}

- - - Start New Chat - - } - /> +
+ + + Start New Chat + New Chat + + } + /> +
-

+

History File: {project.claudeProjectPath ?? "unknown"}

-

+

Conversation Sessions{" "} {sessions.length > 0 ? `(${sessions.length})` : ""}

{/* Filter Controls */} -
- -
+ +
+ + + + +
+ +
+
+
+
{sessions.length === 0 ? ( @@ -117,7 +154,7 @@ export const ProjectPageContent = ({ projectId }: { projectId: string }) => { > - + {session.meta.firstCommand !== null ? firstCommandToTitle(session.meta.firstCommand) : session.id} diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent.tsx index 8fd7b59..dae14d0 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent.tsx @@ -1,7 +1,13 @@ "use client"; import { useMutation } from "@tanstack/react-query"; -import { ArrowLeftIcon, LoaderIcon, PauseIcon, XIcon } from "lucide-react"; +import { + ArrowLeftIcon, + LoaderIcon, + MenuIcon, + PauseIcon, + XIcon, +} from "lucide-react"; import Link from "next/link"; import type { FC } from "react"; import { useEffect, useRef, useState } from "react"; @@ -41,6 +47,7 @@ export const SessionPageContent: FC<{ const [previousConversationLength, setPreviousConversationLength] = useState(0); + const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false); const scrollContainerRef = useRef(null); // 自動スクロール処理 @@ -62,27 +69,44 @@ export const SessionPageContent: FC<{ return (
- +
-
- + + + + +
-

+

{session.meta.firstCommand !== null ? firstCommandToTitle(session.meta.firstCommand) : sessionId} @@ -137,7 +161,7 @@ export const SessionPageContent: FC<{

-
+
= ({ content, getToolResult }) => { if (content.type === "text") { return ( -
+
); @@ -111,7 +111,7 @@ export const AssistantConversationContent: FC<{
{typeof toolResult.content === "string" ? ( -
+                    
                       {toolResult.content}
                     
) : ( @@ -129,7 +129,7 @@ export const AssistantConversationContent: FC<{ return (
                             {item.text}
                           
diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/ConversationList.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/ConversationList.tsx index c45ff53..5b870ac 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/ConversationList.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/ConversationList.tsx @@ -66,7 +66,7 @@ export const ConversationList: FC = ({ }`} key={getConversationKey(conversation)} > -
{elm}
+
{elm}
, ]; })} diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserTextContent.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserTextContent.tsx index 1396322..2364330 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserTextContent.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserTextContent.tsx @@ -78,7 +78,9 @@ export const UserTextContent: FC<{ text: string; id?: string }> = ({
-
{parsed.stdout}
+
+            {parsed.stdout}
+          
); diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/sessionSidebar/SessionSidebar.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/sessionSidebar/SessionSidebar.tsx index 35e6c7c..f6e63e7 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/sessionSidebar/SessionSidebar.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/sessionSidebar/SessionSidebar.tsx @@ -2,6 +2,7 @@ import { ListTodoIcon, MessageSquareIcon, SettingsIcon } from "lucide-react"; import { type FC, useState } from "react"; +import { Dialog, DialogContent } from "@/components/ui/dialog"; import { cn } from "@/lib/utils"; import { useProject } from "../../../../hooks/useProject"; import { SessionsTab } from "./SessionsTab"; @@ -12,7 +13,15 @@ export const SessionSidebar: FC<{ currentSessionId: string; projectId: string; className?: string; -}> = ({ currentSessionId, projectId, className }) => { + isMobileOpen?: boolean; + onMobileOpenChange?: (open: boolean) => void; +}> = ({ + currentSessionId, + projectId, + className, + isMobileOpen = false, + onMobileOpenChange, +}) => { const { data: { sessions }, } = useProject(projectId); @@ -51,71 +60,87 @@ export const SessionSidebar: FC<{ } }; - return ( -
-
- {/* Vertical Icon Menu - Always Visible */} -
-
- + const sidebarContent = ( +
+ {/* Vertical Icon Menu - Always Visible */} +
+
+ - + - -
+
- - {/* Content Area - Only shown when expanded */} - {isExpanded && ( -
- {renderContent()} -
- )}
+ + {/* Content Area - Only shown when expanded */} + {isExpanded && ( +
+ {renderContent()} +
+ )}
); + + return ( + <> + {/* Desktop sidebar */} +
+ {sidebarContent} +
+ + {/* Mobile sidebar - rendered in dialog */} +
+ + +
{sidebarContent}
+
+
+
+ + ); };