瀏覽代碼

Add light settings page

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 2 月之前
父節點
當前提交
47919fe10b
共有 1 個文件被更改,包括 192 次插入2 次删除
  1. 192 2
      App for Indeed/Views/DashboardView.swift

+ 192 - 2
App for Indeed/Views/DashboardView.swift

@@ -45,6 +45,11 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         static let selectionFillHover = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 0.2)
         static let neutralHoverFill = NSColor(srgbRed: 240 / 255, green: 240 / 255, blue: 240 / 255, alpha: 1)
         static let sidebarRowHoverFill = NSColor(srgbRed: 0, green: 0, blue: 0, alpha: 0.04)
+        static let settingsPageBackground = NSColor(srgbRed: 1, green: 1, blue: 1, alpha: 1)
+        static let settingsGroupBackground = NSColor(srgbRed: 1, green: 1, blue: 1, alpha: 1)
+        static let settingsIconBackground = NSColor(srgbRed: 239 / 255, green: 244 / 255, blue: 252 / 255, alpha: 1)
+        static let settingsDivider = NSColor(srgbRed: 228 / 255, green: 228 / 255, blue: 228 / 255, alpha: 1)
+        static let settingsPrimaryText = NSColor(srgbRed: 45 / 255, green: 45 / 255, blue: 45 / 255, alpha: 1)
     }
 
     /// Multiline `NSTextField` often ignores `alignment` for wrapped runs; explicit paragraph alignment matches the title.
