Implementing Predefined Color Themes in loklak Media Wall

Loklak media wall provides predefined color theme buttons which can be used to directly switch to day or night mode. It is important that the colors of the components are updated instantly with a click of a button. To implement pre-defined color options, we should, first, choose a set of color combinations which should be updated on the concerned divisions of the templates. These set of colors should be stored as an object (same interface) and the current state should be updated with this object when another theme is requested.

In this blog, I will explain how to implement predefined theme options and how to add a new theme in media wall.

Working

Media Wall can provide plenty of themes to help the user to choose a theme of their choice. Loklak media wall currently provides two themes, i.e.,  dark and light themes to provide a contrasting variety of themes at first. Ngrx structure makes it easy to add a predefined themes to the media wall. Let’s see how to add a theme to media wall and see it in action.

Adding ngrx structure

The first task is to create actions which will be dispatched from the Angular components to update the media wall. Depending on the action dispatched, state properties will change and when passed to the template, will update the media wall with the requested theme. There is no need of payload since the color options for all the themes are stored already as a reducer variable which will be updated directly to the media wall state.

export class WallLightThemeChangeAction implements Action {
type = ActionTypes.WALL_LIGHT_THEME_CHANGE;constructor(public payload: ) { }
}export class WallDarkThemeChangeAction implements Action {
type = ActionTypes.WALL_DARK_THEME_CHANGE;constructor(public payload: ) { }
}

Next, we have to update reducer functions for the corresponding actions so that the state properties change according to the actions and wall is updated. For color options, we have an interface defined for color options. For a particular type of theme, we have to adjust interface and just have to update state with the personalised theme state. As the default theme is set to light theme, we have to update state to the initial state when user requests for  light theme

case mediaWallCustomAction.ActionTypes.WALL_DARK_THEME_CHANGE: {
state = {
wallHeader: {
backgroundColor: ‘#243447’,
fontColor: ‘#FFFFFF’
},
wallBackground: {
backgroundColor: ‘#2C4158’
},
wallCard: {
fontColor: ‘#FFFFFF’,
backgroundColor: ‘#1B2836’,
accentColor: ‘#1c94e0’
}
}
return state;
}case mediaWallCustomAction.ActionTypes.WALL_LIGHT_THEME_CHANGE: {
state = initialState;return state;
}

Component and Template

Component

Now, we need to define an array of the string value of colors corresponding to a particular theme. These corresponding theme colors will be displayed in a form of color picker to the user through looping in the template. Whenever user requests for a particular theme, at first, the variable currentTheme is updated with the theme color. Next, the action is dispatched according to the selected theme from the method installTheme().

export class MediaWallMenuComponent implements OnInit, OnDestroy {
.
.
public currentTheme: string;
public themes = [ ‘#FFFFFF’, ‘#333’ ];public installTheme() {
if (this.currentTheme === this.themes[0]) {
this.store.dispatch( new mediaWallCustomAction.WallLightThemeChangeAction());
this.store.dispatch(new mediaWallDirectUrlAction.WallGenerateDirectUrlAction());
}
else if (this.currentTheme === this.themes[1]) {
this.store.dispatch( new mediaWallCustomAction.WallDarkThemeChangeAction());
this.store.dispatch(new mediaWallDirectUrlAction.WallGenerateDirectUrlAction());
}
}
.
.
}

Template

Now, we have to provide a menu for color themes in media wall template to make it easier for user to select the theme. Any interaction with the menu buttons will update the current chosen color and calls a method installTheme() and the corresponding action is dispatched and theme will be updated. Also, the check should show the updated theme for the media wall. For this, a check icon is put up based on condition *ngIf=”currentTheme === theme”.

<mdmenu class=“docs-theme-picker-menu” overlapTrigger=“false” #themeMenu=“mdMenu” yposition=“above”>
<mdgridlist cols=“2”>
<mdgridtile *ngFor=“let theme of themes”>
<div mdmenuitem (click)=“currentTheme = theme; installTheme();”>
<div class=“docs-theme-picker-swatch”>
<mdicon class=“docs-theme-chosen-icon” *ngIf=“currentTheme === theme”>check_circle</md-icon>
<div class=”docs-theme-picker-primary” [style.background]=”theme”></div>
</div>
</div>
</md-grid-tile>
</mdgridlist>
</mdmenu>

Now, The swatch menu looks like this and user can select any predefined theme from the menu and now, the wall is updated with the selected color option.

Reference

