Explorar o código

Improve paywall layout and disable traffic lights while it is shown.

Pin footer links to the bottom with even spacing, add top content inset, and keep window controls visible but non-interactive during the paywall flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 hai 3 semanas
pai
achega
35e6c9ddd4

+ 1 - 1
clone _of_clarus_ai_chat_bot/Utilities/MainHostingView.swift

@@ -8,7 +8,7 @@ private enum TrafficLightHitRegion {
 /// Passes mouse events in the traffic-light region through to the native window controls.
 /// Passes mouse events in the traffic-light region through to the native window controls.
 final class MainHostingView<Content: View>: NSHostingView<Content> {
 final class MainHostingView<Content: View>: NSHostingView<Content> {
     override func hitTest(_ point: NSPoint) -> NSView? {
     override func hitTest(_ point: NSPoint) -> NSView? {
-        if isTrafficLightPoint(point) {
+        if WindowChromeState.allowsTrafficLightInteraction, isTrafficLightPoint(point) {
             return nil
             return nil
         }
         }
         return super.hitTest(point)
         return super.hitTest(point)

+ 5 - 0
clone _of_clarus_ai_chat_bot/Utilities/WindowChromeState.swift

@@ -0,0 +1,5 @@
+import Foundation
+
+enum WindowChromeState {
+    static var allowsTrafficLightInteraction = true
+}

+ 8 - 2
clone _of_clarus_ai_chat_bot/Utilities/WindowConfigurator.swift

@@ -8,10 +8,16 @@ enum WindowConfigurator {
         window.titleVisibility = .hidden
         window.titleVisibility = .hidden
         window.isMovableByWindowBackground = true
         window.isMovableByWindowBackground = true
         window.backgroundColor = NSColor(AppTheme.pageBackground)
         window.backgroundColor = NSColor(AppTheme.pageBackground)
+        setTrafficLightsEnabled(true, on: window)
+    }
+
+    static func setTrafficLightsEnabled(_ isEnabled: Bool, on window: NSWindow) {
+        WindowChromeState.allowsTrafficLightInteraction = isEnabled
 
 
         for buttonType in [NSWindow.ButtonType.closeButton, .miniaturizeButton, .zoomButton] {
         for buttonType in [NSWindow.ButtonType.closeButton, .miniaturizeButton, .zoomButton] {
-            window.standardWindowButton(buttonType)?.isEnabled = true
-            window.standardWindowButton(buttonType)?.isHidden = false
+            guard let button = window.standardWindowButton(buttonType) else { continue }
+            button.isHidden = false
+            button.isEnabled = isEnabled
         }
         }
     }
     }
 }
 }

+ 23 - 0
clone _of_clarus_ai_chat_bot/Utilities/WindowTrafficLightsModifier.swift

@@ -0,0 +1,23 @@
+import AppKit
+import SwiftUI
+
+private struct WindowTrafficLightsAccessor: NSViewRepresentable {
+    let isEnabled: Bool
+
+    func makeNSView(context: Context) -> NSView {
+        NSView()
+    }
+
+    func updateNSView(_ nsView: NSView, context: Context) {
+        DispatchQueue.main.async {
+            guard let window = nsView.window else { return }
+            WindowConfigurator.setTrafficLightsEnabled(isEnabled, on: window)
+        }
+    }
+}
+
+extension View {
+    func windowTrafficLightsInteractive(_ isInteractive: Bool) -> some View {
+        background(WindowTrafficLightsAccessor(isEnabled: isInteractive))
+    }
+}

+ 5 - 2
clone _of_clarus_ai_chat_bot/Views/HomeView.swift

@@ -12,10 +12,13 @@ struct HomeView: View {
 
 
             if viewModel.isPaywallPresented, let paywallViewModel = viewModel.paywallViewModel {
             if viewModel.isPaywallPresented, let paywallViewModel = viewModel.paywallViewModel {
                 PaywallView(viewModel: paywallViewModel)
                 PaywallView(viewModel: paywallViewModel)
-                .transition(.opacity.combined(with: .move(edge: .bottom)))
-                .zIndex(1)
+                    .frame(maxWidth: .infinity, maxHeight: .infinity)
+                    .ignoresSafeArea()
+                    .transition(.opacity.combined(with: .move(edge: .bottom)))
+                    .zIndex(1)
             }
             }
         }
         }
+        .windowTrafficLightsInteractive(!viewModel.isPaywallPresented)
         .animation(.easeInOut(duration: 0.25), value: viewModel.isPaywallPresented)
         .animation(.easeInOut(duration: 0.25), value: viewModel.isPaywallPresented)
         .frame(minWidth: AppTheme.windowMinWidth, minHeight: AppTheme.windowMinHeight)
         .frame(minWidth: AppTheme.windowMinWidth, minHeight: AppTheme.windowMinHeight)
         .frame(maxWidth: .infinity, maxHeight: .infinity)
         .frame(maxWidth: .infinity, maxHeight: .infinity)

+ 17 - 5
clone _of_clarus_ai_chat_bot/Views/PaywallView.swift

@@ -23,14 +23,14 @@ struct PaywallView: View {
                     .padding(.bottom, 20)
                     .padding(.bottom, 20)
 
 
                 ctaSection
                 ctaSection
-                    .padding(.bottom, 16)
-
-                legalLinks
 
 
                 Spacer(minLength: 0)
                 Spacer(minLength: 0)
+
+                legalLinks
             }
             }
             .padding(.horizontal, 48)
             .padding(.horizontal, 48)
