Преглед на файлове

Improve theme switching and paywall behavior across light mode.

Refresh the full UI palette when dark mode toggles, restore original sidebar icons with mode-aware tint and hover contrast, and make paywall offer text and selected-card styling respond to the active plan and appearance.

Made-with: Cursor
huzaifahayat12 преди 3 месеца
родител
ревизия
ad631cd0ca
променени са 1 файла, в които са добавени 136 реда и са изтрити 52 реда
  1. 136 52
      meetings_app/ViewController.swift

+ 136 - 52
meetings_app/ViewController.swift

@@ -36,7 +36,7 @@ private enum PremiumPlan: Int {
 }
 
 final class ViewController: NSViewController {
-    private let palette = Palette()
+    private var palette = Palette(isDarkMode: true)
     private let typography = Typography()
     private let launchContentSize = NSSize(width: 920, height: 690)
     private let launchMinContentSize = NSSize(width: 760, height: 600)
@@ -56,6 +56,7 @@ final class ViewController: NSViewController {
     private var selectedPremiumPlan: PremiumPlan = .monthly
     private var paywallPlanViews: [PremiumPlan: NSView] = [:]
     private var premiumPlanByView = [ObjectIdentifier: PremiumPlan]()
+    private weak var paywallOfferLabel: NSTextField?
 
     private let darkModeDefaultsKey = "settings.darkModeEnabled"
     private var darkModeEnabled: Bool {
@@ -66,7 +67,7 @@ final class ViewController: NSViewController {
         set { UserDefaults.standard.set(newValue, forKey: darkModeDefaultsKey) }
     }
 
-    private lazy var settingsPopover: NSPopover = {
+    private func makeSettingsPopover() -> NSPopover {
         let popover = NSPopover()
         popover.behavior = .transient
         popover.animates = true
@@ -82,10 +83,13 @@ final class ViewController: NSViewController {
             }
         )
         return popover
-    }()
+    }
+
+    private var settingsPopover: NSPopover?
 
     override func viewDidLoad() {
         super.viewDidLoad()
+        palette = Palette(isDarkMode: darkModeEnabled)
         setupRootView()
         buildMainLayout()
     }
@@ -195,22 +199,44 @@ private extension ViewController {
 
     private func showSettingsPopover() {
         guard let anchor = sidebarRowViews[.settings] else { return }
-        if settingsPopover.isShown {
-            settingsPopover.performClose(nil)
+        if settingsPopover?.isShown == true {
+            settingsPopover?.performClose(nil)
             return
         }
 
-        if let menu = settingsPopover.contentViewController as? SettingsMenuViewController {
+        settingsPopover = makeSettingsPopover()
+        if let menu = settingsPopover?.contentViewController as? SettingsMenuViewController {
             menu.setDarkModeEnabled(darkModeEnabled)
         }
 
-        settingsPopover.show(relativeTo: anchor.bounds, of: anchor, preferredEdge: .maxX)
+        settingsPopover?.show(relativeTo: anchor.bounds, of: anchor, preferredEdge: .maxX)
     }
 
     private func setDarkMode(_ enabled: Bool) {
         darkModeEnabled = enabled
         NSApp.appearance = NSAppearance(named: enabled ? .darkAqua : .aqua)
         view.appearance = NSAppearance(named: enabled ? .darkAqua : .aqua)
+        palette = Palette(isDarkMode: enabled)
+        settingsPopover?.performClose(nil)
+        settingsPopover = nil
+        reloadTheme()
+    }
+
+    private func reloadTheme() {
+        pageCache.removeAll()
+        sidebarRowViews.removeAll()
+        sidebarPageByView.removeAll()
+        zoomJoinModeByView.removeAll()
+        zoomJoinModeViews.removeAll()
+        settingsActionByView.removeAll()
+        paywallPlanViews.removeAll()
+        premiumPlanByView.removeAll()
+
+        mainContentHost = nil
+        view.subviews.forEach { $0.removeFromSuperview() }
+        setupRootView()
+        buildMainLayout()
+        showSidebarPage(selectedSidebarPage)
     }
 
     private func handleSettingsAction(_ action: SettingsAction) {
@@ -294,19 +320,35 @@ private extension ViewController {
         for (plan, view) in paywallPlanViews {
             applyPaywallPlanStyle(view, isSelected: plan == selectedPremiumPlan)
         }
+        paywallOfferLabel?.stringValue = paywallOfferText(for: selectedPremiumPlan)
+    }
+
+    private func paywallOfferText(for plan: PremiumPlan) -> String {
+        switch plan {
+        case .weekly:
+            return "Rs 1,100.00/week"
+        case .monthly:
+            return "Free for 3 Days then Rs 2,500.00/month"
+        case .yearly:
+            return "Rs 9,900.00/year (about 190.38/week)"
+        case .lifetime:
+            return "Rs 14,900.00 one-time purchase"
+        }
     }
 
     private func applyPaywallPlanStyle(_ card: NSView, isSelected: Bool) {
         let selectedBorder = NSColor(calibratedRed: 1.0, green: 0.60, blue: 0.20, alpha: 1)
         let idleBorder = palette.inputBorder
-        let selectedBackground = NSColor(calibratedRed: 30.0 / 255.0, green: 34.0 / 255.0, blue: 42.0 / 255.0, alpha: 1)
+        let selectedBackground = darkModeEnabled
+            ? NSColor(calibratedRed: 30.0 / 255.0, green: 34.0 / 255.0, blue: 42.0 / 255.0, alpha: 1)
+            : NSColor(calibratedRed: 255.0 / 255.0, green: 246.0 / 255.0, blue: 236.0 / 255.0, alpha: 1)
         card.layer?.backgroundColor = (isSelected ? selectedBackground : palette.sectionCard).cgColor
         card.layer?.borderColor = (isSelected ? selectedBorder : idleBorder).cgColor
         card.layer?.borderWidth = isSelected ? 2 : 1
         card.layer?.shadowColor = NSColor.black.cgColor
-        card.layer?.shadowOpacity = isSelected ? 0.26 : 0.12
+        card.layer?.shadowOpacity = isSelected ? (darkModeEnabled ? 0.26 : 0.10) : 0.12
         card.layer?.shadowOffset = CGSize(width: 0, height: -1)
-        card.layer?.shadowRadius = isSelected ? 10 : 5
+        card.layer?.shadowRadius = isSelected ? (darkModeEnabled ? 10 : 6) : 5
     }
 
     private func viewForPage(_ page: SidebarPage) -> NSView {
@@ -435,14 +477,14 @@ private extension ViewController {
         menuStack.addArrangedSubview(joinRow)
         sidebarRowViews[.joinMeetings] = joinRow
         menuStack.addArrangedSubview(sidebarSectionTitle("Backgrounds"))
-        let photoRow = sidebarItem("Photo", icon: "􀏂", page: .photo, logoImageName: "SidebarPhotoLogo", logoIconWidth: 24, logoHeightMultiplier: 82.0 / 62.0, logoTemplate: false)
+        let photoRow = sidebarItem("Photo", icon: "􀏂", page: .photo, logoImageName: "SidebarPhotoLogo", logoIconWidth: 24, logoHeightMultiplier: 82.0 / 62.0)
         menuStack.addArrangedSubview(photoRow)
         sidebarRowViews[.photo] = photoRow
         let videoRow = sidebarItem("Video", icon: "􀎚", page: .video, logoImageName: "SidebarVideoLogo", logoIconWidth: 28, logoHeightMultiplier: 52.0 / 60.0)
         menuStack.addArrangedSubview(videoRow)
         sidebarRowViews[.video] = videoRow
         menuStack.addArrangedSubview(sidebarSectionTitle("Additional"))
-        let tutorialsRow = sidebarItem("Tutorials", icon: "􀛩", page: .tutorials, logoImageName: "SidebarTutorialsLogo", logoIconWidth: 24, logoHeightMultiplier: 50.0 / 60.0, logoTemplate: false)
+        let tutorialsRow = sidebarItem("Tutorials", icon: "􀛩", page: .tutorials, logoImageName: "SidebarTutorialsLogo", logoIconWidth: 24, logoHeightMultiplier: 50.0 / 60.0)
         menuStack.addArrangedSubview(tutorialsRow)
         sidebarRowViews[.tutorials] = tutorialsRow
         let settingsRow = sidebarItem("Settings", icon: "􀍟", page: .settings, logoImageName: "SidebarSettingsLogo", logoIconWidth: 28, logoHeightMultiplier: 68.0 / 62.0, showsDisclosure: true)
@@ -500,7 +542,8 @@ private extension ViewController {
         ])
 
         let baseColor = palette.primaryBlue
-        let hoverColor = baseColor.blended(withFraction: 0.10, of: NSColor.white) ?? baseColor
+        let hoverBlend = darkModeEnabled ? NSColor.white : NSColor.black
+        let hoverColor = baseColor.blended(withFraction: 0.10, of: hoverBlend) ?? baseColor
         button.onHoverChanged = { hovering in
             button.layer?.backgroundColor = (hovering ? hoverColor : baseColor).cgColor
         }
@@ -648,7 +691,8 @@ private extension ViewController {
         ])
 
         let baseColor = palette.sectionCard
-        let hoverColor = baseColor.blended(withFraction: 0.10, of: NSColor.white) ?? baseColor
+        let hoverBlend = darkModeEnabled ? NSColor.white : NSColor.black
+        let hoverColor = baseColor.blended(withFraction: 0.10, of: hoverBlend) ?? baseColor
         instant.onHoverChanged = { hovering in
             instant.layer?.backgroundColor = (hovering ? hoverColor : baseColor).cgColor
         }
@@ -763,8 +807,9 @@ private extension ViewController {
         updatePaywallPlanSelection()
         contentStack.setCustomSpacing(20, after: lifetimeCard)
 
-        let offer = textLabel("Free for 3 Days then Rs 2,500.00/month", font: NSFont.systemFont(ofSize: 13, weight: .semibold), color: palette.textPrimary)
+        let offer = textLabel(paywallOfferText(for: selectedPremiumPlan), font: NSFont.systemFont(ofSize: 13, weight: .semibold), color: palette.textPrimary)
         offer.alignment = .center
+        paywallOfferLabel = offer
         let offerWrap = NSView()
         offerWrap.translatesAutoresizingMaskIntoConstraints = false
         offerWrap.addSubview(offer)
@@ -948,7 +993,7 @@ private extension ViewController {
         let click = NSClickGestureRecognizer(target: self, action: #selector(paywallFooterLinkClicked(_:)))
         container.addGestureRecognizer(click)
         container.onHoverChanged = { hovering in
-            label.textColor = hovering ? .white : self.palette.textSecondary
+            label.textColor = hovering ? (self.darkModeEnabled ? .white : self.palette.textPrimary) : self.palette.textSecondary
         }
         container.onHoverChanged?(false)
         return container
@@ -1573,8 +1618,8 @@ private final class SettingsMenuViewController: NSViewController {
         view.translatesAutoresizingMaskIntoConstraints = false
         view.wantsLayer = true
         view.layer?.cornerRadius = 12
-        view.layer?.backgroundColor = NSColor(calibratedWhite: 0.12, alpha: 1).cgColor
-        view.layer?.borderColor = NSColor(calibratedWhite: 0.22, alpha: 1).cgColor
+        view.layer?.backgroundColor = palette.sectionCard.cgColor
+        view.layer?.borderColor = palette.inputBorder.cgColor
         view.layer?.borderWidth = 1
         view.layer?.shadowColor = NSColor.black.cgColor
         view.layer?.shadowOpacity = 0.28
@@ -1584,19 +1629,21 @@ private final class SettingsMenuViewController: NSViewController {
     }
 
     private func settingsDarkModeRow(enabled: Bool) -> NSView {
-        let row = HoverTrackingView()
+        let row = NSView()
         row.translatesAutoresizingMaskIntoConstraints = false
         row.heightAnchor.constraint(equalToConstant: 44).isActive = true
+        row.wantsLayer = true
+        row.layer?.cornerRadius = 10
 
         let icon = NSTextField(labelWithString: "◐")
         icon.translatesAutoresizingMaskIntoConstraints = false
         icon.font = NSFont.systemFont(ofSize: 18, weight: .medium)
-        icon.textColor = .white
+        icon.textColor = palette.textPrimary
 
         let title = NSTextField(labelWithString: "Dark Mode")
         title.translatesAutoresizingMaskIntoConstraints = false
         title.font = NSFont.systemFont(ofSize: 16, weight: .semibold)
-        title.textColor = .white
+        title.textColor = palette.textPrimary
 
         let toggle = NSSwitch()
         toggle.translatesAutoresizingMaskIntoConstraints = false
@@ -1608,12 +1655,7 @@ private final class SettingsMenuViewController: NSViewController {
         row.addSubview(icon)
         row.addSubview(title)
         row.addSubview(toggle)
-        row.onHoverChanged = { hovering in
-            row.wantsLayer = true
-            row.layer?.cornerRadius = 10
-            row.layer?.backgroundColor = (hovering ? NSColor(calibratedWhite: 1, alpha: 0.06) : NSColor.clear).cgColor
-        }
-        row.onHoverChanged?(false)
+        row.layer?.backgroundColor = NSColor.clear.cgColor
 
         NSLayoutConstraint.activate([
             icon.leadingAnchor.constraint(equalTo: row.leadingAnchor, constant: 4),
@@ -1637,12 +1679,12 @@ private final class SettingsMenuViewController: NSViewController {
         let iconLabel = NSTextField(labelWithString: icon)
         iconLabel.translatesAutoresizingMaskIntoConstraints = false
         iconLabel.font = NSFont.systemFont(ofSize: 18, weight: .medium)
-        iconLabel.textColor = .white
+        iconLabel.textColor = palette.textPrimary
 
         let titleLabel = NSTextField(labelWithString: title)
         titleLabel.translatesAutoresizingMaskIntoConstraints = false
         titleLabel.font = NSFont.systemFont(ofSize: 16, weight: .semibold)
-        titleLabel.textColor = .white
+        titleLabel.textColor = palette.textPrimary
 
         row.addSubview(iconLabel)
         row.addSubview(titleLabel)
@@ -1660,7 +1702,7 @@ private final class SettingsMenuViewController: NSViewController {
         row.onHoverChanged = { hovering in
             row.wantsLayer = true
             row.layer?.cornerRadius = 10
-            row.layer?.backgroundColor = (hovering ? NSColor(calibratedWhite: 1, alpha: 0.06) : NSColor.clear).cgColor
+            row.layer?.backgroundColor = (hovering ? self.palette.inputBackground : NSColor.clear).cgColor
         }
         row.onHoverChanged?(false)
 
@@ -1732,6 +1774,7 @@ private extension ViewController {
 
         let leadingView: NSView
         if let name = logoImageName, let logo = NSImage(named: name) {
+            logo.isTemplate = true
             let imageView = NSImageView(image: logo)
             imageView.translatesAutoresizingMaskIntoConstraints = false
             imageView.imageScaling = .scaleProportionallyDown
@@ -1792,23 +1835,24 @@ private extension ViewController {
 
     func applySidebarRowStyle(_ item: NSView, page: SidebarPage, logoTemplate: Bool, hovering: Bool = false) {
         let selected = (page == selectedSidebarPage)
-        let hoverColor = NSColor(calibratedWhite: 1, alpha: 0.07)
+        let hoverColor = darkModeEnabled ? NSColor(calibratedWhite: 1, alpha: 0.07) : NSColor(calibratedWhite: 0, alpha: 0.08)
         item.layer?.backgroundColor = (selected ? palette.primaryBlue : (hovering ? hoverColor : NSColor.clear)).cgColor
         let tint = selected ? NSColor.white : palette.textSecondary
+        let sidebarIconTint = darkModeEnabled ? tint : NSColor.black
         guard item.subviews.count >= 2 else { return }
         let leading = item.subviews[0]
         let title = item.subviews.first { $0 is NSTextField } as? NSTextField
         title?.textColor = tint
         // Optional disclosure chevron (if present) is the last text field.
         if let chevron = item.subviews.last as? NSTextField, chevron !== title {
-            chevron.textColor = tint
+            chevron.textColor = sidebarIconTint
         }
         if let imageView = leading as? NSImageView {
             if logoTemplate {
-                imageView.contentTintColor = tint
+                imageView.contentTintColor = sidebarIconTint
             }
         } else if let iconField = leading as? NSTextField {
-            iconField.textColor = tint
+            iconField.textColor = sidebarIconTint
         }
     }
 
@@ -1833,7 +1877,8 @@ private extension ViewController {
         ])
 
         let baseColor = (title == "Cancel") ? palette.cancelButton : color
-        let hoverColor = baseColor.blended(withFraction: 0.12, of: NSColor.white) ?? baseColor
+        let hoverBlend = darkModeEnabled ? NSColor.white : NSColor.black
+        let hoverColor = baseColor.blended(withFraction: 0.12, of: hoverBlend) ?? baseColor
         button.onHoverChanged = { hovering in
             button.layer?.backgroundColor = (hovering ? hoverColor : baseColor).cgColor
         }
@@ -1860,7 +1905,8 @@ private extension ViewController {
         ])
 
         let baseColor = palette.inputBackground
-        let hoverColor = baseColor.blended(withFraction: 0.10, of: NSColor.white) ?? baseColor
+        let hoverBlend = darkModeEnabled ? NSColor.white : NSColor.black
+        let hoverColor = baseColor.blended(withFraction: 0.10, of: hoverBlend) ?? baseColor
         button.onHoverChanged = { hovering in
             button.layer?.backgroundColor = (hovering ? hoverColor : baseColor).cgColor
         }
@@ -1871,22 +1917,60 @@ private extension ViewController {
 }
 
 private struct Palette {
-    let pageBackground = NSColor(calibratedRed: 10.0 / 255.0, green: 11.0 / 255.0, blue: 12.0 / 255.0, alpha: 1)
-    let sidebarBackground = NSColor(calibratedRed: 16.0 / 255.0, green: 17.0 / 255.0, blue: 19.0 / 255.0, alpha: 1)
-    let sectionCard = NSColor(calibratedRed: 22.0 / 255.0, green: 23.0 / 255.0, blue: 26.0 / 255.0, alpha: 1)
-    let tabBarBackground = NSColor(calibratedRed: 22.0 / 255.0, green: 23.0 / 255.0, blue: 26.0 / 255.0, alpha: 1)
-    let tabIdleBackground = NSColor(calibratedRed: 22.0 / 255.0, green: 23.0 / 255.0, blue: 26.0 / 255.0, alpha: 1)
-    let inputBackground = NSColor(calibratedRed: 20.0 / 255.0, green: 21.0 / 255.0, blue: 24.0 / 255.0, alpha: 1)
-    let inputBorder = NSColor(calibratedRed: 38.0 / 255.0, green: 40.0 / 255.0, blue: 44.0 / 255.0, alpha: 1)
-    let primaryBlue = NSColor(calibratedRed: 27.0 / 255.0, green: 115.0 / 255.0, blue: 232.0 / 255.0, alpha: 1)
-    let primaryBlueBorder = NSColor(calibratedRed: 42.0 / 255.0, green: 118.0 / 255.0, blue: 220.0 / 255.0, alpha: 1)
-    let cancelButton = NSColor(calibratedRed: 20.0 / 255.0, green: 21.0 / 255.0, blue: 24.0 / 255.0, alpha: 1)
-    let meetingBadge = NSColor(calibratedRed: 0.88, green: 0.66, blue: 0.14, alpha: 1)
-    let separator = NSColor(calibratedRed: 26.0 / 255.0, green: 27.0 / 255.0, blue: 30.0 / 255.0, alpha: 1)
-    let textPrimary = NSColor(calibratedWhite: 0.98, alpha: 1)
-    let textSecondary = NSColor(calibratedWhite: 0.78, alpha: 1)
-    let textTertiary = NSColor(calibratedWhite: 0.66, alpha: 1)
-    let textMuted = NSColor(calibratedWhite: 0.44, alpha: 1)
+    let pageBackground: NSColor
+    let sidebarBackground: NSColor
+    let sectionCard: NSColor
+    let tabBarBackground: NSColor
+    let tabIdleBackground: NSColor
+    let inputBackground: NSColor
+    let inputBorder: NSColor
+    let primaryBlue: NSColor
+    let primaryBlueBorder: NSColor
+    let cancelButton: NSColor
+    let meetingBadge: NSColor
+    let separator: NSColor
+    let textPrimary: NSColor
+    let textSecondary: NSColor
+    let textTertiary: NSColor
+    let textMuted: NSColor
+
+    init(isDarkMode: Bool) {
+        if isDarkMode {
+            pageBackground = NSColor(calibratedRed: 10.0 / 255.0, green: 11.0 / 255.0, blue: 12.0 / 255.0, alpha: 1)
+            sidebarBackground = NSColor(calibratedRed: 16.0 / 255.0, green: 17.0 / 255.0, blue: 19.0 / 255.0, alpha: 1)
+            sectionCard = NSColor(calibratedRed: 22.0 / 255.0, green: 23.0 / 255.0, blue: 26.0 / 255.0, alpha: 1)
+            tabBarBackground = NSColor(calibratedRed: 22.0 / 255.0, green: 23.0 / 255.0, blue: 26.0 / 255.0, alpha: 1)
+            tabIdleBackground = NSColor(calibratedRed: 22.0 / 255.0, green: 23.0 / 255.0, blue: 26.0 / 255.0, alpha: 1)
+            inputBackground = NSColor(calibratedRed: 20.0 / 255.0, green: 21.0 / 255.0, blue: 24.0 / 255.0, alpha: 1)
+            inputBorder = NSColor(calibratedRed: 38.0 / 255.0, green: 40.0 / 255.0, blue: 44.0 / 255.0, alpha: 1)
+            primaryBlue = NSColor(calibratedRed: 27.0 / 255.0, green: 115.0 / 255.0, blue: 232.0 / 255.0, alpha: 1)
+            primaryBlueBorder = NSColor(calibratedRed: 42.0 / 255.0, green: 118.0 / 255.0, blue: 220.0 / 255.0, alpha: 1)
+            cancelButton = NSColor(calibratedRed: 20.0 / 255.0, green: 21.0 / 255.0, blue: 24.0 / 255.0, alpha: 1)
+            meetingBadge = NSColor(calibratedRed: 0.88, green: 0.66, blue: 0.14, alpha: 1)
+            separator = NSColor(calibratedRed: 26.0 / 255.0, green: 27.0 / 255.0, blue: 30.0 / 255.0, alpha: 1)
+            textPrimary = NSColor(calibratedWhite: 0.98, alpha: 1)
+            textSecondary = NSColor(calibratedWhite: 0.78, alpha: 1)
+            textTertiary = NSColor(calibratedWhite: 0.66, alpha: 1)
+            textMuted = NSColor(calibratedWhite: 0.44, alpha: 1)
+        } else {
+            pageBackground = NSColor(calibratedRed: 244.0 / 255.0, green: 246.0 / 255.0, blue: 249.0 / 255.0, alpha: 1)
+            sidebarBackground = NSColor(calibratedRed: 232.0 / 255.0, green: 236.0 / 255.0, blue: 242.0 / 255.0, alpha: 1)
+            sectionCard = NSColor.white
+            tabBarBackground = NSColor.white
+            tabIdleBackground = NSColor.white
+            inputBackground = NSColor(calibratedRed: 247.0 / 255.0, green: 249.0 / 255.0, blue: 252.0 / 255.0, alpha: 1)
+            inputBorder = NSColor(calibratedRed: 211.0 / 255.0, green: 218.0 / 255.0, blue: 228.0 / 255.0, alpha: 1)
+            primaryBlue = NSColor(calibratedRed: 27.0 / 255.0, green: 115.0 / 255.0, blue: 232.0 / 255.0, alpha: 1)
+            primaryBlueBorder = NSColor(calibratedRed: 42.0 / 255.0, green: 118.0 / 255.0, blue: 220.0 / 255.0, alpha: 1)
+            cancelButton = NSColor(calibratedRed: 240.0 / 255.0, green: 243.0 / 255.0, blue: 248.0 / 255.0, alpha: 1)
+            meetingBadge = NSColor(calibratedRed: 0.88, green: 0.66, blue: 0.14, alpha: 1)
+            separator = NSColor(calibratedRed: 212.0 / 255.0, green: 219.0 / 255.0, blue: 229.0 / 255.0, alpha: 1)
+            textPrimary = NSColor(calibratedRed: 32.0 / 255.0, green: 38.0 / 255.0, blue: 47.0 / 255.0, alpha: 1)
+            textSecondary = NSColor(calibratedRed: 82.0 / 255.0, green: 92.0 / 255.0, blue: 107.0 / 255.0, alpha: 1)
+            textTertiary = NSColor(calibratedRed: 110.0 / 255.0, green: 120.0 / 255.0, blue: 136.0 / 255.0, alpha: 1)
+            textMuted = NSColor(calibratedRed: 134.0 / 255.0, green: 145.0 / 255.0, blue: 162.0 / 255.0, alpha: 1)
+        }
+    }
 }
 
 private struct Typography {