ToolSegmentedTabBar.swift 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import SwiftUI
  2. protocol SegmentedTabItem: Hashable, Identifiable, CaseIterable {
  3. var title: String { get }
  4. }
  5. extension CommentWriterTab: SegmentedTabItem {}
  6. extension PostGeneratorTab: SegmentedTabItem {}
  7. extension TitleOptimizerTab: SegmentedTabItem {}
  8. struct ToolSegmentedTabBar<Tab: SegmentedTabItem>: View {
  9. @Binding var selection: Tab
  10. var accentColor: Color
  11. var width: CGFloat
  12. var badgeCount: ((Tab) -> Int?)?
  13. private let buttonCornerRadius: CGFloat = 8
  14. var body: some View {
  15. HStack(spacing: 6) {
  16. ForEach(Array(Tab.allCases)) { tab in
  17. tabButton(for: tab)
  18. }
  19. }
  20. .frame(width: width)
  21. }
  22. private func tabButton(for tab: Tab) -> some View {
  23. let isSelected = selection == tab
  24. return Button {
  25. withAnimation(.easeInOut(duration: 0.15)) {
  26. selection = tab
  27. }
  28. } label: {
  29. HStack(spacing: 4) {
  30. Text(tab.title)
  31. .font(.system(size: 11, weight: isSelected ? .bold : .medium))
  32. if let count = badgeCount?(tab) {
  33. Text("\(count)")
  34. .font(.system(size: 9, weight: .bold))
  35. .foregroundStyle(.white)
  36. .padding(.horizontal, 5)
  37. .padding(.vertical, 2)
  38. .background(accentColor)
  39. .clipShape(Capsule())
  40. }
  41. }
  42. .foregroundStyle(isSelected ? accentColor : AppTheme.textSecondary)
  43. .frame(maxWidth: .infinity)
  44. .padding(.vertical, 7)
  45. .background(
  46. RoundedRectangle(cornerRadius: buttonCornerRadius, style: .continuous)
  47. .fill(isSelected ? accentColor.opacity(0.12) : AppTheme.cardBackground)
  48. )
  49. .overlay(
  50. RoundedRectangle(cornerRadius: buttonCornerRadius, style: .continuous)
  51. .stroke(
  52. isSelected ? accentColor.opacity(0.5) : AppTheme.cardBorder,
  53. lineWidth: isSelected ? 1.5 : 1
  54. )
  55. )
  56. .shadow(
  57. color: accentColor.opacity(isSelected ? 0.15 : 0),
  58. radius: 2,
  59. y: 1
  60. )
  61. }
  62. .buttonStyle(.plain)
  63. .hoverCursor()
  64. .hoverOverlay(cornerRadius: buttonCornerRadius, isEnabled: !isSelected)
  65. }
  66. }