Skip to content

Instantly share code, notes, and snippets.

@JaimeStill
Last active August 9, 2021 16:37
Show Gist options
  • Save JaimeStill/cf493072394d10cecf33ff6fb1fdcfcb to your computer and use it in GitHub Desktop.
Save JaimeStill/cf493072394d10cecf33ff6fb1fdcfcb to your computer and use it in GitHub Desktop.
Angular 12 Theming Overhaul
@use 'sass:map';
@use '~@angular/material' as mat;
@function get-palette($light: true) {
$palette: (
"red": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$red-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$red-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$red-palette, if($light, 500, A200))
),
"pink": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$pink-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$pink-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$pink-palette, if($light, 500, A200))
),
"purple": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$purple-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$purple-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$purple-palette, if($light, 500, A200))
),
"deep-purple": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$deep-purple-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$deep-purple-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$deep-purple-palette, if($light, 500, A200))
),
"indigo": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$indigo-palette, if($light, A700, A200)),
"color": mat.get-color-from-palette(mat.$indigo-palette, if($light, A700, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$indigo-palette, if($light, A700, A200))
),
"blue": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$blue-palette, if($light, 500, 300)),
"color": mat.get-color-from-palette(mat.$blue-palette, if($light, 500, 300)),
"contrast": mat.get-contrast-color-from-palette(mat.$blue-palette, if($light, 500, 300))
),
"light-blue": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$light-blue-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$light-blue-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$light-blue-palette, if($light, 500, A200))
),
"cyan": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$cyan-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$cyan-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$cyan-palette, if($light, 500, A200))
),
"teal": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$teal-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$teal-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$teal-palette, if($light, 500, A200))
),
"green": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$green-palette, A700),
"color": mat.get-color-from-palette(mat.$green-palette, A700),
"contrast": mat.get-contrast-color-from-palette(mat.$green-palette, A700)
),
"light-green": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$light-green-palette, if($light, A700, A400)),
"color": mat.get-color-from-palette(mat.$light-green-palette, if($light, A700, A400)),
"contrast": mat.get-contrast-color-from-palette(mat.$light-green-palette, if($light, A700, A400))
),
"lime": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$lime-palette, if($light, 700, A200)),
"color": mat.get-color-from-palette(mat.$lime-palette, if($light, 700, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$lime-palette, if($light, 700, A200))
),
"yellow": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$yellow-palette, if($light, 500, A400)),
"color": mat.get-color-from-palette(mat.$yellow-palette, if($light, 500, A400)),
"contrast": mat.get-contrast-color-from-palette(mat.$yellow-palette, if($light, 500, A400))
),
"amber": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$amber-palette, if($light, 500, A400)),
"color": mat.get-color-from-palette(mat.$amber-palette, if($light, 500, A400)),
"contrast": mat.get-contrast-color-from-palette(mat.$amber-palette, if($light, 500, A400))
),
"orange": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$orange-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$orange-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$orange-palette, if($light, 500, A200))
),
"deep-orange": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$deep-orange-palette, if($light, 500, A200)),
"color": mat.get-color-from-palette(mat.$deep-orange-palette, if($light, 500, A200)),
"contrast": mat.get-contrast-color-from-palette(mat.$deep-orange-palette, if($light, 500, A200))
),
"brown": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$brown-palette, if($light, 500, 300)),
"color": mat.get-color-from-palette(mat.$brown-palette, if($light, 500, 300)),
"contrast": mat.get-contrast-color-from-palette(mat.$brown-palette, if($light, 500, 300))
),
"gray": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$gray-palette, if($light, 700, 300)),
"color": mat.get-color-from-palette(mat.$gray-palette, if($light, 700, 300)),
"contrast": mat.get-contrast-color-from-palette(mat.$gray-palette, if($light, 700, 300))
),
"blue-gray": (
"theme": if($light, 'light', 'dark'),
"palette": mat.define-palette(mat.$blue-gray-palette, if($light, 700, 300)),
"color": mat.get-color-from-palette(mat.$blue-gray-palette, if($light, 700, 300)),
"contrast": mat.get-contrast-color-from-palette(mat.$blue-gray-palette, if($light, 700, 300))
)
);
$palette: map.set($palette, "primary", map.get($palette, "blue"));
$palette: map.set($palette, "accent", map.get($palette, "blue-gray"));
$palette: map.set($palette, "warn", map.get($palette, "red"));
@return $palette;
}
@function get-theme($palette) {
@return (
color: (
"primary": get-theme-palette($palette, "primary"),
"accent": get-theme-palette($palette, "accent"),
"warn": get-theme-palette($palette, "warn")
)
);
}
@function get-theme-palette($palette, $color) {
@return map.get(map.get($palette, $color), "palette");
}
@function get-theme-color($palette, $color) {
@return map.get(map.get($palette, $color), "color");
}
@function get-theme-contrast($palette, $color) {
@return map.get(map.get($palette, $color), "contrast");
}
.bold {
font-weight: bold;
}
.italic {
font-style: italic;
}
.pre-wrap {
white-space: pre-wrap;
}
.sticky-top {
position: sticky;
top: 0;
}
.sticky-right {
position: sticky;
right: 0;
}
.sticky-bottom {
position: sticky;
bottom: 0;
}
.sticky-left {
position: sticky;
left: 0;
}
.overflow {
overflow: auto;
}
.overflow-x {
overflow-x: auto;
}
.overflow-y {
overflow-y: auto;
}
.no-resize {
resize: none!important;
}
.resize {
resize: both!important;
}
.resize-horizontal {
resize: horizontal!important;
}
.resize-vertical {
resize: vertical!important;
}
.cursor-pointer {
cursor: pointer!important;
}
.cursor-default {
cursor: default!important;
}
.backdropped {
transition: backdrop-filter 100ms ease-in;
}
.rounded {
border-radius: 4px;
}
.rounded-right {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.rounded-left {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.rounded-top {
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
.rounded-bottom {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
.clip-top {
clip-path: inset(0, -5px, -5px, -5px);
}
.clip-right {
clip-path: inset(-5px, 0, -5px, -5px);
}
.clip-bottom {
clip-path: inset(-5px, -5px, 0, -5px);
}
.clip-left {
clip-path: inset(-5px, -5px, -5px, 0);
}
.no-outline {
outline: 0;
}
.text-align-center {
text-align: center;
}
@for $i from 0 through 24 {
.p#{$i} {
padding: #{$i}px!important;
}
.px#{$i} {
padding-left: #{$i}px!important;
padding-right: #{$i}px!important;
}
.py#{$i} {
padding-top: #{$i}px!important;
padding-bottom: #{$i}px!important;
}
.pt#{$i} {
padding-top: #{$i}px!important;
}
.pr#{$i} {
padding-right: #{$i}px!important;
}
.pb#{$i} {
padding-bottom: #{$i}px!important;
}
.pl#{$i} {
padding-left: #{$i}px!important;
}
.m#{$i} {
margin: #{$i}px!important;
}
.mx#{$i} {
margin-left: #{$i}px!important;
margin-right: #{$i}px!important;
}
.my#{$i} {
margin-top: #{$i}px!important;
margin-bottom: #{$i}px!important;
}
.mt#{$i} {
margin-top: #{$i}px!important;
}
.mr#{$i} {
margin-right: #{$i}px!important;
}
.mb#{$i} {
margin-bottom: #{$i}px!important;
}
.ml#{$i} {
margin-left: #{$i}px!important;
}
}
@use 'sass:map';
@use '~@angular/material' as mat;
div[class*="app-light"] snack-bar-container.mat-snack-bar-container.snacker {
background-color: #ffffff!important;
}
div[class*="app-light"] simple-snack-bar.mat-simple-snackbar,
div[class*="app-light"] .snacker div.mat-simple-snackbar-action {
color: #3e3e3e;
}
div[class*="app-dark"] snack-bar-container.mat-snack-bar-container.snacker {
background-color: #3e3e3e!important;
}
div[class*="app-dark"] simple-snack-bar.mat-simple-snackbar,
div[class*="app-dark"] .snacker div.mat-simple-snackbar-action {
color: #e1e1e1;
}
@mixin style-snacker($palette) {
@each $key, $value in $palette {
div[class*="app-#{map.get($value, 'theme')}"] .snacker-#{$key} simple-snack-bar.mat-simple-snackbar {
color: map.get($value, 'color');
}
}
}
@use '~@angular/material' as mat;
@for $i from 0 through 12 {
.el-#{$i} {
@include mat.elevation($i);
}
}
.elevated {
@include mat.elevation-transition;
@include mat.elevation(2);
&:hover {
@include mat.elevation(4);
}
}
@use 'sass:map';
@use '~@angular/material' as mat;
@mixin style-glow($palette) {
@each $key, $value in $palette {
@for $i from 1 through 24 {
.glow-#{$i}-#{$key} {
@include mat.elevation($i, map.get($value, "color"));
}
}
.glow-#{$key} {
@include mat.elevation-transition;
@include mat.elevation(4, map.get($value, "color"));
&:hover {
@include mat.elevation(8, map.get($value, "color"));
}
}
}
}
* {
box-sizing: border-box;
}
body {
overflow: hidden;
margin: 0;
padding: 0;
height: 100vh;
font-family: Roboto, "Helvetica Neue", sans-serif;
}
.full-height {
height: 100%;
}
.min-full-height {
min-height: 100%;
}
.app-frame {
height: 100%;
}
.app-container {
overflow: auto;
height: calc(100% - 84px);
}
.docs-container {
overflow: auto;
height: 100%;
}
section.toolbar-container {
height: calc(100% - 84px);
}
section.scroll-container {
height: 100%;
overflow: auto;
}
.scrollable {
overflow: auto;
}
table.docs-table {
margin: 4px 4px 12px;
th, td {
padding: 4px;
}
}
mat-toolbar.mat-toolbar mat-form-field.mat-form-field {
font-size: 12px;
label.mat-form-field-label {
font-weight: bold;
}
}
mat-toolbar.mat-toolbar.app-toolbar {
padding: 0 8px;
.header-font,
.header-font:visited {
font-family: 'mandalore-halftone-italic';
font-size: 48px;
margin: 12px 12px 12px 0;
}
button.mat-icon-button,
mat-form-field.mat-form-field {
margin: 0 8px 0 0;
}
button.mat-stroked-button {
margin: 0 4px;
}
button.mat-stroked-button:first-child {
margin-left: 8px;
}
span.header {
margin-right: 24px;
}
}
nav.mat-tab-nav-bar.wrapped div.mat-tab-links {
flex-wrap: wrap;
}
nav.mat-tab-nav-bar.scrolled {
white-space: nowrap;
overflow: auto;
div.mat-tab-links {
display: block;
}
}
a.mat-tab-link,
mat-tab.mat-tab {
min-width: 80px;
}
mat-tab-group.mat-tab-group.flexible div.mat-tab-labels {
display: flex;
flex-direction: row;
align-items: stretch;
justify-items: space-evenly;
div.mat-tab-label {
flex-grow: 1;
flex-basis: auto;
min-width: 0;
}
}
nav.mat-tab-nav-bar.flexible div.mat-tab-links {
display: flex;
flex-direction: row;
align-items: stretch;
justify-items: space-evenly;
a.mat-tab-link {
flex-grow: 1;
flex-basis: auto;
min-width: 0;
}
}
button.mat-icon-button.small {
height: 36px;
width: 36px;
line-height: 36px;
mat-icon.mat-icon {
transform: scale(0.8);
}
}
.mat-menu-panel.app-menu {
width: 180px;
}
@media (min-width: 0) and (max-width: 599px) {
.app-container {
height: calc(100% - 76px);
}
.section.toolbar-container {
height: calc(100% - 76px);
}
}
@use 'sass:map';
@use '~@angular/material' as mat;
@use './palette.scss';
@import './glow.scss';
@import './snacker.scss';
@mixin style-theme($theme, $palette) {
$config: mat.get-color-config($theme);
$b: map.get($config, background);
$f: map.get($config, foreground);
$background: mat.get-color-from-palette($b, background);
$card: mat.get-color-from-palette($b, card);
$app-bar: mat.get-color-from-palette($b, app-bar);
$status-bar: mat.get-color-from-palette($b, status-bar);
$hover: mat.get-color-from-palette($b, hover);
$tooltip: mat.get-color-from-palette($b, tooltip);
$dialog: mat.get-color-from-palette($b, dialog);
$base: mat.get-color-from-palette($f, base);
$text: mat.get-color-from-palette($f, text);
$icon: mat.get-color-from-palette($f, icon);
$hint: mat.get-color-from-palette($f, hint);
$divider: mat.get-color-from-palette($f, divider);
$disabled-button: mat.get-color-from-palette($f, disabled-button);
$disabled-text: mat.get-color-from-palette($f, disabled-text);
.background-default,
.background-card {
background-color: $card!important;
}
.background-app-bar {
background-color: $app-bar!important;
}
.background-stacked {
background-color: $background!important;
}
.background-inverted {
background-color: $text!important;
color: $background!important;
}
.card-outline {
border: 1px solid $text!important;
}
.card-outline-divider {
border: 1px solid $divider!important;
}
.color-text {
color: $text!important;
}
a.mat-list-item,
a.mat-list-item:visited,
a.mat-tab-link,
a.mat-tab-link:visited,
a.mat-menu-item,
a.mat-menu-item:visited,
a.mat-icon-button,
a.mat-icon-button:visited {
color: $text;
}
mat-paginator.mat-paginator {
background-color: $background;
}
div.cdk-overlay-pane mat-dialog-container.mat-dialog-container mat-paginator.mat-paginator {
background-color: $dialog;
}
a,
a.mat-list-item.active,
a.mat-menu-item.active,
a.mat-icon-button.active,
a.mat-tab-link.active {
color: palette.get-theme-color($palette, "primary");
}
a:visited {
color: palette.get-theme-color($palette, "warn");
}
blockquote.docs-quote {
margin: 4px 4px 12px;
padding: 4px;
padding-left: 24px;
border-left: 3px solid palette.get-theme-color($palette, "primary");
p {
margin: 0;
}
}
button.mat-stroked-button:disabled,
a.mat-stroked-button:disabled {
border-color: $disabled-button;
color: $disabled-text!important;
}
mat-toolbar.mat-toolbar.app-toolbar {
.header-font,
.header-font:visited {
text-decoration: none;
color: $text;
}
}
@each $key, $value in $palette {
.background-#{$key} {
background-color: map.get($value, "color")!important;
color: map.get($value, "contrast")!important;
}
.card-outline-#{$key} {
border: 1px solid;
border-color: map.get($value, "color")!important;
}
.color-#{$key},
code.#{$key} {
color: map.get($value, "color")!important;
}
mat-divider.mat-divider.#{$key} {
border-color: map.get($value, "color");
}
mat-toolbar.mat-toolbar.app-toolbar.mat-#{key} {
.header-font,
.header-font:visited,
a.mat-icon-button,
a.mat-icon-button:visited {
color: map.get($value, "contrast");
}
}
}
@include style-glow($palette);
@include style-snacker($palette);
}
@use '~@angular/material' as mat;
@use './palette.scss';
@include mat.core();
@import '~@fortawesome/fontawesome-free/css/all.css';
@import '~roboto-fontface/css/roboto/roboto-fontface.css';
@import './elevation.scss';
@import './icons.scss';
@import './layout.scss';
@import './styles.scss';
@import './typography.scss';
@import './utility.scss';
$light-palette: palette.get-palette();
$light-theme: mat.define-light-theme(palette.get-theme($light-palette));
.prism-theme {
@import '~prism-themes/themes/prism-material-light';
}
@include style-theme($light-theme, $light-palette);
@include mat.all-component-themes($light-theme);
.app-dark {
$dark-palette: palette.get-palette(false);
$dark-theme: mat.define-dark-theme(palette.get-theme($dark-palette));
.prism-theme {
@import '~prism-themes/themes/prism-material-dark';
}
@include style-theme($dark-theme, $dark-palette);
@include mat.all-component-colors($dark-theme);
}
import {
Component,
Input
} from '@angular/core';
@Component({
selector: 'indicator',
templateUrl: 'indicator.component.html'
})
export class IndicatorComponent {
@Input() tooltip: string = 'indicator';
@Input() color: string = 'warn';
@Input() margin: string = 'm4';
@Input() size: number = 8;
styles = () => `background-${this.color} ${this.margin}`;
}
<div [matTooltip]="tooltip"
[class]="styles()"
[style.border-radius.%]="50"
[style.width.px]="size"
[style.height.px]="size"></div>
import {
Component,
Input
} from '@angular/core';
@Component({
selector: 'themed-card',
templateUrl: 'themed-card.component.html'
})
export class ThemedCardComponent {
@Input() heading: string = 'Heading';
@Input() body: string = 'Some descriptive text.';
@Input() color: string = 'primary';
@Input() size: number = 328;
cardClass = () => `rounded elevated m4 card-outline-${this.color}`;
headerClass = () => `background-${this.color}`;
bodyClass = () => `my8 color-${this.color}`;
}
<section fxLayout="column"
fxLayoutAlign="start stretch"
[class]="cardClass()"
[style.width.px]="size">
<section fxLayout="row"
fxLayoutAlign="space-between center"
[class]="headerClass()">
<p class="m8 mat-subheading-2">{{heading}}</p>
</section>
<section fxLayout="column"
fxLayoutAlign="start stretch"
class="p8">
<p [class]="bodyClass()">{{body}}</p>
<mat-divider [class]="color"></mat-divider>
<ng-content></ng-content>
</section>
</section>
import { Component } from '@angular/core';
@Component({
selector: 'theme-overhaul-route',
templateUrl: 'theme-overhaul.route.html'
})
export class ThemeOverhaulRoute {
colors: string[] = [
'primary', 'accent', 'warn',
'red', 'pink', 'purple', 'deep-purple',
'indigo', 'blue', 'light-blue', 'cyan',
'teal', 'green', 'light-green', 'lime',
'yellow', 'amber', 'orange', 'deep-orange',
'brown', 'gray', 'blue-gray'
];
color: string = 'primary';
}
<section fxLayout="column"
fxLayoutAlign="start start"
class="p8">
<mat-form-field>
<mat-label>Color</mat-label>
<mat-select [(ngModel)]="color">
<mat-option *ngFor="let c of colors"
[value]="c">{{c}}</mat-option>
</mat-select>
</mat-form-field>
<themed-card [color]="color">
<section fxLayout="row | wrap"
fxLayoutAlign="start start"
class="pt8">
<indicator *ngFor="let color of colors"
margin="m8"
[tooltip]="color"
[color]="color"
[size]="12"></indicator>
</section>
</themed-card>
</section>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment