Skip to content

Create (dark mode compatible) color assets for Xcode programmatically from a CSS-like textfile

Notifications You must be signed in to change notification settings

nesium/xcode-color-assets

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Xcode Color Assets

This project allows you to create Xcode Assets catalogs for your colors. Instead of tediously creating your named colors in Xcode's UI you can create a CSS-like document and have your Asset catalog generated programmatically. Specify colors in hex (with a twist, to allow specifying the alpha value in percent) and RGBA. Use variables for your colors and support dark mode. Finally, generate a corresponding Swift file to reference the created colors safely in your code.

Since version 0.4.0 it is also possible to generate a Swift file which does not depend on Asset catalogs and uses dynamic colors instead. This solves a problem where Asset Catalogs would not be compiled correctly in the Xcode 11 beta 6/7 and accessing colors at runtime did not work on iOS < 13. See below an example of the generated code.

Specify your colors

// Basic colors
$white: #ffffff
$black: #000000
$black50: #000000 50%
$classic: (light: $black, dark: $white)

// Accent colors
$brightAccent: #5753CF
$mediumBright: rgba(25, 200, 255, 1)
$mediumBrightHighlight: #70D1FA

// Greys
$grey1: $black

// Declarations
Text {
  Primary: (light: #151618, dark: #E7E8EA)
  Secondary: (light: $grey1, dark: #85868A)
}

LightContentSeparator: (light: #F1F2F2, dark: #222525)

NumericInput {
  NumericKey {
    Background: (light: $white, dark: #434343)
    Highlight: (light: #C4CCDA, dark: #666666)
    Shadow: (light: #848587, dark: $black50 50%) // Apply alpha to variables
    Text: $classic
  }

  DoneKey {
    Background: (light: $mediumBright, dark: $brightAccent)
    Highlight: (light: $mediumBrightHighlight, dark: rgba(103, 122, 219, 1))
    Shadow: (light: #6E7073, dark: $black)
    Text: $classic
  }

  Background: (light: #D6D9DE 30%, dark: #313131 40%)
}

Generate your Asset catalog

$ xcode-color-assets gen-assets colors.assetstyles -o Colors.xcassets --color-space srgb

Xcode Screenshot

Generate your Swift code

First option: Reference the generated Asset Catalog

$ xcode-color-assets gen-swift colors.assetstyles -o UIColor+Custom.swift --mode asset-catalog
// This file is automatically generated. Do not edit, your changes will be erased.

import UIKit

extension UIColor {
  enum Custom {
    static let LightContentSeparator = UIColor(named: "LightContentSeparator")!
    enum NumericInput {
      enum NumericKey {
        static let Background = UIColor(named: "NumericInputNumericKeyBackground")!
        static let Highlight = UIColor(named: "NumericInputNumericKeyHighlight")!
        static let Shadow = UIColor(named: "NumericInputNumericKeyShadow")!
        static let Text = UIColor(named: "NumericInputNumericKeyText")!
      }
      enum DoneKey {
        static let Background = UIColor(named: "NumericInputDoneKeyBackground")!
        static let Highlight = UIColor(named: "NumericInputDoneKeyHighlight")!
        static let Shadow = UIColor(named: "NumericInputDoneKeyShadow")!
        static let Text = UIColor(named: "NumericInputDoneKeyText")!
      }
      static let Background = UIColor(named: "NumericInputBackground")!
    }
    enum Text {
      static let Primary = UIColor(named: "TextPrimary")!
      static let Secondary = UIColor(named: "TextSecondary")!
    }
  }
}

Second option: Dynamic colors

$ xcode-color-assets gen-swift colors.assetstyles -o UIColor+Custom.swift --mode dynamic-color
// This file is automatically generated. Do not edit, your changes will be erased.

import UIKit

private struct ColorSet {
  var light: UIColor
  var dark: UIColor?

  init(_ light: UIColor, _ dark: UIColor?) {
    self.light = light
    self.dark = dark
  }
}

private func dynamicColor(_ colorSet: ColorSet) -> UIColor {
  if #available(iOS 13.0, *) {
    return UIColor { traits -> UIColor in
      switch traits.userInterfaceStyle {
        case .dark:
          return colorSet.dark ?? colorSet.light
        case .light, .unspecified:
          fallthrough
        @unknown default:
          return colorSet.light
      }
    }
  } else {
    return colorSet.light
  }
}

private let ColorSets: [ColorSet] = [
  ColorSet(UIColor(red: 0.945, green: 0.949, blue: 0.949, alpha: 1.00), UIColor(red: 0.133, green: 0.145, blue: 0.145, alpha: 1.00)),
  ColorSet(UIColor(red: 0.839, green: 0.851, blue: 0.871, alpha: 0.30), UIColor(red: 0.192, green: 0.192, blue: 0.192, alpha: 0.40)),
  ColorSet(UIColor(red: 0.098, green: 0.784, blue: 1.000, alpha: 1.00), UIColor(red: 0.341, green: 0.325, blue: 0.812, alpha: 1.00)),
  ColorSet(UIColor(red: 0.439, green: 0.820, blue: 0.980, alpha: 1.00), UIColor(red: 0.404, green: 0.478, blue: 0.859, alpha: 1.00)),
  ColorSet(UIColor(red: 0.431, green: 0.439, blue: 0.451, alpha: 1.00), nil),
  ColorSet(UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.00), UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.00)),
  ColorSet(UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.00), UIColor(red: 0.263, green: 0.263, blue: 0.263, alpha: 1.00)),
  ColorSet(UIColor(red: 0.769, green: 0.800, blue: 0.855, alpha: 1.00), UIColor(red: 0.400, green: 0.400, blue: 0.400, alpha: 1.00)),
  ColorSet(UIColor(red: 0.518, green: 0.522, blue: 0.529, alpha: 1.00), UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.00)),
  ColorSet(UIColor(red: 0.082, green: 0.086, blue: 0.094, alpha: 1.00), UIColor(red: 0.906, green: 0.910, blue: 0.918, alpha: 1.00)),
  ColorSet(UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.00), UIColor(red: 0.522, green: 0.525, blue: 0.541, alpha: 1.00)),
]

extension UIColor {
  enum Custom {
    static let LightContentSeparator = dynamicColor(ColorSets[0])
    enum NumericInput {
      static let Background = dynamicColor(ColorSets[1])
      enum DoneKey {
        static let Background = dynamicColor(ColorSets[2])
        static let Highlight = dynamicColor(ColorSets[3])
        static let Shadow = dynamicColor(ColorSets[4])
        static let Text = dynamicColor(ColorSets[5])
      }
      enum NumericKey {
        static let Background = dynamicColor(ColorSets[6])
        static let Highlight = dynamicColor(ColorSets[7])
        static let Shadow = dynamicColor(ColorSets[8])
        static let Text = dynamicColor(ColorSets[5])
      }
    }
    enum Text {
      static let Primary = dynamicColor(ColorSets[9])
      static let Secondary = dynamicColor(ColorSets[10])
    }
  }
}

Installation via Homebrew

$ brew install nesium/tools/xcode-color-assets

Advanced usage

By using FSWatch you can observe your stylesheet for changes and have the Asset Catalog and Swift file generated automatically. See a Makefile example below.

watch_colors:
	@fswatch -o Color_Assets/colors.assetstyles | (while read; do make colors; done)

colors:
	@xcode-color-assets gen-assets Color_Assets/colors.assetstyles -o Colors.xcassets --force --color-space srgb
	@xcode-color-assets gen-swift Color_Assets/colors.assetstyles -o ../Shared/Colors.swift --mode asset-catalog