Continue Reading

Using The Dark and Light Theme in SUSI iOS

SUSI being an AI for interactive chat bots, provides answers to the users in the intelligent way. So, to make the SUSI iOS app more user friendly, the option of switching between themes was introduced. This also enables the user switch between themes based on the environment around. Any user can switch between the light and dark themes easily from the settings.

We start by declaring an enum called `theme` which contains two strings namely, dark and light.

enum theme: String {
    case light
    case dark
}

We can update the color scheme based on the theme selected very easily by checking the currently active theme and based on that check, we update the color scheme. To check the currently active theme, we define a variable in the `AppDelegate` which holds the value.

var activeTheme: String?

Below is the way the color scheme of the LoginViewController is set.

var activeTheme: String?func setupTheme() {
  let image = UIImage(named: ControllerConstants.susi)?.withRenderingMode(.alwaysTemplate)
  susiLogo.image = image
  susiLogo.tintColor = .white
  UIApplication.shared.statusBarStyle = .lightContent
  let activeTheme = AppDelegate().activeTheme
  if activeTheme == theme.light.rawValue {
    view.backgroundColor = UIColor.lightThemeBackground()
  } else if activeTheme == theme.dark.rawValue {
    view.backgroundColor = UIColor.darkThemeBackground()
  }
}

Here, we first get the image and set the rendering mode to `alwaysTemplate` so that we can change the tint color of the image. Next, we assign the image to the `IBOutlet` and change the tint color to `white`. We also change the status bar style to `lightContent`. Next, we check the active theme and change the view’s background color accordingly. For this method to execute, we call it inside, `viewDidLoad` so that the theme loads up as the view loads.

Next, lets add this option of switching between themes inside the `SettingsViewController`. We add a cell with `titleLabel` as `Change Theme` and use the collectionView’s delegate method of `didSelect` to show an alert. This alert contains three options, Dark theme, Light Theme and Cancel. Let’s code that method which presents the alert.

func themeToggleAlert() {
  let imageDialog = UIAlertController(title: ControllerConstants.toggleTheme, message: nil, preferredStyle: UIAlertControllerStyle.alert)
  imageDialog.addAction(UIAlertAction(title: theme.dark.rawValue.capitalized, style: .default, handler: { (_: UIAlertAction!) in
    imageDialog.dismiss(animated: true, completion: nil)
    AppDelegate().activeTheme = theme.dark.rawValue
    self.settingChanged(sender: self.imagePicker)
    self.setupTheme()
  }))
  imageDialog.addAction(UIAlertAction(title: theme.light.rawValue.capitalized, style: .default, handler: { (_: UIAlertAction!) in
    imageDialog.dismiss(animated: true, completion: nil)
    AppDelegate().activeTheme = theme.light.rawValue
    self.settingChanged(sender: self.imagePicker)
    self.setupTheme()
  }))
  imageDialog.addAction(UIAlertAction(title: ControllerConstants.dialogCancelAction, style: .cancel, handler: { (_: UIAlertAction!) in
    imageDialog.dismiss(animated: true, completion: nil)
  }))
  self.present(imageDialog, animated: true, completion: nil)
}

Here, we assign the alert view’s title and add 3 actions and their respective completion handlers. If we see inside these completion handlers, we can notice that we first dismiss the alert followed by updating the activeTheme variable in AppDelegate and call the `settingChanged` function which updates the user’s settings on the server. Finally, we update the color scheme.

Now, if we build and run the app and change the theme from the settings, we will notice that on returning to the chat view, the color scheme is not updated. The reason here is that we are setting up the theme on viewDidLoad which loads only once and is not executed until the controller is presented again. Here, we make use of the `viewDidAppear` method which executes every time the view appears.

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  setupTheme()
}

To persist the selected theme, we used the UserDefaults to save the theme which got assigned everytime to the `activeTheme` variable when the app loads up.

UserDefaults.standard.set(AppDelegate().activeTheme, forKey: ControllerConstants.UserDefaultsKeys.theme)

On app launch, we assigned this User Default the value of the light theme as a default.

Below is the final output:

References:

Continue Reading

Use of Flux Architecture to Switch between Themes in SUSI Web Chat

While we were developing the SUSI Web Chat we got a requirement to build a dark theme. And to build a way that user can switch between dark and light theme.

SUSI Web Chat application is made according to the Flux architecture, So we had to build sub components according to that architecture.

What is flux:

