2
votes

Absolutely every single demo I've seen for creating an angular material theme involves the use of a pre-defined color palette (e.g. $mat-blue). I want to create a theme starting solely from HEX values. How can I do this? (Surely I'm not expected to start with my HEX values and somehow work backward to find the corresponding pallete in material's extremely limited predefined universe?!)

Here's an example of the HEX values I want to use: https://material.io/resources/color/#!/?view.left=0&view.right=1&primary.color=2C3E50&secondary.color=95a5a6&primary.text.color=ffffff&secondary.text.color=000000

Edit: for clarification, I know how to create custom themes using pre-defined colors supplied by angular-material (e.g. basing $primary off of $mat-blue), but what I want to be able to base $primary off of e.g. #2C3E50.

1
You may wanna take a look at this blog post. Explains everything you need to know to be able to create your own custom material themes. - atalantus
Yes, I already understood your question. What you need is to define a custom color palette with whatever color values you want as described in the medium article I gave you. See the Defining custom palette-section. - atalantus
@atalantus Thanks for the link, but it did not contain the detailed scss syntax I was looking for to go from HEX values to working themes. Those details are in the answer now provided. - Magnus

1 Answers

6
votes

Here's the workflow I settled on to get as close as possible to what I wanted to achieve.

First of all, make sure you know your scss fundamentals when attempting theming. If you don't know what these items and their syntax are (i.e. how they translate to css):

... then you need to first read the linked documentation. (They're not complicated and won't take long.) At the end of the day, angular themes are just scss maps of maps, so building them and accessing their contents just comes down to some scss know-how.

In angular material, you basically start with three choices of color to build your theme around: primary, accent, and warn. Suppose you choose the three colors #375a7f, #444444, and #eb0000 respectively. Go to this site and, for each color, name the palette (e.g. darkprimarymap) and input the HEX color into the menu like so:

enter image description here

... then click on View Code, select Angular 2, then copy and paste the code you see from something like this:

enter image description here

... into your theming file. An "out-of-the-box" theming file looks like this:

$app-dark-primary: mat-palette($mat-grey, 700, 300, 900);
$app-dark-accent: mat-palette($mat-blue-grey, 400);
$app-dark-warn: mat-palette($mat-red, 500);

$app-dark-theme: mat-dark-theme($app-dark-primary, $app-dark-accent, $app-dark-warn);

... where mat-palette is a function that accepts nested maps of the form we just copied. So paste the code we copied to create alternative palette variables like this:

@import '~@angular/material/theming';

// Create nested scss map
$dark-primary-map: (
  50: #e7ebf0,
  100: #c3ced9,
  200: #9badbf,
  300: #738ca5,
  400: #557392,
  500: #375a7f, // original primary color you built this map around
  600: #315277,
  700: #2a486c,
  800: #233f62,
  900: #162e4f,
  A100: #8bb8ff,
  A200: #5898ff,
  A400: #2579ff,
  A700: #0c69ff,
  contrast: (
    50: #000000,
    100: #000000,
    200: #000000,
    300: #000000,
    400: #ffffff,
    500: #ffffff,
    600: #ffffff,
    700: #ffffff,
    800: #ffffff,
    900: #ffffff,
    A100: #000000,
    A200: #000000,
    A400: #ffffff,
    A700: #ffffff
  )
);

$dark-accent-map: (
  50: #e9e9e9,
  100: #c7c7c7,
  200: #a2a2a2,
  300: #7c7c7c,
  400: #606060,
  500: #444444, // original accent color you built this map around
  600: #3e3e3e,
  700: #353535,
  800: #2d2d2d,
  900: #1f1f1f,
  A100: #f07a7a,
  A200: #eb4c4c,
  A400: #ff0505,
  A700: #eb0000,
  contrast: (
    50: #000000,
    100: #000000,
    200: #000000,
    300: #ffffff,
    400: #ffffff,
    500: #ffffff,
    600: #ffffff,
    700: #ffffff,
    800: #ffffff,
    900: #ffffff,
    A100: #000000,
    A200: #ffffff,
    A400: #ffffff,
    A700: #ffffff
  )
);

$dark-warn-map: (
  50: #fde0e0,
  100: #f9b3b3,
  200: #f58080,
  300: #f14d4d,
  400: #ee2626,
  500: #eb0000,  // original warn color you built this map around
  600: #e90000,
  700: #e50000,
  800: #e20000,
  900: #dd0000,
  A100: #ffffff,
  A200: #ffd1d1,
  A400: #ff9e9e,
  A700: #ff8585,
  contrast: (
    50: #000000,
    100: #000000,
    200: #000000,
    300: #ffffff,
    400: #ffffff,
    500: #ffffff,
    600: #ffffff,
    700: #ffffff,
    800: #ffffff,
    900: #ffffff,
    A100: #000000,
    A200: #000000,
    A400: #000000,
    A700: #000000
  )
);

// Convert maps into 'palettes'
$dark-primary-palette: mat-palette($dark-primary-map);
$dark-accent-palette: mat-palette($dark-accent-map);
$dark-warn-palette: mat-palette($dark-warn-map);

// Create 'theme' from palettes
$app-dark-theme: mat-dark-theme($dark-primary-palette, $dark-accent-palette, $dark-warn-palette);

You can of course manually create/edit these maps (which might be smart since the linked site makes simplistic extrapolations from your single-color input). If this code is in a file called dark-theme.scss, you then incorporate that theme into your angular app with this sort of syntax in your main/global styles.scss file:

@import '~@angular/material/theming';
@include mat-core();
@import 'themes/dark-theme.scss'; // imports $app-dark-theme

.dark-theme {
  @include angular-material-theme($app-dark-theme);
  @include custom-components-theme($app-dark-theme);
}

Now, when you color a material component with the color="primary" directive on this theme, it will get colored as #375a7f, and so on.

To pull other colors out of these palettes for use in your app in customized components, you use this sort of syntax in a app.component.scss-theme.scss file:

@import '~@angular/material/theming';

// Define scss mixin that takes a $theme map and injects its content 
// into css styles; we'll inject our $app-dark-theme here later
@mixin app-component-theme($theme) {
  // Get the primary, secondary and warn palettes 
  // you created back from the active theme using the map-get() function
  $primary: map-get($theme, primary);
  $accent: map-get($theme, accent);
  $warn: map-get($theme, warn);

  // Extract colors from those palettes using the mat-color() function
  // E.g. use the 'darker' input to get the color keyed by '700'
  $color1: mat-color($primary, darker);

  // E.g. use 'A100' to get the color keyed by 'A100' (A = Additional I think)
  $color2: mat-color($primary, A100);

  // E.g. use 'A100-contrast' to get the color keyed by 'A100' within the contrast sub-map
  $color3: mat-color($primary, A100-contrast);

  // Then use these color-value variables as per normal scss. E.g.
  mat-sidenav-container {
      background: $color1;
    mat-toolbar {
      background-color: $color2;
      mat-list{
        background-color: $color3;
      }
    }
  }
}

... then incorporate all such custom-component themes into your main/global styles.scss file like so:

@import 'component.scss-theme';

// Define custom component themes
@mixin custom-components-theme($theme) {
  @include app-component-theme($theme);
}