Bläddra i källkod

Add theme-colored segmented tab bars across tool pages.

Extract a shared tab bar component so Comment Writer, Post Generator, and Title Optimizer each highlight the selected tab with their page accent color.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 månad sedan
förälder
incheckning
5c4a6e0688

+ 6 - 41
Reddit App/Views/CommentWriterView.swift

@@ -155,48 +155,13 @@ struct CommentWriterView: View {
     // MARK: - Tab Bar
 
     private var tabBar: some View {
-        HStack(spacing: 0) {
-            ForEach(CommentWriterTab.allCases) { tab in
-                Button {
-                    withAnimation(.easeInOut(duration: 0.15)) {
-                        viewModel.selectedTab = tab
-                    }
-                } label: {
-                    HStack(spacing: 4) {
-                        Text(tab.title)
-                            .font(.system(size: 11, weight: .semibold))
-
-                        if tab == .variants, !viewModel.variants.isEmpty {
-                            Text("\(viewModel.variants.count)")
-                                .font(.system(size: 9, weight: .bold))
-                                .foregroundStyle(.white)
-                                .padding(.horizontal, 5)
-                                .padding(.vertical, 2)
-                                .background(AppTheme.accentGreen)
-                                .clipShape(Capsule())
-                        }
-                    }
-                    .foregroundStyle(viewModel.selectedTab == tab ? AppTheme.textPrimary : AppTheme.textSecondary)
-                    .frame(maxWidth: .infinity)
-                    .padding(.vertical, 7)
-                    .background(
-                        viewModel.selectedTab == tab
-                            ? AppTheme.cardBackground
-                            : Color.clear
-                    )
-                    .clipShape(RoundedRectangle(cornerRadius: 7))
-                }
-                .buttonStyle(AppPlainButtonStyle())
-                .hoverOverlay(cornerRadius: 7, isEnabled: viewModel.selectedTab != tab)
+        ToolSegmentedTabBar(
+            selection: $viewModel.selectedTab,
+            accentColor: AppTheme.accentGreen,
+            width: 300,
+            badgeCount: { tab in
+                tab == .variants && !viewModel.variants.isEmpty ? viewModel.variants.count : nil
             }
-        }
-        .padding(3)
-        .frame(width: 300)
-        .background(AppTheme.panelBackground)
-        .clipShape(RoundedRectangle(cornerRadius: 9))
-        .overlay(
-            RoundedRectangle(cornerRadius: 9)
-                .stroke(AppTheme.cardBorder, lineWidth: 1)
         )
     }
 

+ 74 - 0
Reddit App/Views/Components/ToolSegmentedTabBar.swift

@@ -0,0 +1,74 @@
+import SwiftUI
+
+protocol SegmentedTabItem: Hashable, Identifiable, CaseIterable {
+    var title: String { get }
+}
+
+extension CommentWriterTab: SegmentedTabItem {}
+extension PostGeneratorTab: SegmentedTabItem {}
+extension TitleOptimizerTab: SegmentedTabItem {}
+
+struct ToolSegmentedTabBar<Tab: SegmentedTabItem>: View {
+    @Binding var selection: Tab
+    var accentColor: Color
+    var width: CGFloat
+    var badgeCount: ((Tab) -> Int?)?
+
+    private let buttonCornerRadius: CGFloat = 8
+
+    var body: some View {
+        HStack(spacing: 6) {
+            ForEach(Array(Tab.allCases)) { tab in
+                tabButton(for: tab)
+            }
+        }
+        .frame(width: width)
+    }
+
+    private func tabButton(for tab: Tab) -> some View {
+        let isSelected = selection == tab
+
+        return Button {
+            withAnimation(.easeInOut(duration: 0.15)) {
+                selection = tab
+            }
+        } label: {
+            HStack(spacing: 4) {
+                Text(tab.title)
+                    .font(.system(size: 11, weight: isSelected ? .bold : .medium))
+
+                if let count = badgeCount?(tab) {
+                    Text("\(count)")
+                        .font(.system(size: 9, weight: .bold))
+                        .foregroundStyle(.white)
+                        .padding(.horizontal, 5)
+                        .padding(.vertical, 2)
+                        .background(accentColor)
+                        .clipShape(Capsule())
+                }
+            }
+            .foregroundStyle(isSelected ? accentColor : AppTheme.textSecondary)
+            .frame(maxWidth: .infinity)
+            .padding(.vertical, 7)
+            .background(
+                RoundedRectangle(cornerRadius: buttonCornerRadius, style: .continuous)
+                    .fill(isSelected ? accentColor.opacity(0.12) : AppTheme.cardBackground)
+            )
+            .overlay(
+                RoundedRectangle(cornerRadius: buttonCornerRadius, style: .continuous)
+                    .stroke(
+                        isSelected ? accentColor.opacity(0.5) : AppTheme.cardBorder,
+                        lineWidth: isSelected ? 1.5 : 1
+                    )
+            )
+            .shadow(
+                color: accentColor.opacity(isSelected ? 0.15 : 0),
+                radius: 2,
+                y: 1
+            )
+        }
+        .buttonStyle(.plain)
+        .hoverCursor()
+        .hoverOverlay(cornerRadius: buttonCornerRadius, isEnabled: !isSelected)
+    }
+}

+ 4 - 30
Reddit App/Views/PostGeneratorView.swift

@@ -172,36 +172,10 @@ struct PostGeneratorView: View {
     // MARK: - Tab Bar
 
     private var tabBar: some View {
-        HStack(spacing: 0) {
-            ForEach(PostGeneratorTab.allCases) { tab in
-                Button {
-                    withAnimation(.easeInOut(duration: 0.15)) {
-                        viewModel.selectedTab = tab
-                    }
-                } label: {
-                    Text(tab.title)
-                        .font(.system(size: 11, weight: .semibold))
-                        .foregroundStyle(viewModel.selectedTab == tab ? AppTheme.textPrimary : AppTheme.textSecondary)
-                        .frame(maxWidth: .infinity)
-                        .padding(.vertical, 7)
-                        .background(
-                            viewModel.selectedTab == tab
-                                ? AppTheme.cardBackground
-                                : Color.clear
-                        )
-                        .clipShape(RoundedRectangle(cornerRadius: 7))
-                }
-                .buttonStyle(AppPlainButtonStyle())
-                .hoverOverlay(cornerRadius: 7, isEnabled: viewModel.selectedTab != tab)
-            }
-        }
-        .padding(3)
-        .frame(width: 220)
-        .background(AppTheme.panelBackground)
-        .clipShape(RoundedRectangle(cornerRadius: 9))
-        .overlay(
-            RoundedRectangle(cornerRadius: 9)
-                .stroke(AppTheme.cardBorder, lineWidth: 1)
+        ToolSegmentedTabBar(
+            selection: $viewModel.selectedTab,
+            accentColor: AppTheme.accentPurple,
+            width: 220
         )
     }
 

+ 4 - 30
Reddit App/Views/TitleOptimizerView.swift

@@ -140,36 +140,10 @@ struct TitleOptimizerView: View {
     // MARK: - Tab Bar
 
     private var tabBar: some View {
-        HStack(spacing: 0) {
-            ForEach(TitleOptimizerTab.allCases) { tab in
-                Button {
-                    withAnimation(.easeInOut(duration: 0.15)) {
-                        viewModel.selectedTab = tab
-                    }
-                } label: {
-                    Text(tab.title)
-                        .font(.system(size: 11, weight: .semibold))
-                        .foregroundStyle(viewModel.selectedTab == tab ? AppTheme.textPrimary : AppTheme.textSecondary)
-                        .frame(maxWidth: .infinity)
-                        .padding(.vertical, 7)
-                        .background(
-                            viewModel.selectedTab == tab
-                                ? AppTheme.cardBackground
-                                : Color.clear
-                        )
-                        .clipShape(RoundedRectangle(cornerRadius: 7))
-                }
-                .buttonStyle(AppPlainButtonStyle())
-                .hoverOverlay(cornerRadius: 7, isEnabled: viewModel.selectedTab != tab)
-            }
-        }
-        .padding(3)
-        .frame(width: 300)
-        .background(AppTheme.panelBackground)
-        .clipShape(RoundedRectangle(cornerRadius: 9))
-        .overlay(
-            RoundedRectangle(cornerRadius: 9)
-                .stroke(AppTheme.cardBorder, lineWidth: 1)
+        ToolSegmentedTabBar(
+            selection: $viewModel.selectedTab,
+            accentColor: AppTheme.accentBlue,
+            width: 300
         )
     }