It’s time to implement an electron app navigation in the Electron tutorial app. Not the main kind of menubar but a left menu kind. For this step some use react or some other framework. But i wanted to keep it simple so this tutorial does not use a UI framework. This is the way the navigation is implemented in the Electron api demos application.
The name of the app is now called Electron tutorial app instead of electron hello world as it was before. I thought that name suits it better since it’s not only a hello world from now on. To get the source code of this application as it looks at the end of this tutorial you can download it from github.
1. Adding a design
First off the app looks pretty dull and does not have a menu. Since the design is out of scope for the tutorial we will use a template from HTML5up called hyperspace. Go ahead and download it.
Once you’ve downloaded and unpacked hyperspace, copy the folder called assets into the root folder of our electron app. Then copy this HTML-markup into our index.html.
This is the hyperspace markup but with two differences
- Internet explorer specific css has been removed. Electron uses chromium.
- The import of jquery at the bottom has been changed
<!DOCTYPE HTML>
<!--
Hyperspace by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>Electron tutorial app</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body>
<!-- Sidebar -->
<section id="sidebar">
<div class="inner">
<nav>
<ul>
<li><a href="#intro">Welcome</a></li>
<li><a href="#one">Who we are</a></li>
<li><a href="#two">What we do</a></li>
<li><a href="#three">Get in touch</a></li>
</ul>
</nav>
</div>
</section>
<!-- Wrapper -->
<div id="wrapper">
<!-- Intro -->
<section id="intro" class="wrapper style1 fullscreen fade-up">
<div class="inner">
<h1>Electron tutorial app!</h1>
<p>Hopefully this helps someone to get up to speed with electron.</p>
<ul class="actions">
<li><a href="#one" class="button scrolly">Learn more</a></li>
</ul>
</div>
</section>
<!-- One -->
<section id="one" class="wrapper style2 spotlights">
<section>
<a href="#" class="image"><img src="images/pic01.jpg" alt="" data-position="center center" /></a>
<div class="content">
<div class="inner">
<h2>Sed ipsum dolor</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.</p>
<ul class="actions">
<li><a href="#" class="button">Learn more</a></li>
</ul>
</div>
</div>
</section>
<section>
<a href="#" class="image"><img src="images/pic02.jpg" alt="" data-position="top center" /></a>
<div class="content">
<div class="inner">
<h2>Feugiat consequat</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.</p>
<ul class="actions">
<li><a href="#" class="button">Learn more</a></li>
</ul>
</div>
</div>
</section>
<section>
<a href="#" class="image"><img src="images/pic03.jpg" alt="" data-position="25% 25%" /></a>
<div class="content">
<div class="inner">
<h2>Ultricies aliquam</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.</p>
<ul class="actions">
<li><a href="#" class="button">Learn more</a></li>
</ul>
</div>
</div>
</section>
</section>
<!-- Two -->
<section id="two" class="wrapper style3 fade-up">
<div class="inner">
<h2>What we do</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus, lacus eget hendrerit bibendum, urna est aliquam sem, sit amet imperdiet est velit quis lorem.</p>
<div class="features">
<section>
<span class="icon major fa-code"></span>
<h3>Lorem ipsum amet</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-lock"></span>
<h3>Aliquam sed nullam</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-cog"></span>
<h3>Sed erat ullam corper</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-desktop"></span>
<h3>Veroeros quis lorem</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-chain"></span>
<h3>Urna quis bibendum</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-diamond"></span>
<h3>Aliquam urna dapibus</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
</div>
<ul class="actions">
<li><a href="#" class="button">Learn more</a></li>
</ul>
</div>
</section>
<!-- Three -->
<section id="three" class="wrapper style1 fade-up">
<div class="inner">
<h2>Get in touch</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus, lacus eget hendrerit bibendum, urna est aliquam sem, sit amet imperdiet est velit quis lorem.</p>
<div class="split style1">
<section>
<form method="post" action="#">
<div class="field half first">
<label for="name">Name</label>
<input type="text" name="name" id="name" />
</div>
<div class="field half">
<label for="email">Email</label>
<input type="text" name="email" id="email" />
</div>
<div class="field">
<label for="message">Message</label>
<textarea name="message" id="message" rows="5"></textarea>
</div>
<ul class="actions">
<li><a href="" class="button submit">Send Message</a></li>
</ul>
</form>
</section>
<section>
<ul class="contact">
<li>
<h3>Address</h3>
<span>12345 Somewhere Road #654<br />
Nashville, TN 00000-0000<br />
USA</span>
</li>
<li>
<h3>Email</h3>
<a href="#">[email protected]</a>
</li>
<li>
<h3>Phone</h3>
<span>(000) 000-0000</span>
</li>
<li>
<h3>Social</h3>
<ul class="icons">
<li><a href="#" class="fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="fa-facebook"><span class="label">Facebook</span></a></li>
<li><a href="#" class="fa-github"><span class="label">GitHub</span></a></li>
<li><a href="#" class="fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="fa-linkedin"><span class="label">LinkedIn</span></a></li>
</ul>
</li>
</ul>
</section>
</div>
</div>
</section>
</div>
<!-- Footer -->
<footer id="footer" class="wrapper style1-alt">
<div class="inner">
<ul class="menu">
<li>© Untitled. All rights reserved.</li><li>Design: <a href="http://html5up.net">HTML5 UP</a></li>
</ul>
</div>
</footer>
<!-- Scripts -->
<script>window.$ = window.jQuery = require('./assets/js/jquery.min.js');</script>
<script src="assets/js/jquery.scrollex.min.js"></script>
<script src="assets/js/jquery.scrolly.min.js"></script>
<script src="assets/js/skel.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>
The media query that show the menu in hyperspace is defined to be over 1280 pixels. So go into our main.js file and go to line 13 and make it look like this:
mainWindow = new BrowserWindow({width: 1281, height: 800, minWidth: 1281, minHeight: 800})
We change the startup width to 1281, the startup height to 800 and setting the minWidth and minHeight to the same values. You can read more about the BrowserWindow Class and it’s properties at the official documentation.
If you fire up the electron app now it looks very fancy ! (Read the hello world if you need help firing it up)
You can download the repo at this stage from this commit.
2 .Making the sidebar menu load content
Hyperspace is a single page layout. So it works as it is now. But that’s not what i’m going for. If you scroll the main window you can see all the pages in our app. And if you click on a menu item you will be scrolled down to that section. An app with a lot of menu items will create a lot of markup in index.html this way. In this step we’ll make all the menu items load it’s own .html file with the markup we want.
2.1 Extract sections
Create a new folder called sections and add four new files to it that are called: getintouch.html, welcome.html, whatwedo.html and whoweare.html
The contents in these files are the different sections you can find in index.html at this point. But when they are extracted i also wrap a template tag around the sections. They will be used in the javascript later on. I’ve also deleted the fade-in classes on the sections because the didn’t work that well. They also got new id’s.
getintouch.html
<template class="section-template">
<section id="getintouch" class="wrapper style1">
<div class="inner">
<h2>Get in touch</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus, lacus eget hendrerit bibendum, urna est aliquam sem, sit amet imperdiet est velit quis lorem.</p>
<div class="split style1">
<section>
<form method="post" action="#">
<div class="field half first">
<label for="name">Name</label>
<input type="text" name="name" id="name" />
</div>
<div class="field half">
<label for="email">Email</label>
<input type="text" name="email" id="email" />
</div>
<div class="field">
<label for="message">Message</label>
<textarea name="message" id="message" rows="5"></textarea>
</div>
<ul class="actions">
<li><a href="" class="button submit">Send Message</a></li>
</ul>
</form>
</section>
<section>
<ul class="contact">
<li>
<h3>Address</h3>
<span>12345 Somewhere Road #654<br />
Nashville, TN 00000-0000<br />
USA</span>
</li>
<li>
<h3>Email</h3>
<a href="#">[email protected]</a>
</li>
<li>
<h3>Phone</h3>
<span>(000) 000-0000</span>
</li>
<li>
<h3>Social</h3>
<ul class="icons">
<li><a href="#" class="fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="fa-facebook"><span class="label">Facebook</span></a></li>
<li><a href="#" class="fa-github"><span class="label">GitHub</span></a></li>
<li><a href="#" class="fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="fa-linkedin"><span class="label">LinkedIn</span></a></li>
</ul>
</li>
</ul>
</section>
</div>
</div>
</section>
</template>
welcome.html
<template class="section-template">
<section id="welcome" class="wrapper style1 fullscreen intro">
<div class="inner">
<h1>Electron tutorial app!</h1>
<p>Hopefully this helps someone to get up to speed with electron.</p>
<ul class="actions">
<li><a href="#one" class="button scrolly">Learn more</a></li>
</ul>
</div>
</section>
</template>
whatwedo.html
<template class="section-template">
<section id="whatwedo" class="wrapper style3">
<div class="inner">
<h2>What we do</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus, lacus eget hendrerit bibendum, urna est aliquam sem, sit amet imperdiet est velit quis lorem.</p>
<div class="features">
<section>
<span class="icon major fa-code"></span>
<h3>Lorem ipsum amet</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-lock"></span>
<h3>Aliquam sed nullam</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-cog"></span>
<h3>Sed erat ullam corper</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-desktop"></span>
<h3>Veroeros quis lorem</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-chain"></span>
<h3>Urna quis bibendum</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
<section>
<span class="icon major fa-diamond"></span>
<h3>Aliquam urna dapibus</h3>
<p>Phasellus convallis elit id ullam corper amet et pulvinar. Duis aliquam turpis mauris, sed ultricies erat dapibus.</p>
</section>
</div>
<ul class="actions">
<li><a href="#" class="button">Learn more</a></li>
</ul>
</div>
</section>
</template>
whoweare.html
<template class="section-template">
<section id="whoweare" class="wrapper style2 spotlights">
<section>
<div class="content">
<div class="inner">
<h2>Sed ipsum dolor</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.</p>
<ul class="actions">
<li><a href="#" class="button">Learn more</a></li>
</ul>
</div>
</div>
</section>
<section>
<div class="content">
<div class="inner">
<h2>Feugiat consequat</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.</p>
<ul class="actions">
<li><a href="#" class="button">Learn more</a></li>
</ul>
</div>
</div>
</section>
<section>
<div class="content">
<div class="inner">
<h2>Ultricies aliquam</h2>
<p>Phasellus convallis elit id ullamcorper pulvinar. Duis aliquam turpis mauris, eu ultricies erat malesuada quis. Aliquam dapibus.</p>
<ul class="actions">
<li><a href="#" class="button">Learn more</a></li>
</ul>
</div>
</div>
</section>
</section>
</template>
2.2 Empty index.html wrapper
Now the sections are extracted into their own respective files we can empty the div with the id wrapper in index.html. This is not the full index.html, only what the wrapper looks like. the HTML above and under should be left as is.
index.hml
<!-- Wrapper -->
<div id="wrapper">
</div>
<!-- Footer -->
3. Preparing the menu and importing sections
3.1 data-section
In index.html there is a navigation in the sidebar section. Update the anchor tags to look like this:
<li><a id="welcome-menu" data-section="welcome" href="#">Welcome</a></li>
<li><a data-section="whoweare" href="#">Who we are</a></li>
<li><a data-section="whatwedo" href="#">What we do</a></li>
<li><a data-section="getintouch" href="#">Get in touch</a></li>
We’ve added a data-section attribute with the value of the file names that we created in step 2. We’ll later use this when loading the sections with javascript.
3.2 Importing section html files
Update the head-section in index.html to look like below. We use import so that chromium can load the contents before we need to use them in our javascript. You can read more about how the rel=”import” works on html5rocks.
<head>
<title>Electron tutorial app</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="assets/css/main.css" />
<link rel="import" href="sections/getintouch.html">
<link rel="import" href="sections/welcome.html">
<link rel="import" href="sections/whatwedo.html">
<link rel="import" href="sections/whoweare.html">
</head>
4. Making the menu do something
Add a new script to the assets/js folder called menu.js and import in in index.html with the require function.
<!-- Scripts -->
<script>window.$ = window.jQuery = require('./assets/js/jquery.min.js');</script>
<script src="assets/js/jquery.scrollex.min.js"></script>
<script src="assets/js/jquery.scrolly.min.js"></script>
<script src="assets/js/skel.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
<script>
require('./assets/js/menu')
</script>
</body>
And now to the contents of menu.js:
window.navigation = window.navigation || {},
function(n) {
navigation.menu = {
constants: {
sectionTemplate: '.section-template',
contentContainer: '#wrapper',
startSectionMenuItem: '#welcome-menu',
startSection: '#welcome'
},
importSectionsToDOM: function() {
const links = document.querySelectorAll('link[rel="import"]')
Array.prototype.forEach.call(links, function (link) {
let template = link.import.querySelector(navigation.menu.constants.sectionTemplate)
let clone = document.importNode(template.content, true)
document.querySelector(navigation.menu.constants.contentContainer).appendChild(clone)
})
},
setMenuOnClickEvent: function () {
document.body.addEventListener('click', function (event) {
if (event.target.dataset.section) {
navigation.menu.hideAllSections()
navigation.menu.showSection(event)
}
})
},
showSection: function(event) {
const sectionId = event.target.dataset.section
$('#' + sectionId).show()
$('#' + sectionId + ' section').show()
},
showStartSection: function() {
$(this.constants.startSectionMenuItem).click()
$(this.constants.startSection).show()
$(this.constants.startSection + ' section').show()
},
hideAllSections: function() {
$(this.constants.contentContainer + ' section').hide()
},
init: function() {
this.importSectionsToDOM()
this.setMenuOnClickEvent()
this.showStartSection()
}
};
n(function() {
navigation.menu.init()
})
}(jQuery);
Lets go trough it. Start by looking in the init() function. This function will run when the document is loaded. It calls importSectionsToDOM(), setMenuOnClickEvent() and showStartSection().
importSectionsToDom()
This function loads all the rel=”imports” that we added to the head section in index.html and adds it to the div with id #wrapper in index.html.
setMenuOnClickEvent()
This function adds an eventlistener and looks for events where the data attribute section is set. If it is it calls hideAllSections() and showSection(event). More on these soon.
showStartSection()
We need to show a section when the app is started the first time. That is what this function does. Line 36 make sure that the first menu item is clicken, 37 and 38 makes the start section show.
hideAllSections()
This function is called before a new sections is shown. As the name hints it hides all the other sections so they are not in the way of the one that is about to show.
showSection(event)
If the user has clicked a menu item this function will be called on line 24. it takes the id of the section to be shown and uses jquerys show to display it.
This makes our menu work. But the hyperspace template needs some updates to make it work better.
5. Updating hyperspace to work with our menu
Hyperspace uses sass so we’ll continue to do that. If you don’t want to do that. you can do the changes directly to assets/css/main.css or just download the css from the repo and replace the your own file with it.
5.1 Adding config.rb
Add this content to a file and name it config.rb to get the correct paths to sass files. Save it in the same directory as index.html
css_dir = "assets/css" # by Compass.app
sass_dir = "assets/sass" # by Compass.app
images_dir = "assets/css/images" # by Compass.app
output_style = :compressed # :expanded or :nested or :compact or :compressed
relative_assets = false # by Compass.app
line_comments = true # by Compass.app
sass_options = {:debug_info=>false} # by Compass.app
sourcemap = false # by Compass.app
5.2 Updating some styles
open the file assets/sass/components/_section.scss and add this:
#wrapper {
section {
display: none;
}
}
Next go into assets/sass/layout/_intro.scss and change #intro to .intro and add .inner:
.intro {
background-attachment: fixed;
background-image: url('images/intro.svg');
background-position: top right;
background-repeat: no-repeat;
background-size: 100% 100%;
.inner {
padding-top:255px;
}
5.3 Updating hyperspace javascripts
Hyperspace uses scrollex on some pages, that does not work to well now when we split the sections to separate files. open up assets/js/main.js then go to line 149 and comment out that function all the way to line line 185:
// Spotlights.
/*$('.spotlights > section')
.scrollex({
mode: 'middle',
top: '-10vh',
bottom: '-10vh',
initialize: function() {
// Deactivate section.
if (skel.canUse('transition'))
$(this).addClass('inactive');
},
enter: function() {
// Activate section.
$(this).removeClass('inactive');
}
})
.each(function() {
var $this = $(this),
$image = $this.find('.image'),
$img = $image.find('img'),
x;
// Assign image.
$image.css('background-image', 'url(' + $img.attr('src') + ')');
// Set background position.
if (x = $img.data('position'))
$image.css('background-position', x);
// Hide .
$img.hide();
});*/
// Features.
Thats it for this short(oh my satan it’s to long!) tutorial.