mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
feat(menu): add more detail in Menu (#1570)
This commit is contained in:
@ -168,6 +168,7 @@
|
|||||||
"node-html-parser": "6.1.12",
|
"node-html-parser": "6.1.12",
|
||||||
"node-id3": "0.2.6",
|
"node-id3": "0.2.6",
|
||||||
"peerjs": "1.5.2",
|
"peerjs": "1.5.2",
|
||||||
|
"semver": "7.5.4",
|
||||||
"serve": "14.2.1",
|
"serve": "14.2.1",
|
||||||
"simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9",
|
"simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9",
|
||||||
"ts-morph": "21.0.1",
|
"ts-morph": "21.0.1",
|
||||||
@ -181,6 +182,7 @@
|
|||||||
"@types/electron-localshortcut": "3.1.3",
|
"@types/electron-localshortcut": "3.1.3",
|
||||||
"@types/howler": "2.2.11",
|
"@types/howler": "2.2.11",
|
||||||
"@types/html-to-text": "9.0.4",
|
"@types/html-to-text": "9.0.4",
|
||||||
|
"@types/semver": "7.5.6",
|
||||||
"@typescript-eslint/eslint-plugin": "6.16.0",
|
"@typescript-eslint/eslint-plugin": "6.16.0",
|
||||||
"bufferutil": "4.0.8",
|
"bufferutil": "4.0.8",
|
||||||
"builtin-modules": "3.3.0",
|
"builtin-modules": "3.3.0",
|
||||||
|
|||||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@ -117,6 +117,9 @@ dependencies:
|
|||||||
peerjs:
|
peerjs:
|
||||||
specifier: 1.5.2
|
specifier: 1.5.2
|
||||||
version: 1.5.2
|
version: 1.5.2
|
||||||
|
semver:
|
||||||
|
specifier: 7.5.4
|
||||||
|
version: 7.5.4
|
||||||
serve:
|
serve:
|
||||||
specifier: 14.2.1
|
specifier: 14.2.1
|
||||||
version: 14.2.1
|
version: 14.2.1
|
||||||
@ -152,6 +155,9 @@ devDependencies:
|
|||||||
'@types/html-to-text':
|
'@types/html-to-text':
|
||||||
specifier: 9.0.4
|
specifier: 9.0.4
|
||||||
version: 9.0.4
|
version: 9.0.4
|
||||||
|
'@types/semver':
|
||||||
|
specifier: 7.5.6
|
||||||
|
version: 7.5.6
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: 6.16.0
|
specifier: 6.16.0
|
||||||
version: 6.16.0(@typescript-eslint/parser@6.14.0)(eslint@8.56.0)(typescript@5.3.3)
|
version: 6.16.0(@typescript-eslint/parser@6.14.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||||
@ -1113,7 +1119,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
|
resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
rollup: 4.9.1
|
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
rollup:
|
rollup:
|
||||||
optional: true
|
optional: true
|
||||||
|
|||||||
@ -170,7 +170,8 @@
|
|||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"label": "Plugins"
|
"label": "Plugins",
|
||||||
|
"new": "NEW"
|
||||||
},
|
},
|
||||||
"view": {
|
"view": {
|
||||||
"label": "View",
|
"label": "View",
|
||||||
|
|||||||
@ -170,7 +170,8 @@
|
|||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"enabled": "활성화",
|
"enabled": "활성화",
|
||||||
"label": "확장"
|
"label": "확장",
|
||||||
|
"new": "NEW"
|
||||||
},
|
},
|
||||||
"view": {
|
"view": {
|
||||||
"label": "보기",
|
"label": "보기",
|
||||||
|
|||||||
25
src/menu.ts
25
src/menu.ts
@ -9,6 +9,7 @@ import {
|
|||||||
shell,
|
shell,
|
||||||
} from 'electron';
|
} from 'electron';
|
||||||
import prompt from 'custom-electron-prompt';
|
import prompt from 'custom-electron-prompt';
|
||||||
|
import { satisfies } from 'semver';
|
||||||
|
|
||||||
import { allPlugins } from 'virtual:plugins';
|
import { allPlugins } from 'virtual:plugins';
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ import promptOptions from './providers/prompt-options';
|
|||||||
import { getAllMenuTemplate, loadAllMenuPlugins } from './loader/menu';
|
import { getAllMenuTemplate, loadAllMenuPlugins } from './loader/menu';
|
||||||
import { setLanguage, t } from '@/i18n';
|
import { setLanguage, t } from '@/i18n';
|
||||||
|
|
||||||
|
import packageJson from '../package.json';
|
||||||
|
|
||||||
export type MenuTemplate = Electron.MenuItemConstructorOptions[];
|
export type MenuTemplate = Electron.MenuItemConstructorOptions[];
|
||||||
|
|
||||||
// True only if in-app-menu was loaded on launch
|
// True only if in-app-menu was loaded on launch
|
||||||
@ -31,10 +34,14 @@ const inAppMenuActive = config.plugins.isEnabled('in-app-menu');
|
|||||||
const pluginEnabledMenu = (
|
const pluginEnabledMenu = (
|
||||||
plugin: string,
|
plugin: string,
|
||||||
label = '',
|
label = '',
|
||||||
|
description: string | undefined = undefined,
|
||||||
|
isNew = false,
|
||||||
hasSubmenu = false,
|
hasSubmenu = false,
|
||||||
refreshMenu: (() => void) | undefined = undefined,
|
refreshMenu: (() => void) | undefined = undefined,
|
||||||
): Electron.MenuItemConstructorOptions => ({
|
): Electron.MenuItemConstructorOptions => ({
|
||||||
label: label || plugin,
|
label: label || plugin,
|
||||||
|
sublabel: isNew ? t('main.menu.plugins.new') : undefined,
|
||||||
|
toolTip: description,
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked: config.plugins.isEnabled(plugin),
|
checked: config.plugins.isEnabled(plugin),
|
||||||
click(item: Electron.MenuItem) {
|
click(item: Electron.MenuItem) {
|
||||||
@ -66,12 +73,15 @@ export const mainMenuTemplate = async (
|
|||||||
|
|
||||||
const menuResult = Object.entries(getAllMenuTemplate()).map(
|
const menuResult = Object.entries(getAllMenuTemplate()).map(
|
||||||
([id, template]) => {
|
([id, template]) => {
|
||||||
const pluginLabel = allPlugins[id]?.name?.() ?? id;
|
const plugin = allPlugins[id];
|
||||||
|
const pluginLabel = plugin?.name?.() ?? id;
|
||||||
|
const pluginDescription = plugin?.description?.() ?? undefined;
|
||||||
|
const isNew = plugin?.addedVersion ? satisfies(packageJson.version, plugin.addedVersion) : false;
|
||||||
|
|
||||||
if (!config.plugins.isEnabled(id)) {
|
if (!config.plugins.isEnabled(id)) {
|
||||||
return [
|
return [
|
||||||
id,
|
id,
|
||||||
pluginEnabledMenu(id, pluginLabel, true, innerRefreshMenu),
|
pluginEnabledMenu(id, pluginLabel, pluginDescription, isNew, true, innerRefreshMenu),
|
||||||
] as const;
|
] as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,10 +89,14 @@ export const mainMenuTemplate = async (
|
|||||||
id,
|
id,
|
||||||
{
|
{
|
||||||
label: pluginLabel,
|
label: pluginLabel,
|
||||||
|
sublabel: isNew ? t('main.menu.plugins.new') : undefined,
|
||||||
|
toolTip: pluginDescription,
|
||||||
submenu: [
|
submenu: [
|
||||||
pluginEnabledMenu(
|
pluginEnabledMenu(
|
||||||
id,
|
id,
|
||||||
t('main.menu.plugins.enabled'),
|
t('main.menu.plugins.enabled'),
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
true,
|
true,
|
||||||
innerRefreshMenu,
|
innerRefreshMenu,
|
||||||
),
|
),
|
||||||
@ -106,9 +120,12 @@ export const mainMenuTemplate = async (
|
|||||||
const predefinedTemplate = menuResult.find((it) => it[0] === id);
|
const predefinedTemplate = menuResult.find((it) => it[0] === id);
|
||||||
if (predefinedTemplate) return predefinedTemplate[1];
|
if (predefinedTemplate) return predefinedTemplate[1];
|
||||||
|
|
||||||
const pluginLabel = allPlugins[id]?.name?.() ?? id;
|
const plugin = allPlugins[id];
|
||||||
|
const pluginLabel = plugin?.name?.() ?? id;
|
||||||
|
const pluginDescription = plugin?.description?.() ?? undefined;
|
||||||
|
const isNew = plugin?.addedVersion ? satisfies(packageJson.version, plugin.addedVersion) : false;
|
||||||
|
|
||||||
return pluginEnabledMenu(id, pluginLabel, true, innerRefreshMenu);
|
return pluginEnabledMenu(id, pluginLabel, pluginDescription, isNew, true, innerRefreshMenu);
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableLanguages = Object.keys(languageResources);
|
const availableLanguages = Object.keys(languageResources);
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export default createPlugin({
|
|||||||
name: () => t('plugins.album-actions.name'),
|
name: () => t('plugins.album-actions.name'),
|
||||||
description: () => t('plugins.album-actions.description'),
|
description: () => t('plugins.album-actions.description'),
|
||||||
restartNeeded: false,
|
restartNeeded: false,
|
||||||
|
addedVersion: '3.2.0',
|
||||||
config: {
|
config: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -52,6 +52,18 @@ export const createPanel = (
|
|||||||
menu.appendChild(iconWrapper);
|
menu.appendChild(iconWrapper);
|
||||||
menu.append(item.label);
|
menu.append(item.label);
|
||||||
|
|
||||||
|
if (item.sublabel) {
|
||||||
|
menu.classList.add('badge');
|
||||||
|
const menuBadge = document.createElement('menu-item-badge');
|
||||||
|
menuBadge.append(item.sublabel);
|
||||||
|
menu.append(menuBadge);
|
||||||
|
}
|
||||||
|
if (item.toolTip) {
|
||||||
|
const menuTooltip = document.createElement('menu-item-tooltip');
|
||||||
|
menuTooltip.append(item.toolTip);
|
||||||
|
menu.append(menuTooltip);
|
||||||
|
}
|
||||||
|
|
||||||
menu.addEventListener('click', async () => {
|
menu.addEventListener('click', async () => {
|
||||||
await window.ipcRenderer.invoke('menu-event', item.commandId);
|
await window.ipcRenderer.invoke('menu-event', item.commandId);
|
||||||
const menuItem = (await window.ipcRenderer.invoke(
|
const menuItem = (await window.ipcRenderer.invoke(
|
||||||
|
|||||||
@ -97,6 +97,8 @@ menu-panel.position-by-bottom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
menu-item {
|
menu-item {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
-webkit-app-region: none;
|
-webkit-app-region: none;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@ -109,6 +111,9 @@ menu-item {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
menu-item.badge {
|
||||||
|
grid-template-columns: 32px 1fr auto minmax(32px, auto);
|
||||||
|
}
|
||||||
menu-item:hover {
|
menu-item:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
@ -128,6 +133,56 @@ menu-separator {
|
|||||||
background-color: rgba(255, 255, 255, 0.2);
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu-item-badge {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
min-width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 0 4px;
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
|
color: #f1f1f1;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu-item-tooltip {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
left: 0;
|
||||||
|
top: calc(100% + 4px);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
min-width: 32px;
|
||||||
|
padding: 4px;
|
||||||
|
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: rgba(25, 25, 25, 0.8);
|
||||||
|
color: #f1f1f1;
|
||||||
|
font-size: 10px;
|
||||||
|
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
scale: 0.9;
|
||||||
|
|
||||||
|
transform-origin: 50% 0;
|
||||||
|
transition: all 0.225s ease-out;
|
||||||
|
}
|
||||||
|
menu-item:hover > menu-item-tooltip {
|
||||||
|
opacity: 1;
|
||||||
|
scale: 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
/* classes */
|
/* classes */
|
||||||
|
|
||||||
.title-bar-icon {
|
.title-bar-icon {
|
||||||
|
|||||||
@ -38,6 +38,7 @@ export default createPlugin({
|
|||||||
name: () => t('plugins.music-together.name'),
|
name: () => t('plugins.music-together.name'),
|
||||||
description: () => t('plugins.music-together.description'),
|
description: () => t('plugins.music-together.description'),
|
||||||
restartNeeded: false,
|
restartNeeded: false,
|
||||||
|
addedVersion: '3.2.0',
|
||||||
config: {
|
config: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
|
|||||||
@ -47,6 +47,7 @@ export interface PluginDef<
|
|||||||
name: () => string;
|
name: () => string;
|
||||||
authors?: Author[];
|
authors?: Author[];
|
||||||
description?: () => string;
|
description?: () => string;
|
||||||
|
addedVersion?: string;
|
||||||
config?: Config;
|
config?: Config;
|
||||||
|
|
||||||
menu?: (
|
menu?: (
|
||||||
|
|||||||
Reference in New Issue
Block a user