Flux is not a framework. It is an Architecture/pattern that we can use to build applications using react and some other frameworks. Below figure shows the way how that architecture works and how it communicate.

How flux works:

Flux has four types of components. Those are views, actions, dispatcher and stores. We use JSX to build and integrate views into our JavaScript code.

When someone triggers an event from view, it triggers an action and that action sends particular action details  such as Actiontype, action name  and data to dispatcher. Dispatcher broadcasts those details to every store which are registered with the particular dispatcher. That means every store gets all the action details and data which are broadcasting from dispatchers which they are registered.

Let’s say we have triggered an action from view that is going to change the value of the store. Those action details are coming to dispatcher. Then dispatcher broadcasts those data to every store that registered with it. Matching action will trigger and update its value. If there is any change happened in store, view automatically updates corresponding view.

How themes are changing:

We have a store called “SettingStore.js”. This “SettingStore” contains theme values like current theme. We store other settings of the application such as: Mic input settings, Custom server details, Speech Output details, Default Language, etc.it is responsible to provide these details to corresponding view.

let CHANGE_EVENT = 'change';
class SettingStore extends EventEmitter {
   constructor() {
       super();
       this.theme = true; 
   }

We use “this.theme = true” in constructor to switch light theme as the default theme.

getTheme() { //provides current value of theme
       return this.theme;
   }

This method returns the value of the current theme when it triggers.

   changeTheme(themeChanges) {
       this.theme = !this.theme;
       this.emit(CHANGE_EVENT);
   }

We use “changeTheme” method to change the selected theme.

   handleActions(action) {
       switch (action.type) {
           case ActionTypes.THEME_CHANGED: {
               this.changeTheme(action.theme);
               break;
           }
           default: {
               // do nothing
           }
       }
   }
}

This switch case is the place that store gets actions distributed from the dispatcher and executes relevant method.

const settingStore = new SettingStore();
ChatAppDispatcher.register(settingStore.handleActions.bind(settingStore));
export default settingStore;

Here we registered our store(SettingStore) to “ChatAppDispatcher” .

This is how Store works.
Now we need to get the default light theme to the view. For that we have to call ”getTheme()” function. We can use the value it returns to update the state of the application.
Now we are going to change the theme. To do that we have to trigger “changeTheme” method of “Settingstrore” from view ( MessageSection.react.js ).
We trigger below method on click of the “Change Theme” button. It triggers the action called “themeChanged”.

 themeChanger(event) {
   Actions.themeChanged(!this.state.darkTheme);
 }

Previous method executes “themeChanged()” function of the actions.js file.

export function themeChanged(theme) {
 ChatAppDispatcher.dispatch({
   type: ActionTypes.THEME_CHANGED,
   theme //data came from parameter
 });
};

In above function we collect data from the view and send those data, method details to dispatcher.
Dispatcher sends those details to each and every registered store. In our case we have “SettingStore” and update the state to new dark theme.
This is how themes are changing in SUSI AI Web Chat application. Check this link to see the preview.

Resources:

  • Read About Flux: https://facebook.github.io/flux/
  • GitHub repository: https://github.com/fossasia/chat.susi.ai
  • Live Web Chat: http://chat.susi.ai/
Continue Reading

Implementing Themes in Angular JS for Susper

Adding themes to any website, makes it more interesting to use, and also helps customize the website according to personal preferences. This blog deals with how we implemented themes in Susper.
Susper offers the following themes

  • Default
  • Dark
  • Basic
  • Contrast
  • Terminal

This is how some of the themes look
Dark:

Contrast:  
Terminal:
Lets go through a step by step guide how to implement this:

  1. Add a Themes service  (In app/src/theme.service.ts in Susper)

Here is the code snippet:

import { Injectable } from ‘@angular/core’;

@Injectable()
export class ThemeService {

public titleColor: string;
public linkColor: string;
public descriptionColor: string;
public backgroundColor: string;

constructor() { }

}

  1.  Create a component for themes, and define functions for various themes in the .ts file.(src/app/theme/theme.component.ts in Susper)

Here is the example code:

import { Component, OnInit } from ‘@angular/core’;
import { ThemeService } from ‘../theme.service’;@Component({
selector: ‘app-theme’,
templateUrl: ‘./theme.component.html’,
styleUrls: [‘./theme.component.css’]
})
export class ThemeComponent implements OnInit {constructor(
private themeService: ThemeService
) { }ngOnInit() {
}darkTheme() {
this.themeService.backgroundColor = ‘#FFFFFF’;
this.themeService.titleColor = ‘#050404’;
this.themeService.linkColor = ‘#7E716E’;
this.themeService.descriptionColor = ‘#494443’;
}

defaultTheme() {
this.themeService.backgroundColor = ‘#FFFFFF’;
this.themeService.titleColor = ‘#1a0dab’;
this.themeService.linkColor = ‘#006621’;
this.themeService.descriptionColor = ‘#545454’;
}

basicTheme() {
this.themeService.backgroundColor = ‘#FFFFFF’;
this.themeService.titleColor = ‘#1a0dab’;
this.themeService.linkColor = ‘#494443’;
this.themeService.descriptionColor = ‘#7E716E’;
}

In the above code, the first few lines  include the constructor, which defines the theme service, and include a default function that runs as soon as the page is initialized.

We then see three kinds of themes implemented, dark, default and contrast. Let us examine the darkTheme:

darkTheme() {
this.themeService.backgroundColor = ‘#FFFFFF’;
this.themeService.titleColor = ‘#050404’;
this.themeService.linkColor = ‘#7E716E’;
this.themeService.descriptionColor = ‘#494443’;
}
  • The first line sets the background color of the screen(to white).
  • The second line is used to set the color of all the titles of the search results
  • The third line is used to set the link/url color
  • The fourth line sets the description color
    1.   Link the appropriate attributes in your html pages, using [style.’css-attribute’]

(src/app/results/results.component.html in Susper)

Following this example, you can link different parts of the html file to the attributes in your theme service and you are done!
If implementing this in a project like Susper, a few points of caution:

  • Make sure you write your spec.ts file well, and add your component for proper compilation and testing.
  • Do not forget to import the service into any component before you use it in its html files.

Resources 

Continue Reading

Using custom themes with Yaydoc to build documentation

What is Yaydoc?

Yaydoc aims to be a one stop solution for all your documentation needs. It is continuously integrated to your repository and builds the site on each commit. One of it’s primary aim is to minimize user configuration. It is currently in active development.

Why Themes?

Themes gives the user ability to generate visually different sites with the same markup documents without any configuration. It is one of the many features Yaydoc inherits from sphinx.

Now sphinx comes with 10 built in themes but there are much more custom themes available on PyPI, the official Python package repository. To use these custom themes, sphinx requires some setup. But Yaydoc being an automated system needs to performs those tasks automatically.

To use a custom theme which has been installed, sphinx needs to know the name of the theme and where to find it. We do that by specifying two variables in the sphinx configuration file. html_theme and html_theme_path respectively. Custom themes provide a method that can be called to get the html_theme_path of the theme. Usually that method is named get_html_theme_path . But that is not always the case. We have no way find the appropriate method automatically.

So how do we get the path of an installed theme just by it’s name and how do we add it to the generated configuration file.

The configuration file is generated by the sphinx-quickstart command which Yaydoc uses to initialize the documentation directory. We can override the default generated files by providing our own project templates. The templates are based on the Jinja2 template engine.

Firstly, I replaced

html_theme = ‘alabaster’

With

html_theme = ‘{{ html_theme }}’

This provides us the ability to pass the name of the theme as a parameter to sphinx-quickstart. Now the user has an option to choose between 10 built-in themes. For custom themes however there is a different story. I had to solve two major issues.

  • The name of the package and the theme may differ.
  • We also need the absolute path to the theme.

The following code snippet solves the above mentioned problems.

{% if html_theme in (['alabaster', 'classic', 'sphinxdoc', 'scrolls',
'agogo', 'traditional', 'nature', 'haiku',
'pyramid', 'bizstyle'])
%}
# Theme is builtin. Just set the name
html_theme = '{{ html_theme }}'
{% else %}
# Theme is a custom python package. Lets install it.
import pip
exitcode = pip.main(['install', '{{ html_theme }}'])
if exitcode:
    # Non-zero exit code
    print("""{0} is not available on pypi. Please ensure the theme can be installed using 'pip install {0}'.""".format('{{ html_theme }}'), file=sys.stderr)
else:
    import {{ html_theme }}
    def get_path_to_theme():
        package_path = os.path.dirname({{ html_theme }}.__file__)
        for root, dirs, files in os.walk(package_path):
            if 'theme.conf' in files:
                return root
    path_to_theme = get_path_to_theme()
    if path_to_theme is None:
        print("\n{0} does not appear to be a sphinx theme.".format('{{ html_theme }}'), file=sys.stderr)
        html_theme = 'alabaster'
    else:
        html_theme = os.path.basename(path_to_theme)
        html_theme_path = [os.path.abspath(os.path.join(path_to_theme, os.pardir))]
{% endif %}

It performs the following tasks in order:

