SASS-only Material Angular 2 Palette generator (2025 Update)

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.

mat-palette-gen.scss
@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;
  }
}

Read more

Angular 20 SSR with AWS CDK v2

In this article we’re going to set up an Angular 20 web application with server-side rendering, using AWS Lambda and Cloudfront to serve it, and AWS CDK v2 to manage the infrastructure.

If you’re reading this, I’m assuming that you know how CDK and Angular work. I’m not going to explain in detail how to set up your projects.

The CDK Construct

Create a CDK application wherever you want. I usually create a folder within my Angular project, called aws or infrastructure.

Now create a new file in the lib folder called angular-ssr.ts (or whatever you want) and put this code in it.

TypeScript
import {CfnOutput} from 'aws-cdk-lib';
import {Code, Function, FunctionUrl, FunctionUrlAuthType, HttpMethod, Runtime} from 'aws-cdk-lib/aws-lambda';
import {Construct} from 'constructs';
import {Certificate} from 'aws-cdk-lib/aws-certificatemanager';
import {
  CachePolicy,
  Distribution,
  OriginRequestPolicy,
  PriceClass,
  ViewerProtocolPolicy
} from 'aws-cdk-lib/aws-cloudfront';
import {FunctionUrlOrigin} from 'aws-cdk-lib/aws-cloudfront-origins';

export interface AngularSSRProps {
  /**
   * Used to comment the Cloudfront distribution
   */
  appName?: string;
  /**
   * If set, the Cloudfront distribution will have custom domains and an SSL certificate.
   * The certificate domains must cover the domains specified in `domainNames`.
   */
  certificate?: Certificate;
  /**
   * If set, the Cloudfront distribution will have custom domains.
   * For this to work, you must specify a `certificate` as well.
   */
  domainNames?: string[];
}

export class AngularSSR extends Construct {

  public distribution: Distribution;
  public lambdaUrl: FunctionUrl;
  public ssrLambda: Function;

  constructor(scope: Construct, id: string, props: AngularSSRProps) {
    super(scope, id);

    this.ssrLambda = new Function(this, 'WebsiteSSRLambda', {
      // Adjust this if it's outdated
      runtime: Runtime.NODEJS_22_X,
      handler: 'index.handler',
      // We'll create this file later, change path if needed
      code: Code.fromAsset(`./assets/ssr-lambda`),
      // Adjust to your project needs
      memorySize: 1024
    });

    this.lambdaUrl = this.ssrLambda.addFunctionUrl({
      authType: FunctionUrlAuthType.NONE,
      cors: {
        allowedOrigins: [
          'https://localhost:4200',
          ...(props.domainNames?.map(d => `https://${d}`) ?? []),
        ],
        allowedMethods: [HttpMethod.GET],
        allowCredentials: true,
        allowedHeaders: ["*"]
      }
    });

    this.distribution = new Distribution(this, 'WebsiteSSRDistribution', {
      certificate: props.certificate,
      domainNames: props.domainNames,
      defaultBehavior: {
        origin: new FunctionUrlOrigin(this.lambdaUrl),
        viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
        originRequestPolicy: OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER,
        cachePolicy: CachePolicy.CACHING_OPTIMIZED
      },
      priceClass: PriceClass.PRICE_CLASS_ALL,
      comment: props.appName,
      errorResponses: [
        {httpStatus: 403, responseHttpStatus: 200, responsePagePath: '/index.html'},
        {httpStatus: 404, responseHttpStatus: 200, responsePagePath: '/index.html'}
      ]
    });

    new CfnOutput(this, 'ClientLambdaURL', {value: this.lambdaUrl.url});
    new CfnOutput(this, 'DistributionID', {value: this.distribution.distributionId});
  }

}

Some remarks on this code

  • Line 51: I’ve included https://localhost:4200 in the allowedOrigins property. This is only useful for debug purposes if you also plan to include additional API endpoints in your lambda, but it won’t be covered here.
  • Line 52: This line maps the domains array we’ll be using later, and adds “https://” to each of them, so that they can be used by CORS headers. If you also need old fashioned “http://“, you don’t.

Read more

RxJS 6 Patterns with Angular Material: Refresh Button

RxJS + Angular + Material

In this article, we’ll be looking at a very simple RxJS 6 pattern that allows us to easily refresh data coming from REST APIs (or any other async data source).

In Angular, we’ll be using a service to handle most of the work, including the data fetching and the refresh logic.

Let’s look at a mock service that we’ll be using to fetch some data from a REST API.

TypeScript
export class MockService {

  refresh$ = new ReplaySubject(1);
  data$: Observable<SomeDataType>;

  constructor(private http: HttpClient) {

    this.refresh();

    this.data$ = this.refresh$.pipe(
      switchMap(() => this.getData()),
      share()
    );
  }

  refresh() {
    this.refresh$.next();
  }

  // This one could also be private
  getData(): Observable<SomeDataType> {
    return this.http.get<SomeDataType>(`url`);
  }
}

Read more

RxJS 6 Patterns with Angular Material: Confirmation Dialog

RxJS + Angular + Material

Intro

This basic pattern applies to RxJS 6 in combination with Angular Material. However, it can be applied to any other environment that supports RxJS 6, as long as you have an observable-based dialog implementation.

Desired behaviour

  1. A user clicks on a button
  2. A confirmation dialog is shown
  3. If the user confirms, an action is performed

Read more

SASS-only Material Angular Palette generator

SASS Material Angular Palette Generator

OUTDATED!! Click here for the 2025 updated version: SASS-only Material Angular 2 Palette generator (2025 Update)

With my job, I often need to replicate projects from a template based on Angular Material. When I do that, one of the first things that I usually need to change is the color scheme.

Angular Material’s color scheme is defined by two palettes: primary and accent. These two palettes define a range of colors used by all components.

There are many tools available online to generate such palettes. My personal favourite is Material Design Color Generator (also available on GitHub). This tool includes a code generator that automatically creates a SASS list in Angular Material’s accepted format.

I based my SASS color palette generator on Mikel Bitson‘s code. This is a simple SASS translation that makes it easier to adjust colors directly from your code. 

Read more

Unique random coupon code generation in PHP

Generating pseudo random codes is usually a trivial task. However, coupon codes should have two features that make them computationally complex:

  • They have to be unique
  • They should be hard to guess

A third optional feature would be readability. This means that the final user should not be thinking “is this 0 or O?“.

I found the problem intriguing and decided to make my personal implementation of a coupon code generator in PHP.

Read more

Google’s Codebase Insight: great for small businesses?

The 2015 edition of @Scale featured an extremely interesting insight on how Google handles its codebase.

I won’t repeat what is so clearly explained in the video. Instead, I would like to focus on its potential viability for very small companies.

Indeed, sky high numbers like Google’s require a huge effort in tooling, standardization and definition of constraints and procedures. As a result, similar companies willing to unify their codebase would generally consider it unpractical.

However, I believe that a monolithic codebase could be a huge improvement in efficiency and reliability for small software houses, for several reasons.

 

#1: Organization

Small companies tend to have little to no policies in terms of repositories, code quality, conventions, etc. Thus, code improvements, modifications, copies, versions, docs and changelogs have a tendency to scatter around company systems, personal computers and the internet. If there is one repository, then everything can be kept together and under control.

#2: Code reuse

That’s pretty much the same for Google. You write code once and then use it across multiple softwares. However, in small companies code reuse can become a nightmare (see versions fragmentation, unmerged customizations,…). With little to no policies, versions can even be lost on some hard disk placed somewhere. A unified codebase may help keeping things tidy.

#3: Everyone knows everything

In small companies, that’s quite common as well. The team is small and everyone knows what the others are doing, even if they’re working on different projects. In a collaborative environment, one repository facilitates code browsing and shortens times to access snippets and functions. Changes and improvements to shared codes and services can be discussed together and implemented, without requiring huge investments on tools.

#4: You can always detach projects

If things are going well and the company quickly scales up, you always have the option to detach projects from the main repository. This is obviously a choice that can be either great or terribly wrong depending on the context. However, it is always good to know that you have an “emergency button”.

 

CONCLUSION

Small companies that cannot invest in the definition of software developement processes may benefit from a monolithic codebase like Google’s. It helps keeping things organized and accessible while leaving the option to adopt a different strategy when things get more complex. As always, it’s a decision that needs to be evaluated in its context of application, but I believe it’s worth considering.

An easy and maintainable implementation of IsolatedStorageSettings

Recently I’ve been working on a Windows Phone app that comes with a good number of settings to implement. The official examples that anyone can find online report a simple procedure. Let’s say I want to implement the UserToken setting, then I would have to do something like this: [code language=”csharp”] // Access the settings … Read more