@@ -91,6 +96,8 @@ final class DashboardView: NSView, NSTextFieldDelegate {
     private let savedJobsScrollView = NSScrollView()
     private let savedJobsDocumentView = JobListingsDocumentView()
     private let savedJobsStack = NSStackView()
+    private let settingsPageContainer = NSView()
+    private let themeControl = NSSegmentedControl(labels: ["System", "Light", "Dark"], trackingMode: .selectOne, target: nil, action: nil)
 
     private var currentSidebarItems: [SidebarItem] = []
     private var selectedSidebarIndex: Int = 0
@@ -769,8 +776,10 @@ final class DashboardView: NSView, NSTextFieldDelegate {
 
         nonHomeGenericContainer.translatesAutoresizingMaskIntoConstraints = false
         savedJobsPageContainer.translatesAutoresizingMaskIntoConstraints = false
+        settingsPageContainer.translatesAutoresizingMaskIntoConstraints = false
         nonHomeHost.addSubview(nonHomeGenericContainer)
         nonHomeHost.addSubview(savedJobsPageContainer)
+        nonHomeHost.addSubview(settingsPageContainer)
 
         NSLayoutConstraint.activate([
             nonHomeGenericContainer.leadingAnchor.constraint(equalTo: nonHomeHost.leadingAnchor),
@@ -781,7 +790,12 @@ final class DashboardView: NSView, NSTextFieldDelegate {
             savedJobsPageContainer.leadingAnchor.constraint(equalTo: nonHomeHost.leadingAnchor),
             savedJobsPageContainer.trailingAnchor.constraint(equalTo: nonHomeHost.trailingAnchor),
             savedJobsPageContainer.topAnchor.constraint(equalTo: nonHomeHost.topAnchor),
-            savedJobsPageContainer.bottomAnchor.constraint(equalTo: nonHomeHost.bottomAnchor)
+            savedJobsPageContainer.bottomAnchor.constraint(equalTo: nonHomeHost.bottomAnchor),
+
+            settingsPageContainer.leadingAnchor.constraint(equalTo: nonHomeHost.leadingAnchor),
+            settingsPageContainer.trailingAnchor.constraint(equalTo: nonHomeHost.trailingAnchor),
+            settingsPageContainer.topAnchor.constraint(equalTo: nonHomeHost.topAnchor),
+            settingsPageContainer.bottomAnchor.constraint(equalTo: nonHomeHost.bottomAnchor)
         ])
 
         nonHomeTitleLabel.font = .systemFont(ofSize: 22, weight: .bold)
@@ -872,6 +886,162 @@ final class DashboardView: NSView, NSTextFieldDelegate {
             savedJobsDocumentView.leadingAnchor.constraint(equalTo: savedJobsScrollView.contentView.leadingAnchor),
             savedJobsDocumentView.widthAnchor.constraint(equalTo: savedJobsScrollView.contentView.widthAnchor)
         ])
+
+        configureSettingsPage()
+    }
+
+    private func configureSettingsPage() {
+        settingsPageContainer.wantsLayer = true
+        settingsPageContainer.layer?.backgroundColor = Theme.settingsPageBackground.cgColor
+        settingsPageContainer.isHidden = true
+
+        let contentStack = NSStackView()
+        contentStack.orientation = .vertical
+        contentStack.spacing = 26
+        contentStack.alignment = .leading
+        contentStack.translatesAutoresizingMaskIntoConstraints = false
+
+        let settingsSection = makeSettingsSection(rows: [
+            makeSettingsRow(title: "Share App", systemImage: "square.and.arrow.up", accessory: nil),
+            makeSettingsRow(title: "Theme", systemImage: "circle.lefthalf.filled", accessory: makeThemeControl()),
+            makeSettingsRow(title: "More Apps", systemImage: "square.grid.2x2", accessory: nil)
+        ])
+
+        let aboutTitle = NSTextField(labelWithString: "About")
+        aboutTitle.font = .systemFont(ofSize: 15, weight: .bold)
+        aboutTitle.textColor = Theme.settingsPrimaryText
+        aboutTitle.alignment = .left
+
+        let aboutSection = makeSettingsSection(rows: [
+            makeSettingsRow(title: "Support", systemImage: "questionmark.circle", accessory: nil),
+            makeSettingsRow(title: "Terms of Use", systemImage: "doc.text", accessory: nil),
+            makeSettingsRow(title: "Privacy Policy", systemImage: "shield", accessory: nil)
+        ])
+
+        let aboutStack = NSStackView(views: [aboutTitle, aboutSection])
+        aboutStack.orientation = .vertical
+        aboutStack.spacing = 14
+        aboutStack.alignment = .leading
+        aboutStack.translatesAutoresizingMaskIntoConstraints = false
+
+        contentStack.addArrangedSubview(settingsSection)
+        contentStack.addArrangedSubview(aboutStack)
+        settingsPageContainer.addSubview(contentStack)
+
+        NSLayoutConstraint.activate([
+            contentStack.leadingAnchor.constraint(equalTo: settingsPageContainer.leadingAnchor, constant: 42),
+            contentStack.trailingAnchor.constraint(lessThanOrEqualTo: settingsPageContainer.trailingAnchor, constant: -42),
+            contentStack.topAnchor.constraint(equalTo: settingsPageContainer.topAnchor, constant: 48),
+            settingsSection.widthAnchor.constraint(equalTo: contentStack.widthAnchor),
+            aboutStack.widthAnchor.constraint(equalTo: contentStack.widthAnchor),
+            aboutSection.widthAnchor.constraint(equalTo: aboutStack.widthAnchor),
+            contentStack.widthAnchor.constraint(equalTo: settingsPageContainer.widthAnchor, constant: -84)
+        ])
+    }
+
+    private func makeThemeControl() -> NSSegmentedControl {
+        themeControl.target = self
+        themeControl.action = #selector(didChangeThemeSelection(_:))
+        themeControl.selectedSegment = 0
+        themeControl.segmentStyle = .rounded
+        themeControl.controlSize = .large
+        themeControl.font = .systemFont(ofSize: 13, weight: .semibold)
+        themeControl.translatesAutoresizingMaskIntoConstraints = false
+        themeControl.widthAnchor.constraint(equalToConstant: 204).isActive = true
+        themeControl.heightAnchor.constraint(equalToConstant: 30).isActive = true
+        return themeControl
+    }
+
+    private func makeSettingsSection(rows: [NSView]) -> NSView {
+        let section = NSStackView()
+        section.orientation = .vertical
+        section.spacing = 0
+        section.alignment = .leading
+        section.translatesAutoresizingMaskIntoConstraints = false
+        section.wantsLayer = true
+        section.layer?.backgroundColor = Theme.settingsGroupBackground.cgColor
+        section.layer?.cornerRadius = 14
+        section.layer?.borderWidth = 1
+        section.layer?.borderColor = Theme.border.cgColor
+        section.layer?.masksToBounds = true
+
+        for (index, row) in rows.enumerated() {
+            section.addArrangedSubview(row)
+            row.widthAnchor.constraint(equalTo: section.widthAnchor).isActive = true
+
+            if index < rows.count - 1 {
+                let divider = NSView()
+                divider.translatesAutoresizingMaskIntoConstraints = false
+                divider.wantsLayer = true
+                divider.layer?.backgroundColor = Theme.settingsDivider.cgColor
+                section.addArrangedSubview(divider)
+                NSLayoutConstraint.activate([
+                    divider.heightAnchor.constraint(equalToConstant: 1),
+                    divider.leadingAnchor.constraint(equalTo: section.leadingAnchor),
+                    divider.trailingAnchor.constraint(equalTo: section.trailingAnchor)
+                ])
+            }
+        }
+
+        return section
+    }
+
+    private func makeSettingsRow(title: String, systemImage: String, accessory: NSView?) -> NSView {
+        let row = NSView()
+        row.translatesAutoresizingMaskIntoConstraints = false
+        row.wantsLayer = true
+
+        let iconTile = NSView()
+        iconTile.translatesAutoresizingMaskIntoConstraints = false
+        iconTile.wantsLayer = true
+        iconTile.layer?.backgroundColor = Theme.settingsIconBackground.cgColor
+        iconTile.layer?.cornerRadius = 9
+
+        let icon = NSImageView()
+        icon.translatesAutoresizingMaskIntoConstraints = false
+        icon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 15, weight: .medium)
+        icon.image = NSImage(systemSymbolName: systemImage, accessibilityDescription: title)
+        icon.contentTintColor = Theme.brandBlue
+
+        let titleLabel = NSTextField(labelWithString: title)
+        titleLabel.font = .systemFont(ofSize: 17, weight: .semibold)
+        titleLabel.textColor = Theme.settingsPrimaryText
+        titleLabel.alignment = .left
+
+        let rowStack = NSStackView()
+        rowStack.orientation = .horizontal
+        rowStack.spacing = 16
+        rowStack.alignment = .centerY
+        rowStack.translatesAutoresizingMaskIntoConstraints = false
+
+        let spacer = NSView()
+        spacer.translatesAutoresizingMaskIntoConstraints = false
+        spacer.setContentHuggingPriority(NSLayoutConstraint.Priority(1), for: .horizontal)
+
+        iconTile.addSubview(icon)
+        rowStack.addArrangedSubview(iconTile)
+        rowStack.addArrangedSubview(titleLabel)
+        rowStack.addArrangedSubview(spacer)
+        if let accessory {
+            rowStack.addArrangedSubview(accessory)
+        }
+        row.addSubview(rowStack)
+
+        NSLayoutConstraint.activate([
+            row.heightAnchor.constraint(equalToConstant: 68),
+            iconTile.widthAnchor.constraint(equalToConstant: 38),
+            iconTile.heightAnchor.constraint(equalToConstant: 38),
+            icon.centerXAnchor.constraint(equalTo: iconTile.centerXAnchor),
+            icon.centerYAnchor.constraint(equalTo: iconTile.centerYAnchor),
+            icon.widthAnchor.constraint(equalToConstant: 20),
+            icon.heightAnchor.constraint(equalToConstant: 20),
+            rowStack.leadingAnchor.constraint(equalTo: row.leadingAnchor, constant: 16),
+            rowStack.trailingAnchor.constraint(equalTo: row.trailingAnchor, constant: -16),
+            rowStack.topAnchor.constraint(equalTo: row.topAnchor),
+            rowStack.bottomAnchor.constraint(equalTo: row.bottomAnchor)
+        ])
+
+        return row
     }
 
     private func reloadSavedJobsListings() {
@@ -909,16 +1079,25 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         return currentSidebarItems[index].title == "Home"
     }
 
