This is an updated version of my old article SASS-only Material Angular Palette generator published in 2020. It’s updated to be compatible with Angular 18+ and Material 2.
@use 'sass:math';
@use 'sass:map';
@use 'sass:color';
$values: (50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A700);
@mixin _output-palette-variables($map, $prefix) {
@each $key, $value in $map {
@if ($value) {
@if ($key == 'contrast') {
@include _output-palette-variables($value, '#{$prefix}-contrast');
} @else {
--#{$prefix}-#{$key}: #{$value};
}
}
}
}
@function createPalette($color) {
$white: #fff;
$black: #000;
$baseDark: multiply($color, $color);
$palette: (
50 : color.mix($color, $white, 12%),
100 : color.mix($color, $white, 30%),
200 : color.mix($color, $white, 50%),
300 : color.mix($color, $white, 70%),
400 : color.mix($color, $white, 85%),
500 : color.mix($color, $white, 100%),
600 : color.mix($color, $baseDark, 87%),
700 : color.mix($color, $baseDark, 70%),
800 : color.mix($color, $baseDark, 54%),
900 : color.mix($color, $baseDark, 25%),
A100: color.adjust(color.mix($black, $baseDark, 15%), $lightness: 65%, $saturation: 80%),
A200: color.adjust(color.mix($black, $baseDark, 15%), $lightness: 55%, $saturation: 80%),
A400: color.adjust(color.mix($black, $baseDark, 15%), $lightness: 45%, $saturation: 100%),
A700: color.adjust(color.mix($black, $baseDark, 15%), $lightness: 40%, $saturation: 100%),
);
$contrast: ();
@each $v in $values {
$contrast: map.merge($contrast, ($v: getContrast(map.get($palette, $v))))
}
$palette: map.merge($palette, (contrast: $contrast));
@return $palette;
}
@function multiply($rgb1, $rgb2) {
$r: math.floor(math.div(color.channel($rgb1, "red", $space: rgb) * color.channel($rgb2, "red", $space: rgb), 255));
$g: math.floor(math.div(color.channel($rgb1, "green", $space: rgb) * color.channel($rgb2, "green", $space: rgb), 255));
$b: math.floor(math.div(color.channel($rgb1, "blue", $space: rgb) * color.channel($rgb2, "blue", $space: rgb), 255));
@return rgb($r, $g, $b);
}
@function getBrightness($color) {
@return math.div(color.channel($color, "red", $space: rgb) * 299 + color.channel($color, "green", $space: rgb) * 587 + color.channel($color, "blue", $space: rgb) * 114, 1000);
}
@function isLight($color) {
@return getBrightness($color) >= 128;
}
@function getContrast($color) {
@if isLight($color) {
@return #000;
} @else {
@return #fff;
}
}