I have this map
$colors: (
black: $black,
blue1: $blue1,
blue2: $blue2,
blue3: $blue3,
blue4: $blue4,
blue5: $blue5,
blue6: $blue6,
coral1: $coral1,
coral2: $coral2,
coral3: $coral3,
coral4: $coral4,
coral5: $coral5,
green1: $green1,
green2: $green2,
green3: $green3,
grey1: $grey1,
grey2: $grey2,
grey3: $grey3,
grey4: $grey4,
grey5: $grey5,
grey6: $grey6,
orange1: $orange1,
orange2: $orange2,
red1: $red1,
red2: $red2,
red3: $red3,
saffron2: $saffron2,
transparent: $transparent,
white: $white,
);
And I want to export every key of it, like:
:export {
#each $name, $color in $colors {
name: $name
}
}
What I get after importing it is an object with only the last key of the map, why is that? I want the object to be filled with every key
Don't ask me why but apparently putting the key in an interpolation made it to work as intented
:export {
#each $name, $color in $colors {
#{$name}: $name
}
}
Now I get the full object
Related
I'm trying to get a module name from a string. Here is an example of what I imagine it would look like:
#use 'dark'; /* _dark.scss, with a $color variable */
#use 'light'; /* _light.scss, with a $color variable */
#mixin theme($name) {
body {
color: #{$name}.$color;
}
}
If I passed in "dark" as an argument, I would want this result:
...
color: dark.$color;
...
If I passed in "light" as an argument, I would want this result:
...
color: light.$color;
...
I would like to create a function that gets 2 variables as input and, if the first one exists, returns that variable and if not, it returns the fallback value.
I was trying this
#function component-token($token-name, $fallback) {
#if variable-exists($token-name) {
#return $token-name;
}
#return $fallback;
}
And I wanted to use it as
.my-class {
color: component-token($component-button-primary-color, $color-primary-base);
}
However, this poses two problems:
variable-exists expects a string to be passed in.
If $component-button-primary-color does not exist, compilation fails.
I tried calling the function by passing in a string, as such
.my-class {
color: component-token(component-button-primary-color, $color-primary-base);
}
but this left me with color being the string component-button-primary-color, which is of course not what I want.
To give a little bit of context, we're preparing a project for multibranding, in which we want to have our CSS have a base set of values, but every value should be overwriteable by a brand.
In the example above, we can assume that a brand will always have $color-primary-base. But a brand can also define the $component-button-primary-color variable, which should then overwrite the value.
Our first approach was going with !default as can be seen here. But this brings a lot of boilerplate, will require a lot of context switching because you can't find the needed information in the one line.
Any idea?
You can use optional parameters to get the required result.
Required parameters must precede optional parameters.
#function button-color($color-primary-base, $color-primary-button: null) {
#if $color-primary-button != null {
#return $color-primary-button;
}
#return $color-primary-base;
}
I changed the code / names to match your use case : changing the color of a button.
The caller:
$customer-color-primary-base : red;
$customer-color-primary-button: green;
button {
color: button-color($customer-color-primary-base, $customer-color-primary-button);
}
As you can see, it does not require a string as parameter.
You can experiment with keeping the parameters empty or not providing the optional parameter at all:
$customer-color-primary-button: null;
or
color: button-color($customer-color-primary-base);
it does allow you to change the variable later on (dynamic props are not possible, but it is possible to decalare it with a null value at first):
$customer-color-primary-base : red;
$customer-color-primary-button: null;
$customer-color-primary-button: green;
.button {
color: button-color($customer-color-primary-base, $customer-color-primary-button);
}
You can never call the mixin with an undefined variable. What you can do is make sure it exist just before calling the mixin and give a default value of 'false', for example.
EDIT: Another choice is to use a map or list to store the colors, instead of using regular variables, like so:
$color-primary-base: red;
$colors: (
component-button-primary-color: #007dc6
);
#function component-token($token-name, $fallback) {
#if (map-has-key($colors, $token-name)) {
#return map-get($colors, $token-name);
}
#return $fallback;
}
.my-class {
color: component-token(component-button-primary-color, $color-primary-base);
}
.my-class-2 {
color: component-token(unexistent-key, $color-primary-base);
}
I am trying to create a sass mixin which allows to redefine the value of a variable according to a class added on . I am stuck at this stage (which does not work) and I wonder if it is finally possible to do so:
$color-1: #9E619B;
$color-2: #BB496A;
$themecolor: red !default;
$color-themes: (
theme1-pages:
(
themecolor: $color-1
)
theme2-pages:
(
themecolor: $color-2
)
);
#each $name, $theme in $color-themes {
body.#{$name} {
$themecolor: map-get ($name, themecolor);
}
}
I think you've got a syntax error (extra space after map-get) and a mistake in the arguments for map-get(): the arguments should be $theme and themecolor respectively, not $name and themecolor:
#each $name, $theme in $color-themes {
body.#{$name} {
$themecolor: map-get($theme, themecolor);
}
}
That is because $name is simply the key, while $theme is the reference to the value. If you paste the fixed version of your code into SassMeister:
$color-1: #9E619B;
$color-2: #BB496A;
$themecolor: red !default;
$color-themes: (
theme1-pages:
(
themecolor: $color-1
),
theme2-pages:
(
themecolor: $color-2
)
);
#each $name, $theme in $color-themes {
body.#{$name} {
$themecolor: map-get($theme, themecolor);
color: $themecolor;
}
}
You should expect to get this back without any error:
body.theme1-pages {
color: #9E619B;
}
body.theme2-pages {
color: #BB496A;
}
How can I isolate nested sass map into a new map? For example I have sass map like this:
$susy-setting: (
s: (
'columns': 4,
'gutters': 30px,
),
m: (
'columns': 8,
'gutters': 30px,
),
l: (
'columns': 12,
'gutters': 30px,
)
);
Then I need to isolate each map inside after the loop, because my other mixin need map for its parameter.
#each $setting in $susy-setting{
#include susy-settings-block($setting) { // This mixin need map
#for $i from 1 through map-get($setting, 'columns') {
#content;
}
}
}
To answer your primary question, you'll need to get both the key and value in your loop: #each $size, $setting in $susy-setting. The $size variable will store the key (e.g. s, m, l) while the $setting variable stores the map value assigned to that key.
EDIT: I saw your comment on my gist, which provides a bit more context. Try this:
#mixin susy-settings-block(
$name,
$config: $susy-settings
) {
// store the old settings
$global: $susy;
// Get the new settings by name
$new: map-get($config, $name);
// apply the new settings
$susy: map-merge($susy, $new) !global;
// allow nested styles, using new settings
#content;
// return to the initial settings
$susy: $global !global;
}
I've just started my scss experience and I'm trying to figure out why this kind of code it's not respond like I want.
#each $key,
$par in (a:1, b:0, c:1) {
#if #{$par}==1 {
.#{$key} {
color:red
}
}
}
I'm trying to create a class only if the $par element of the map is equal to 1. I'm preety sure that I'm stucking in some logical easy step, but searching around have found nothing about this simple example.
my_codepen
Lose the interpolation in the if-statement and you're good.
#each $key, $par in (a:1, b:0, c:1) {
#if ($par == 1) {
.#{$key} {
color:red
}
}
}