Bladeren bron

Replace the settings button with a custom outline gear icon for a cleaner header.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 maand geleden
bovenliggende
commit
f5835c62e1

+ 28 - 16
gramora/Views/Components/GradientButton.swift

@@ -77,29 +77,41 @@ struct ToolbarButton: View {
 }
 
 struct IconButton: View {
-    let iconName: String
     let action: () -> Void
+    private let iconName: String?
+    private let customIcon: (() -> AnyView)?
 
     @State private var isHovered = false
 
-    var body: some View {
-        Button(action: action) {
+    init(iconName: String, action: @escaping () -> Void) {
+        self.iconName = iconName
+        self.customIcon = nil
+        self.action = action
+    }
+
+    init<Content: View>(@ViewBuilder icon: @escaping () -> Content, action: @escaping () -> Void) {
+        self.iconName = nil
+        self.customIcon = { AnyView(icon()) }
+        self.action = action
+    }
+
+    @ViewBuilder
+    private var iconContent: some View {
+        if let iconName {
             Image(systemName: iconName)
                 .font(.system(size: 14))
+        } else if let customIcon {
+            customIcon()
+        }
+    }
+
+    var body: some View {
+        Button(action: action) {
+            iconContent
                 .foregroundStyle(isHovered ? AppTheme.toolbarForegroundHover : AppTheme.textSecondary)
-                .frame(width: 36, height: 36)
-                .background(isHovered ? AppTheme.toolbarBackgroundHover : Color.white)
-                .clipShape(RoundedRectangle(cornerRadius: 8))
-                .overlay(
-                    RoundedRectangle(cornerRadius: 8)
-                        .stroke(isHovered ? AppTheme.toolbarBorderHover : AppTheme.border, lineWidth: 1)
-                )
-                .shadow(
-                    color: isHovered ? AppTheme.toolbarShadowHover : AppTheme.toolbarShadow,
-                    radius: isHovered ? 5 : 3,
-                    y: isHovered ? 2 : 1
-                )
-                .scaleEffect(isHovered ? 1.02 : 1.0)
+                .padding(4)
+                .contentShape(Rectangle())
+                .scaleEffect(isHovered ? 1.05 : 1.0)
                 .animation(.easeOut(duration: 0.15), value: isHovered)
         }
         .buttonStyle(.plain)

+ 88 - 0
gramora/Views/Components/SettingsGearIcon.swift

@@ -0,0 +1,88 @@
+import SwiftUI
+
+struct SettingsGearIcon: View {
+    var size: CGFloat = 25
+
+    private var strokeWidth: CGFloat { size / 12 }
+
+    var body: some View {
+        ZStack {
+            SettingsGearOutline()
+                .stroke(
+                    style: StrokeStyle(
+                        lineWidth: strokeWidth,
+                        lineCap: .round,
+                        lineJoin: .round
+                    )
+                )
+
+            SettingsGearCenterHole()
+                .stroke(
+                    style: StrokeStyle(
+                        lineWidth: strokeWidth,
+                        lineCap: .round,
+                        lineJoin: .round
+                    )
+                )
+        }
+        .frame(width: size, height: size)
+        .accessibilityHidden(true)
+    }
+}
+
+private struct SettingsGearOutline: Shape {
+    private let teeth = 8
+    private let outerRadius: CGFloat = 8.75
+    private let innerRadius: CGFloat = 6.15
+    private let center = CGPoint(x: 12, y: 12)
+
+    func path(in rect: CGRect) -> Path {
+        let scale = min(rect.width, rect.height) / 24
+        let origin = CGPoint(
+            x: rect.midX - 12 * scale,
+            y: rect.midY - 12 * scale
+        )
+
+        var path = Path()
+
+        for index in 0..<(teeth * 2) {
+            let angle = (CGFloat(index) / CGFloat(teeth * 2)) * (.pi * 2) - (.pi / 2)
+            let radius = index.isMultiple(of: 2) ? outerRadius : innerRadius
+            let point = CGPoint(
+                x: origin.x + (center.x + cos(angle) * radius) * scale,
+                y: origin.y + (center.y + sin(angle) * radius) * scale
+            )
+
+            if index == 0 {
+                path.move(to: point)
+            } else {
+                path.addLine(to: point)
+            }
+        }
+
+        path.closeSubpath()
+        return path
+    }
+}
+
+private struct SettingsGearCenterHole: Shape {
+    private let holeRadius: CGFloat = 2.65
+
+    func path(in rect: CGRect) -> Path {
+        let scale = min(rect.width, rect.height) / 24
+        let scaledRadius = holeRadius * scale
+        let centerPoint = CGPoint(
+            x: rect.midX,
+            y: rect.midY
+        )
+
+        return Path(
+            ellipseIn: CGRect(
+                x: centerPoint.x - scaledRadius,
+                y: centerPoint.y - scaledRadius,
+                width: scaledRadius * 2,
+                height: scaledRadius * 2
+            )
+        )
+    }
+}

+ 4 - 1
gramora/Views/GrammarCheckerView.swift

@@ -54,7 +54,10 @@ struct GrammarCheckerView: View {
 
             Spacer()
 
-            IconButton(iconName: "gearshape") {}
+            IconButton {
+                SettingsGearIcon()
+            } action: {}
+            .accessibilityLabel("Settings")
         }
     }