Icons For Days

Extending the IonIcon Library with the full Material icons repository

Posted by Andrew Graham-Yooll on September 14, 2016

Let me start off by saying that the folks over at Ionic are doing a great job. They are responsive to user issues, requests, and questions.

However, one thing that I believe the Ionic 2 Framework needs more of are... icons.

How could you have too many, right?

Here, I document the way I set up an Ionic project to handle the element:

 <i class="material-icons">face</i> 

to render something like

thumbs_up_downfacethumbs_up_down

for offline use.

Summary

  1. Start an Ionic project
  2. Get the Material Icons font files, and place them in /app
  3. Modify gulpfile.js to accept your new Icon files
  4. Add CSS in order to declare the HTML elements
  5. Declare the Material Icons in your project HTML

The lines

I assume you have node.js, npm and Ionic configured for simple Ionic Project generation. If not, I will be including a short description on how to get started (or you can visit the Ionic Quickstart Page).

$ ionic start material-icons --v2
$ cd material-icons
$ ionic serve

Depending on the way you set up NPM on your device, you might get an error

Error: EACCES: permission denied...

and you will have to use

$ sudo ionic serve

Your project should be up, running and viewable in your browser.

Getting the icons

Navigate to the Material-Icons repository, and download the latest woff, woff2, wot, ttf, svg, and css file.

Once downloaded, we need to include them in our app. To do that, we need to understand how the app works.

In Ionic2, the file structure setup when you run the command

$ ionic start material-icons --v2
, is relatively straight forward. For our purposes in this tutorial, the basic structure goes like this:

material-icons <--root
--/app <-- where your code goes       
--/www <-- where your app is built to(don't touch anything in hear unless told to)       
--gulpfile.js <-- what builds your app  

Yes, I know that there are other things in your file. But let's KISS (keep it stupid simple), and pretend we can not see those other files at the moment.

within /app, you write all your code
		   ||
		   \/
gulpfile.js "sees" your code in /app
		   ||
		   \/		
code in /app is processed from typescript
		   ||
		   \/
placed into /www for your browser/device to read

Now, you may be asking yourself, "why don't we just put all code into the /www folder?"

Experiment Time!

I strongly encourage you to try to put the Material Icons files we downloaded earlier, directly into the /www file.

If you do, make sure to copy the files and don't just drag and drop. You'll thank me later.

Once you re-start the server and see the app in your browser, look back in your editor. Checkout your /www file and search for the Material Icons file you placed in there. You will notice something that really frustrated me the first time I tried this, but it taught me a lot about the process of building an app.

If you do end up going on with this experiment, let us know what happened!

Note: I doubt anything destructive will occur, but if you do something and you can't get your app to function anymore, don't sweat! Just revert back to your last commit, or restart the app.

Put them in the right place

While placing the font files into /www is interesting, it is clearly not the right place.

If you did the experiment, you should have noticed that the Material Icons folders disappeared when the changes were saved. The reason lies in gulpfile.js and we will get to that in a bit.

The "right" place to put the font-files is is not well documented at this point in Ionic2. Therefore, I went ahead and created a folder in /app called /md-icons. That is where I dropped them off at. If you follow this method, the rest will work. But if you find a different place, please change the paths respectively in your code.

And just a recap of what our project looks like now:

material-icons <--root
--/app 
----/md-icons
--------MaterialIcons-Regular.eot       
--------MaterialIcons-Regular.svg       
--------MaterialIcons-Regular.ttf       
--------MaterialIcons-Regular.woff       
--------MaterialIcons-Regular.woff2       
--/www <-- where your app is built to        
--gulpfile.js <-- what builds your app  

Adjusting your gulpfile.js

As we said earlier, the gulpfile is responsible for taking our code or scripts, minifying, and then placing them into the /www. From there, the browser is served the files in the /www folder that it needs to produce a view or function.

The issue with our gulpfile.js file, and the reason our files disappeared from the /www folder is that we never told the gulpfile that we wanted those files processed and placed into the /www folder. That is what we are now going to do.

Add this to your gulpfile.js:

var isRelease = argv.indexOf('--release') > -1;

gulp.task('watch', ['clean'], function(done){
  runSequence(
    ['sass', 'html', 'fonts', //ADD THIS HERE! --> 'customFonts', 'scripts'],
    function(){
      gulpWatch('app/**/*.scss', function(){ gulp.start('sass'); });
      gulpWatch('app/**/*.html', function(){ gulp.start('html'); });
      buildBrowserify({ watch: true }).on('end', done);
    }
  );
});

gulp.task('build', ['clean'], function(done){
  runSequence(
    ['data', 'sass', 'html', 'fonts', //ADD THIS HERE! --> 'customFonts', 'scripts' ],
    function(){
      buildBrowserify({
        minify: isRelease,
        browserifyOptions: {
          debug: !isRelease
        },
        uglifyOptions: {
          mangle: false
        }
      }).on('end', done);
    }
  );
});

gulp.task('customFonts', function () {
    return copyFonts({
        src: [
          "app/md-icons/*.+(eot|ttf|woff|woff2|svg)"
        ]
    });
});

This basically says, that all those Material-Icon files should be copied and placed in your /build directory.

We add the 'customFonts' argument into the 'watch' and 'build' phases of the gulptask.js

The home stretch

We are almost there!

Now, we just have to specify in our CSS what it means when we declare an element to have class="material-icons".

Open your /app/theme/app.core.scss and place the following toward the bottom:

@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: url('../fonts/MaterialIcons-Regular.eot'); /* For IE6-8 */<---- notice the path changes from original!
  src: url('../fonts/MaterialIcons-Regular.woff2') format('woff2'),<-- notice the path changes from original!
       url('../fonts/MaterialIcons-Regular.woff') format('woff'),<---- notice the path changes from original!
       url('../fonts/MaterialIcons-Regular.ttf') format('truetype'),<- notice the path changes from original!
       url('../fonts/MaterialIcons-Regular.svg') format('svg'); <----- notice the path changes from original!
}

.material-icons {
  font-family: 'Material Icons';
  font-weight: normal;
  font-style: normal;
  font-size: 24px;  /* Preferred icon size */
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;

  /* Support for all WebKit browsers. */
  -webkit-font-smoothing: antialiased;
  /* Support for Safari and Chrome. */
  text-rendering: optimizeLegibility;

  /* Support for Firefox. */
  -moz-osx-font-smoothing: grayscale;

  /* Support for IE. */
  font-feature-settings: 'liga';
}

Finally, you should be able to call the element

 <i class="material-icons">face</i> 
and have it render:

starsflarestars

Have any cool icon images? Send them, and I’ll post them!