mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-18 21:54:09 +00:00
refactor: improve native menu links
This commit is contained in:
committed by
Carlos Valente
parent
f1cac8d1c4
commit
0a53018930
@@ -1,185 +1,267 @@
|
||||
const { shell } = require('electron');
|
||||
const { Menu, shell } = require('electron');
|
||||
|
||||
const { linkToGitHub, linkToDocs, linkToDiscord, isMac, releaseTag, downloadPath } = require('../external');
|
||||
|
||||
/**
|
||||
* Build description of application menu
|
||||
* @param {boolean} isMac - Whether the target platform is mac
|
||||
* Creates the application menu
|
||||
* @param {function} askToQuit - function for quitting process
|
||||
* @param {string} clientUrl - base url for the application
|
||||
* @param {string} serverUrl - base url for the application
|
||||
* @param {function} redirectWindow - function to redirect main window content
|
||||
* @param {function} download - function to download a resource from url
|
||||
* @returns {Menu} - application menu
|
||||
*/
|
||||
function getApplicationMenu(isMac, askToQuit, urlBase, version, redirectWindow) {
|
||||
return [
|
||||
...(isMac
|
||||
? [
|
||||
{
|
||||
label: 'Ontime',
|
||||
submenu: [
|
||||
{ role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Quit',
|
||||
click: () => askToQuit(),
|
||||
accelerator: 'Cmd+Q',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [isMac ? { role: 'close' } : { role: 'quit' }],
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ role: 'undo' },
|
||||
{ role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' },
|
||||
...(isMac
|
||||
? [
|
||||
{ role: 'pasteAndMatchStyle' },
|
||||
{ role: 'delete' },
|
||||
{ role: 'selectAll' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Speech',
|
||||
submenu: [{ role: 'startSpeaking' }, { role: 'stopSpeaking' }],
|
||||
},
|
||||
]
|
||||
: [{ role: 'delete' }, { type: 'separator' }, { role: 'selectAll' }]),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Views',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Ontime Views (opens in browser)',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Public',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/public`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Lower Thirds',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/lower`);
|
||||
},
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Timer',
|
||||
accelerator: 'CmdOrCtrl+V',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/timer`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Clock',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/clock`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Minimal Timer',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/minimal`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Backstage',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/backstage`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Timeline (beta)',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/timeline`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Studio Clock',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/studio`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Countdown',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/countdown`);
|
||||
},
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Editor',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/editor`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Cuesheet',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/cuesheet`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Operator',
|
||||
click: async () => {
|
||||
await shell.openExternal(`${urlBase}/op`);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ role: 'forceReload' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{ role: 'minimize' },
|
||||
{ role: 'zoom' },
|
||||
...(isMac
|
||||
? [{ type: 'separator' }, { role: 'front' }, { type: 'separator' }, { role: 'window' }]
|
||||
: [{ role: 'close' }]),
|
||||
],
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About',
|
||||
click: () => redirectWindow('editor?settings=about'),
|
||||
},
|
||||
{
|
||||
label: version,
|
||||
click: () => redirectWindow('editor?settings=about'),
|
||||
},
|
||||
{
|
||||
label: 'See on github',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://github.com/cpvalente/ontime');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Online documentation',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://docs.getontime.no/');
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
function getApplicationMenu(askToQuit, clientUrl, serverUrl, redirectWindow, download) {
|
||||
const template = [
|
||||
...(isMac ? [makeMacMenu(askToQuit)] : []),
|
||||
makeFileMenu(serverUrl, redirectWindow, download),
|
||||
makeViewMenu(clientUrl),
|
||||
makeSettingsMenu(redirectWindow),
|
||||
makeHelpMenu(redirectWindow),
|
||||
];
|
||||
return Menu.buildFromTemplate(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function generates the app menu (macOS only)
|
||||
* @param {function} askToQuit - function for quitting process
|
||||
* @returns {Object}
|
||||
*/
|
||||
function makeMacMenu(askToQuit) {
|
||||
return {
|
||||
label: 'Ontime',
|
||||
submenu: [
|
||||
{ role: 'about', label: 'About Ontime' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide', label: 'Hide Ontime' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Quit',
|
||||
click: () => askToQuit(),
|
||||
accelerator: isMac ? 'Cmd+Q' : 'Alt+F4',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function generates the file menu
|
||||
* @param {string} serverUrl - base url for the application
|
||||
* @param {function} redirectWindow - function to redirect main window content
|
||||
* @param {function} download - function to download a resource from url
|
||||
* @returns {Object}
|
||||
*/
|
||||
function makeFileMenu(serverUrl, redirectWindow, download) {
|
||||
const downloadProject = () => {
|
||||
try {
|
||||
download(serverUrl + downloadPath);
|
||||
} catch (_error) {
|
||||
/** unhandled error */
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{
|
||||
label: 'New project...',
|
||||
click: () => redirectWindow('editor?settings=project__manage&create=true'),
|
||||
},
|
||||
{
|
||||
label: 'Edit project info',
|
||||
click: () => redirectWindow('editor?settings=project__data'),
|
||||
},
|
||||
{
|
||||
label: 'Manage projects...',
|
||||
click: () => redirectWindow('editor?settings=project__manage'),
|
||||
},
|
||||
{
|
||||
label: 'Download project',
|
||||
click: downloadProject,
|
||||
},
|
||||
{ role: isMac ? 'close' : 'quit' },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function generates the views menu
|
||||
* @param {string} clientUrl - base url for the application
|
||||
* @returns {Object}
|
||||
*/
|
||||
function makeViewMenu(clientUrl) {
|
||||
return {
|
||||
label: 'Views',
|
||||
submenu: [
|
||||
makeItemOpenInShell('Public', `${clientUrl}/public`),
|
||||
makeItemOpenInShell('Lower Thirds', `${clientUrl}/lower`),
|
||||
{ type: 'separator' },
|
||||
makeItemOpenInShell('Timer', `${clientUrl}/timer`),
|
||||
makeItemOpenInShell('Minimal Timer', `${clientUrl}/minimal`),
|
||||
makeItemOpenInShell('Clock', `${clientUrl}/clock`),
|
||||
makeItemOpenInShell('Backstage', `${clientUrl}/backstage`),
|
||||
makeItemOpenInShell('Timeline (beta)', `${clientUrl}/timeline`),
|
||||
makeItemOpenInShell('Studio Clock', `${clientUrl}/studio`),
|
||||
makeItemOpenInShell('Countdown', `${clientUrl}/countdown`),
|
||||
{ type: 'separator' },
|
||||
makeItemOpenInShell('Editor', `${clientUrl}/editor`),
|
||||
makeItemOpenInShell('Cuesheet', `${clientUrl}/cuesheet`),
|
||||
makeItemOpenInShell('Operator', `${clientUrl}/op`),
|
||||
|
||||
{ type: 'separator' },
|
||||
{ role: 'forceReload' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function generates the settings menu
|
||||
* @param {function} redirectWindow - function to redirect main window content
|
||||
* @returns {Object}
|
||||
*/
|
||||
function makeSettingsMenu(redirectWindow) {
|
||||
return {
|
||||
label: 'Settings',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Open Settings',
|
||||
accelerator: 'CommandOrControl+,',
|
||||
click: () => redirectWindow('editor?settings=project'),
|
||||
},
|
||||
{
|
||||
label: 'Project',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Project data',
|
||||
click: () => redirectWindow('editor?settings=project__data'),
|
||||
},
|
||||
{
|
||||
label: 'Manage projects',
|
||||
click: () => redirectWindow('editor?settings=project__manage'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'App Settings',
|
||||
submenu: [
|
||||
{
|
||||
label: 'General settings',
|
||||
click: () => redirectWindow('editor?settings=general__settings'),
|
||||
},
|
||||
{
|
||||
label: 'Editor settings',
|
||||
click: () => redirectWindow('editor?settings=general__editor'),
|
||||
},
|
||||
{
|
||||
label: 'View settings',
|
||||
click: () => redirectWindow('editor?settings=general__view'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Feature Settings',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Custom fields',
|
||||
click: () => redirectWindow('editor?settings=feature_settings__custom'),
|
||||
},
|
||||
{
|
||||
label: 'URL presets',
|
||||
click: () => redirectWindow('editor?settings=feature_settings__urlpresets'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Data Sources',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Import spreadsheet',
|
||||
click: () => redirectWindow('editor?settings=sources__xlsx'),
|
||||
},
|
||||
{
|
||||
label: 'Sync with Google Sheet',
|
||||
click: () => redirectWindow('editor?settings=sources__gsheet'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Integrations',
|
||||
submenu: [
|
||||
{
|
||||
label: 'OSC settings',
|
||||
click: () => redirectWindow('editor?settings=integrations__osc'),
|
||||
},
|
||||
{
|
||||
label: 'HTTP settings',
|
||||
click: () => redirectWindow('editor?settings=integrations__http'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Network',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Event log',
|
||||
click: () => redirectWindow('editor?settings=network__log'),
|
||||
},
|
||||
{
|
||||
label: 'Manage cleints',
|
||||
click: () => redirectWindow('editor?settings=network__clients'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function generates the help menu
|
||||
* @param {function} redirectWindow - function to redirect main window content
|
||||
* @returns {Object}
|
||||
*/
|
||||
function makeHelpMenu(redirectWindow) {
|
||||
return {
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: `Ontime ${releaseTag}`,
|
||||
click: () => redirectWindow('editor?settings=about'),
|
||||
},
|
||||
{
|
||||
type: 'separator',
|
||||
},
|
||||
makeItemOpenInShell('See on github', linkToGitHub),
|
||||
makeItemOpenInShell('Online documentation', linkToDocs),
|
||||
makeItemOpenInShell('Join us on Discord', linkToDiscord),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to safely open a URL in the default browser
|
||||
* @param {string} label
|
||||
* @param {string} url
|
||||
* @returns {object} - MenuItem
|
||||
*/
|
||||
function makeItemOpenInShell(label, url) {
|
||||
return {
|
||||
label: `${label} ↗`,
|
||||
click: async () => {
|
||||
try {
|
||||
await shell.openExternal(url);
|
||||
} catch (_error) {
|
||||
/** unhandled error */
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { getApplicationMenu };
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
const { Menu } = require('electron');
|
||||
|
||||
/**
|
||||
* Build description of tray context menu
|
||||
* Creates the application tray menu
|
||||
* @param {function} showApp - function for making the window visible
|
||||
* @param {function} askToQuit - function for quitting process
|
||||
* @returns {Menu} - application tray menu
|
||||
*/
|
||||
function getTrayMenu(showApp, askToQuit) {
|
||||
return [
|
||||
return Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'Show App',
|
||||
click: () => showApp(),
|
||||
click: showApp,
|
||||
},
|
||||
{
|
||||
label: 'Shutdown',
|
||||
click: () => askToQuit(),
|
||||
click: askToQuit,
|
||||
},
|
||||
];
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = { getTrayMenu };
|
||||
|
||||
Reference in New Issue
Block a user