+    private func isSettingsSidebarIndex(_ index: Int) -> Bool {
+        guard index >= 0, index < currentSidebarItems.count else { return false }
+        return currentSidebarItems[index].title == "Settings"
+    }
+
     private func updateMainContentVisibility() {
         let home = isHomeSidebarIndex(selectedSidebarIndex)
         let savedJobs = isSavedJobsSidebarIndex(selectedSidebarIndex)
+        let settings = isSettingsSidebarIndex(selectedSidebarIndex)
         mainOverlay.isHidden = !home
         nonHomeHost.isHidden = home
-        nonHomeGenericContainer.isHidden = savedJobs
+        nonHomeGenericContainer.isHidden = savedJobs || settings
         savedJobsPageContainer.isHidden = !savedJobs
+        settingsPageContainer.isHidden = !settings
         if !home, selectedSidebarIndex < currentSidebarItems.count {
             if savedJobs {
                 reloadSavedJobsListings()
+            } else if settings {
+                window?.makeFirstResponder(nil)
             } else {
                 nonHomeTitleLabel.stringValue = currentSidebarItems[selectedSidebarIndex].title
             }
@@ -1186,6 +1365,17 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         NSWorkspace.shared.open(url)
     }
 
+    @objc private func didChangeThemeSelection(_ sender: NSSegmentedControl) {
+        switch sender.selectedSegment {
+        case 1:
+            NSApp.appearance = NSAppearance(named: .aqua)
+        case 2:
+            NSApp.appearance = NSAppearance(named: .darkAqua)
+        default:
+            NSApp.appearance = nil
+        }
+    }
+
     private func selectSidebarItem(at index: Int) {
         guard index >= 0, index < currentSidebarItems.count else { return }
         let selectingHome = isHomeSidebarIndex(index)