-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into TNT-205-alarmPage
- Loading branch information
Showing
29 changed files
with
1,257 additions
and
65 deletions.
There are no files selected for viewing
4 changes: 2 additions & 2 deletions
4
...stem/Resources/Assets.xcassets/Icons/icn_clock.imageset/Size=16, Type=clock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
2 changes: 1 addition & 1 deletion
2
...art_empty.imageset/Size=16, Type=star.svg → .../icn_star.imageset/Size=16, Type=star.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 4 additions & 4 deletions
8
...Resources/Assets.xcassets/Icons/icn_star_smile.imageset/Size=24, Type=smile.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions
48
TnT/Projects/DesignSystem/Sources/Components/BottomSheet/AutoSizingBottomSheetModifier.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// | ||
// AutoSizingBottomSheetModifier.swift | ||
// DesignSystem | ||
// | ||
// Created by 박민서 on 2/2/25. | ||
// Copyright © 2025 yapp25thTeamTnT. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
/// 바텀시트의 높이를 자동 조정하는 ViewModifier | ||
/// 내부 컨텐츠의 크기를 측정하여 적절한 높이를 설정합니다 | ||
struct AutoSizingBottomSheetModifier: ViewModifier { | ||
/// 바텀시트 상단의 그래버 표시 | ||
let presentationDragIndicator: Visibility | ||
/// 측정된 컨텐츠의 높이 (초기값 300) | ||
@State private var contentHeight: CGFloat = 300 | ||
|
||
init(presentationDragIndicator: Visibility = .visible) { | ||
self.presentationDragIndicator = presentationDragIndicator | ||
} | ||
|
||
func body(content: Content) -> some View { | ||
content | ||
.background( | ||
GeometryReader { proxy in | ||
Color.clear | ||
.onAppear { | ||
contentHeight = proxy.size.height + 50 | ||
} | ||
.onChange(of: proxy.size.height) { _, newHeight in | ||
contentHeight = newHeight + 50 | ||
} | ||
} | ||
) | ||
.presentationDetents([.height(contentHeight)]) | ||
.presentationDragIndicator(presentationDragIndicator) | ||
} | ||
} | ||
|
||
public extension View { | ||
/// 뷰에 자동 크기 조정 바텀시트를 적용하는 Modifier | ||
/// - Parameter presentationDragIndicator: 바텀시트 상단 Grabber의 가시성 설정 (기본값: .visible) | ||
/// - Returns: 자동 크기 조정 바텀시트가 적용된 뷰 | ||
func autoSizingBottomSheet(presentationDragIndicator: Visibility = .visible) -> some View { | ||
self.modifier(AutoSizingBottomSheetModifier(presentationDragIndicator: presentationDragIndicator)) | ||
} | ||
} |
183 changes: 183 additions & 0 deletions
183
TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarCell.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
// | ||
// TCalendarCell.swift | ||
// DesignSystem | ||
// | ||
// Created by 박민서 on 2/1/25. | ||
// Copyright © 2025 yapp25thTeamTnT. All rights reserved. | ||
// | ||
|
||
import FSCalendar | ||
|
||
/// TCalendar에 사용되는 Cell 입니다 | ||
final class TCalendarCell: FSCalendarCell { | ||
// MARK: Properties | ||
static let identifier: String = "TCalendarCell" | ||
static let cellSize: CGSize = CGSize(width: 51, height: 54) | ||
|
||
/// Cell에 표시되는 날짜 | ||
private var customDate: Date? | ||
/// Cell 이 선택되었는지 표시 | ||
private var isCellSelected: Bool = false | ||
/// Cell 스타일 | ||
private var style: Style = .default | ||
/// Cell에 표시되는 일정 카운트 | ||
private var eventCount: Int = 0 | ||
/// 주간/월간 모드인지 표시 | ||
private var isWeekMode: Bool = false | ||
|
||
// MARK: UI Elements | ||
private let dayLabel: UILabel = UILabel() | ||
private let eventStackView: UIStackView = UIStackView() | ||
private let eventIcon: UIImageView = UIImageView() | ||
private let eventCountLabel: UILabel = UILabel() | ||
private let backgroundContainer: UIView = UIView() | ||
|
||
override init(frame: CGRect) { | ||
super.init(frame: frame) | ||
setupUI() | ||
setUpHierarchy() | ||
setUpConstraint() | ||
} | ||
|
||
required init(coder aDecoder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
private func setupUI() { | ||
backgroundContainer.layer.cornerRadius = 8 | ||
|
||
dayLabel.font = Typography.FontStyle.body2Medium.uiFont | ||
dayLabel.textAlignment = .center | ||
|
||
eventStackView.axis = .horizontal | ||
eventStackView.spacing = 2 | ||
eventStackView.alignment = .center | ||
|
||
eventIcon.image = UIImage(resource: .icnStar).withRenderingMode(.alwaysTemplate) | ||
eventIcon.tintColor = UIColor(.red300) | ||
eventIcon.contentMode = .scaleAspectFit | ||
eventIcon.frame = CGRect(x: 0, y: 0, width: 12, height: 12) | ||
|
||
eventCountLabel.font = Typography.FontStyle.label2Medium.uiFont | ||
eventCountLabel.textColor = UIColor(.neutral400) | ||
} | ||
|
||
private func setUpHierarchy() { | ||
eventStackView.addArrangedSubview(eventIcon) | ||
eventStackView.addArrangedSubview(eventCountLabel) | ||
|
||
contentView.addSubview(backgroundContainer) | ||
contentView.addSubview(dayLabel) | ||
contentView.addSubview(eventStackView) | ||
} | ||
|
||
private func setUpConstraint() { | ||
dayLabel.translatesAutoresizingMaskIntoConstraints = false | ||
eventStackView.translatesAutoresizingMaskIntoConstraints = false | ||
backgroundContainer.translatesAutoresizingMaskIntoConstraints = false | ||
|
||
NSLayoutConstraint.activate([ | ||
dayLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), | ||
dayLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5), | ||
dayLabel.widthAnchor.constraint(equalToConstant: 32), | ||
dayLabel.heightAnchor.constraint(equalToConstant: 32), | ||
|
||
backgroundContainer.centerXAnchor.constraint(equalTo: dayLabel.centerXAnchor), | ||
backgroundContainer.centerYAnchor.constraint(equalTo: dayLabel.centerYAnchor), | ||
backgroundContainer.widthAnchor.constraint(equalTo: dayLabel.widthAnchor), | ||
backgroundContainer.heightAnchor.constraint(equalTo: dayLabel.heightAnchor), | ||
|
||
eventStackView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), | ||
eventStackView.topAnchor.constraint(equalTo: dayLabel.bottomAnchor, constant: 4) | ||
]) | ||
} | ||
|
||
/// 셀 스타일 표시 업데이트 | ||
private func updateAppearance() { | ||
dayLabel.textColor = style.textColor | ||
backgroundContainer.backgroundColor = style.backgroundColor | ||
} | ||
|
||
/// 일정 카운트 표시 업데이트 | ||
private func updateEventDisplay() { | ||
eventCountLabel.text = "\(eventCount)" | ||
let eventExists: Bool = eventCount > 0 | ||
eventStackView.isHidden = !eventExists | ||
let presentCount: Bool = !isWeekMode && eventExists | ||
eventCountLabel.isHidden = !presentCount | ||
} | ||
|
||
override func prepareForReuse() { | ||
super.prepareForReuse() | ||
// 날짜 및 선택 상태 초기화 | ||
customDate = nil | ||
isCellSelected = false | ||
isWeekMode = false | ||
|
||
// 일정 관련 초기화 | ||
eventCount = 0 | ||
eventStackView.isHidden = true | ||
eventCountLabel.text = nil | ||
|
||
// 스타일 초기화 | ||
style = .default | ||
updateAppearance() | ||
updateEventDisplay() | ||
} | ||
} | ||
|
||
extension TCalendarCell { | ||
/// 셀 설정 | ||
func configure( | ||
with date: Date, | ||
isCellSelected: Bool, | ||
eventCount: Int = 0, | ||
isWeekMode: Bool = false | ||
) { | ||
self.customDate = date | ||
self.isCellSelected = isCellSelected | ||
self.eventCount = eventCount | ||
self.isWeekMode = isWeekMode | ||
|
||
// 현재 날짜 및 선택 상태를 반영, Style 설정 | ||
if isCellSelected { | ||
self.style = .selected | ||
} else if Calendar.current.isDateInToday(date) { | ||
self.style = .today | ||
} else { | ||
self.style = .default | ||
} | ||
|
||
dayLabel.text = "\(Calendar.current.component(.day, from: date))" | ||
self.updateAppearance() | ||
self.updateEventDisplay() | ||
} | ||
} | ||
|
||
extension TCalendarCell { | ||
enum Style { | ||
case `default` | ||
case today | ||
case selected | ||
|
||
var textColor: UIColor { | ||
switch self { | ||
case .default, .today: | ||
return UIColor(.neutral600) | ||
case .selected: | ||
return UIColor(.common0) | ||
} | ||
} | ||
|
||
var backgroundColor: UIColor { | ||
switch self { | ||
case .default: | ||
return .clear | ||
case .today: | ||
return UIColor(.neutral200) | ||
case .selected: | ||
return UIColor(.neutral900) | ||
} | ||
} | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarHeader.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// | ||
// TCalendarHeader.swift | ||
// DesignSystem | ||
// | ||
// Created by 박민서 on 2/2/25. | ||
// Copyright © 2025 yapp25thTeamTnT. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
/// TCalendarView의 헤더입니다 | ||
/// 월 이동 로직을 추가합니다 | ||
public struct TCalendarHeader<RightView: View>: View { | ||
|
||
@Binding private var currentPage: Date | ||
private var formatter: (Date) -> String | ||
private var rightView: (() -> RightView)? | ||
|
||
public init( | ||
currentPage: Binding<Date>, | ||
formatter: @escaping (Date) -> String, | ||
rightView: (() -> RightView)? = nil | ||
) { | ||
self._currentPage = currentPage | ||
self.formatter = formatter | ||
self.rightView = rightView | ||
} | ||
|
||
public var body: some View { | ||
HStack(spacing: 0) { | ||
Button(action: { | ||
movePage(-1) | ||
}, label: { | ||
Image(.icnTriangleLeft32px) | ||
.resizable() | ||
.frame(width: 32, height: 32) | ||
}) | ||
|
||
Text("\(formatter(currentPage))") | ||
.typographyStyle(.heading3, with: .neutral900) | ||
|
||
Button(action: { | ||
movePage(1) | ||
}, label: { | ||
Image(.icnTriangleRight32px) | ||
.resizable() | ||
.frame(width: 32, height: 32) | ||
}) | ||
} | ||
.frame(maxWidth: .infinity) | ||
.overlay(alignment: .trailing) { | ||
rightView?() | ||
} | ||
.padding(.vertical, 8) | ||
.padding(.horizontal, 20) | ||
} | ||
|
||
private func movePage(_ direction: Int) { | ||
if let nextPage = Calendar.current.date(byAdding: .month, value: direction, to: currentPage) { | ||
currentPage = nextPage | ||
} | ||
} | ||
} |
Oops, something went wrong.