From 1575f9e6802c9a5598fce9815ac221c4030b154a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=B3=91=EC=B2=A0?= Date: Thu, 22 Jan 2026 22:31:40 +0900 Subject: [PATCH] =?UTF-8?q?feat(WEB):=20=EC=8A=A4=EC=BC=88=EB=A0=88?= =?UTF-8?q?=ED=86=A4=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F?= =?UTF-8?q?=20=EB=8B=AC=EB=A0=A5=20UI=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 스켈레톤 시스템: - 타이틀은 항상 표시, 나머지 영역만 스켈레톤 처리 - 헤더 액션, 검색, 테이블 영역 개별 스켈레톤 적용 달력 UI: - 경계선 색상 border-gray-200으로 통일 - 지난 일자 배경색 bg-gray-300으로 더 어둡게 - 선택/오늘 날짜 색상 보라색으로 변경 (이벤트 바와 구분) - 날짜-이벤트 바 간격 8px 추가 Co-Authored-By: Claude Opus 4.5 --- .../common/ScheduleCalendar/DayCell.tsx | 8 +- .../common/ScheduleCalendar/MonthView.tsx | 10 +- .../common/ScheduleCalendar/ScheduleBar.tsx | 2 +- .../templates/IntegratedListTemplateV2.tsx | 120 ++++++++++-------- src/components/ui/skeleton.tsx | 10 +- 5 files changed, 79 insertions(+), 71 deletions(-) diff --git a/src/components/common/ScheduleCalendar/DayCell.tsx b/src/components/common/ScheduleCalendar/DayCell.tsx index c8aa7d5a..8ab779b9 100644 --- a/src/components/common/ScheduleCalendar/DayCell.tsx +++ b/src/components/common/ScheduleCalendar/DayCell.tsx @@ -52,10 +52,10 @@ export function DayCell({ isWeekend && isCurrentMonth && !isPast && 'text-red-500', // 지난 주말 - 연한 색상 isWeekend && isCurrentMonth && isPast && !isToday && !isSelected && 'text-red-300', - // 오늘 - 굵은 글씨 (외곽선은 부모 셀에 적용) - isToday && !isSelected && 'font-bold text-primary', - // 선택됨 - 배경색 하이라이트 - isSelected && 'bg-primary text-primary-foreground hover:bg-primary' + // 오늘 - 굵은 글씨 (외곽선은 부모 셀에 적용) - 보라색 + isToday && !isSelected && 'font-bold text-purple-600', + // 선택됨 - 배경색 하이라이트 - 보라색 + isSelected && 'bg-purple-500 text-white hover:bg-purple-600' )} > {/* 날짜 숫자 */} diff --git a/src/components/common/ScheduleCalendar/MonthView.tsx b/src/components/common/ScheduleCalendar/MonthView.tsx index fcf2df3d..02a6e06d 100644 --- a/src/components/common/ScheduleCalendar/MonthView.tsx +++ b/src/components/common/ScheduleCalendar/MonthView.tsx @@ -158,11 +158,11 @@ function WeekRow({ // 셀 최소 높이 계산 (이벤트 행 수에 따라) - 더 넉넉하게 확보 const segmentRowIndices = eventSegments.map(s => globalRowAssignments.get(s.event.id) || 0); const maxRowIndex = Math.max(0, ...segmentRowIndices); - const rowHeight = Math.max(120, 40 + Math.min(maxRowIndex + 1, visibleRows) * 28 + 24); + const rowHeight = Math.max(120, 48 + Math.min(maxRowIndex + 1, visibleRows) * 28 + 24); return (
{/* 날짜 셀들 */} @@ -182,15 +182,15 @@ function WeekRow({
onDateClick(date)} diff --git a/src/components/common/ScheduleCalendar/ScheduleBar.tsx b/src/components/common/ScheduleCalendar/ScheduleBar.tsx index 200e227d..de39d527 100644 --- a/src/components/common/ScheduleCalendar/ScheduleBar.tsx +++ b/src/components/common/ScheduleCalendar/ScheduleBar.tsx @@ -76,7 +76,7 @@ export function ScheduleBar({ style={{ width: `calc(${widthPercent}% - 4px)`, left: `calc(${leftPercent}% + 2px)`, - top: `${rowIndex * 24 + 32}px`, // 날짜 영역(32px) 아래부터 시작 + top: `${rowIndex * 24 + 40}px`, // 날짜 영역(40px) 아래부터 시작 (간격 8px 추가) }} > {isStart && {event.title}} diff --git a/src/components/templates/IntegratedListTemplateV2.tsx b/src/components/templates/IntegratedListTemplateV2.tsx index b7b57e69..d6881080 100644 --- a/src/components/templates/IntegratedListTemplateV2.tsx +++ b/src/components/templates/IntegratedListTemplateV2.tsx @@ -483,30 +483,35 @@ export function IntegratedListTemplateV2({ setShowDeleteDialog(false); }; - // 로딩 시 전체 페이지 스켈레톤 표시 - // - isLoading이 true면 전체 스켈레톤 표시 (헤더, 달력, 버튼, 카드, 테이블 모두) - // - 이렇게 하면 "따닥" 현상 없이 매끄러운 로딩 경험 제공 - if (isLoading) { - return ( - - 0} - statsCount={stats?.length || 4} - tableRows={pagination.itemsPerPage || 10} - tableColumns={tableColumns.length || 6} - mobileCards={6} - /> - - ); - } + // 헤더 액션 스켈레톤 (달력 + 프리셋 버튼 + 등록 버튼) + const renderHeaderActionSkeleton = () => ( +
+ {dateRangeSelector?.enabled && ( + <> +
+
+
+
+
+
+
+
+
+
+
+
+
+ + )} + {createButton && ( +
+ )} +
+ ); return ( - {/* 페이지 헤더 */} + {/* 페이지 헤더 - 항상 표시 */} ({ {/* 헤더 액션 (달력, 버튼 등) - 타이틀 아래 배치 */} {/* 레이아웃: [달력 (왼쪽)] -------------- [등록 버튼 (오른쪽 끝)] */} {(dateRangeSelector?.enabled || createButton || headerActions) && ( -
- {/* 날짜 범위 선택기 (왼쪽) */} - {dateRangeSelector?.enabled && ( - - )} - {/* 레거시 헤더 액션 (기존 호환성 유지) */} - {headerActions} - {/* 등록 버튼 (오른쪽 끝) */} - {createButton && ( - - )} -
+ isLoading ? renderHeaderActionSkeleton() : ( +
+ {/* 날짜 범위 선택기 (왼쪽) */} + {dateRangeSelector?.enabled && ( + + )} + {/* 레거시 헤더 액션 (기존 호환성 유지) */} + {headerActions} + {/* 등록 버튼 (오른쪽 끝) */} + {createButton && ( + + )} +
+ ) )} {/* 커스텀 탭 콘텐츠 (헤더 아래, 검색 위) */} @@ -576,13 +583,20 @@ export function IntegratedListTemplateV2({ {!hideSearch && ( - {})} - searchPlaceholder={searchPlaceholder} - filterButton={false} - extraActions={extraFilters} - /> + {isLoading ? ( +
+
+
+
+ ) : ( + {})} + searchPlaceholder={searchPlaceholder} + filterButton={false} + extraActions={extraFilters} + /> + )} )} diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx index ddc6a14e..6cbd8b9b 100644 --- a/src/components/ui/skeleton.tsx +++ b/src/components/ui/skeleton.tsx @@ -403,15 +403,9 @@ function ListPageSkeleton({ }: ListPageSkeletonProps) { return (
- {/* 페이지 헤더 (타이틀 + 설명) */} + {/* 페이지 헤더 (타이틀 + 설명) - 스켈레톤 없이 빈 공간만 */} {showHeader && ( -
-
-
-
-
-
-
+
)} {/* 헤더 액션 영역: 날짜 범위 선택기 + 프리셋 버튼 + 등록 버튼 */}