In Part 1 of this series covering themes in the Sails Framework, we bootstrapped our sample Sails app (step 1). Here in Part 2, we will complete steps 2 and 3, compiling our theme’s CSS and the necessary Less files and setting up the theme Sails hook to complete our application.
Let’s pick things back up where we left of in Part 1. We now want to customize our page to have our burrito style. We need to add a task that compiles our themes. Edit your /tasks/config/less.js so that it looks like this one:
module.exports = function (grunt) {
grunt.config.set('less', {
dev: {
files: [{
expand: true,
cwd: 'assets/styles/',
src: ['importer.less'],
dest: '.tmp/public/styles/',
ext: '.css'
}, {
expand: true,
cwd: 'assets/themes/export',
src: ['*.less'],
dest: '.tmp/public/themes/',
ext: '.css'
}]
}
});
grunt.loadNpmTasks('grunt-contrib-less');
};
Basically, we added a second object to the files section, which tells the Less compiler task to look for any Less file in assets/themes/export, compile it, and put the resulting CSS in the .tmp/public/themes folder. In case you were not aware of it, the .tmp/public folder is the one Sails uses to publish its assets.
We now create two themes: one is default.less and the other is burrito.less, which is based on default.less.
We also have two other Less files, each one holding the variables for each theme. This technique allows you to have one base theme and many other themes based on the default.
/assets/themes/variables.less
@app-navbar-background-color: red;
@app-navbar-brand-color: white;
/assets/themes/variablesBurrito.less
@app-navbar-background-color: green;
@app-navbar-brand-color: yellow;
/assets/themes/export/default.less
@import "../variables.less";
.navbar-inverse {
background-color: @app-navbar-background-color;
.navbar-brand {
color: @app-navbar-brand-color;
}
}
/assets/themes/export/burrito.less
@import "default.less";
@import "../variablesBurrito.less";
So, burrito.less just inherits from default.less but overrides the variables with the ones on its own, creating a new theme based on the default.
If you lift Sails now, you will notice that the Navigation bar has a red background on white.
The last step involves creating a Hook, a Node module that adds functionality to the Sails corethat catches the hostname, and if it has burrito in it, sets the new theme.
First, let’s create the folder for the hook:
mkdir -p ./api/hooks/theme
Now create a file named index.js in that folder with this content:
/**
* theme hook - Sets the correct CSS to be displayed
*/
module.exports = function (sails) {
return {
routes: {
before: {
'all /*': function (req, res, next) {
if (!req.isSocket) {
// makes theme variable available in views
res.locals.theme = sails.hooks.theme.getTheme(req);
}
returnnext();
}
}
},
/**
* getTheme defines which css needs to be used for this request
* In this case, we select the theme by pattern matching certain words from the hostname
*/
getTheme: function (req) {
var hostname = 'default';
var theme = 'default';
try {
hostname = req.get('host').toLowerCase();
} catch(e) {
// host may not be available always (ie, socket calls. If you need that, add a Host header in your
// sails socket configuration)
}
// if burrito is found on the hostname, change the theme
if (hostname.indexOf('burrito') > -1) {
theme = 'burrito';
}
return theme;
}
};
};
Finally, to test our configuration, we need to add a host entry in our OS hosts file. In Linux/Unix-based operating systems, you have to edit /etc/hosts (with sudo or root).
Add the following line:
127.0.0.1 burrito.smartdelivery.localwww.smartdelivery.local
Now navigate using those host names, first to www.smartdelivery.local:
And lastly, navigate to burrito.smartdelivery.local:
You now have your Burrito Smart Delivery! And you have a Themed Sails Application! I hope you have enjoyed this series. You can get the source code from here. Enjoy!
Luis Lobo Borobia is the CTO at FictionCity.NET, is a mentor and advisor, independent software engineer consultant, and conference speaker. He has a background as a software analyst and designer, creating, designing, and implementing software products, solutions, frameworks, and platforms for several kinds of industries. In the last few years, he has focused on research and development for the Internet of Things, using the latest bleeding-edge software and hardware technologies available.