I have custom theme colors
$theme-colors-custom: (
abc--bg: #fafafa,
abc--text: #ccc
);
my problem is that I would have to manualy type names (abc--bg,abc--text,...) but I would like to generate them using other variables from below.
I it possible to dinamicly assign color using each, something like this to $theme-colors-custom:
$my-variable-prefix: "abc";
$theme-light-name: 'light';
$theme-dark-name: 'dark';
$body-bg-light: #fafafa;
$body-text-light: #ccc;
$body-bg-dark: #212121;
$body-text-dark: #ddd;
$themes: (
light: (
bg: $body-bg-light,
text: $body-text-light,
),
dark: (
bg: $body-bg-dark,
text: $body-text-dark,
),
);
$theme-colors-custom: (
$name-variables: map-get($themes, 'light');
#each $key, $value in $name-variables {
#{$my-variable-prefix}--#{$key}: #{$value},
}
);
The expected result would be:
$theme-colors-custom: (
abc--bg: #fafafa,
abc--text: #ccc,
);
Yes it is possible, but you need to do the each loop outside of the map and use map-merge:
$theme-colors-custom: ();
$name-variables: map-get($themes, 'light');
#each $key, $value in $name-variables {
$keyName: #{$my-variable-prefix}--#{$key};
$theme-colors-custom: map-merge($theme-colors-custom, ($keyName: $value));
}
Related
I am defining values for a theme via a map, like this:
$sizes: (
small: 768,
medium: 1024,
large: 1200,
xlarge: 1600,
gutter: 48
);
and afterwards give them a unit with the following function:
#function sz($size) {
#return map-get($sizes, $size) + px;
}
How can I define a variable by calculating with one of the values out of the function, e.g.
$gutterhalf: (sz(gutter) / 2);
So the variable would return 48px / 2 = 24px? I know I could just go with the unitless value and add the unit afterwards, like so:
$gutterhalf: (map-get($sizes, gutter) / 2) + px;
Would there be a way to handle it differently with the value from the function?
Normally I would use sassmeister to do live sass demos but I can't seem to share my sass demo without it automatically switching to dart-sass. Very weird.
But I've made a fiddle outputting results to a before pseudo content style on divs by id.
See experimental ideas in fiddle... https://jsfiddle.net/joshmoto/0mbsc2g3/
And here is scss code below...
// array with no pixel unit, just integers
$sizes_0: (
sm: 768,
md: 1024,
lg: 1200,
xl: 1600,
gutter: 48
);
// both functions below use array above
// this function allows you pass diving data through
#function sz_0($size, $divide: 1) {
#return map-get($sizes_0, $size) / $divide + px;
}
// this outputs 24px
$gutterhalf_0: sz_0(gutter, 2);
// this function simply returns the array value
#function sz_2($size) {
#return map-get($sizes_0, $size);
}
// this outputs 24px
$gutterhalf_2: ( sz_2(gutter) / 2 ) + px;
// array with pixel unit
$sizes_1: (
sm: 768px,
md: 1024px,
lg: 1200px,
xl: 1600px,
gutter: 48px
);
// this function simply returns the array value with unit
#function sz_1($size) {
#return map-get($sizes_1, $size);
}
// this outputs 24px
$gutterhalf_1: sz_1(gutter) / 2;
// sass results in content
#sz_0::before {
content: '#{$gutterhalf_0}';
}
#sz_1::before {
content: '#{$gutterhalf_1}';
}
#sz_2::before {
content: '#{$gutterhalf_2}';
}
I've variable named classes where each key has style values
$classes : (
class1: (
font-size: 15px,
color: blue
),
class2: (
font-size: 20px,
font-weight: 600,
background-color: red
)
)
I'm writing #each rule in scss like below.
#each $key, $value in $classes {
.#{$label} {
// How to assign values here
}
}
I'm able to get class name but unable to add all values here. Any idea how to do it.
I found the solution of above problem.
We can't assign key - value pair directly in scss.
Here we need to apply #each loop till the end
#each $key, $value in $classes {
.#{$label} {
#each $key1, $value1 in $value {
.#{$key1}: $value1
}
}
}
I have a class with the name .text-black, I also have a map with some values.
$black: #000;
map:
dark: $black;
I want to loop through this map and create a new class with the $key and then extend they new class with using the value text-black.
There are 2 problems I have. The first I think I have solved, if I can get the $value as $black instead of #000. Then I can remove the $ using string replacement.
The second challenge however is proving a headache for me. I need to get $black in stead of #000.
Here is my code showing my approach so far.
// String Replacement to remove '$' from varaible name.
#function str-replace($string, $search, $replace: '') {
$index: str-index($string, $search);
#if $index {
#return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace)
}
#return $string;
}
// get color from map
#function text-color($key: "weekly-digest") {
#return map-get($text-colors, $key);
}
$black: #000000;
// map text-colors
$text-colors: () !default;
$text-colors: map-merge(
(
"news": $black,
),
$text-colors
);
// Extendable classes.
.text-black{
color: $black;
}
// Loop function
#each $name, $value in $text-colors {
&--#{$name} {
background-color: $value;
#extend .text-#{$value} // This should return '.text-black' not '.text-#000000'
}
}
I try to give you 3 different solutions. In all these solutions I used 2 colors (black & red) only to see if they could work in combination:
1. Using a function str-split() (maybe the most intricated, but use your code)
I found a magical function that splits a string in 2 elements How to split a string into two lists of numbers in SASS?.
So my idea is to use that function (thanks to #dayenite: if you like this solution, please upvote him ;)) in a string using a character (in my example "_") to split your maps in 3 different value (something like 2 keys and 1 value):
1. "news"
2. "black"
3. "#000"
Your map could become something like this:
$text-colors: map-merge(
(
"news_black":$black,
"info_red": $red
),
$text-colors
);
This is all the code in action:
#function str-split($string, $separator) {
// empty array/list
$split-arr: ();
// first index of separator in string
$index : str-index($string, $separator);
// loop through string
#while $index != null {
// get the substring from the first character to the separator
$item: str-slice($string, 1, $index - 1);
// push item to array
$split-arr: append($split-arr, $item);
// remove item and separator from string
$string: str-slice($string, $index + 1);
// find new index of separator
$index : str-index($string, $separator);
}
// add the remaining string to list (the last item)
$split-arr: append($split-arr, $string);
#return $split-arr;
}
/* Example with 2 colors */
$black: #000000;
$red: #ff0000;
$text-colors: () !default;
$text-colors: map-merge(
(
"news_black":$black,
"info_red": $red //my add
),
$text-colors
);
// Extendable classes.
.text-black{
color: $black;
}
.text-red{
color: $red;
}
// Loop function
.my-div{
#each $name, $value in $text-colors {
$list: (); // Create every time an empty list with my 2 argoments, for example "news" and "black"
$split-values: str-split($name, "_"); //use the function to split the string
#each $valore in $split-values {
$list: append($list, str-split($valore, " "));
}
//set here the first part of the string (i.e. news/info)
&--#{nth($list, 1)} {
background-color: $value;
#extend .text-#{nth($list, 2)} // set here the second part: black/red
}
}
}
https://www.sassmeister.com/gist/08f699dba4436d3bae6a4d8b666e815b
2. Using a nested list
This time I created a simple nested list with 3 value ("news", "black", $black), the result is the same.
$black: #000000;
$red: #ff0000;
// list text-colors
$text-colors: (
( "news", "black", $black ),
( "info", "red", $red )
);
// Extendable classes.
.text-black{
color: $black;
}
.text-red{
color: $red;
}
.mydiv{
// Loop function
#each $item in $text-colors {
&--#{nth($item, 1)} {
background-color: nth($item, 3);
#extend .text-#{nth($item, 2)}
}
}
}
https://www.sassmeister.com/gist/59adf5ee60ea46dd7a24e94d7db91d85
3. Using a nested map
Here I use nested maps, but the structure is different from yours and I don't know if it's ok for you.
$black: #000000;
$red: #ff0000;
// map text-colors
$text-colors: (
news:(black: $black),
info:(red: $red)
);
.text-black{
color: $black;
}
.text-red{
color: $red;
}
.mydiv{
// Loop function
#each $name, $value in $text-colors {
&--#{$name} {
#each $name-color, $value-color in $value {
background-color: $value-color;
#extend .text-#{$name-color}
}
}
}
}
https://www.sassmeister.com/gist/8ddec08755befc84f6e4846fbc625130
Well, I haven't another ideas. I hope at least one way could help you to solve your problem.
Cheers :)
I am using sass palettes and I would like know how can I make this function works for more than 1 palettes.
right now I can just use 1 palette with this function, how can make this function works for more than 1 palette?
#function palette($palette, $shade: 'base') {
#return map-get(map-get($color-palettes, $palette), $shade);
}
$primary-palette: (
grey: (
xx-light : lighten($grey, 43%),
x-light : lighten($grey, 35%),
light : lighten($grey, 6%),
base : $grey,
dark : darken($grey, 8%),
x-dark : darken($grey, 16%)
),
);
// will be my secondary paletter
$secondary-palette: (
black: (
light : lighten($grey, 6%),
base : $grey,
dark : darken($grey, 8%),
x-dark : darken($grey, 16%)
),
);
applied in the css
body {
background-color: palette(grey,dark);
}
Someone can help? Thanks
I've not done anything like this before, but it looks really powerful. I did some searching and this article seems to suggest you'd put the black palette within $primary-palette as well, only having one master set of palettes.
From the post:
$colors: (
blue: (
0: hsl(198, 74%, 49%),
1: hsl(200, 72%, 61%),
2: hsl(200, 71%, 73%),
[...]
),
red: (
0: hsl(3, 72%, 62%),
1: hsl(4, 85%, 66%),
2: hsl(4, 84%, 78%),
[...]
)
)
#function get-color($color, $value: 0) {
#return map-get(map-get($colors, $color), $value);
}
.button--blue{
color: get-color(blue, 0);
background: get-color(blue, 4);
&:hover{
background: get-color(blue, 3);
}
}
Im fairly new to SASS and I'm confused by the way lists work. I have a multidimensional list like this:
$stylethemes: {
(15, bold, red),
(12, normal, blue)
}
I now want a function that makes a class for each list in $stylethemes and then puts the values of that list into that class. The output I want from the above list is this:
.theme1{
font-size: 15;
font-weight: bold;
color: red;
}
.theme2{
font-size: 12;
font-weight: normal;
color: blue;
}
Can anyone show me how I can do this? Thanks in advance.
The code to produce the desired results would look like this:
$stylethemes: (
(15, bold, red),
(12, normal, blue)
);
#for $i from 1 through length($stylethemes) {
.theme#{$i} {
font-size: nth(nth($stylethemes, $i), 1);
font-weight: nth(nth($stylethemes, $i), 2);
color: nth(nth($stylethemes, $i), 3);
}
}
However, you'll find this isn't particularly flexible. You're better off using mappings for the property/values so that you don't have to guarantee a specific order:
$stylethemes: (
(font-size: 15, font-weight: bold, color: red),
(font-size: 12, font-weight: normal, color: blue)
);
#for $i from 1 through length($stylethemes) {
.theme#{$i} {
#each $prop, $val in nth($stylethemes, $i) {
#{$prop}: $val;
}
}
}
Or
$stylethemes: (
theme1: (font-size: 15, font-weight: bold, color: red),
theme2: (font-size: 12, font-weight: normal, color: blue)
);
#each $theme, $properties in $stylethemes {
.#{$theme} {
#each $prop, $val in $properties {
#{$prop}: $val;
}
}
}
Youa re basically asking us to solve your pboelm, but fine, since SASS is very deep and fun to use and can be a bit daunting with its lack of map looping functions. I changed a couple of things but this is essentially it:
// first off, I decided to make your style themes a SASS map. This is useful because your
// your theme will be intricately linked to its name, making it easier to read
// you could to the same with the values, but for now I'll count them.
$stylethemes: (
theme-1 : (15, bold, red),
theme-2 : (12, normal, blue)
);
// first, we need to create a regular list we can loop through with a for loop
// map-keys returns a list we can use for that
$allthemes : map-keys($stylethemes);
// then we can run through all the themes by finding the theme name from the above list
#for $var from 1 through length($allthemes) {
// heres how we get the theme name
$theme : nth($allthemes, $var);
// heres how we get the values stored in your SASS map
$this : map-get($stylethemes, $theme);
// then I assign all your variables to vars, but its not necessary
$size : nth($this, 1);
$style : nth($this, 2);
$color : nth($this, 3);
// now print the theme name as a classname
.#{$theme}{
// then print the values - you could also use the above nth($this, n) to get them.
font-size: $size;
font-weight: $style;
color: $color;
}
}
I got all the function info from the SASS documentation site: http://sass-lang.com/documentation/Sass/Script/Functions.html, so have a look around there, there is a dedicated section for lists and maps. Have a look at lists and maps as they will be very useful for this kind of thing.