Theme Assets
-
ThemeColoris aNSColorsubclass that dynamically changes its colors whenever a new theme is make current.Theme-aware means you don’t need to check any conditions when choosing which color to draw or set on a control. E.g.:
myTextField.textColor = ThemeColor.myContentTextColor ThemeColor.myCircleFillColor.setFill() NSBezierPath(rect: bounds).fill()The text color of
myTextFieldwill automatically change when the user switches a theme. Similarly, the drawing code will draw with different color depending on the selected theme. Unless some drawing cache is being done, there’s no need to refresh the UI after changing the current theme.You can also define a color to be a pattern image using
NSColor(patternImage:).Defining theme-aware colors
The recommended way of adding your own dynamic colors is as follows:
Add a
ThemeColorclass extension (orTKThemeColorcategory on Objective-C) to add class methods for your colors. E.g.:In Swift:
extension ThemeColor { static var brandColor: ThemeColor { return ThemeColor.color(with: #function) } }In Objective-C:
@interface TKThemeColor (Demo) + (TKThemeColor*)brandColor; @end @implementation TKThemeColor (Demo) + (TKThemeColor*)brandColor { return [TKThemeColor colorWithSelector:_cmd]; } @endAdd Class Extensions on any
Themeyou want to support (e.g.,LightThemeandDarkTheme-TKLightThemeandTKDarkThemeon Objective-C) to provide instance methods for each theme color class method defined on (1). E.g.:In Swift:
extension LightTheme { var brandColor: NSColor { return NSColor.orange } } extension DarkTheme { var brandColor: NSColor { return NSColor.white } }In Objective-C:
@interface TKLightTheme (Demo) @end @implementation TKLightTheme (Demo) - (NSColor*)brandColor { return [NSColor orangeColor]; } @end @interface TKDarkTheme (Demo) @end @implementation TKDarkTheme (Demo) - (NSColor*)brandColor { return [NSColor whiteColor]; } @endIf supporting
UserTheme‘s, define properties on user theme files (.theme) for each theme color class method defined on (1). E.g.:displayName = Sample User Theme identifier = com.luckymarmot.ThemeKit.SampleUserTheme darkTheme = false brandColor = rgba(96, 240, 12, 0.5)
Overriding system colors
Besides your own colors added as
ThemeColorclass methods, you can also overrideNSColorclass methods so that they return theme-aware colors. The procedure is exactly the same, so, for example, if adding a method namedlabelColorto aThemeColorextension, that method will be overriden inNSColorand the colors fromThemesubclasses will be used instead. In sum, callingNSColor.labelColorwill return theme-aware colors.You can get the full list of available/overridable color methods (class methods) calling
NSColor.colorMethodNames().At any time, you can check if a system color is being overriden by current theme by checking the
NSColor.isThemeOverridenproperty (e.g.,NSColor.labelColor.isThemeOverriden).When a theme does not override a system color, the original system color will be used instead. E.g., you have overrided
ThemeColor.labelColor, but currently applied theme does not implementlabelColor-> originallabelColorwill be used.Fallback colors
With the exception of system overrided named colors, which defaults to the original system provided named color when theme does not specifies it, unimplemented properties/methods on target theme class will default to
fallbackForegroundColorandfallbackBackgroundColor, for foreground and background colors respectively. These too, can be customized per theme.Please check
See moreThemeGradientfor theme-aware gradients andThemeImagefor theme-aware images.Declaration
Swift
open class ThemeColor: NSColor
-
ThemeGradientis aNSGradientsubclass that dynamically changes its colors whenever a new theme is make current.Theme-aware means you don’t need to check any conditions when choosing which gradient to draw. E.g.:
ThemeGradient.rainbowGradient.draw(in: bounds, angle: 0)The drawing code will draw with different gradient depending on the selected theme. Unless some drawing cache is being done, there’s no need to refresh the UI after changing the current theme.
Defining theme-aware gradients
The recommended way of adding your own dynamic gradients is as follows:
Add a
ThemeGradientclass extension (orTKThemeGradientcategory on Objective-C) to add class methods for your gradients. E.g.:In Swift:
extension ThemeGradient { static var brandGradient: ThemeGradient { return ThemeGradient.gradient(with: #function) } }In Objective-C:
@interface TKThemeGradient (Demo) + (TKThemeGradient*)brandGradient; @end @implementation TKThemeGradient (Demo) + (TKThemeGradient*)brandGradient { return [TKThemeGradient gradientWithSelector:_cmd]; } @endAdd Class Extensions on any
Themeyou want to support (e.g.,LightThemeandDarkTheme-TKLightThemeandTKDarkThemeon Objective-C) to provide instance methods for each theme gradient class method defined on (1). E.g.:In Swift:
extension LightTheme { var brandGradient: NSGradient { return NSGradient(starting: NSColor.white, ending: NSColor.black) } } extension DarkTheme { var brandGradient: NSGradient { return NSGradient(starting: NSColor.black, ending: NSColor.white) } }In Objective-C:
@interface TKLightTheme (Demo) @end @implementation TKLightTheme (Demo) - (NSGradient*)brandGradient { return [[NSGradient alloc] initWithStartingColor:[NSColor whiteColor] endingColor:[NSColor blackColor]]; } @end @interface TKDarkTheme (Demo) @end @implementation TKDarkTheme (Demo) - (NSGradient*)brandGradient { return [[NSGradient alloc] initWithStartingColor:[NSColor blackColor] endingColor:[NSColor whiteColor]]; } @endIf supporting
UserTheme‘s, define properties on user theme files (.theme) for each theme gradient class method defined on (1). E.g.:displayName = Sample User Theme identifier = com.luckymarmot.ThemeKit.SampleUserTheme darkTheme = false orangeSky = rgb(160, 90, 45, .5) brandGradient = linear-gradient($orangeSky, rgb(200, 140, 60))
Fallback colors
Unimplemented properties/methods on target theme class will default to
fallbackGradient. This too, can be customized per theme.Please check
See moreThemeColorfor theme-aware colors andThemeImagefor theme-aware images.Declaration
Swift
open class ThemeGradient: NSGradient
-
ThemeImageis aNSImagesubclass that dynamically changes its colors whenever a new theme is make current.Theme-aware means you don’t need to check any conditions when choosing which image to draw. E.g.:
ThemeImage.logoImage.draw(in: bounds)The drawing code will draw with different image depending on the selected theme. Unless some drawing cache is being done, there’s no need to refresh the UI after changing the current theme.
Defining theme-aware images
The recommended way of adding your own dynamic images is as follows:
Add a
ThemeImageclass extension (orTKThemeImagecategory on Objective-C) to add class methods for your images. E.g.:In Swift:
extension ThemeImage { static var logoImage: ThemeImage { return ThemeImage.image(with: #function) } }In Objective-C:
@interface TKThemeImage (Demo) + (TKThemeImage*)logoImage; @end @implementation TKThemeImage (Demo) + (TKThemeImage*)logoImage { return [TKThemeImage imageWithSelector:_cmd]; } @endAdd Class Extensions on any
Themeyou want to support (e.g.,LightThemeandDarkTheme-TKLightThemeandTKDarkThemeon Objective-C) to provide instance methods for each theme image class method defined on (1). E.g.:In Swift:
extension LightTheme { var logoImage: NSImage? { return NSImage(named: "MyLightLogo") } } extension DarkTheme { var logoImage: NSImage? { return NSImage(contentsOfFile: "somewhere/MyDarkLogo.png") } }In Objective-C:
@interface TKLightTheme (Demo) @end @implementation TKLightTheme (Demo) - (NSImage*)logoImage { return [NSImage imageNamed:@"MyLightLogo"]; } @end @interface TKDarkTheme (Demo) @end @implementation TKDarkTheme (Demo) - (NSImage*)logoImage { return [NSImage alloc] initWithContentsOfFile:@"somewhere/MyDarkLogo.png"]; } @endIf supporting
UserTheme‘s, define properties on user theme files (.theme) for each theme image class method defined on (1). E.g.:displayName = Sample User Theme identifier = com.luckymarmot.ThemeKit.SampleUserTheme darkTheme = false logoImage = image(named:MyLogo) //logoImage = image(file:../some/path/MyLogo.png)
Fallback images
Unimplemented properties/methods on target theme class will default to
fallbackImage. This too, can be customized per theme.Please check
See moreThemeColorfor theme-aware colors andThemeGradientfor theme-aware gradients.Declaration
Swift
open class ThemeImage: NSImage
View on GitHub
Install in Dash
Theme Assets Reference