Explorar o código

Add custom sparkle icon to Quick Start section titles.

Refactor section title icons behind an enum and use bold typography for section headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 hai 13 horas
pai
achega
c88f4b8ea4
Modificáronse 2 ficheiros con 95 adicións e 20 borrados
  1. 57 0
      smart_printer/UIComponents.swift
  2. 38 20
      smart_printer/ViewController.swift

+ 57 - 0
smart_printer/UIComponents.swift

@@ -204,6 +204,63 @@ final class PillButton: NSButton {
204
     }
204
     }
205
 }
205
 }
206
 
206
 
207
+// MARK: - Sparkle Icon
208
+
209
+final class SparkleIconView: NSView {
210
+    var color: NSColor = AppTheme.blue
211
+
212
+    override var isFlipped: Bool { true }
213
+    override var isOpaque: Bool { false }
214
+
215
+    override func draw(_ dirtyRect: NSRect) {
216
+        super.draw(dirtyRect)
217
+        guard let context = NSGraphicsContext.current?.cgContext else { return }
218
+
219
+        let s = min(bounds.width, bounds.height)
220
+        let cx = bounds.midX
221
+        let cy = bounds.midY
222
+
223
+        let tipR = s * 0.34
224
+        let valleyR = s * 0.09
225
+
226
+        let tips = [
227
+            CGPoint(x: cx, y: cy - tipR),
228
+            CGPoint(x: cx + tipR, y: cy),
229
+            CGPoint(x: cx, y: cy + tipR),
230
+            CGPoint(x: cx - tipR, y: cy),
231
+        ]
232
+        let valleys = [
233
+            CGPoint(x: cx + valleyR, y: cy - valleyR),
234
+            CGPoint(x: cx + valleyR, y: cy + valleyR),
235
+            CGPoint(x: cx - valleyR, y: cy + valleyR),
236
+            CGPoint(x: cx - valleyR, y: cy - valleyR),
237
+        ]
238
+
239
+        let starPath = CGMutablePath()
240
+        starPath.move(to: tips[0])
241
+        for i in 0..<4 {
242
+            starPath.addQuadCurve(to: tips[(i + 1) % 4], control: valleys[i])
243
+        }
244
+        starPath.closeSubpath()
245
+
246
+        context.setFillColor(color.cgColor)
247
+        context.addPath(starPath)
248
+        context.fillPath()
249
+
250
+        let dotR = s * 0.052
251
+        let dotOffset = s * 0.30
252
+        let dotPositions = [
253
+            CGPoint(x: cx + dotOffset, y: cy - dotOffset),
254
+            CGPoint(x: cx + dotOffset, y: cy + dotOffset),
255
+            CGPoint(x: cx - dotOffset, y: cy + dotOffset),
256
+            CGPoint(x: cx - dotOffset, y: cy - dotOffset),
257
+        ]
258
+        for pos in dotPositions {
259
+            context.fillEllipse(in: CGRect(x: pos.x - dotR, y: pos.y - dotR, width: dotR * 2, height: dotR * 2))
260
+        }
261
+    }
262
+}
263
+
207
 // MARK: - Quick Start Card
264
 // MARK: - Quick Start Card
208
 
265
 
