npm package: @rb-mwindh/ngx-theme-manager
Description: Angular component to switch between different theming stylesheets
Author: Markus Windhager
Latest version: 5.0.1

# ngx-theme-manager

`@rb-mwindh/ngx-theme-manager` provides the basics tools for a robust theme-switcher implementation.

This package does not provide ready-made visual components,
but only supports their implementation by providing the necessary services and tools.

---
![sponsors](https://img.shields.io/github/sponsors/rb-mwindh)
![License](https://img.shields.io/github/license/rb-mwindh/ngx-theme-manager?color=blue)
![latest release](https://img.shields.io/github/v/release/rb-mwindh/ngx-theme-manager?color=brightgreen)

![open issues](https://img.shields.io/github/issues/rb-mwindh/ngx-theme-manager?color=red)
![open pr](https://img.shields.io/github/issues-pr/rb-mwindh/ngx-theme-manager?color=orange)

![nodejs](https://img.shields.io/node/v/@rb-mwindh/ngx-theme-manager?color=lightgray&logo=nodedotjs)
![angular](https://img.shields.io/npm/dependency-version/@rb-mwindh/ngx-theme-manager/peer/@angular/core?color=lightgray&logo=angular)

* [API Docs](https://rb-mwindh.github.io/ngx-theme-manager)
* [Demo](https://ngx-theme-manager.vercel.app/)

---

## Table of Contents <!-- omit in toc -->

- [How it works](#how-it-works)
- [Getting Started](#getting-started)
- [Building and Testing](#building-and-testing)
- [Contribution Guidelines](#contribution-guidelines)
- [Get help](#get-help)
- [About](#about)
  - [Maintainers](#maintainers)
  - [Contributors](#contributors)
  - [3rd Party Licenses](#3rd-party-licenses)
  - [Used Encryption](#used-encryption)
  - [License](#license)

## How it works

This implementation is based on the regular way Angular loads styles for components.
Since theme styles are usually global styles, theme components will normally use `ViewEncapsulation.None`.

Since Angular does not provide a direct way to access the `<style>` element associated with a component,
the `@rb-mwindh/ngx-theme-manager` applies a little trick:
Style elements provided as themes should carry annotations in the form of [predefined CSS comments](#known-annotations).
These annotations are searched throughout all `<style>` elements of the application using regular expressions
and are registered in the theme registry. Also, an additional attribute (`data-theme="<id>"`) is added to the
corresponding style elements, which is used as a query selector.

Hereafter, the ThemeService leverages the [`media` attribute][selfhtml:media] to enable or disable the styles of a theme.
For inactive themes, the `media="none"` attribute is added to the associated `<style>` element. For active themes,
the `media` attribute of the associated `<style>` element is simply removed again.

## Getting Started

### Install the package

```shell
npm install ngx-theme-manager --save
```

### Implement your theme stylesheets

`@rb-mwindh/ngx-theme-manager` identifies your stylesheets (css/scss/...) as themes through annotations
in css comments. To prevent your annotations from being disposed at build time
by minification, you should use the css comment format `/*! ... */`.

> ... By default, multi-line comments be stripped from the compiled CSS
> in compressed mode. **If a comment begins with /*!, though, it will
> always be included in the CSS output.** ...
> 
> _from https://sass-lang.com/documentation/syntax/comments_

Known annotations are:
- `@@id` - required, any character until end-of-line
- `@@displayName` - optional, defaults to `<@@id>`, any character until end-of-line
- `@@description` - optional, any character until end-of-line
- `@@default` - optional, no value, value is `true` when given, or `false` when omitted

```scss
/*!
 * @@id my-theme-id
 * @@displayName My Fantastic Theme
 * @@description This is my fantastic theme with magic colors
 * @@default
 */

// add all your theme styles below this line, e.g.
@import "@angular/material/prebuilt-themes/indigo-pink.css";
@import "some-other-library/theme.css";
```

### Loading your theme stylesheets

By using an Angular component to load your stylesheets, you make the
Angular compiler pick up and compile your stylesheets automatically.

```typescript
@Component({
  selector: 'app-themes',
  template: '', // no template needed
  styleUrls: [
    'assets/themes/theme-a.scss',
    'assets/themes/theme-b.scss',
    'assets/themes/theme-c.scss',
  ], // load all theme stylesheets here
  encapsulation: ViewEncapsulation.None, // make the styles global
})
export class AppThemesComponent { /* no implementation needed */ }
```

This way, loading the theme stylesheets is easily done by using
your AppThemesComponent, preferably at the top of your AppComponent.

```typescript
@Component({
  selector: 'app-root',
  template: `
    <app-themes></app-themes>
    
    <!-- you app template here -->
  `,
})
export class AppComponent() { ... }
```

### Implement your theme-picker component

The desired look-and-feel of your visual theme-picker component usually is very
specific for the respective project. Thus, I've decided not to implement any
visual stuff, but instead provide you with the required data.

Assuming, you've implemented a theme picker component named `app-theme-picker`,
you would provide it with the available themes, the current theme and a
theme selection callback like this:

```typescript
@Component({
  selector: 'app-root',
  template: `
    <app-theme-picker
      [themes]="themeService.themes$ | async"
      [currentTheme]="themeService.currentTheme$ | async"
      (select)="themeService.selectTheme($event)"
    ></app-theme-picker>
    
    <!-- you app template here -->
  `,
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  constructor(public readonly themeService: ThemeService) {
  }
}
```

## Building and Testing

1. Clone the repository

```shell
git clone https://github.com/rb-mwindh/ngx-theme-manager.git <workspace>
cd <workspace>
```

2. Initialize the workspace

The `init` script installs all dependencies and sets up the pre-commit hooks.

**This is mandatory to guarantee the code style and quality!**

```shell
npm run init
```

3. Run the demo app

```shell
npm run start
```

4. Build the library

```shell
npm run build
```

5. Run the unit tests

```shell
npm run test
```

## Contribution Guidelines

Thank you for your interest in contributing to this library.

Please read the [Contribution Guidelines](CONTRIBUTING.md)

## Get help

Please check my [wiki::faq] and [wiki::troubleshooting] wiki page first.

If this doesn't answer your question, you may [post a question][issue::question] to the issue tracker.

## About

### Maintainers

- [Markus Windhager](https://github.com/rb-mwindh)

### Contributors

<!--
Consider listing contributors in this section to give explicit credit.
You could also ask contributors to add themselves in this file on their own.
-->

- none ;(

### 3rd Party Licenses

<!--
The `<bom></bom>` tags will be processed by `tools/oss-bom.ts` as a pre-commit hook.
-->

<bom>

| Name | License | Type |
| --- | --- | --- |
| [@angular/animations](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [@angular/cdk](https://github.com/angular/components) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [@angular/common](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [@angular/compiler](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [@angular/core](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [@angular/forms](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [@angular/platform-browser-dynamic](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [@angular/platform-browser](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [@angular/router](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [entities](https://github.com/fb55/entities) | [BSD-2-Clause](http://opensource.org/licenses/BSD-2-Clause) | Dependency |
| [material-icons](https://github.com/marella/material-icons) | [Apache-2.0](http://opensource.org/licenses/Apache-2.0) | Dependency |
| [ngx-theme-manager](https://github.com/rb-mwindh/ngx-theme-manager) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [parse5](https://github.com/inikulin/parse5) | [MIT](http://opensource.org/licenses/MIT) | Dependency |
| [rxjs](https://github.com/reactivex/rxjs) | [Apache-2.0](http://opensource.org/licenses/Apache-2.0) | Dependency |
| [tslib](https://github.com/Microsoft/tslib) | 0BSD | Dependency |
| [zone.js](https://github.com/angular/angular) | [MIT](http://opensource.org/licenses/MIT) | Dependency |

</bom>

### License

![License](https://badgen.net/github/license/rb-mwindh/ngx-theme-manager)


[wiki::faq]: https://github.com/rb-mwindh/ngx-theme-manager/wiki/FAQ

[wiki::troubleshooting]: https://github.com/rb-mwindh/ngx-theme-manager/wiki/Troubleshooting

[issue::question]: https://github.com/rb-mwindh/ngx-theme-manager/issues/new?template=question.md&title=❓%20

[license]: https://badgen.net/github/license/rb-mwindh/ngx-theme-manager



[selfhtml:media]: https://wiki.selfhtml.org/wiki/HTML/Attribute/media

[known-annotations]: #known-annotations