feat: card layout reorder, description/issue text-2xl, 관리현황 fixed bottom area
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -229,41 +229,57 @@ export function DepartmentColumn({ title: initialTitle, titleEn, subtitle: initi
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 업무 카드 목록 */}
|
||||
{/* 프로젝트 카드 목록 (스크롤 영역) */}
|
||||
<div
|
||||
className="flex-1 overflow-y-auto p-4 min-h-0"
|
||||
onContextMenu={handleListContextMenu}
|
||||
>
|
||||
{orderedTasks.length === 0 ? (
|
||||
<div className="flex items-center justify-center h-40 text-2xl text-gray-300">
|
||||
해당 업무 없음
|
||||
</div>
|
||||
) : (() => {
|
||||
{(() => {
|
||||
const projectTasks = orderedTasks.filter((t) => t.taskType !== '상시업무');
|
||||
const routineTasks = orderedTasks.filter((t) => t.taskType === '상시업무');
|
||||
return (
|
||||
return projectTasks.length === 0 ? (
|
||||
<div className="flex items-center justify-center h-40 text-2xl text-gray-300">
|
||||
해당 업무 없음
|
||||
</div>
|
||||
) : (
|
||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
||||
<SortableContext items={orderedTasks.map((t) => t.id)} strategy={verticalListSortingStrategy}>
|
||||
<SortableContext items={projectTasks.map((t) => t.id)} strategy={verticalListSortingStrategy}>
|
||||
{projectTasks.map((task) => (
|
||||
<SortableTaskCard key={task.id} task={task} sectionOptions={sectionOptions} onSelect={onSelectTask} />
|
||||
))}
|
||||
{routineTasks.length > 0 && (
|
||||
<>
|
||||
<div className="flex items-center gap-2 my-2">
|
||||
<div className="flex-1 border-t border-dashed border-gray-300" />
|
||||
<span className="text-xs text-gray-400 font-semibold shrink-0">상시업무</span>
|
||||
<div className="flex-1 border-t border-dashed border-gray-300" />
|
||||
</div>
|
||||
{routineTasks.map((task) => (
|
||||
<SortableTaskCard key={task.id} task={task} sectionOptions={sectionOptions} onSelect={onSelectTask} />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
|
||||
{/* 관리현황 고정 영역 (하단 2칸) */}
|
||||
{(() => {
|
||||
const routineTasks = orderedTasks.filter((t) => t.taskType === '상시업무');
|
||||
return (
|
||||
<div className="shrink-0 border-t border-gray-200">
|
||||
<div className="flex items-center gap-2 px-4 py-1.5">
|
||||
<div className="flex-1 border-t border-dashed border-gray-300" />
|
||||
<span className="text-xs text-gray-400 font-bold shrink-0 tracking-wide">관리현황</span>
|
||||
<div className="flex-1 border-t border-dashed border-gray-300" />
|
||||
</div>
|
||||
<div className="px-4 pb-3 h-[200px] overflow-y-auto">
|
||||
{routineTasks.length === 0 ? (
|
||||
<div className="flex items-center justify-center h-full text-base text-gray-300">
|
||||
관리현황 없음
|
||||
</div>
|
||||
) : (
|
||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
||||
<SortableContext items={routineTasks.map((t) => t.id)} strategy={verticalListSortingStrategy}>
|
||||
{routineTasks.map((task) => (
|
||||
<SortableTaskCard key={task.id} task={task} sectionOptions={sectionOptions} onSelect={onSelectTask} />
|
||||
))}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
|
||||
{/* 컨텍스트 메뉴 */}
|
||||
|
||||
@@ -189,15 +189,8 @@ export function TaskCard({
|
||||
</div>
|
||||
|
||||
|
||||
{/* ── description ── */}
|
||||
{task.description && (
|
||||
<div className="mt-1 text-sm text-gray-500 font-medium truncate">
|
||||
{task.description}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── 기간 + 상태 ── */}
|
||||
<div className="mt-1.5 flex items-center gap-2">
|
||||
<div className="mt-1 flex items-center gap-2">
|
||||
<span className="text-sm text-gray-400 font-medium flex-1 truncate">
|
||||
{(task.startDate || task.dueDate)
|
||||
? `${task.startDate ? fmtDate(task.startDate) : '?'} ~ ${task.dueDate ? fmtDate(task.dueDate) : '?'}`
|
||||
@@ -208,10 +201,17 @@ export function TaskCard({
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* ── description ── */}
|
||||
{task.description && (
|
||||
<div className="mt-1.5 text-2xl text-gray-700 truncate">
|
||||
{task.description}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── 이슈 메모 ── */}
|
||||
{task.issueNote && (
|
||||
<div className="mt-1.5 flex gap-2 text-sm font-semibold text-red-600 min-w-0">
|
||||
<span className="shrink-0">▶ 이슈 :</span>
|
||||
<div className="mt-1 flex gap-2 text-2xl text-red-500 min-w-0">
|
||||
<span className="shrink-0">▶</span>
|
||||
<span className="truncate">{task.issueNote}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user