// If `$___defined-colors` doesn't exist then this creates it. // This variable is to store the different namespaces and colors as they're defined. @if not global-variable-exists(___defined-colors){ $___defined-colors: () !global; } // This should never change. If you want to change them just define your // own variable `$color-settings` to overwrite one or more of these settings. @if not global-variable-exists(___color-settings){ $___color-settings: ( base: 0, // defines the base color to look for in the maps increment: 5%, // this is a fall back increment if the color functions that are defined are lists and not maps colors: (), // placeholder for defined colors, these will always be defined in $color-settings colors map: "integers", // determins if you're using integers to get your light and dark values or words.(@feature - this hasn't been added yet) smart-color: .25, // determins how far you go back if the color is #fff or #000 (example if you called color(#ccc, 25) that will be black but if smart color is set then it will be #060606) functions: ( // holds the light and dark functions to use for the different variations. (only light, and dark can be the keys of this map) light: ( // holds the light functions that will run if the variation is less than 0 lighten: 5% ), dark: ( // holds the dark functions that will run if the variation is less than 0 darken: 5% ) ) ) !global; } // @author Tyler Benton // @page helpers/mixins // // @description // This is used to set the color settings for the default namespace // The main reason this is a seperate mixin is for the simple fact that it // increases the performance. Only having to merge the namespace settings // with the necessary defaults once is a huge performance increase. // // @arg {string} $namespace (default) - the namespace for your colors // @arg {map} $settings (false) - the settings for your namespace. If false it will use the default settings // @arg {boolean} $merge-color-settings (true) - Determins if you want to merge your default settings that where defined in `$color-settings` // // @markup {scss} - How to define default color settings // $color-settings: ( // smart-color: .45, // colors: ( // a: ( // 0: #ccc, // name: gray // ) // ) // ); // \@import "_colors.scss"; // /\/ define-color-set doesn't need to be called if you define $color-settings (defaults) before you import colors.scss // // @markup {scss} - How to define default color settings after you import colors.scss // \@import "_colors.scss"; // $color-settings: ( // smart-color: .45, // colors: ( // a: ( // 0: #ccc, // name: gray // ) // ) // ); // \@include define-color-set; // // @markup {scss} - How to define a different namespace of colors // /@include define-color-set(messaging, ( // smart-color: .33, // colors: ( // info: ( // 0: #cbe8f5, // name: light blue // ) // ) // ) // ); @mixin define-color-set($namespace: "default", $settings: false, $merge-color-settings: true){ // This merges the default color settings(`$color-settings`) with the default settings. $default-settings: if($merge-color-settings and global-variable-exists(color-settings) and type-of($color-settings) == map, map-merge($___color-settings, $color-settings), $___color-settings ); // Merges $settings with default color settings $settings: if(type-of($settings) == map, map-merge($default-settings, $settings), $default-settings); // this will add a theme for the color $colors: map-get($settings, colors); @each $theme, $base in $colors{ @if type-of($base) == map and map-get($base, theme) == null{ $base: map-merge($base, (theme: $theme)) } $colors: map-merge($colors, ($theme: $base)); } $settings: map-merge($settings, (colors: $colors)); $defined-namespace: map-get($___defined-colors, $namespace); $___defined-colors: map-merge($___defined-colors, if($defined-namespace == null, ($namespace: (settings: $settings, defined-colors: ())), ($namespace: (map-merge($defined-namespace, (settings: $settings)))) ) ) !global; } @include define-color-set; // @name color // @author Tyler Benton // @page helpers/functions // // @description // This function helps control the colors that are used on the site. // It will get dynamic color values based off a **base** color See the examples for more information. // It's highly configurable, and focuses on performance. // // @arg {color | map | key-of-a-map(string)} $this - The type determins how to find the correct color. // @arg {integer} $variation - This accepts any integer value, and does support decimal points. // @arg {boolean} $force - This forces the function to ignore already defined color values, and has it get a new varation. // @arg {boolean} $save - This determins if you want to save the color variation. The reason there're two defaults is that if $force is true then by default the status of $save changes to false // @arg {boolean | map} $settings - These are the user defined settings stored in $this-settings, if there're no color settings then it's false // @arg {boolean} $list - This will list out the colors theme, color, and name that you specify in the settings. // // @returns {color} - The color variation that you specified from the namespace that you specifed // // @markup {scss} (example="false") - Simplest form: // color(#fff, 1.75); /\/ #e9e9e9 // // @markup {scss} (example="false") - Defined colors: // $color-settings: ( // colors: ( // a: #ccc // ) // ); // .foo{ // color(a, 3); /\/ #a6a6a6 // } // // @markup {scss} (example="false") - Using a different map of colors other than default // /\/ option 1 // $messaging-colors: ( // info: ( // -1: #cbe8f5, // 0: #457da6 // ), // ... // ); // .foo{ // color(map-get($messaging-colors, info), 2); // } // /\/ option 2(much better way) // $messaging-settings: ( // name-space: "messaging", // colors: ( // info: ( // -1: #cbe8f5, // 0: #457da6 // ), // ... // ) // ); // \@function messaging-color($type, $variation: 0){ // \@return color($type, $variation, $settings: $messaging-settings); // } // .foo{ // color: messaging-color(info, -1); /\/ #cbe8f5 // } // // @markup {scss} (example="false") - How to force this function to get a variation without checking locally // $color-settings: ( // colors: ( // a: ( // 5: #e2e2e2, // 0: #ccc, // name: gray // ), // ... // ) // ); // color(#fff, 5, true) /\/ forcing it will return #7f7f7f instead of #e2e2e2 which was defined @function color($this: #000, $variation: 0, $force: false, $save: true, $namespace: "default"){ // Sets save to false because, if you're forcing a color variation you probably don't want to save it. @if $force{ $save: false; } $this-namespace: map-get($___defined-colors, $namespace); // The current set to work with @if $this-namespace == null{ @error "to use the #{$namespace} you must first set your settings using `@include define-color-set(#{$namespace}, (your settings in a map))`"; @return false; } $settings: map-get($this-namespace, settings); // helper variables $this-type: type-of($this); // stores the type of this so it doesn't have to be called multiple times. $this-base-color: false; // placeholder for the base color $result: false; // placeholder for result $base: map-get($settings, base); // how to determin the base color if the color is in a map $name-of-color: null; // placeholder for the actual name of the color $theme-of-color: null; // placeholder for the key name // ```scss // $color-settings: ( // colors: ( // a: #ccc, // b: ( // 0: #aaa // ) // ) // ); // color(a, 3); // #b2b2b2 // ``` @if $this-type == string{ // stores the name of this theme $theme-of-color: $this; // try to find $this in the settings colors map $this: map-get(map-get($settings, colors), $this); // reset $this-type to be the new type of this. $this-type: type-of($this); @if $this == null{ @error "Couldn't find '#{$theme-of-color}' in map-get($settings, colors): #{map-get($settings, colors)}"; @return false; } } // ```scss // color(#fff, 2); // ``` @if $this-type == color{ $this-base-color: $this; @if $variation == $base{ // ```scss // color(#ccc, 0); // #ccc // ``` $result: $this-base-color; } } // ```scss // $messaging-settings: ( // name-space: "messaging", // colors: ( // info: ( // -1: #cbe8f5, // 0: #457da6 // ), // ... // ) // ); // \@function messaging-color($type, $variation: 0){ // \@return color($type, $variation, $settings: $messaging-settings); // } // messaging-color(info, -1) /\/ #cbe8f5 // ``` @if not $result and $this-type == map{ // defineds base color $this-base-color: map-get($this, $base); $name-of-color: map-get($this, name); // if there isn't a base color defined then throw this error. @if not $this-base-color{ @error "If you are going to use a map of colors, you have to specify a base color (aka. `0`)"; } // try to find the local variation @if not $force{ $local-attempt: map-get($this, $variation); @if $local-attempt{ $result: $local-attempt; } } } // Ensures that the base color is infact a color @if type-of($this-base-color) != color{ @error "#{$this-base-color} isn't a base color"; @return false; } // try to find the color variation in storage (`$___defined-colors`) @if not $result and not $force{ $stored-attempt: map-get(map-get($this-namespace, defined-colors), "#{$this-base-color}"); $stored-attempt: if($stored-attempt != null, map-get($stored-attempt, $variation), null); @if $stored-attempt { // since the color is already defined it doens't need to be defined again so just return the color $result: $stored-attempt; } } // Finds the color variation programatically if the color variation // isn't found locally, and isn't found in storage @if not $result{ $functions: map-get($settings, functions); // This determins wether or not to use the light or dark function set $functions: if($variation > 0, map-get($functions, dark), map-get($functions, light)); // if it's a list then make it into a map using the settings default values @if type-of($functions) == list{ $temp: (); @each $function in $functions{ $temp: map-merge($temp, (#{$function}: map-get($settings, increment))); } $functions: $temp; } // store the absolute value of the variation as a variable $variation-floor: floor(abs($variation)); $variation-remander: abs($variation) - $variation-floor; // reset the $result to be the base color because that's what's going to get modified. $result: $this-base-color; // Reverse for loop so you can wrap the color functions correctly in reverse order. // Where the last function in the map is the first function to get called. // Example: (lighten: 5%, tint: 5%) ==> lighten(tint([base color], 5%), 5%); @for $i from length($functions) through 1{ // gets the color function name from $function-set $function: nth(map-keys($functions), $i); // the value of the function is the incrementor $incrementor: map-get($functions, $function); // gets the current increment $increment: $variation-floor * $incrementor; // this handles the decimal values for variations @if $variation-remander > 0{ $increment: $increment + ($incrementor * $variation-remander); } // updates the result to be the new value // "DEPRECATION WARNING: Passing a string to call() is deprecated and will be // illegal in Sass 4.0" with lib-sass 3.5.0" // Sass 3.5 compatibility: Use call(get-function('foo'), $args) instead of call('foo', $args) $result: call(get-function($function), $result, $increment); } // if the smart color is greater than 0 $smart-color: abs(map-get($settings, smart-color)); // the abs is to ensure it's using positive numbers since it has to be manipulated to work for both white and black values. @if $smart-color > 0 and index((white, #fff, #ffffff, black, #000, #000000), $result){ // i went with a index of the color values just incase sass changes what it returns in a later release. $result: color( $this, $variation + ($smart-color * if($result == white, 1, -1)), // new variation based off of the smart color $force, // force is same as what was passed because the previous variation could already bed defined. false, // it's false because it's shouldn't be saved. $namespace ); } } // return the result @if type-of($result) == color{ @if $save == true{ $defined-colors: map-get($this-namespace, defined-colors); // get the current color set to work with $this-base-color-string: "#{$this-base-color}"; $base-map: (0: $this-base-color); // the map of this colors variations $this-color: map-get($defined-colors, $this-base-color-string); // if this-color doesn't already exist then create it and set the base color @if $this-color == null{ $this-namespace: map-merge($this-namespace, (defined-colors: map-merge($defined-colors, ($this-base-color-string: $base-map)))); $defined-colors: map-get($this-namespace, defined-colors); $this-color: map-get($defined-colors, $this-base-color-string); } // attempt to get the variation, if there's a defined variation already // then return this attempt and skip everything below $storage-attempt: map-get($this-color, $variation); @if $storage-attempt{ @return $storage-attempt; } // add the new color variation to this color $this-color: map-merge($this-color, ($variation: $result)); // update defined colors to include the new color $defined-colors: map-merge($defined-colors, ($this-base-color-string: $this-color)); // update this-namespace with this color $this-namespace: map-merge($this-namespace, (defined-colors: $defined-colors)); // update $___defined-colors with the new namespace $___defined-colors: map-merge($___defined-colors, ($namespace: $this-namespace)) !global; } @return $result; }@else{ @return $result unquote("/* @errror { #{type-of($result)} isn't a color } */"); } }; // @author Tyler Benton // @page helpers/functions // // @description // This will list out the colors of a color namespace and what they're actually called if you need that // This is just a helper function to `color`, and is purely for debuging and convenience // // @arg {string} $namespace ("default") - this is the namespace that you want to list, or "all" to see all the namespaces // @arg {string} $to-console ("colors") - "colors" | "settings" | "defined-colors" | "all" // // @markup {scss} (example="false") - How to list the current colors and their names in the console: // @include define-color-set("messaging", ( // namespace: "messaging" // colors: ( // info: ( // 0: #ccc, // name: blue /\/ this has to be specifed for every color if you want to see it in the console // ), // ... // ) // )); // // .foo{ // color: color(info); /\/ called to add it to the stored map // } // // $console: console-colors("messaging"); // // @markup {scss} (example="false") - How to log every namespace and their colors, settings, and defined-colors // $console: console-colors(all, all); @function console-colors($namespace: "default", $to-console: "colors"){ @if $namespace == all{ @each $space in map-keys($___defined-colors){ $d: console-colors($space, $to-console); } @return false; } @if $to-console == "all"{ @each $name in (colors, settings, defined-colors){ $d: console-colors($namespace, $name); } @return false; } $this-namespace: map-get($___defined-colors, $namespace); $settings: map-get($this-namespace, settings); $seperator: "---------------------------------------------------------------------"; $title: "colors #{str-slice($seperator, 0, 3)} #{$namespace} #{str-slice($seperator, 0, 3)} #{$to-console}"; $title: $title + str-slice($seperator, str-length($title) + 1); @debug unquote(" "); @debug $title; @if $to-console == "colors"{ @each $theme, $value in map-get($settings, colors){ @if type-of($value) == map{ $color-name: map-get($value, name); $color-name: unquote(if($color-name != null, "// #{$color-name}", "")); @debug "#{map-get($value, theme)} = #{map-get($value, 0)} #{$color-name}"; } } }@else if $to-console == "settings"{ // @debug $settings; @each $setting, $setting-value in $settings{ @if type-of($setting-value) == map{ @debug "#{$setting}: ("; @each $key, $value in $setting-value{ @if type-of($value) == map{ @debug " #{$key}: ("; @each $variation, $color in $value{ @debug " #{$variation}: #{$color},"; } @debug " )," }@else{ @debug "#{$key}: #{$value}"; } } @debug "),"; }@else{ @debug "#{$setting}: #{$setting-value},"; } } }@else if $to-console == "defined-colors"{ @each $color, $variations in map-get($this-namespace, defined-colors){ @debug "#{$color}: ("; @each $variation, $color-value in $variations{ @debug " #{$variation}: #{$color-value},"; } @debug ");"; } } @debug $seperator; @debug unquote(" "); @return false; }; // @author Tyler Benton // @page helpers/mixins // // @description // This will list out the colors of a color namespace and what they're actually called if you need that // This is just a helper function to `color`, and is purely for debuging and convenience // // @arg {string} $namespace ("default") - this is the namespace that you want to list, or "all" to see all the namespaces // @arg {string} $to-console ("colors") - "colors" | "settings" | "defined-colors" | "all" // // @markup {scss} (example="false") - How to list the current colors and their names in the console: // @include define-color-set("messaging", ( // namespace: "messaging" // colors: ( // info: ( // 0: #ccc, // name: blue /\/ this has to be specifed for every color if you want to see it in the console // ), // ... // ) // )); // // .foo{ // color: color(info); /\/ called to add it to the stored map // } // // @include console-colors("messaging"); // // @markup {scss} (example="false") - How to log every namespace and their colors, settings, and defined-colors // @include console-colors(all, all); @mixin console-colors($namespace: "default", $to-console: "colors"){ $console-log: console-colors($namespace, $to-console); }