Let’s build a system tray cryptocurrency tracker for Mac using Electron — Part 1

Hi everyone!

In this tutorial I will teach you the basics of Electron. In order to do so, we will build a cryptocurrency tracker that will be located in the menu bar:

This looks pretty good!

DISCLAIMER: the visuals are loosely based off another app called Mammon:

Go try it out!


Step 1: Install Electron through package.json

Create a package.json file with the following content inside:

{
"name": "MyElectronApp",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"package": "electron-packager ./ --platform=darwin --arch=x64 --out=out --overwrite"
},
"devDependencies": {
"electron-packager": "^7.3.0",
"electron-prebuilt": "^1.2.7",
"electron-prebuilt-compile": "^1.7.9"
},
"dependencies": {
"auto-launch": "^5.0.5",
"electron-reload": "^1.2.2"
}
}

Step 2: Create a basic index.html file

Here is the content of the index.html file:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>MyElectronApp</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="window">
<div class="window-content">
<h1>Hello world!</h1>
<ul id="marketTabCoins"></ul>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

As you can see, this is a very basic template. We create an <ul> element where we will find a list of all our coins, fetched from an API. This code will be located in a script.js file that we’ll come back to later on.

Step 3: Create a main.js file

This file contains all of our Electron logic. Here is the content of our main.js file, broken down in segments:

const { app, BrowserWindow, ipcMain, Tray } = require('electron');
const path = require('path');
let tray = undefined;
let window = undefined;
// Don't show the app in the doc
app.dock.hide();
app.on('ready', () => {
createTray();
createWindow();
});

We first start by importing Electron and the main modules we’re going to need through a require statement. We then define the variables for our tray and window. We then create a ‘ready’ statement, similar to jQuery’s .ready() method.

Now, let’s see what our createTray() method looks like!

const createTray = () => {
tray = new Tray(path.join('bitcoin.png'));
tray.on('click', function (event) {
toggleWindow();
})
}

We assign a tray to our tray variable using Electron’s Tray class. To create the icon, we’re using a 32px / 32px PNG file (in this case, the Bitcoin logo) located at the root of our project’s folder:

How lovely!

When we click on the icon, the toggleWindow() method is called:

const toggleWindow = () => {
window.isVisible() ? window.hide() : showWindow();
}

This is a simple show / hide method. We’re using a one-line if statement; if the window is visible, hide it. If not, show it. The isVisible() method comes from Electron. Here is our showWindow() method:

const showWindow = () => {
const position = getWindowPosition();
window.setPosition(position.x, position.y, false);
window.show();
}

Since we want the window to be shown under our icon, we need to get the position of the icon and then set the position of the window to be right under it. To achieve this, we create a getWindowPosition() method:

const getWindowPosition = () => {
const windowBounds = window.getBounds();
const trayBounds = tray.getBounds();

// Center window horizontally below the tray icon
const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2))
    // Position window 4 pixels vertically below the tray icon
const y = Math.round(trayBounds.y + trayBounds.height + 4)
    return {x: x, y: y}
}

This code is pretty self-explanatory; We get the position of the tray and then center the window accordingly. We then return the x and y coordinates to our showWindow() method.

And with this, our tray is complete! All we need now is to define the createWindow() method:

const createWindow = () => {
window = new BrowserWindow({
width: 320,
height: 450,
show: false,
frame: false,
fullscreenable: false,
resizable: false,
transparent: true,
});
window.loadURL(`file://${path.join('index.html')}`);
    // Hide the window when it loses focus
window.on('blur', () => {
if (!window.webContents.isDevToolsOpened()) {
window.hide();
}
});
}

We first configure a few parameters, notably the width and height of the window. We then load the content located in our index.html file. Lastly, we declare a simple rule that hides our window when it loses focus.

Here is the complete code for the main.js file.


Now I’m sure you’re eager to try your code! So let’s run this thing; position yourself at the root of the folder and run the following command:

npm install && npm start

This gives us:

We did it!

Stay tuned for part 2 where we will fetch the coins from an API and display them in our Electron window.

You can see the entire code of this application here:

https://github.com/nahoc10/electronCryptoTutorial