xcode-color-assets icon indicating copy to clipboard operation
xcode-color-assets copied to clipboard

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

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