Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rich HTML tray menu in a desktop web application

I want to create a tray menu app with custom buttons, sliders, maybe some nice transition effect, a header and footer like this:

menu

The application needs to work on Linux, Windows and Mac. I guessed it should be possible with a desktop web app + some HTML, but I can't find any useful example for any framework. Every example uses the OS' menu that just doesn't have the elements I need.

Can anyone direct me how to more or less implement this in any of the web app frameworks?

like image 662
Janek Olszak Avatar asked Dec 06 '22 16:12

Janek Olszak


1 Answers

This can be done in electron quite easily, I've actually created a few tray apps myself in the below images:

Tray app Trap app 2

The rudimentary files you need are:

  • index.html
  • main.js
  • package.json

In the index.html you would design your app the way you wanted it to look. In my example above I just used a couple of input boxes and styled them with CSS.

The main.js file is where you would put your main code to power the app.

In the package.json file is where you put the details about your app, dev dependencies etc.

The main file you should be concerned with is the main.js file. Below is an example of the main.js file for the app above. I've added comments to help you understand:

// Sets variables (const)
const {app, BrowserWindow, ipcMain, Tray} = require('electron')
const path = require('path')

const assetsDirectory = path.join(__dirname, 'img')

let tray = undefined
let window = undefined

// Don't show the app in the doc
app.dock.hide()

// Creates tray & window
app.on('ready', () => {
  createTray()
  createWindow()
})

// Quit the app when the window is closed
app.on('window-all-closed', () => {
  app.quit()
})

// Creates tray image & toggles window on click
const createTray = () => {
  tray = new Tray(path.join(assetsDirectory, 'icon.png'))
  tray.on('click', function (event) {
    toggleWindow()
  })
}

  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 + 3)

  return {x: x, y: y}
}

// Creates window & specifies its values
const createWindow = () => {
  window = new BrowserWindow({
        width: 250,
        height: 310,
        show: false,
        frame: false,
        fullscreenable: false,
        resizable: false,
        transparent: true,
        'node-integration': false
    })
    // This is where the index.html file is loaded into the window
    window.loadURL('file://' + __dirname + '/index.html');

  // Hide the window when it loses focus
  window.on('blur', () => {
    if (!window.webContents.isDevToolsOpened()) {
      window.hide()
    }
  })
}

const toggleWindow = () => {
  if (window.isVisible()) {
    window.hide()
  } else {
    showWindow()
  }
}

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

ipcMain.on('show-window', () => {
  showWindow()
})

Below is an example of the package.json file:

{
  "name": "NAMEOFAPP",
  "description": "DESCRIPTION OF APP",
  "version": "0.1.0",
  "main": "main.js",
  "license": "MIT",
  "author": "NAME OF AUTHOR",
  "scripts": {
    "start": "electron ."
  },
  "devDependencies": {
    "electron-packager": "^8.2.0"
  }
}

So, If you create a simple index.html file saying "Hello World", place the above codes into the main.js file and package.json file respectively and run the app it will run from the tray.

If you have no idea how to use Electron, you need to figure that out first (Electron docs). It will then become clear where to place which file and how to run the app.

like image 111
Luka Kerr Avatar answered Jan 28 '23 02:01

Luka Kerr