This is the 7th day of my participation in Gwen Challenge

Today we started talking about the Mac Menubar function display.

Before the opening

There is one place on the Mac that is modest but very valuable — the Menubar on the right side of the top menu. In fact, The Mac Menubar is designed to be more than just a showcase of programs that live in the background like Windows. It relies on the “anything goes” feature of Menubar at the top. Menubar expands Mac interaction with other applications, from simple display to quick operation. Using Menubar effectively improves Mac efficiency.

So, again, I’d like to have this feature on the Mac Calendar I’m working on.

Electron Tray

We have to introduce Electron’s Tray first.

Meaning: ICONS and the context menu is added to the system notification area The official document: www.electronjs.org/docs/api/tr…

In this project, we mainly refer to Timestamp and encapsulate it into TrayService:

import type { Rectangle} from 'electron'; import { Tray, nativeImage} from 'electron'; export default class TrayService { tray: Tray; label: string; clickHandler: any; constructor() { this.label = ''; const icon = nativeImage.createEmpty(); this.tray = new Tray(icon); this.tray.on('click', () => (this.clickHandler || (() => {}))()); } getBounds(): Rectangle { return this.tray.getBounds(); } getLabel(): string { return this.label; } setLabel(label: string): this { if (this.tray.isDestroyed()) { return this; } this.tray.setTitle((this.label = label)); return this; } onClick(fn: any): void { this.clickHandler = fn; }}Copy the code

Here’s the code:

  1. Because I have not designed the Icon of this product well, I leave it blank first.
  2. The content of Label has external control. Today, it mainly displays the information of the three elements “Time of lunar Week”, and there will be more complex internal presentation later (here it will be kept secret first).
  3. clickThe event, this is easy to understand, just click on Tray and Electron or disappear;
  4. In order to make the calendar Electron display right below the Menubar, we need helpgetBounds()Value to view the document specifically:www.electronjs.org/docs/api/tr…

Electron display

With the TrayService done, you now need to display Electron directly below it.

// Tray click the event to get getBounds(), Service for Election shows this. TrayService. (onClick () = > {const bounds = this. TrayService. GetBounds (); const currentMousePosition = screen.getCursorScreenPoint(); const currentDisplay = screen.getDisplayNearestPoint( currentMousePosition, ); this.setPosition(bounds.x + bounds.width / 2, currentDisplay.workArea.y); if (this.isVisible()) { this.hide(); } else { this.show(); }});Copy the code

Look at the this.setPosition() method:

setPosition(x: number, y: number, centerToX = true): this {
this.window.setPosition(
  centerToX ? Math.round(x - this.window.getSize()[0] / 2) : x,
  y,
);
return this;
}
Copy the code

Contents of the output

Everything is there except what we need to show. Today is just a dynamic display: “Lunar week time”.

In order to match the dynamic real-time display effect, we need to use the timer function, which is encapsulated as: ClockService, directly look at the code:

'use strict'; import { app } from 'electron'; const Moment = require('moment'); import LunarService from './LunarService'; export default class ClockService { format: any; onTickHandler: any; intervalId: any; constructor() { Moment.locale(app.getLocale()); // this.setFormat("MM/DD HH:mm:ss"); // lll this.setFormat('MMMDo dddd HH:mm:ss'); this.start(); } start(): this { if (typeof this.onTickHandler ! == 'function') { this.onTickHandler = () => {}; } this.intervalId = setInterval(() => this.onTickHandler(this), 1000); return this; } stop(): this { if (this.intervalId) { this.intervalId = clearInterval(this.intervalId); } return this; } onTick(callback: any): this { this.onTickHandler = callback; return this; } getFormat(): any { return this.format; } setFormat(format: any): this { if (typeof format ! == 'string') { return this; } this.format = format; return this; } toString(): string { const lunarService = new LunarService(); const dayTextInChinese = lunarService.showNongliData(true); return dayTextInChinese + ' ' + Moment().format(this.getFormat()); }}Copy the code

I’m sure you understand what this means. When the timer is executed, get the displayed content in real time and fill it on the Tray Label:

this.clockService.onTick((clock: { toString: () => string; }) => {
  this.trayService.setLabel(clock.toString());
});
Copy the code

Moment() = Moment(); Moment() = Moment();

This “lunar data” is consistent with the date shown in the calendar, which should be familiar from the previous notes:

showNongliData(changeShowFestivals: boolean): string { if (changeShowFestivals) { const solarFestivals = this.solar.getFestivals(); if (solarFestivals.length > 0) { return solarFestivals.join(' '); } const lunarFestivals = this.lunar.getFestivals(); if (lunarFestivals.length > 0) { return lunarFestivals.join(' '); }} to return this. The lunar. GetJieQi () | | ` ${this. Lunar. GetMonthInChinese ()} month ${this. Lunar. GetDayInChinese ()} `; }Copy the code

summary

Oh, and finally, we yarn watch directly to the effect:

As for the content display on Memubar, it remains to be explored continuously in the next step.

Note: Timestamps use new time components over time: Date-fns, maybe I will refer to this in the next stage. At present, FullCalendar also uses moment.js, so I still use this component to reduce the introduction of the third party and the volume of the software as much as possible.

Today is the beginning of the development of Electron, as for more Electron functions we continue to toss, to be continued!

All the records of this project are basically in the column, welcome to check out: Electron+Vue3 MAC Calendar Development records