// // CVTemplateMiniPreview.swift // App for Indeed // // Realistic mini résumé thumbnails for the template gallery — typography, // spacing, and layout vary by design family so cards read as finished previews. // import Cocoa // MARK: - Palette (shared with gallery card) struct CVTemplateCardPalette { let border: NSColor let borderHover: NSColor let borderSelected: NSColor let selectionGlow: NSColor let footerBackground: NSColor let previewSurface: NSColor let previewPaper: NSColor let previewSidebarTint: NSColor let previewInk: NSColor let previewMuted: NSColor let previewAccentRed: NSColor let previewAccentBlue: NSColor let primaryText: NSColor let secondaryText: NSColor let overlayTint: NSColor } // MARK: - Demo résumé content fileprivate enum CVPreviewDemoContent { static let fullName = "Sarah Johnson" /// Shown in the header / contact band (broad role). static let title = "Senior Product Manager" /// Scoped title under Experience so it is not a verbatim repeat of the header line. static let experienceRole = "Group PM, Consumer Growth & Activation" static let company = "Google" static let companyLine = "Google · Mountain View, CA · 2019 – Present" static let university = "Stanford University" static let degree = "M.S. Management Science & Engineering" static let educationYears = "2014 – 2016" static let email = "sarah.johnson@email.com" static let phone = "(415) 555-0198" static let location = "Mountain View, CA" static let summary = "Product leader shipping roadmap, discovery, and analytics for high-scale consumer experiences." static let bullet1 = "Defined multi-year platform strategy with exec stakeholders and quarterly OKRs." static let bullet2 = "Partnered with engineering and design to launch experiments improving activation by 12%." static let bullet3 = "Stood up quarterly business reviews with finance and GTM, aligning spend to north-star metrics." /// Sidebar “highlights” blurb kept distinct from the experience bullets. static let careerHighlights = "Presented roadmap shifts to the leadership team and translated trade-offs into clear investment asks." /// Single tools line reused wherever the résumé lists a stack (avoids scattered near-duplicate strings). static let toolsLine = "Figma · SQL · Amplitude · Jira · BigQuery" static let skillsList = ["Product Strategy", "SQL", "Figma", "A/B Testing", "Roadmapping"] } // MARK: - Mini preview final class CVTemplatePreviewView: NSView { private let template: CVTemplate private let palette: CVTemplateCardPalette private let paper = NSView() /// Stable 0…11 from template identity so each row looks different (not just by `family`). private var idVariant: Int { var h: UInt64 = 1469598103934665603 let layoutDesc: String switch template.layout { case .singleColumn: layoutDesc = "1col" case .twoColumn(let s, let t): layoutDesc = "2col_\(s)_\(t)" } let blob = "\(template.id)|\(template.family.rawValue)|\(template.headline)|\(template.accent)|\(layoutDesc)|\(template.sectionLabelStyle)" for b in blob.utf8 { h ^= UInt64(b) h &*= 1_099_511_628_211 } return Int(h % 12) } init(template: CVTemplate, palette: CVTemplateCardPalette) { self.template = template self.palette = palette super.init(frame: .zero) wantsLayer = true translatesAutoresizingMaskIntoConstraints = false configurePaper() } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func configurePaper() { paper.translatesAutoresizingMaskIntoConstraints = false paper.wantsLayer = true paper.layer?.backgroundColor = paperBackgroundColor().cgColor paper.layer?.cornerRadius = 6 paper.layer?.borderColor = NSColor(srgbRed: 228 / 255, green: 232 / 255, blue: 240 / 255, alpha: 1).cgColor paper.layer?.borderWidth = 1 paper.layer?.masksToBounds = true addSubview(paper) NSLayoutConstraint.activate([ paper.topAnchor.constraint(equalTo: topAnchor), paper.bottomAnchor.constraint(equalTo: bottomAnchor), paper.centerXAnchor.constraint(equalTo: centerXAnchor), paper.widthAnchor.constraint(equalTo: heightAnchor, multiplier: 0.82), paper.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor), paper.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor) ]) let root = buildResumeRoot() root.translatesAutoresizingMaskIntoConstraints = false paper.addSubview(root) NSLayoutConstraint.activate([ root.leadingAnchor.constraint(equalTo: paper.leadingAnchor, constant: 7), root.trailingAnchor.constraint(equalTo: paper.trailingAnchor, constant: -7), root.topAnchor.constraint(equalTo: paper.topAnchor, constant: 7), root.bottomAnchor.constraint(lessThanOrEqualTo: paper.bottomAnchor, constant: -7) ]) } private func buildResumeRoot() -> NSView { switch template.family { case .professional: return buildProfessionalResume() case .modern: return buildModernResume() case .minimal: return buildMinimalResume() case .executive: return buildExecutiveResume() case .creative: return buildCreativeResume() } } private func paperBackgroundColor() -> NSColor { switch idVariant % 5 { case 0: return palette.previewPaper case 1: return NSColor(srgbRed: 0.995, green: 0.992, blue: 0.985, alpha: 1) case 2: return NSColor(srgbRed: 0.96, green: 0.99, blue: 1, alpha: 1) case 3: return NSColor(srgbRed: 0.99, green: 0.99, blue: 0.99, alpha: 1) default: return NSColor(srgbRed: 0.99, green: 0.98, blue: 0.995, alpha: 1) } } // MARK: - Family: Professional (ATS-friendly) private func buildProfessionalResume() -> NSView { let swapExpFirst = (idVariant % 3) == 1 let showRail = (idVariant % 4) == 0 let sidebarMult: CGFloat = (idVariant % 5 == 2) ? 0.38 : 0.34 switch template.layout { case .singleColumn: let v = NSStackView() v.orientation = .vertical v.spacing = 4 + CGFloat(idVariant % 3) v.alignment = .leading v.addArrangedSubview(proHeaderBlock()) if (idVariant % 6) == 4 { v.addArrangedSubview(proInlineSkillsRow()) } v.addArrangedSubview(hairline()) let main = proMainColumn(compact: false, experienceFirst: swapExpFirst) if showRail { v.addArrangedSubview(horizontalWithLeadingRail(theme: template.themeColor, content: main)) } else { v.addArrangedSubview(main) } return v case .twoColumn(let side, let tinted): let bar = proHeaderBlock() let rule = hairline() let row = NSStackView() row.orientation = .horizontal row.spacing = 5 + CGFloat(idVariant % 3) row.alignment = .top let sidebar = proSidebarColumn(tinted: tinted, variant: idVariant) let main = proMainColumn(compact: true, experienceFirst: swapExpFirst) if side == .leading { row.addArrangedSubview(sidebar) row.addArrangedSubview(main) } else { row.addArrangedSubview(main) row.addArrangedSubview(sidebar) } sidebar.widthAnchor.constraint(equalTo: row.widthAnchor, multiplier: sidebarMult).isActive = true let wrap = NSStackView(views: [bar, rule, row]) wrap.orientation = .vertical wrap.spacing = 5 wrap.alignment = .leading return wrap } } private func horizontalWithLeadingRail(theme: NSColor, content: NSView) -> NSView { let rail = NSView() rail.translatesAutoresizingMaskIntoConstraints = false rail.wantsLayer = true rail.layer?.backgroundColor = theme.cgColor rail.layer?.cornerRadius = 1 rail.widthAnchor.constraint(equalToConstant: 3).isActive = true let row = NSStackView(views: [rail, content]) row.orientation = .horizontal row.spacing = 7 row.alignment = .top return row } private func proInlineSkillsRow() -> NSView { let joined = CVPreviewDemoContent.skillsList.prefix(4).joined(separator: " · ") return makeLabel(joined, font: .systemFont(ofSize: 5.8, weight: .medium), color: template.themeColor, alignment: .left, maxLines: 2) } private func proHeaderBlock() -> NSView { let theme = template.themeColor let ink = palette.previewInk let muted = palette.previewMuted let name = makeLabel(CVPreviewDemoContent.fullName, font: .systemFont(ofSize: 9.5, weight: .semibold), color: ink, alignment: .left, maxLines: 1) let role = makeLabel(CVPreviewDemoContent.title, font: .systemFont(ofSize: 7.4, weight: .regular), color: muted, alignment: .left, maxLines: 1) let contact = makeLabel("\(CVPreviewDemoContent.email) · \(CVPreviewDemoContent.phone)", font: .systemFont(ofSize: 6.2, weight: .regular), color: muted.withAlphaComponent(0.88), alignment: .left, maxLines: 1) let textCol = NSStackView(views: [name, role, contact]) textCol.orientation = .vertical textCol.spacing = 2 textCol.alignment = .leading let row = NSStackView() row.orientation = .horizontal row.spacing = 6 row.alignment = .centerY switch template.headline { case .centered: textCol.alignment = .centerX name.alignment = .center role.alignment = .center contact.alignment = .center let accent = headlineAccent(theme: theme, width: 0.42) let stack = NSStackView(views: [textCol, accent]) stack.orientation = .vertical stack.spacing = 4 stack.alignment = .centerX return stack case .leftAligned: row.addArrangedSubview(textCol) let col = NSStackView(views: [row, headlineAccent(theme: theme, width: 0.38)]) col.orientation = .vertical col.spacing = 4 col.alignment = .leading return col case .leftWithInitials: let avatar = initialsAvatar(diameter: 22, ink: ink) row.addArrangedSubview(textCol) row.addArrangedSubview(NSView()) // spacer row.addArrangedSubview(avatar) let col = NSStackView(views: [row, headlineAccent(theme: theme, width: 0.36)]) col.orientation = .vertical col.spacing = 4 col.alignment = .leading return col case .avatarStacked: let avatar = initialsAvatar(diameter: 24, ink: ink) let stack = NSStackView() stack.orientation = .vertical stack.spacing = 3 stack.alignment = .centerX stack.addArrangedSubview(avatar) textCol.alignment = .centerX name.alignment = .center role.alignment = .center contact.alignment = .center stack.addArrangedSubview(textCol) stack.addArrangedSubview(headlineAccent(theme: theme, width: 0.4)) return stack } } private func proSidebarColumn(tinted: Bool, variant: Int) -> NSView { let box = NSStackView() box.orientation = .vertical box.spacing = 4 + CGFloat(variant % 3) box.alignment = .leading if tinted { box.wantsLayer = true let tint = (variant % 4 == 1) ? template.themeColor.withAlphaComponent(0.08) : palette.previewSidebarTint box.layer?.backgroundColor = tint.cgColor box.layer?.cornerRadius = variant % 3 == 0 ? 5 : 4 } let pad: CGFloat = tinted ? 5 : 0 let inner = NSStackView() inner.edgeInsets = NSEdgeInsets(top: pad, left: pad, bottom: pad, right: pad) inner.orientation = .vertical inner.spacing = 5 inner.alignment = .leading inner.addArrangedSubview(sectionHeading("CONTACT")) inner.addArrangedSubview(makeLabel(CVPreviewDemoContent.email, font: .systemFont(ofSize: 6.2), color: palette.previewInk, alignment: .left, maxLines: 2)) inner.addArrangedSubview(makeLabel(CVPreviewDemoContent.phone, font: .systemFont(ofSize: 6.2), color: palette.previewMuted, alignment: .left, maxLines: 1)) inner.addArrangedSubview(makeLabel(CVPreviewDemoContent.location, font: .systemFont(ofSize: 6.2), color: palette.previewMuted, alignment: .left, maxLines: 1)) inner.addArrangedSubview(sectionHeading("SKILLS")) if variant % 5 == 2 { inner.addArrangedSubview(tagRow(theme: template.themeColor)) } else { for s in CVPreviewDemoContent.skillsList.prefix(4) { inner.addArrangedSubview(skillLineBullet(s)) } } if variant % 7 == 3 { inner.addArrangedSubview(sectionHeading("TOOLS")) inner.addArrangedSubview(makeLabel(CVPreviewDemoContent.toolsLine, font: .systemFont(ofSize: 5.9), color: palette.previewMuted, alignment: .left, maxLines: 1)) } box.addArrangedSubview(inner) return box } private func proMainColumn(compact: Bool, experienceFirst: Bool) -> NSView { let stack = NSStackView() stack.orientation = .vertical stack.spacing = compact ? 4 : 5 + CGFloat(idVariant % 2) stack.alignment = .leading let sp: CGFloat = compact ? 6.2 : 6.5 let profileBlock: () -> Void = { stack.addArrangedSubview(self.sectionHeading("PROFILE")) stack.addArrangedSubview(self.makeLabel(CVPreviewDemoContent.summary, font: .systemFont(ofSize: sp), color: self.palette.previewInk, alignment: .left, maxLines: 3)) } let experienceBlock: () -> Void = { stack.addArrangedSubview(self.sectionHeading("EXPERIENCE")) stack.addArrangedSubview(self.makeLabel(CVPreviewDemoContent.experienceRole, font: .systemFont(ofSize: 6.8, weight: .semibold), color: self.palette.previewInk, alignment: .left, maxLines: 1)) stack.addArrangedSubview(self.makeLabel(CVPreviewDemoContent.companyLine, font: .systemFont(ofSize: 6.2, weight: .medium), color: self.template.themeColor, alignment: .left, maxLines: 1)) stack.addArrangedSubview(self.bulletRow(CVPreviewDemoContent.bullet1, size: sp)) stack.addArrangedSubview(self.bulletRow(CVPreviewDemoContent.bullet2, size: sp)) stack.addArrangedSubview(self.bulletRow(CVPreviewDemoContent.bullet3, size: sp)) } if experienceFirst { experienceBlock() profileBlock() } else { profileBlock() experienceBlock() } stack.addArrangedSubview(sectionHeading("EDUCATION")) stack.addArrangedSubview(makeLabel(CVPreviewDemoContent.university, font: .systemFont(ofSize: 6.6, weight: .semibold), color: palette.previewInk, alignment: .left, maxLines: 1)) stack.addArrangedSubview(makeLabel("\(CVPreviewDemoContent.degree) · \(CVPreviewDemoContent.educationYears)", font: .systemFont(ofSize: 6.2), color: palette.previewMuted, alignment: .left, maxLines: 2)) return stack } // MARK: - Family: Modern (three distinct silhouettes per id) private func buildModernResume() -> NSView { switch idVariant % 3 { case 0: return buildModernClassicBandLayout() case 1: return buildModernRailDocLayout() default: return buildModernSplitHeaderLayout() } } private func modernPrimaryBody(theme: NSColor) -> NSView { switch template.layout { case .singleColumn: return modernBodySingleColumn(theme: theme) case .twoColumn(let side, let tinted): let main = modernBodySingleColumn(theme: theme) let sideCol = modernSidebar(theme: theme, tinted: tinted) let row = NSStackView() row.orientation = .horizontal row.spacing = 5 + CGFloat(idVariant % 3) row.alignment = .top if side == .leading { row.addArrangedSubview(sideCol) row.addArrangedSubview(main) } else { row.addArrangedSubview(main) row.addArrangedSubview(sideCol) } let mult: CGFloat = (idVariant % 4 == 2) ? 0.36 : 0.32 sideCol.widthAnchor.constraint(equalTo: row.widthAnchor, multiplier: mult).isActive = true return row } } private func buildModernClassicBandLayout() -> NSView { let theme = template.themeColor let header = NSView() header.translatesAutoresizingMaskIntoConstraints = false header.wantsLayer = true header.layer?.backgroundColor = theme.cgColor header.layer?.cornerRadius = idVariant % 2 == 0 ? 5 : 3 let white = NSColor.white let name = makeLabel(CVPreviewDemoContent.fullName, font: .systemFont(ofSize: 9, weight: .bold), color: white, alignment: .left, maxLines: 1) let role = makeLabel(CVPreviewDemoContent.title, font: .systemFont(ofSize: 7.2, weight: .medium), color: white.withAlphaComponent(0.92), alignment: .left, maxLines: 1) let hstack = NSStackView(views: [name, role]) hstack.orientation = .vertical hstack.spacing = 2 hstack.alignment = .leading hstack.translatesAutoresizingMaskIntoConstraints = false let iconRow = NSStackView() iconRow.orientation = .horizontal iconRow.spacing = 5 iconRow.translatesAutoresizingMaskIntoConstraints = false for sym in ["mappin.and.ellipse", "phone.fill", "envelope.fill"] { guard let img = NSImage(systemSymbolName: sym, accessibilityDescription: nil) else { continue } let iv = NSImageView(image: img) iv.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 6, weight: .semibold) iv.contentTintColor = white.withAlphaComponent(0.85) iconRow.addArrangedSubview(iv) } let topRow = NSStackView() topRow.orientation = .horizontal topRow.spacing = 8 topRow.alignment = .centerY topRow.translatesAutoresizingMaskIntoConstraints = false topRow.addArrangedSubview(hstack) topRow.addArrangedSubview(NSView()) topRow.addArrangedSubview(iconRow) header.addSubview(topRow) NSLayoutConstraint.activate([ topRow.leadingAnchor.constraint(equalTo: header.leadingAnchor, constant: 7), topRow.trailingAnchor.constraint(equalTo: header.trailingAnchor, constant: -7), topRow.topAnchor.constraint(equalTo: header.topAnchor, constant: 6), topRow.bottomAnchor.constraint(equalTo: header.bottomAnchor, constant: -6), header.heightAnchor.constraint(greaterThanOrEqualToConstant: 32 + CGFloat(idVariant % 3) * 2) ]) let body = modernPrimaryBody(theme: theme) let wrap = NSStackView(views: [header, body]) wrap.orientation = .vertical wrap.spacing = 6 + CGFloat(idVariant % 2) wrap.alignment = .leading return wrap } private func buildModernRailDocLayout() -> NSView { let theme = template.themeColor let ink = palette.previewInk let muted = palette.previewMuted let rail = NSView() rail.translatesAutoresizingMaskIntoConstraints = false rail.wantsLayer = true rail.layer?.backgroundColor = theme.cgColor rail.layer?.cornerRadius = 2 rail.widthAnchor.constraint(equalToConstant: 3 + CGFloat(idVariant % 2)).isActive = true let inner = NSStackView() inner.orientation = .vertical inner.spacing = 5 inner.alignment = .leading inner.addArrangedSubview(makeLabel(CVPreviewDemoContent.fullName, font: .systemFont(ofSize: 9.5, weight: .bold), color: ink, alignment: .left, maxLines: 1)) inner.addArrangedSubview(makeLabel(CVPreviewDemoContent.title, font: .systemFont(ofSize: 7.2, weight: .semibold), color: theme, alignment: .left, maxLines: 1)) inner.addArrangedSubview(makeLabel("\(CVPreviewDemoContent.email) · \(CVPreviewDemoContent.phone)", font: .systemFont(ofSize: 6), color: muted, alignment: .left, maxLines: 1)) inner.addArrangedSubview(hairline()) inner.addArrangedSubview(tagRow(theme: theme)) inner.addArrangedSubview(modernPrimaryBody(theme: theme)) let row = NSStackView(views: [rail, inner]) row.orientation = .horizontal row.spacing = 7 row.alignment = .top return row } private func buildModernSplitHeaderLayout() -> NSView { let theme = template.themeColor let ink = palette.previewInk let muted = palette.previewMuted let left = NSStackView() left.orientation = .vertical left.spacing = 3 left.alignment = .leading left.addArrangedSubview(makeLabel(CVPreviewDemoContent.fullName, font: .systemFont(ofSize: 9.2, weight: .bold), color: ink, alignment: .left, maxLines: 2)) left.addArrangedSubview(makeLabel(CVPreviewDemoContent.title, font: .systemFont(ofSize: 7, weight: .medium), color: muted, alignment: .left, maxLines: 2)) left.addArrangedSubview(makeLabel(CVPreviewDemoContent.location, font: .systemFont(ofSize: 6), color: muted.withAlphaComponent(0.85), alignment: .left, maxLines: 1)) let right = NSStackView() right.orientation = .vertical right.spacing = 4 right.alignment = .leading right.wantsLayer = true right.layer?.backgroundColor = theme.cgColor right.layer?.cornerRadius = 5 right.edgeInsets = NSEdgeInsets(top: 6, left: 7, bottom: 6, right: 7) let onW = NSColor.white right.addArrangedSubview(makeLabel(CVPreviewDemoContent.email, font: .systemFont(ofSize: 5.9, weight: .medium), color: onW.withAlphaComponent(0.95), alignment: .left, maxLines: 2)) right.addArrangedSubview(makeLabel(CVPreviewDemoContent.phone, font: .systemFont(ofSize: 5.9, weight: .medium), color: onW.withAlphaComponent(0.9), alignment: .left, maxLines: 1)) right.addArrangedSubview(makeLabel("Open to relocation", font: .systemFont(ofSize: 5.6, weight: .regular), color: onW.withAlphaComponent(0.75), alignment: .left, maxLines: 1)) let top = NSStackView(views: [left, right]) top.orientation = .horizontal top.spacing = 6 top.alignment = .top left.widthAnchor.constraint(equalTo: top.widthAnchor, multiplier: 0.54).isActive = true let col = NSStackView(views: [top, hairline(), modernPrimaryBody(theme: theme)]) col.orientation = .vertical col.spacing = 7 col.alignment = .leading return col } private func modernSidebar(theme: NSColor, tinted: Bool) -> NSView { let box = NSStackView() box.orientation = .vertical box.spacing = 5 box.alignment = .leading if tinted { box.wantsLayer = true box.layer?.backgroundColor = theme.withAlphaComponent(0.1).cgColor box.layer?.cornerRadius = 4 } box.edgeInsets = NSEdgeInsets(top: 4, left: 4, bottom: 4, right: 4) box.addArrangedSubview(modernSectionRow(symbol: "person.crop.circle", title: "About", theme: theme)) box.addArrangedSubview(makeLabel(CVPreviewDemoContent.summary, font: .systemFont(ofSize: 6), color: palette.previewInk, alignment: .left, maxLines: 4)) box.addArrangedSubview(modernSectionRow(symbol: "star.fill", title: "Highlights", theme: theme)) box.addArrangedSubview(makeLabel(CVPreviewDemoContent.careerHighlights, font: .systemFont(ofSize: 6), color: palette.previewMuted, alignment: .left, maxLines: 3)) return box } private func modernSectionRow(symbol: String, title: String, theme: NSColor) -> NSView { guard let img = NSImage(systemSymbolName: symbol, accessibilityDescription: nil) else { return makeLabel(title, font: .systemFont(ofSize: 6.5, weight: .bold), color: palette.previewInk, alignment: .left, maxLines: 1) } let iv = NSImageView(image: img) iv.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 6, weight: .semibold) iv.contentTintColor = theme let t = makeLabel(title, font: .systemFont(ofSize: 6.5, weight: .bold), color: palette.previewInk, alignment: .left, maxLines: 1) let r = NSStackView(views: [iv, t]) r.orientation = .horizontal r.spacing = 4 r.alignment = .centerY return r } private func modernBodySingleColumn(theme: NSColor) -> NSView { let stack = NSStackView() stack.orientation = .vertical stack.spacing = 5 stack.alignment = .leading stack.addArrangedSubview(modernSectionRow(symbol: "briefcase.fill", title: "Experience", theme: theme)) stack.addArrangedSubview(makeLabel("\(CVPreviewDemoContent.experienceRole) — \(CVPreviewDemoContent.company)", font: .systemFont(ofSize: 6.6, weight: .semibold), color: palette.previewInk, alignment: .left, maxLines: 2)) stack.addArrangedSubview(makeLabel("2019 – Present · Led cross-functional pods from discovery through launch and post-ship learning.", font: .systemFont(ofSize: 6.1), color: palette.previewMuted, alignment: .left, maxLines: 2)) stack.addArrangedSubview(tagRow(theme: theme)) stack.addArrangedSubview(modernSectionRow(symbol: "graduationcap.fill", title: "Education", theme: theme)) stack.addArrangedSubview(makeLabel("\(CVPreviewDemoContent.university), \(CVPreviewDemoContent.degree) (\(CVPreviewDemoContent.educationYears))", font: .systemFont(ofSize: 6.2), color: palette.previewInk, alignment: .left, maxLines: 2)) return stack } private func tagRow(theme: NSColor) -> NSView { let row = NSStackView() row.orientation = .horizontal row.spacing = 3 row.alignment = .centerY for s in CVPreviewDemoContent.skillsList.prefix(4) { let tag = NSView() tag.wantsLayer = true tag.layer?.backgroundColor = theme.withAlphaComponent(0.14).cgColor tag.layer?.cornerRadius = 3 tag.translatesAutoresizingMaskIntoConstraints = false let lab = makeLabel(s, font: .systemFont(ofSize: 5.5, weight: .semibold), color: theme.blended(withFraction: 0.35, of: palette.previewInk) ?? palette.previewInk, alignment: .center, maxLines: 1) lab.translatesAutoresizingMaskIntoConstraints = false tag.addSubview(lab) NSLayoutConstraint.activate([ lab.leadingAnchor.constraint(equalTo: tag.leadingAnchor, constant: 4), lab.trailingAnchor.constraint(equalTo: tag.trailingAnchor, constant: -4), lab.topAnchor.constraint(equalTo: tag.topAnchor, constant: 2), lab.bottomAnchor.constraint(equalTo: tag.bottomAnchor, constant: -2) ]) row.addArrangedSubview(tag) } return row } // MARK: - Family: Minimal private func buildMinimalResume() -> NSView { let ink = palette.previewInk let muted = palette.previewMuted let nameWeight: NSFont.Weight = (idVariant % 3 == 0) ? .ultraLight : .light let nameSize: CGFloat = template.headline == .centered ? 11 + CGFloat(idVariant % 2) : 9.5 + CGFloat(idVariant % 3) let name = makeLabel(CVPreviewDemoContent.fullName, font: .systemFont(ofSize: nameSize, weight: nameWeight), color: ink, alignment: .left, maxLines: 1) let role = makeLabel(CVPreviewDemoContent.title.uppercased(), font: .systemFont(ofSize: 6.5, weight: .medium), color: muted, alignment: .left, maxLines: 1) let contact = makeLabel("\(CVPreviewDemoContent.email) \(CVPreviewDemoContent.phone)", font: .systemFont(ofSize: 5.8, weight: .regular), color: muted.withAlphaComponent(0.75), alignment: .left, maxLines: 1) let head = NSStackView() head.orientation = .vertical head.spacing = template.headline == .avatarStacked ? 8 : 4 + CGFloat(idVariant % 4) head.alignment = template.headline == .centered ? .centerX : .leading if template.headline == .avatarStacked { head.addArrangedSubview(initialsAvatar(diameter: 24 + CGFloat(idVariant % 2) * 2, ink: ink)) } if template.headline == .centered { name.alignment = .center role.alignment = .center contact.alignment = .center } head.addArrangedSubview(name) head.addArrangedSubview(role) head.addArrangedSubview(contact) head.addArrangedSubview(hairlineSoft()) if idVariant % 5 == 1 { head.addArrangedSubview(hairlineSoft()) } let swapEdu = (idVariant % 4) == 2 let body: NSView switch template.layout { case .singleColumn: body = minimalBody(spacing: 6 + CGFloat(idVariant % 3), educationBeforeExperience: swapEdu) case .twoColumn(let side, _): let a = minimalBody(spacing: 5, educationBeforeExperience: swapEdu) let b = minimalAside(numbered: idVariant % 3 == 1) let row = NSStackView() row.orientation = .horizontal row.spacing = 8 + CGFloat(idVariant % 3) row.alignment = .top if side == .leading { row.addArrangedSubview(b) row.addArrangedSubview(a) } else { row.addArrangedSubview(a) row.addArrangedSubview(b) } let mult: CGFloat = (idVariant % 5 == 0) ? 0.34 : 0.3 b.widthAnchor.constraint(equalTo: row.widthAnchor, multiplier: mult).isActive = true body = row } let wrap = NSStackView(views: [head, body]) wrap.orientation = .vertical wrap.spacing = 7 + CGFloat(idVariant % 2) wrap.alignment = .leading return wrap } private func minimalBody(spacing: CGFloat, educationBeforeExperience: Bool) -> NSView { let stack = NSStackView() stack.orientation = .vertical stack.spacing = spacing stack.alignment = .leading let edu: () -> Void = { stack.addArrangedSubview(self.sectionHeading("EDUCATION")) stack.addArrangedSubview(self.makeLabel("\(CVPreviewDemoContent.university) — \(CVPreviewDemoContent.degree) · \(CVPreviewDemoContent.educationYears)", font: .systemFont(ofSize: 6.1, weight: .light), color: self.palette.previewInk, alignment: .left, maxLines: 2)) } let prof: () -> Void = { stack.addArrangedSubview(self.sectionHeading("PROFILE")) stack.addArrangedSubview(self.makeLabel(CVPreviewDemoContent.summary, font: .systemFont(ofSize: 6.3, weight: .light), color: self.palette.previewInk, alignment: .left, maxLines: 3)) } let exp: () -> Void = { stack.addArrangedSubview(self.sectionHeading("EXPERIENCE")) stack.addArrangedSubview(self.makeLabel("\(CVPreviewDemoContent.experienceRole) · \(CVPreviewDemoContent.company)", font: .systemFont(ofSize: 6.5, weight: .regular), color: self.palette.previewInk, alignment: .left, maxLines: 2)) stack.addArrangedSubview(self.makeLabel(CVPreviewDemoContent.bullet1, font: .systemFont(ofSize: 6, weight: .light), color: self.palette.previewMuted, alignment: .left, maxLines: 2)) stack.addArrangedSubview(self.makeLabel(CVPreviewDemoContent.bullet2, font: .systemFont(ofSize: 6, weight: .light), color: self.palette.previewMuted, alignment: .left, maxLines: 2)) } if educationBeforeExperience { edu() prof() exp() } else { prof() exp() edu() } return stack } private func minimalAside(numbered: Bool) -> NSView { let stack = NSStackView() stack.orientation = .vertical stack.spacing = 6 stack.alignment = .leading stack.addArrangedSubview(sectionHeading("SKILLS")) for (i, s) in CVPreviewDemoContent.skillsList.enumerated() { let prefix = numbered ? "\(i + 1). " : "· " stack.addArrangedSubview(makeLabel("\(prefix)\(s)", font: .systemFont(ofSize: 6, weight: .light), color: palette.previewMuted, alignment: .left, maxLines: 1)) } return stack } // MARK: - Family: Executive (serif) private func buildExecutiveResume() -> NSView { let serif = NSFont(name: "Georgia", size: 6.4) ?? .systemFont(ofSize: 6.4) let serifBase = NSFont(name: "Georgia", size: 7.8) ?? .systemFont(ofSize: 7.8) let serifBold = NSFontManager.shared.convert(serifBase, toHaveTrait: .boldFontMask) let ink = palette.previewInk let muted = palette.previewMuted let theme = template.themeColor let centeredHead = (idVariant % 2) == 0 let name = makeLabel(CVPreviewDemoContent.fullName, font: serifBold, color: ink, alignment: centeredHead ? .center : .left, maxLines: 1) let role = makeLabel(CVPreviewDemoContent.title, font: serif, color: muted, alignment: centeredHead ? .center : .left, maxLines: 1) let contact = makeLabel("\(CVPreviewDemoContent.email) · \(CVPreviewDemoContent.phone) · \(CVPreviewDemoContent.location)", font: NSFont(name: "Georgia", size: 5.8) ?? serif, color: muted.withAlphaComponent(0.9), alignment: centeredHead ? .center : .left, maxLines: 2) let rule = executiveRule(theme: theme, wide: idVariant % 3 == 0) let head = NSStackView(views: [name, role, contact, rule]) head.orientation = .vertical head.spacing = 4 head.alignment = centeredHead ? .centerX : .leading let body: NSView switch template.layout { case .singleColumn: body = executiveBody(serif: serif, ink: ink, muted: muted, theme: theme, compact: false, tightLeading: idVariant % 5 == 2) case .twoColumn(let side, let tinted): let main = executiveBody(serif: serif, ink: ink, muted: muted, theme: theme, compact: true, tightLeading: idVariant % 5 == 2) let sideC = executiveSidebar(serif: serif, tinted: tinted, showMetrics: idVariant % 4 == 1) let row = NSStackView() row.orientation = .horizontal row.spacing = 6 + CGFloat(idVariant % 3) row.alignment = .top if side == .leading { row.addArrangedSubview(sideC) row.addArrangedSubview(main) } else { row.addArrangedSubview(main) row.addArrangedSubview(sideC) } let mult: CGFloat = (idVariant % 5 == 3) ? 0.38 : 0.33 sideC.widthAnchor.constraint(equalTo: row.widthAnchor, multiplier: mult).isActive = true body = row } let wrap = NSStackView(views: [head, body]) wrap.orientation = .vertical wrap.spacing = 6 + CGFloat(idVariant % 2) wrap.alignment = .leading return wrap } private func executiveRule(theme: NSColor, wide: Bool) -> NSView { let v = NSView() v.translatesAutoresizingMaskIntoConstraints = false v.wantsLayer = true v.layer?.backgroundColor = theme.withAlphaComponent(0.45).cgColor v.heightAnchor.constraint(equalToConstant: wide ? 2 : 1).isActive = true v.widthAnchor.constraint(equalToConstant: wide ? 160 : 110).isActive = true return v } private func executiveBody(serif: NSFont, ink: NSColor, muted: NSColor, theme: NSColor, compact: Bool, tightLeading: Bool) -> NSView { let stack = NSStackView() stack.orientation = .vertical stack.spacing = (compact ? 4 : 5) - (tightLeading ? 1 : 0) stack.alignment = .leading let sumTitle = (idVariant % 6 == 3) ? "SUMMARY" : "PROFESSIONAL SUMMARY" stack.addArrangedSubview(sectionHeading(sumTitle)) stack.addArrangedSubview(makeLabel(CVPreviewDemoContent.summary, font: serif, color: ink, alignment: .left, maxLines: 3)) stack.addArrangedSubview(sectionHeading("SELECTED EXPERIENCE")) let jobFont = NSFontManager.shared.convert(serif, toHaveTrait: .boldFontMask) stack.addArrangedSubview(makeLabel("\(CVPreviewDemoContent.experienceRole), \(CVPreviewDemoContent.company)", font: jobFont, color: ink, alignment: .left, maxLines: 2)) stack.addArrangedSubview(makeLabel("2019 – Present", font: serif, color: theme, alignment: .left, maxLines: 1)) stack.addArrangedSubview(makeLabel(CVPreviewDemoContent.bullet1, font: serif, color: muted, alignment: .left, maxLines: 2)) stack.addArrangedSubview(makeLabel(CVPreviewDemoContent.bullet2, font: serif, color: muted, alignment: .left, maxLines: 2)) stack.addArrangedSubview(sectionHeading("EDUCATION")) stack.addArrangedSubview(makeLabel("\(CVPreviewDemoContent.university), \(CVPreviewDemoContent.degree) · \(CVPreviewDemoContent.educationYears)", font: serif, color: ink, alignment: .left, maxLines: 2)) return stack } private func executiveSidebar(serif: NSFont, tinted: Bool, showMetrics: Bool) -> NSView { let stack = NSStackView() stack.orientation = .vertical stack.spacing = 4 stack.alignment = .leading if tinted { stack.wantsLayer = true let fill = (idVariant % 3 == 0) ? NSColor(srgbRed: 0.97, green: 0.97, blue: 0.98, alpha: 1) : template.themeColor.withAlphaComponent(0.07) stack.layer?.backgroundColor = fill.cgColor stack.layer?.cornerRadius = idVariant % 4 == 2 ? 5 : 3 stack.edgeInsets = NSEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) } stack.addArrangedSubview(sectionHeading("CORE COMPETENCIES")) for s in CVPreviewDemoContent.skillsList { stack.addArrangedSubview(makeLabel("· \(s)", font: serif, color: palette.previewInk, alignment: .left, maxLines: 1)) } stack.addArrangedSubview(sectionHeading("TOOLS")) stack.addArrangedSubview(makeLabel(CVPreviewDemoContent.toolsLine, font: serif, color: palette.previewMuted, alignment: .left, maxLines: 2)) if showMetrics { stack.addArrangedSubview(sectionHeading("IMPACT")) stack.addArrangedSubview(makeLabel("+12% activation · $4.2M ARR influenced", font: serif, color: palette.previewInk, alignment: .left, maxLines: 2)) } return stack } // MARK: - Family: Creative (sidebar + bold accent) private func buildCreativeResume() -> NSView { let theme = template.themeColor let deep = creativeDeepBackground(theme: theme) let onSidebar = NSColor.white.withAlphaComponent(0.95) let skillPrefix = (idVariant % 3 == 0) ? "• " : "▸ " let sidebar = NSStackView() sidebar.orientation = .vertical sidebar.spacing = 4 + CGFloat(idVariant % 3) sidebar.alignment = .leading sidebar.wantsLayer = true sidebar.layer?.backgroundColor = deep.cgColor sidebar.layer?.cornerRadius = idVariant % 2 == 0 ? 6 : 4 sidebar.edgeInsets = NSEdgeInsets(top: 6, left: 6, bottom: 6, right: 6) let sbTitle = makeLabel(CVPreviewDemoContent.fullName, font: .systemFont(ofSize: 7.5 + CGFloat(idVariant % 2), weight: .bold), color: onSidebar, alignment: .left, maxLines: 2) sidebar.addArrangedSubview(sbTitle) sidebar.addArrangedSubview(makeLabel(CVPreviewDemoContent.title, font: .systemFont(ofSize: 6.5, weight: .medium), color: onSidebar.withAlphaComponent(0.85), alignment: .left, maxLines: 2)) sidebar.addArrangedSubview(makeLabel(CVPreviewDemoContent.email, font: .systemFont(ofSize: 5.8), color: onSidebar.withAlphaComponent(0.8), alignment: .left, maxLines: 1)) sidebar.addArrangedSubview(makeLabel(CVPreviewDemoContent.phone, font: .systemFont(ofSize: 5.8), color: onSidebar.withAlphaComponent(0.8), alignment: .left, maxLines: 1)) sidebar.addArrangedSubview(creativeSidebarHeading("STRENGTHS", onSidebar: onSidebar, accent: theme)) for s in CVPreviewDemoContent.skillsList.prefix(5) { sidebar.addArrangedSubview(makeLabel("\(skillPrefix)\(s)", font: .systemFont(ofSize: 6, weight: .semibold), color: onSidebar.withAlphaComponent(0.92), alignment: .left, maxLines: 1)) } let main = NSStackView() main.orientation = .vertical main.spacing = 4 + CGFloat(idVariant % 3) main.alignment = .leading main.addArrangedSubview(creativeMainHeader(theme: theme)) main.addArrangedSubview(sectionHeading("PROFILE")) main.addArrangedSubview(makeLabel(CVPreviewDemoContent.summary, font: .systemFont(ofSize: 6.2), color: palette.previewInk, alignment: .left, maxLines: 3)) main.addArrangedSubview(sectionHeading("IMPACT")) main.addArrangedSubview(makeLabel("\(CVPreviewDemoContent.company) — \(CVPreviewDemoContent.experienceRole)", font: .systemFont(ofSize: 6.6, weight: .heavy), color: palette.previewInk, alignment: .left, maxLines: 2)) let bMark = (idVariant % 2 == 0) ? "— " : "▸ " main.addArrangedSubview(makeLabel("\(bMark)\(CVPreviewDemoContent.bullet1)", font: .systemFont(ofSize: 6), color: palette.previewMuted, alignment: .left, maxLines: 2)) main.addArrangedSubview(makeLabel("\(bMark)\(CVPreviewDemoContent.bullet2)", font: .systemFont(ofSize: 6), color: palette.previewMuted, alignment: .left, maxLines: 2)) main.addArrangedSubview(sectionHeading("EDUCATION")) main.addArrangedSubview(makeLabel("\(CVPreviewDemoContent.university) · \(CVPreviewDemoContent.degree) · \(CVPreviewDemoContent.educationYears)", font: .systemFont(ofSize: 6.1), color: palette.previewInk, alignment: .left, maxLines: 2)) let sidebarMult = 0.32 + CGFloat(idVariant % 3) * 0.02 switch template.layout { case .singleColumn: let banner = NSView() banner.translatesAutoresizingMaskIntoConstraints = false banner.wantsLayer = true banner.layer?.backgroundColor = theme.cgColor banner.layer?.cornerRadius = idVariant % 4 == 1 ? 6 : 3 let inner = makeLabel(" \(CVPreviewDemoContent.fullName) · \(CVPreviewDemoContent.title)", font: .systemFont(ofSize: 6.5, weight: .bold), color: .white, alignment: .left, maxLines: 1) inner.translatesAutoresizingMaskIntoConstraints = false banner.addSubview(inner) NSLayoutConstraint.activate([ inner.leadingAnchor.constraint(equalTo: banner.leadingAnchor, constant: 5), inner.trailingAnchor.constraint(lessThanOrEqualTo: banner.trailingAnchor, constant: -5), inner.topAnchor.constraint(equalTo: banner.topAnchor, constant: 4 + CGFloat(idVariant % 2)), inner.bottomAnchor.constraint(equalTo: banner.bottomAnchor, constant: -4) ]) let col = NSStackView(views: [banner, main]) col.orientation = .vertical col.spacing = 6 col.alignment = .leading return col case .twoColumn(let side, _): let row = NSStackView() row.orientation = .horizontal row.spacing = 5 + CGFloat(idVariant % 3) row.alignment = .top if side == .leading { row.addArrangedSubview(sidebar) row.addArrangedSubview(main) } else { row.addArrangedSubview(main) row.addArrangedSubview(sidebar) } sidebar.widthAnchor.constraint(equalTo: row.widthAnchor, multiplier: sidebarMult).isActive = true return row } } private func creativeDeepBackground(theme: NSColor) -> NSColor { let navy = NSColor(srgbRed: 0.08, green: 0.1, blue: 0.18, alpha: 1) let plum = NSColor(srgbRed: 0.14, green: 0.07, blue: 0.24, alpha: 1) switch idVariant % 4 { case 0: return theme.blended(withFraction: 0.52, of: navy) ?? theme case 1: return theme.blended(withFraction: 0.7, of: NSColor.black) ?? theme case 2: return palette.previewInk.blended(withFraction: 0.38, of: theme) ?? theme default: return theme.blended(withFraction: 0.4, of: plum) ?? theme } } private func creativeSidebarHeading(_ raw: String, onSidebar: NSColor, accent: NSColor) -> NSView { let t = makeLabel(raw, font: .systemFont(ofSize: 5.5, weight: .heavy), color: onSidebar, alignment: .left, maxLines: 1) let bar = NSView() bar.translatesAutoresizingMaskIntoConstraints = false bar.wantsLayer = true bar.layer?.backgroundColor = accent.cgColor bar.heightAnchor.constraint(equalToConstant: 2).isActive = true let c = NSStackView(views: [t, bar]) c.orientation = .vertical c.spacing = 2 c.alignment = .leading bar.leadingAnchor.constraint(equalTo: t.leadingAnchor).isActive = true bar.trailingAnchor.constraint(lessThanOrEqualTo: c.trailingAnchor).isActive = true bar.widthAnchor.constraint(equalToConstant: 56).isActive = true return c } private func creativeMainHeader(theme: NSColor) -> NSView { let v = NSView() v.translatesAutoresizingMaskIntoConstraints = false v.wantsLayer = true v.layer?.borderColor = theme.cgColor v.layer?.borderWidth = 0 let stripe = NSView() stripe.translatesAutoresizingMaskIntoConstraints = false stripe.wantsLayer = true stripe.layer?.backgroundColor = theme.cgColor v.addSubview(stripe) let row = NSStackView() row.orientation = .horizontal row.spacing = 5 row.translatesAutoresizingMaskIntoConstraints = false let lab = makeLabel("PORTFOLIO SNAPSHOT", font: .systemFont(ofSize: 6.5, weight: .black), color: palette.previewInk, alignment: .left, maxLines: 1) row.addArrangedSubview(stripe) row.addArrangedSubview(lab) v.addSubview(row) NSLayoutConstraint.activate([ stripe.widthAnchor.constraint(equalToConstant: 3), stripe.heightAnchor.constraint(equalToConstant: 12), row.leadingAnchor.constraint(equalTo: v.leadingAnchor), row.topAnchor.constraint(equalTo: v.topAnchor), row.bottomAnchor.constraint(equalTo: v.bottomAnchor) ]) return v } // MARK: - Shared pieces private func sectionHeading(_ raw: String) -> NSTextField { let s = formattedSectionLabel(raw) let accent = accentDecorationColor() return makeLabel(s, font: .systemFont(ofSize: 5.8, weight: .bold), color: accent, alignment: .left, maxLines: 1) } private func formattedSectionLabel(_ raw: String) -> String { switch template.sectionLabelStyle { case .uppercase: return raw case .slashed: return "// \(raw.capitalized)" case .bracketed: return "[ \(raw) ]" } } private func accentDecorationColor() -> NSColor { switch template.accent { case .redUnderline, .redBar: return palette.previewAccentRed case .blueBar: return palette.previewAccentBlue case .none: return template.themeColor.blended(withFraction: 0.5, of: palette.previewInk) ?? palette.previewInk } } private func headlineAccent(theme: NSColor, width: CGFloat) -> NSView { let v = NSView() v.translatesAutoresizingMaskIntoConstraints = false v.wantsLayer = true switch template.accent { case .none: v.layer?.backgroundColor = theme.withAlphaComponent(0.35).cgColor case .redUnderline: v.layer?.backgroundColor = palette.previewAccentRed.cgColor case .redBar: v.layer?.backgroundColor = palette.previewAccentRed.cgColor case .blueBar: v.layer?.backgroundColor = palette.previewAccentBlue.cgColor } v.heightAnchor.constraint(equalToConstant: template.accent == .redUnderline ? 1.2 : 2.2).isActive = true v.widthAnchor.constraint(equalToConstant: 72 * width).isActive = true return v } private func hairline() -> NSView { let v = NSView() v.translatesAutoresizingMaskIntoConstraints = false v.wantsLayer = true v.layer?.backgroundColor = palette.previewMuted.withAlphaComponent(0.35).cgColor v.heightAnchor.constraint(equalToConstant: 1).isActive = true return v } private func hairlineSoft() -> NSView { let v = NSView() v.translatesAutoresizingMaskIntoConstraints = false v.wantsLayer = true v.layer?.backgroundColor = palette.previewMuted.withAlphaComponent(0.22).cgColor v.heightAnchor.constraint(equalToConstant: 1).isActive = true return v } private func initialsAvatar(diameter: CGFloat, ink: NSColor) -> NSView { let avatar = NSView() avatar.translatesAutoresizingMaskIntoConstraints = false avatar.wantsLayer = true avatar.layer?.backgroundColor = template.themeColor.withAlphaComponent(0.12).cgColor avatar.layer?.borderColor = template.themeColor.withAlphaComponent(0.35).cgColor avatar.layer?.borderWidth = 1 avatar.layer?.cornerRadius = diameter / 2 avatar.widthAnchor.constraint(equalToConstant: diameter).isActive = true avatar.heightAnchor.constraint(equalToConstant: diameter).isActive = true let initials = makeLabel("SJ", font: .systemFont(ofSize: diameter * 0.32, weight: .bold), color: ink, alignment: .center, maxLines: 1) initials.translatesAutoresizingMaskIntoConstraints = false avatar.addSubview(initials) NSLayoutConstraint.activate([ initials.centerXAnchor.constraint(equalTo: avatar.centerXAnchor), initials.centerYAnchor.constraint(equalTo: avatar.centerYAnchor) ]) return avatar } private func skillLineBullet(_ text: String) -> NSView { makeLabel("· \(text)", font: .systemFont(ofSize: 6.1, weight: .regular), color: palette.previewInk, alignment: .left, maxLines: 1) } private func bulletRow(_ text: String, size: CGFloat) -> NSView { let row = NSStackView() row.orientation = .horizontal row.spacing = 3 row.alignment = .top let mark = makeLabel("•", font: .systemFont(ofSize: size, weight: .bold), color: template.themeColor, alignment: .left, maxLines: 1) mark.setContentHuggingPriority(.required, for: .horizontal) let body = makeLabel(text, font: .systemFont(ofSize: size), color: palette.previewInk, alignment: .left, maxLines: 3) row.addArrangedSubview(mark) row.addArrangedSubview(body) return row } private func makeLabel( _ text: String, font: NSFont, color: NSColor, alignment: NSTextAlignment, maxLines: Int ) -> NSTextField { let tf: NSTextField if maxLines == 1 { tf = NSTextField(labelWithString: text) } else { tf = NSTextField(wrappingLabelWithString: text) tf.maximumNumberOfLines = maxLines } tf.font = font tf.textColor = color tf.alignment = alignment tf.isEditable = false tf.isSelectable = false tf.drawsBackground = false tf.isBordered = false tf.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) return tf } }