8

Vmware Clarity 0.10.16 just released the new dark theme. This is great!

They described how to add that new theme, but nothing about the possibility to dynamically change it inside the page. Is it because it is not doable?

If it is, how can I do it with Angular 4+? Any site that could help me explaining how to realize that?

Thanks in advance!

David
  • 1,241
  • 20
  • 36

4 Answers4

5

Clarity now ships with stylesheets for both light and dark themes. We document how to consume them here with both angular-cli or webpack build configurations. That means that once the app is built, that is only style it has.

I have some ideas about how to implement a theme switcher for toggling between the two. Here is a rough idea I might start my prototype with:

  1. Build the app without either of the theme css files (no clarity style at all)
  2. Copy both css files to the assets folder (during the build)
  3. Write a directive or component that can take an @Input of the the src for a stylesheet in the <head>
  4. Store the both paths /path/to/light.css and /path/to/dark.css in a service so the app could pass the active theme value around and modify it when needed.
  5. Add the service to the app components where we want to let users update the theme.

Does this give you some ideas for your app?

I'll update here after I have a prototype working so you can see it in action and find the source code.

hippeelee
  • 1,788
  • 1
  • 10
  • 21
  • Interesting. I am curious to see your POC. What do you think about the technique described here: https://stackoverflow.com/questions/42481704/angular-material-2-switch-theme-from-light-to-dark-on-click – David Dec 04 '17 at 23:49
  • I think to support an approach like that we would have to build and deliver styles for each and every theme as a single style.css file. This would double the size of our css file even if users didn't need one theme or the other. An approach I would like to explore is `CSS custom properties (CSS variables)` so that a theme could be applied from the app side of things. The big hurdle is lack of support in IE11. (Edge v15 does have support for it) so this would also mean adding a polyfill in order to support IE11. – hippeelee Dec 07 '17 at 21:20
  • Were you able to make a demo of your idea? Or is your idea similar to Jeremy's answer. It would be great if that initial lag could be circumvented somehow. – Sayak Mukhopadhyay Feb 02 '18 at 17:06
  • Hey there, My idea was similar to Jeremy's. – hippeelee Feb 23 '18 at 17:13
2

I've built a proof of concept how you could do this, but it does have some limitations. Since you can only include one theme file at a time, there can be some lag for the correct theme to render since it happens later in the Angular rendering cycle. It would only big a big deal when the cache is empty for a browser, as subsequent visits would render quickly, but that is a major consideration here. Its a start that you might be able to build something more robust upon.

https://stackblitz.com/edit/clarity-theme-switcher?file=app%2Fapp.component.ts

Jeremy Wilken
  • 6,965
  • 22
  • 21
  • Got "Unexpected value 'undefined' imported by the module 'AppModule' Evaluating main.ts" when trying it. :-(. Also, there is no way that we could something described here? https://stackoverflow.com/questions/42481704/angular-material-2-switch-theme-from-light-to-dark-on-click – David Dec 04 '17 at 23:48
  • 1
    It is working for me currently on Chrome, I haven't tested other browsers. StackBlitz is still new so there could be issues perhaps. That might be an option, though its also kinda hacky. You would have to rebuild the Clarity themes yourself to make this work, and then ship both versions to the user regardless which theme they are using. Thats not a trivial amount of code to ship. I'm working on other options to address the shortcomings. – Jeremy Wilken Dec 06 '17 at 01:41
  • @JeremyWilken Is it not possible to somehow force the angular rendering cycle to execute? – Sayak Mukhopadhyay Feb 05 '18 at 10:42
  • Sure you can force a new change detection cycle, but that isn’t the issue here. The issue is the time it takes for the theme css file to load in the browser. – Jeremy Wilken Feb 05 '18 at 15:30
  • I wonder if something like Google's Material Design themeing could be achieved. They are using mixins to put all the styles into a class. https://material.angular.io/guide/theming#multiple-themes – Sayak Mukhopadhyay Feb 08 '18 at 18:18
  • Its on our radar to do a different approach for theming in the future, but its not likely to be implemented in the near term. – Jeremy Wilken Feb 09 '18 at 00:58
1

I have implemented it adding a link in the index.html

<link id="theme" rel="stylesheet" href="https://unpkg.com/@clr/ui/clr-ui.min.css" />

Then in your app.component.ts

linkRef: HTMLLinkElement;
themes = [
    'https://unpkg.com/@clr/ui/clr-ui.min.css',
    'https://unpkg.com/@clr/ui/clr-ui-dark.min.css'
];
constructor(){
  this.linkRef = document.getElementById('theme') as HTMLLinkElement;
  // you could change here the theme if you have it stored in local storage
  // for example
  // const theme = localStorage.getItem('theme')
  // if(theme) this.linkRef.href = this.themes[parseInt(theme)]
}
setTheme(dark:bool){
  this.linkRef.href = this.themes[dark ? 1 : 0]
}
David Viejo
  • 751
  • 1
  • 6
  • 6
1

Here is what I did:

  1. I created two SCSS stylesheets. Load them both in the angular.json configuration. In stylesheet 1, import Clarity default theme. In stylesheet 2, import Clarity dark theme inside an class-selector. Like so:
.dark-mode {
    @import "~@clr/ui/src/utils/theme.dark.clarity"; // Dark theme variables
    @import '~@clr/ui/src/utils/components.clarity';

    // @import third party styling...

    // Fix styling HTML-tag.
    // node_modules\@clr\ui\src\typography\_typography.clarity.scss
    & html {
        color: $clr-global-font-color;
        font-family: $clr-font;
        font-size: $clr-baseline-px;
    }
}
  1. In the AppComponent constructor import @Inject(DOCUMENT) private document: Document.
  2. To enable dark-mode, I used the following code:
this.document.documentElement.classList.add('dark-mode');

I used localStorage to store the users preference.

The advantage of this is:

  • There is no FOUC.
  • I don't need to tweak with existing stylesheets or replace existing stylesheets.

The disadvantage is:

  • Every CSS selector will be duplicated with in the .dark-mode class-selector. This doubles the file size. I didn't consider this any problem.
  • A small fix is needed for the html-element styling. Solution included in the example above.
jerone
  • 16,206
  • 4
  • 39
  • 57