diff --git a/Harmony/Harmony/Views/MemoryCard/MemoryCardView.swift b/Harmony/Harmony/Views/MemoryCard/MemoryCardView.swift index 7f1859f..6c99e44 100644 --- a/Harmony/Harmony/Views/MemoryCard/MemoryCardView.swift +++ b/Harmony/Harmony/Views/MemoryCard/MemoryCardView.swift @@ -17,24 +17,30 @@ struct MemoryCardView: View { var body: some View { GeometryReader { geometry in + + let isNew = (viewModel.newMemoryCard == card) + VStack(alignment: .leading, spacing: 10) { ZStack(alignment: .topTrailing) { if let url = URL(string: card.image), !card.image.isEmpty { KFImage(url) .resizable() .aspectRatio(contentMode: .fill) - .frame(width: geometry.size.width, height: 120) + .frame( + width: geometry.size.width, + height: isNew ? 180 : 120 + ) .clipped() - .cornerRadius(10, corners: [.topLeft, .topRight]) } else { Rectangle() .fill(Color.gray.opacity(0.2)) - .frame(width: geometry.size.width, height: 120) - .cornerRadius(10, corners: [.topLeft, .topRight]) + .frame( + width: geometry.size.width, + height: isNew ? 180 : 120 + ) } - // "새로운 추억" 캡슐 추가 - if viewModel.newMemoryCard == card { + if isNew { Text("새로운 추억") .font(.system(size: 14, weight: .bold)) .foregroundColor(.white) @@ -42,7 +48,7 @@ struct MemoryCardView: View { .padding(.horizontal, 10) .background(Color.mainGreen) .cornerRadius(15) - .offset(x: -10, y: 10) // 위치 조정 + .offset(x: -10, y: 10) } } @@ -58,15 +64,14 @@ struct MemoryCardView: View { .padding([.horizontal, .bottom]) } .background(Color.white) - .cornerRadius(15) .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 5) .overlay( - RoundedRectangle(cornerRadius: 15) + RoundedRectangle(cornerRadius: 0) .stroke(Color.gray3, lineWidth: 0.5) ) } .padding(.horizontal) - .frame(height: 200) + .frame(height: (viewModel.newMemoryCard == card) ? 260 : 200) .frame(maxHeight: .infinity) .transition(.opacity.combined(with: .scale)) } diff --git a/Harmony/Harmony/Views/MemoryCard/MemoryCardsView.swift b/Harmony/Harmony/Views/MemoryCard/MemoryCardsView.swift index f2c9353..c7e9246 100644 --- a/Harmony/Harmony/Views/MemoryCard/MemoryCardsView.swift +++ b/Harmony/Harmony/Views/MemoryCard/MemoryCardsView.swift @@ -14,11 +14,12 @@ struct MemoryCardsView: View { @State private var isAppeared = false @State private var isContentVisible = false @State private var appearingCardIndex = 0 - + let columns = [ - GridItem(.flexible(), spacing: 20), GridItem(.flexible(), spacing: 20) + GridItem(.flexible(), spacing: 20), + GridItem(.flexible(), spacing: 20) ] - + var body: some View { NavigationStack { ZStack { @@ -28,6 +29,7 @@ struct MemoryCardsView: View { .background(Color.gray1) } else { VStack(spacing: 0) { + // MARK: - 상단 바 요소들 VStack(spacing: 0) { if isSearchBarVisible { HStack { @@ -80,7 +82,8 @@ struct MemoryCardsView: View { .background(Color.white) } } - + + // 정렬 버튼 HStack { Spacer() Button(action: { @@ -102,27 +105,55 @@ struct MemoryCardsView: View { Divider() .background(Color.gray3) - + + // 오류 메시지 if let errorMessage = viewModel.errorMessage { Text(errorMessage) .foregroundColor(.red) .padding() } else { + // MARK: - ScrollView 영역 ScrollView { - LazyVGrid(columns: columns, spacing: 30) { - ForEach(Array(viewModel.filteredMemoryCards.enumerated()), id: \.element.id) { index, card in - NavigationLink(destination: MemoryCardDetailView(memoryCardId: card.id, groupId: card.groupId ?? 1)) { - MemoryCardView(card: card, viewModel: viewModel) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .padding(.horizontal, -15) - .padding(.bottom, -15) - .opacity(index <= appearingCardIndex ? 1 : 0) - .offset(y: index <= appearingCardIndex ? 0 : 100) - .animation(.spring(response: 0.4, dampingFraction: 0.7, blendDuration: 0.2).delay(Double(index) * 0.03), value: appearingCardIndex) + VStack(spacing: 0) { + if let newCard = viewModel.newMemoryCard { + NavigationLink( + destination: MemoryCardDetailView( + memoryCardId: newCard.id, + groupId: newCard.groupId ?? 1 + ) + ) { + MemoryCardView(card: newCard, viewModel: viewModel) + .padding(.top, 20) } } + + LazyVGrid(columns: columns, spacing: 30) { + ForEach(Array(viewModel.filteredMemoryCards.enumerated()), id: \.element.id) { index, card in + if card != viewModel.newMemoryCard { + NavigationLink( + destination: MemoryCardDetailView( + memoryCardId: card.id, + groupId: card.groupId ?? 1 + ) + ) { + MemoryCardView(card: card, viewModel: viewModel) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .padding(.horizontal, -15) + .padding(.bottom, -15) + .opacity(index <= appearingCardIndex ? 1 : 0) + .offset(y: index <= appearingCardIndex ? 0 : 100) + .animation( + .spring(response: 0.4, dampingFraction: 0.7, blendDuration: 0.2) + .delay(Double(index) * 0.03), + value: appearingCardIndex + ) + } + } + } + } + .padding([.horizontal, .top]) + .background(Color.gray1) } - .padding([.horizontal, .top]) .background(Color.gray1) } .background(Color.gray1) @@ -143,10 +174,6 @@ struct MemoryCardsView: View { isContentVisible = true } } - - - - .onChange(of: viewModel.isLoading) { isLoading in if !isLoading { withAnimation(.easeInOut(duration: 0.3)) { @@ -155,9 +182,10 @@ struct MemoryCardsView: View { animateCards() } } - } } + + // MARK: - 카드 애니메이션 private func animateCards() { let totalCards = viewModel.filteredMemoryCards.count for index in 0..