-            .padding(.vertical, 28)
+            .padding(.top, 82)
+            .padding(.bottom, 20)
             .frame(maxWidth: 920)
             .frame(maxWidth: 920)
             .frame(maxWidth: .infinity, maxHeight: .infinity)
             .frame(maxWidth: .infinity, maxHeight: .infinity)
         }
         }
@@ -185,22 +185,31 @@ struct PaywallView: View {
     // MARK: - Legal Links
     // MARK: - Legal Links
 
 
     private var legalLinks: some View {
     private var legalLinks: some View {
-        HStack(spacing: 16) {
+        HStack(spacing: 0) {
             PaywallLinkButton(title: "Continue with Free Plan") {
             PaywallLinkButton(title: "Continue with Free Plan") {
                 viewModel.dismiss()
                 viewModel.dismiss()
             }
             }
+            .frame(maxWidth: .infinity)
+
             PaywallLinkButton(title: "Restore Purchase") {
             PaywallLinkButton(title: "Restore Purchase") {
                 viewModel.restorePurchases()
                 viewModel.restorePurchases()
             }
             }
+            .frame(maxWidth: .infinity)
+
             PaywallLinkButton(title: "Privacy Policy") {
             PaywallLinkButton(title: "Privacy Policy") {
                 openURL(AppLinks.privacyPolicy)
                 openURL(AppLinks.privacyPolicy)
             }
             }
+            .frame(maxWidth: .infinity)
+
             PaywallLinkButton(title: "Support") {
             PaywallLinkButton(title: "Support") {
                 openURL(AppLinks.support)
                 openURL(AppLinks.support)
             }
             }
+            .frame(maxWidth: .infinity)
+
             PaywallLinkButton(title: "Terms") {
             PaywallLinkButton(title: "Terms") {
                 openURL(AppLinks.termsOfUse)
                 openURL(AppLinks.termsOfUse)
             }
             }
+            .frame(maxWidth: .infinity)
         }
         }
         .frame(maxWidth: .infinity)
         .frame(maxWidth: .infinity)
     }
     }
@@ -388,6 +397,9 @@ private struct PaywallLinkButton: View {
                 .font(.system(size: 11))
                 .font(.system(size: 11))
                 .foregroundStyle(AppTheme.textSecondary)
                 .foregroundStyle(AppTheme.textSecondary)
                 .underline(false)
                 .underline(false)
+                .multilineTextAlignment(.center)
+                .lineLimit(2)
+                .frame(maxWidth: .infinity)
         }
         }
         .buttonStyle(.plain)
         .buttonStyle(.plain)
         .accessibilityLabel(title)
         .accessibilityLabel(title)