From 489b402bfdbd6e08789c67a2ed37afdab3d66f98 Mon Sep 17 00:00:00 2001 From: nelee Date: Wed, 13 May 2026 17:25:43 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix(layout):=20=ED=97=A4=EB=8D=94=20?= =?UTF-8?q?=EC=98=A4=ED=94=84=EC=85=8B=20=EC=B2=98=EB=A6=AC=EB=A5=BC=20roo?= =?UTF-8?q?t=20layout=EC=9C=BC=EB=A1=9C=20=ED=86=B5=EC=9D=BC=20(#98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - layout.tsx content div에 pt-16 추가로 단일 오프셋 처리 - Container의 py-25를 pb-25 pt-6으로 분리해 상단 중복 제거 - workspace 페이지 로딩/메인 div의 pt-16 제거 Co-Authored-By: Claude Sonnet 4.6 --- src/app/(main)/project/workspace/[id]/page.tsx | 4 ++-- src/app/layout.tsx | 2 +- src/components/shared/Container.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/(main)/project/workspace/[id]/page.tsx b/src/app/(main)/project/workspace/[id]/page.tsx index 73b229d..289dcee 100644 --- a/src/app/(main)/project/workspace/[id]/page.tsx +++ b/src/app/(main)/project/workspace/[id]/page.tsx @@ -302,7 +302,7 @@ export default function ProjectPage() { if (tasksLoading) { return ( -
+
{[1, 2, 3].map((i) => (
@@ -318,7 +318,7 @@ export default function ProjectPage() { } return ( -
+
{/* 메인 콘텐츠 */} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 25c8711..ad2694b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -36,7 +36,7 @@ export default function RootLayout({
-
{children}
+
{children}
diff --git a/src/components/shared/Container.tsx b/src/components/shared/Container.tsx index 183c6f2..d63da06 100644 --- a/src/components/shared/Container.tsx +++ b/src/components/shared/Container.tsx @@ -9,7 +9,7 @@ export default function Container({ }: ContainerProps) { return (
{children} From b235a901de576aa50682de41c1dd07cffd97bd9e Mon Sep 17 00:00:00 2001 From: nelee Date: Wed, 13 May 2026 17:56:28 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix(ux):=20=EB=A9=94=EB=AA=A8=20=ED=8C=A8?= =?UTF-8?q?=EB=84=90=20=ED=86=A0=EA=B8=80=EC=9D=84=20BottomNavigation?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9B=8C=ED=81=AC=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=ED=97=A4=EB=8D=94=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20(#99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BottomNavigation에서 메모 탭 제거 (캘린더/칸반 뷰 전환만 담당) - KanbanHeader, CalendarHeader에 메모 토글 버튼 추가 - KanbanBoard, CalendarView에 onToggleMemo/showMemoPanel prop 연결 - 뷰 전환 시 메모 패널 강제 닫힘 동작 제거 Co-Authored-By: Claude Sonnet 4.6 --- .../(main)/project/workspace/[id]/page.tsx | 5 ++- .../features/calendarView/CalendarView.tsx | 6 +++ .../components/CalendarHeader.tsx | 8 +++- .../features/kanban/KanbanBoard.tsx | 6 +++ .../kanban/components/KanbanHeader.tsx | 44 +++++++++++++------ src/components/layout/BottomNavigation.tsx | 20 +-------- 6 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/app/(main)/project/workspace/[id]/page.tsx b/src/app/(main)/project/workspace/[id]/page.tsx index 289dcee..399dec8 100644 --- a/src/app/(main)/project/workspace/[id]/page.tsx +++ b/src/app/(main)/project/workspace/[id]/page.tsx @@ -296,7 +296,6 @@ export default function ProjectPage() { router.push("/"); } else { setCurrentView(view); - setShowMemoPanel(false); } }; @@ -330,6 +329,8 @@ export default function ProjectPage() { onCreateTask={handleCreateTask} onUpdateTask={handleUpdateTask} onDeleteTask={handleDeleteTask} + onToggleMemo={()=>{setShowMemoPanel((prev)=>!prev)}} + showMemoPanel={showMemoPanel} onProjectInfoClick={() => { setShowProjectInfoPanel((prev) => !prev); setShowMemoPanel(false); }} project={{ project_id: projectId, @@ -355,6 +356,8 @@ export default function ProjectPage() { onDeleteTask={handleDeleteTask} onSelectTask={() => {}} onTaskCreated={handleRefresh} + onToggleMemo={()=>{setShowMemoPanel((prev)=>!prev)}} + showMemoPanel={showMemoPanel} onProjectInfoClick={() => { setShowProjectInfoPanel((prev) => !prev); setShowMemoPanel(false); }} /> )} diff --git a/src/components/features/calendarView/CalendarView.tsx b/src/components/features/calendarView/CalendarView.tsx index c5329aa..51ecee2 100644 --- a/src/components/features/calendarView/CalendarView.tsx +++ b/src/components/features/calendarView/CalendarView.tsx @@ -45,6 +45,7 @@ interface CalendarViewProps { started_at?: string; ended_at?: string; } | null; + showMemoPanel?: boolean; onCreateTask?: ( taskData: Omit ) => void; @@ -52,6 +53,7 @@ interface CalendarViewProps { onDeleteTask?: (taskId: string) => void; onSelectTask?: (task: Task) => void; onTaskCreated?: () => void; + onToggleMemo?: () => void; onProjectInfoClick?: () => void; } @@ -59,11 +61,13 @@ export default function CalendarView({ tasks = [], boardId, project, + showMemoPanel, onCreateTask, onUpdateTask, onDeleteTask, onSelectTask, onTaskCreated, + onToggleMemo, onProjectInfoClick, }: CalendarViewProps) { // 프로젝트 정보 추출 @@ -296,8 +300,10 @@ export default function CalendarView({ currentDate={currentDate} eventsCount={filteredTasks.length} showHelp={showHelp} + showMemo={showMemoPanel} showFilter={showFilter} onToggleHelp={() => setShowHelp(!showHelp)} + onToggleMemo={onToggleMemo} onToggleFilter={() => setShowFilter(!showFilter)} onProjectInfoClick={onProjectInfoClick} onAddTask={() => { diff --git a/src/components/features/calendarView/components/CalendarHeader.tsx b/src/components/features/calendarView/components/CalendarHeader.tsx index e36a047..dd0a0e2 100644 --- a/src/components/features/calendarView/components/CalendarHeader.tsx +++ b/src/components/features/calendarView/components/CalendarHeader.tsx @@ -13,17 +13,19 @@ import { showToast } from "@/lib/utils/toast"; interface CalendarHeaderProps { projectName: string; - projectStartedAt?: string; - projectEndedAt?: string; currentView: View; currentDate: Date; eventsCount: number; showHelp: boolean; + showMemo?: boolean; showFilter?: boolean; + projectStartedAt?: string; + projectEndedAt?: string; onToggleHelp: () => void; onToggleFilter?: () => void; onAddTask?: () => void; onProjectInfoClick?: () => void; + onToggleMemo?: () => void; } export default function CalendarHeader({ @@ -33,8 +35,10 @@ export default function CalendarHeader({ currentView, currentDate, eventsCount, + showMemo, showHelp, showFilter, + onToggleMemo, onToggleHelp, onToggleFilter, onAddTask, diff --git a/src/components/features/kanban/KanbanBoard.tsx b/src/components/features/kanban/KanbanBoard.tsx index f38260f..ce00baa 100644 --- a/src/components/features/kanban/KanbanBoard.tsx +++ b/src/components/features/kanban/KanbanBoard.tsx @@ -39,6 +39,8 @@ interface KanbanBoardProps { started_at?: string; ended_at?: string; } | null; + showMemoPanel?: boolean; + onToggleMemo?: () => void; onCreateTask?: ( taskData: Omit ) => void; @@ -59,6 +61,8 @@ const KanbanBoard = ({ onSelectTask, onTaskCreated, onProjectInfoClick, + showMemoPanel, + onToggleMemo, }: KanbanBoardProps) => { const projectId = project?.project_id || ""; const projectName = project?.project_name || "이름 없는 프로젝트"; @@ -333,6 +337,7 @@ const KanbanBoard = ({ onToggleFilter={() => setShowFilter(!showFilter)} onToggleHelp={() => setShowHelp(!showHelp)} showHelp={showHelp} + showMemo={showMemoPanel} hasActiveFilter={ filter.priority !== "all" || filter.assignee !== "all" || @@ -340,6 +345,7 @@ const KanbanBoard = ({ } searchQuery={searchQuery} onSearchChange={setSearchQuery} + onToggleMemo={onToggleMemo} tasksCount={tasks.length} project={project} onProjectInfoClick={onProjectInfoClick} diff --git a/src/components/features/kanban/components/KanbanHeader.tsx b/src/components/features/kanban/components/KanbanHeader.tsx index 2f41ac9..7b76861 100644 --- a/src/components/features/kanban/components/KanbanHeader.tsx +++ b/src/components/features/kanban/components/KanbanHeader.tsx @@ -4,39 +4,43 @@ import { useState, useRef, useEffect } from "react"; import { format } from "date-fns"; import { ko } from "date-fns/locale"; import { showToast } from "@/lib/utils/toast"; -import { Info, SlidersHorizontal, HelpCircle, Plus, Search, X } from "lucide-react"; +import { Info, SlidersHorizontal, HelpCircle, Plus, Search, X, StickyNote } from "lucide-react"; interface KanbanHeaderProps { projectName: string; - onAddClick: () => void; - onToggleFilter: () => void; - onToggleHelp: () => void; - showHelp: boolean; - hasActiveFilter?: boolean; - searchQuery?: string; - onSearchChange?: (q: string) => void; - tasksCount: number; project?: { project_id?: string; project_name: string; started_at?: string; ended_at?: string; } | null; + showHelp: boolean; + showMemo?: boolean; + tasksCount: number; + searchQuery?: string; + hasActiveFilter?: boolean; + onAddClick: () => void; + onToggleHelp: () => void; + onToggleMemo?: () => void; + onToggleFilter: () => void; onProjectInfoClick?: () => void; + onSearchChange?: (q: string) => void; } export default function KanbanHeader({ + project, projectName, + showHelp, + showMemo, + tasksCount, + searchQuery = "", + hasActiveFilter = false, onAddClick, onToggleFilter, onToggleHelp, - showHelp, - hasActiveFilter = false, - searchQuery = "", onSearchChange, - tasksCount, - project, onProjectInfoClick, + onToggleMemo, }: KanbanHeaderProps) { const [searchOpen, setSearchOpen] = useState(false); const searchRef = useRef(null); @@ -178,6 +182,18 @@ export default function KanbanHeader({ )} + {onToggleMemo && ( + + )} + + diff --git a/src/components/layout/BottomNavigation.tsx b/src/components/layout/BottomNavigation.tsx index 7f7ba4d..3ac4739 100644 --- a/src/components/layout/BottomNavigation.tsx +++ b/src/components/layout/BottomNavigation.tsx @@ -52,25 +52,7 @@ const BottomNavigation = ({ ), }, - { - id: "memo" as NavItem, - label: "메모", - icon: ( - - - - ), - }, + ]; return ( From d0784ab0e44dc41f69bcea2e772a211e850cf2c0 Mon Sep 17 00:00:00 2001 From: nelee Date: Wed, 13 May 2026 18:52:08 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix(ux):=20ProjectCard=20=EC=88=98=EC=A0=95?= =?UTF-8?q?/=EC=82=AD=EC=A0=9C=20=EB=B2=84=ED=8A=BC=EC=9D=84=20=ED=95=AD?= =?UTF-8?q?=EC=83=81=20=ED=91=9C=EC=8B=9C=EB=90=98=EB=8A=94=20=EB=A9=94?= =?UTF-8?q?=EB=89=B4=EB=A1=9C=20=EA=B5=90=EC=B2=B4=20(#100)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - opacity-0 group-hover 방식 제거 → 터치 기기 접근 불가 문제 해결 - 우상단 ⋮ 버튼 추가, 클릭 시 수정/삭제 드롭다운 표시 - 외부 클릭 시 메뉴 닫힘 처리 Co-Authored-By: Claude Sonnet 4.6 --- src/features/project/ui/ProjectCard.tsx | 59 ++++++++++++++++++------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/src/features/project/ui/ProjectCard.tsx b/src/features/project/ui/ProjectCard.tsx index c865707..95a0e71 100644 --- a/src/features/project/ui/ProjectCard.tsx +++ b/src/features/project/ui/ProjectCard.tsx @@ -1,5 +1,7 @@ "use client"; +import { useState } from "react"; + import { Icon } from "@/components/shared/Icon"; import { DeleteDialog } from "./DeleteDialog"; import { deleteProject, deleteProjectMember } from "../model"; @@ -8,7 +10,7 @@ import { showToast } from "@/lib/utils/toast"; import { useQueryClient } from "@tanstack/react-query"; import { queryKeys } from "@/lib/constants/queryKeys"; import type { Project, ProjectStatus } from "../model"; -import { Pencil } from "lucide-react"; +import { MoreVertical,Pencil } from "lucide-react"; interface ProjectCardProps { project: Project; @@ -38,6 +40,8 @@ export default function ProjectCard({ project, projectMember }: ProjectCardProps const dot = STATUS_DOT[project.status] ?? STATUS_DOT.active; const deadline = formatDeadline(project.ended_at); + const [isMenuOpen, setIsMenuOpen] = useState(false); + async function handleDelete() { await deleteProject(project.project_id); await deleteProjectMember(project.project_id); @@ -50,6 +54,42 @@ export default function ProjectCard({ project, projectMember }: ProjectCardProps onClick={() => router.push(`/project/workspace/${project.project_id}`)} className="group relative flex flex-col bg-white dark:bg-card rounded-[14px] border border-[#bde3ec] dark:border-border p-6 cursor-pointer transition-all duration-200 hover:shadow-md hover:-translate-y-0.5" > + {/* ⋮ 메뉴 버튼 — 항상 표시 */} +
e.stopPropagation()} +> + + + {isMenuOpen && ( + <> + {/* 외부 클릭 시 닫기 */} +
setIsMenuOpen(false)} + /> +
+ +
+ { setIsMenuOpen(false); handleDelete(); }} /> +
+
+ + )} +
+ {/* 타입 라벨 */}
@@ -66,7 +106,7 @@ export default function ProjectCard({ project, projectMember }: ProjectCardProps

- {/* 마감일 + 멤버 수 + 호버 액션 */} + {/* 마감일 + 멤버 수 */}
{deadline ?? "마감일 없음"} @@ -77,20 +117,7 @@ export default function ProjectCard({ project, projectMember }: ProjectCardProps {memberCount}명 -
e.stopPropagation()} - > - -
- -
-
+
From af3043a615590a94cf9548675795d55b17c26d34 Mon Sep 17 00:00:00 2001 From: nelee Date: Wed, 13 May 2026 20:57:10 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix(ux):=20MemoView=20=ED=97=A4=EB=8D=94?= =?UTF-8?q?=EC=97=90=20=EB=8B=AB=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - onClose prop 추가 및 헤더 내 X 버튼 렌더링 - workspace에서 onClose={() => setShowMemoPanel(false)} 전달 Co-Authored-By: Claude Sonnet 4.6 --- src/app/(main)/project/workspace/[id]/page.tsx | 2 +- src/components/features/kanban/MemoView.tsx | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/app/(main)/project/workspace/[id]/page.tsx b/src/app/(main)/project/workspace/[id]/page.tsx index 399dec8..9992c24 100644 --- a/src/app/(main)/project/workspace/[id]/page.tsx +++ b/src/app/(main)/project/workspace/[id]/page.tsx @@ -390,7 +390,7 @@ export default function ProjectPage() { : "w-0 opacity-0" }`} > - + setShowMemoPanel(false)} />
diff --git a/src/components/features/kanban/MemoView.tsx b/src/components/features/kanban/MemoView.tsx index 4983199..c8301b5 100644 --- a/src/components/features/kanban/MemoView.tsx +++ b/src/components/features/kanban/MemoView.tsx @@ -53,9 +53,10 @@ type SortType = "newest" | "oldest"; interface MemoFormProps { projectId: string; + onClose?: () => void; } -const MemoView = ({ projectId }: MemoFormProps) => { +const MemoView = ({ projectId, onClose }: MemoFormProps) => { // === 기본 상태 관리 === const [memos, setMemos] = useState([]); // 서버에서 받은 원본 메모 목록 const [newMemo, setNewMemo] = useState(""); // 새 메모 입력 내용 @@ -524,6 +525,16 @@ const MemoView = ({ projectId }: MemoFormProps) => { }`} /> + {onClose && ( + + )}