Bläddra i källkod

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 15 timmar sedan
förälder
incheckning
c88f4b8ea4
2 ändrade filer med 95 tillägg och 20 borttagningar
  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 264
 // MARK: - Quick Start Card
208 265
 
209 266
 struct QuickStartCardData {

+ 38 - 20
smart_printer/ViewController.swift

@@ -162,7 +162,7 @@ class ViewController: NSViewController {
162 162
         let documentView = FlippedDocumentView()
163 163
         documentView.translatesAutoresizingMaskIntoConstraints = false
164 164
 
165
-        let sectionTitle = makeSectionTitle(title, showGridIcon: true)
165
+        let sectionTitle = makeSectionTitle(title, icon: .grid)
166 166
         let grid = makeFeatureRow(features: features)
167 167
 
168 168
         documentView.addSubview(sectionTitle)
@@ -271,40 +271,58 @@ class ViewController: NSViewController {
271 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 281
         let container = NSView()
276 282
         container.translatesAutoresizingMaskIntoConstraints = false
277 283
 
278 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 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 317
         let label = NSTextField(labelWithString: text)
300
-        label.font = AppTheme.semiboldFont(size: 20)
318
+        label.font = .systemFont(ofSize: 20, weight: .bold)
301 319
         label.textColor = AppTheme.textPrimary
302 320
         label.translatesAutoresizingMaskIntoConstraints = false
303 321
         container.addSubview(label)
304 322
 
305 323
         NSLayoutConstraint.activate([
306 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 326
             label.centerYAnchor.constraint(equalTo: container.centerYAnchor),
309 327
             label.trailingAnchor.constraint(equalTo: container.trailingAnchor),
310 328
         ])
@@ -316,7 +334,7 @@ class ViewController: NSViewController {
316 334
         let section = NSView()
317 335
         section.translatesAutoresizingMaskIntoConstraints = false
318 336
 
319
-        let title = makeSectionTitle("Quick Start")
337
+        let title = makeSectionTitle("Quick Start", icon: .sparkle)
320 338
         section.addSubview(title)
321 339
 
322 340
         let cardsStack = NSStackView()
@@ -375,7 +393,7 @@ class ViewController: NSViewController {
375 393
         let section = NSView()
376 394
         section.translatesAutoresizingMaskIntoConstraints = false
377 395
 
378
-        let title = makeSectionTitle("Create & Print", showGridIcon: true)
396
+        let title = makeSectionTitle("Create & Print", icon: .grid)
379 397
         section.addSubview(title)
380 398
 
381 399
         let features: [FeatureCardData] = [