  • It first checks if the provided theme is one of the built in themes. If that is indeed the case, we just set the html_theme config value to the name of the theme.
  • Otherwise, It installs the package using pip.
  • Now __file__ has a special meaning in python. It returns us the path of the module. We use it to get the path of the installed package.
  • Now each sphinx theme must have a file named `theme.conf` which defines several properties of the theme. We do a recursive search for that file.
  • We set html_theme to be the name of the directory which contains that file, and html_theme_path to be it’s parent directory.

Now let’s see everything in action. Here are four pages created by Yaydocs from a single markup document with no user configuration.

 

Now you can choose between many of the themes available on PyPI. You can even create your own theme. Follow this blog to get more insights and latest news about Yaydoc.

 

Continue Reading

SASS for the theme based concept

Until yesterday, I was exploring all around the internet, to find the best possible way for the theme concept in the web app. The theme concept allows an organizer to choose the theme for the web app from the set of provided themes.

After some time, I realised that this awesomeness to the web app can be added by using Syntactically Awesome Stylesheets.

How SASS supports the theme concept?

 

In the web app, a folder name _scss is added which has the directory structure as shown

tree
_scss folder directory structure

There is a file _config.scss inside the _base folder that includes the SASS variables which are used in all the files after importing it.

Each of the SASS variables uses a flag !default at the end, which means it can be overwritten in any other file. This property of SASS leads to the theme concept.

//_.config.scss

@charset "UTF-8";
 
// Colors
$black: #000;
$white: #fff;
$red: #e2061c;
$gray-light: #c9c8c8;
$gray: #838282;
$gray-dark: #333333;
$blue: #253652;
 
// Corp-Colors
$corp-color: $white !default;
$corp-color-dark: darken($corp-color, 15%) !default;
$corp-color-second: $red !default;
$corp-color-second-dark: darken($corp-color-second, 15%) !default;
 
// Fontbasic
$base-font-size: 1.8 !default;
$base-font-family: Helvetica, Arial, Sans-Serif !default;
$base-font-color: $gray-dark !default;
 
// Border
$base-border-radius: 2px !default;
$rounded-border-radius: 50% !default;
$base-border-color: $gray !default;

The main file that includes all the required style is the application.scss. Here, $corp-color takes default value from  _config.scss. It can be overwritten by the themes.

//application.scss

@charset 'UTF-8';

// 1.Base
@import '_base/_config.scss';

/* Offsets for fixed navbar */
body {
 margin-top: 50px;
 background-color:$corp-color !important;
}

Making a light theme 

 

The light theme will overwrite the $corp-color value to $gray-light which is defined in _config.scss. This will change the background-color defined in application.scss to #c9c8c8. So, in this way a light theme is generated. The similar approach can be followed to generate the dark theme.

//_light.scss

@charset 'UTF-8';
@import '../../_base/config';
// 1.Overwrite stuff
$corp-color: $gray-light;

@import '../../application';

Making a dark theme 

 

//_dark.scss

@charset 'UTF-8';
@import '../../_base/config';
// 1.Overwrite stuff
$corp-color: $gray;

@import '../../application';

How to compile the CSS from SASS files ?

 

  1. We can easily compile these SASS files by using command
    sass /path/application.scss /path/schedule.css

    For generating light theme and dark theme:

    sass /path/_light.scss  /path/schedule.css
    sass /path/_dark.scss  /path/schedule.css

Optimization of Code

 

SASS is very powerful for optimizing the code. It allows the concepts such as nesting, mixins which reduce the line of code. I have rewritten schedule.css into application.scss to make it more optimized.

/* Adjustments for smaller screens */

@media (min-width: 450px) {
 body {
 font-size: 14px
 }
 .session {
   &-list{
     .label{
         font-size: 90%;
         padding: .2em .6em .3em;
           }
         }
    &-title {
         float:left;
         width: 75%;
         }
    &-location {
         float: right;
         width: 25%;
         text-align: right;
        }
  }
}

Further Exploration

 

This is one of the ways to deal with the SASS structure, but there are other resources that can be helpful in dealing with SASS projects.

Also, check out, Jeremy Hexon article here.

Continue Reading
Close Menu