209
 struct QuickStartCardData {
266
 struct QuickStartCardData {

+ 38 - 20
smart_printer/ViewController.swift

@@ -162,7 +162,7 @@ class ViewController: NSViewController {
162
         let documentView = FlippedDocumentView()
162
         let documentView = FlippedDocumentView()
163
         documentView.translatesAutoresizingMaskIntoConstraints = false
163
         documentView.translatesAutoresizingMaskIntoConstraints = false
164
 
164
 
165
-        let sectionTitle = makeSectionTitle(title, showGridIcon: true)
165
+        let sectionTitle = makeSectionTitle(title, icon: .grid)
166
         let grid = makeFeatureRow(features: features)
166
         let grid = makeFeatureRow(features: features)
167
 
167
 
168
         documentView.addSubview(sectionTitle)
168
         documentView.addSubview(sectionTitle)
@@ -271,40 +271,58 @@ class ViewController: NSViewController {
271
         return scrollView
271
         return scrollView
272
     }
272
     }
273
 
273
 
274
-    private func makeSectionTitle(_ text: String, showGridIcon: Bool = false) -> NSView {
274
+    private enum SectionTitleIcon {
275
+        case none
276
+        case sparkle
277
+        case grid
278
+    }
279
+
280
+    private func makeSectionTitle(_ text: String, icon: SectionTitleIcon = .none) -> NSView {
275
         let container = NSView()
281
         let container = NSView()
276
         container.translatesAutoresizingMaskIntoConstraints = false
282
         container.translatesAutoresizingMaskIntoConstraints = false
277
 
283
 
278
         var leadingAnchor = container.leadingAnchor
284
         var leadingAnchor = container.leadingAnchor
279
-
280
-        if showGridIcon {
281
-            let gridIcon = NSImageView()
282
-            gridIcon.translatesAutoresizingMaskIntoConstraints = false
283
-            if let image = NSImage(systemSymbolName: "square.grid.2x2", accessibilityDescription: nil) {
284
-                let config = NSImage.SymbolConfiguration(pointSize: 16, weight: .medium)
285
-                gridIcon.image = image.withSymbolConfiguration(config)
285
+        var iconSpacing: CGFloat = 0
286
+
287
+        if icon != .none {
288
+            let titleIcon: NSView
289
+            switch icon {
290
+            case .sparkle:
291
+                titleIcon = SparkleIconView()
292
+            case .grid:
293
+                let gridIcon = NSImageView()
294
+                if let image = NSImage(systemSymbolName: "square.grid.2x2", accessibilityDescription: nil) {
295
+                    let config = NSImage.SymbolConfiguration(pointSize: 16, weight: .medium)
296
+                    gridIcon.image = image.withSymbolConfiguration(config)
297
+                }
298
+                gridIcon.contentTintColor = AppTheme.textPrimary
299
+                titleIcon = gridIcon
300
+            case .none:
301
+                titleIcon = NSView()
286
             }
302
             }
287
-            gridIcon.contentTintColor = AppTheme.textPrimary
288
-            container.addSubview(gridIcon)
303
+
304
+            titleIcon.translatesAutoresizingMaskIntoConstraints = false
305
+            container.addSubview(titleIcon)
289
 
306
 
290
             NSLayoutConstraint.activate([
307
             NSLayoutConstraint.activate([
291
-                gridIcon.leadingAnchor.constraint(equalTo: container.leadingAnchor),
292
-                gridIcon.centerYAnchor.constraint(equalTo: container.centerYAnchor),
293
-                gridIcon.widthAnchor.constraint(equalToConstant: 20),
294
-                gridIcon.heightAnchor.constraint(equalToConstant: 20),
308
+                titleIcon.leadingAnchor.constraint(equalTo: container.leadingAnchor),
309
+                titleIcon.centerYAnchor.constraint(equalTo: container.centerYAnchor),
310
+                titleIcon.widthAnchor.constraint(equalToConstant: 24),
311
+                titleIcon.heightAnchor.constraint(equalToConstant: 24),
295
             ])
312
             ])
296
-            leadingAnchor = gridIcon.trailingAnchor
313
+            leadingAnchor = titleIcon.trailingAnchor
314
+            iconSpacing = 8
297
         }
315
         }
298
 
316
 
299
         let label = NSTextField(labelWithString: text)
317
         let label = NSTextField(labelWithString: text)
300
-        label.font = AppTheme.semiboldFont(size: 20)
318
+        label.font = .systemFont(ofSize: 20, weight: .bold)
301
         label.textColor = AppTheme.textPrimary
319
         label.textColor = AppTheme.textPrimary
302
         label.translatesAutoresizingMaskIntoConstraints = false
320
         label.translatesAutoresizingMaskIntoConstraints = false
303
         container.addSubview(label)
321
         container.addSubview(label)
304
 
322
 
305
         NSLayoutConstraint.activate([
323
         NSLayoutConstraint.activate([
306
             container.heightAnchor.constraint(equalToConstant: 28),
324
             container.heightAnchor.constraint(equalToConstant: 28),
307
-            label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: showGridIcon ? 8 : 0),
325
+            label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: iconSpacing),
308
             label.centerYAnchor.constraint(equalTo: container.centerYAnchor),
326
             label.centerYAnchor.constraint(equalTo: container.centerYAnchor),
309
             label.trailingAnchor.constraint(equalTo: container.trailingAnchor),
327
             label.trailingAnchor.constraint(equalTo: container.trailingAnchor),
310
         ])
328
         ])
@@ -316,7 +334,7 @@ class ViewController: NSViewController {
316
         let section = NSView()
334
         let section = NSView()
317
         section.translatesAutoresizingMaskIntoConstraints = false
335
         section.translatesAutoresizingMaskIntoConstraints = false
318
 
336
 
319
-        let title = makeSectionTitle("Quick Start")
337
+        let title = makeSectionTitle("Quick Start", icon: .sparkle)
320
         section.addSubview(title)
338
         section.addSubview(title)
321
 
339
 
322
         let cardsStack = NSStackView()
340
         let cardsStack = NSStackView()
@@ -375,7 +393,7 @@ class ViewController: NSViewController {
375
         let section = NSView()
393
         let section = NSView()
376
         section.translatesAutoresizingMaskIntoConstraints = false
394
         section.translatesAutoresizingMaskIntoConstraints = false
377
 
395
 
378
-        let title = makeSectionTitle("Create & Print", showGridIcon: true)
396
+        let title = makeSectionTitle("Create & Print", icon: .grid)
379
         section.addSubview(title)
397
         section.addSubview(title)
380
 
398
 
381
         let features: [FeatureCardData] = [
399
         let features: [FeatureCardData] = [