mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-14 03:41:46 +00:00
in-app-menu
This commit is contained in:
@ -1,21 +1,28 @@
|
|||||||
import titlebarStyle from './titlebar.css?inline';
|
import titlebarStyle from './titlebar.css?inline';
|
||||||
|
import { createPlugin } from '@/utils';
|
||||||
|
import { onMainLoad } from '@/plugins/in-app-menu/main';
|
||||||
|
import { onMenu } from '@/plugins/in-app-menu/menu';
|
||||||
|
import { onPlayerApiReady, onRendererLoad } from '@/plugins/in-app-menu/renderer';
|
||||||
|
|
||||||
import { createPluginBuilder } from '../utils/builder';
|
export interface InAppMenuConfig {
|
||||||
|
enabled: boolean;
|
||||||
|
hideDOMWindowControls: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const builder = createPluginBuilder('in-app-menu', {
|
export default createPlugin({
|
||||||
name: 'In-App Menu',
|
name: 'In-App Menu',
|
||||||
restartNeeded: true,
|
restartNeeded: true,
|
||||||
config: {
|
config: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
hideDOMWindowControls: false,
|
hideDOMWindowControls: false,
|
||||||
|
} as InAppMenuConfig,
|
||||||
|
stylesheets: [titlebarStyle],
|
||||||
|
menu: onMenu,
|
||||||
|
|
||||||
|
backend: onMainLoad,
|
||||||
|
renderer: {
|
||||||
|
start: onRendererLoad,
|
||||||
|
onPlayerApiReady,
|
||||||
},
|
},
|
||||||
styles: [titlebarStyle],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default builder;
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface PluginBuilderList {
|
|
||||||
[builder.id]: typeof builder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -2,75 +2,71 @@ import { register } from 'electron-localshortcut';
|
|||||||
|
|
||||||
import { BrowserWindow, Menu, MenuItem, ipcMain, nativeImage } from 'electron';
|
import { BrowserWindow, Menu, MenuItem, ipcMain, nativeImage } from 'electron';
|
||||||
|
|
||||||
import builder from './index';
|
import { BackendContext } from '@/types/contexts';
|
||||||
|
import { InAppMenuConfig } from '@/plugins/in-app-menu/index';
|
||||||
|
|
||||||
export default builder.createMain(({ handle, send }) => {
|
export const onMainLoad = ({ window: win, ipc: { handle, send } }: BackendContext<InAppMenuConfig>) => {
|
||||||
|
win.on('close', () => {
|
||||||
|
send('close-all-in-app-menu-panel');
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
win.once('ready-to-show', () => {
|
||||||
onLoad(win) {
|
register(win, '`', () => {
|
||||||
win.on('close', () => {
|
send('toggle-in-app-menu');
|
||||||
send('close-all-in-app-menu-panel');
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
win.once('ready-to-show', () => {
|
handle(
|
||||||
register(win, '`', () => {
|
'get-menu',
|
||||||
send('toggle-in-app-menu');
|
() => JSON.parse(JSON.stringify(
|
||||||
});
|
Menu.getApplicationMenu(),
|
||||||
});
|
(key: string, value: unknown) => (key !== 'commandsMap' && key !== 'menu') ? value : undefined),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
handle(
|
const getMenuItemById = (commandId: number): MenuItem | null => {
|
||||||
'get-menu',
|
const menu = Menu.getApplicationMenu();
|
||||||
() => JSON.parse(JSON.stringify(
|
|
||||||
Menu.getApplicationMenu(),
|
|
||||||
(key: string, value: unknown) => (key !== 'commandsMap' && key !== 'menu') ? value : undefined),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const getMenuItemById = (commandId: number): MenuItem | null => {
|
let target: MenuItem | null = null;
|
||||||
const menu = Menu.getApplicationMenu();
|
const stack = [...menu?.items ?? []];
|
||||||
|
while (stack.length > 0) {
|
||||||
|
const now = stack.shift();
|
||||||
|
now?.submenu?.items.forEach((item) => stack.push(item));
|
||||||
|
|
||||||
let target: MenuItem | null = null;
|
if (now?.commandId === commandId) {
|
||||||
const stack = [...menu?.items ?? []];
|
target = now;
|
||||||
while (stack.length > 0) {
|
break;
|
||||||
const now = stack.shift();
|
}
|
||||||
now?.submenu?.items.forEach((item) => stack.push(item));
|
}
|
||||||
|
|
||||||
if (now?.commandId === commandId) {
|
return target;
|
||||||
target = now;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
|
||||||
};
|
|
||||||
|
|
||||||
ipcMain.handle('menu-event', (event, commandId: number) => {
|
|
||||||
const target = getMenuItemById(commandId);
|
|
||||||
if (target) target.click(undefined, BrowserWindow.fromWebContents(event.sender), event.sender);
|
|
||||||
});
|
|
||||||
|
|
||||||
handle('get-menu-by-id', (commandId: number) => {
|
|
||||||
const result = getMenuItemById(commandId);
|
|
||||||
|
|
||||||
return JSON.parse(JSON.stringify(
|
|
||||||
result,
|
|
||||||
(key: string, value: unknown) => (key !== 'commandsMap' && key !== 'menu') ? value : undefined),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
handle('window-is-maximized', () => win.isMaximized());
|
|
||||||
|
|
||||||
handle('window-close', () => win.close());
|
|
||||||
handle('window-minimize', () => win.minimize());
|
|
||||||
handle('window-maximize', () => win.maximize());
|
|
||||||
win.on('maximize', () => send('window-maximize'));
|
|
||||||
handle('window-unmaximize', () => win.unmaximize());
|
|
||||||
win.on('unmaximize', () => send('window-unmaximize'));
|
|
||||||
|
|
||||||
handle('image-path-to-data-url', (imagePath: string) => {
|
|
||||||
const nativeImageIcon = nativeImage.createFromPath(imagePath);
|
|
||||||
return nativeImageIcon?.toDataURL();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
ipcMain.handle('menu-event', (event, commandId: number) => {
|
||||||
|
const target = getMenuItemById(commandId);
|
||||||
|
if (target) target.click(undefined, BrowserWindow.fromWebContents(event.sender), event.sender);
|
||||||
|
});
|
||||||
|
|
||||||
|
handle('get-menu-by-id', (commandId: number) => {
|
||||||
|
const result = getMenuItemById(commandId);
|
||||||
|
|
||||||
|
return JSON.parse(JSON.stringify(
|
||||||
|
result,
|
||||||
|
(key: string, value: unknown) => (key !== 'commandsMap' && key !== 'menu') ? value : undefined),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
handle('window-is-maximized', () => win.isMaximized());
|
||||||
|
|
||||||
|
handle('window-close', () => win.close());
|
||||||
|
handle('window-minimize', () => win.minimize());
|
||||||
|
handle('window-maximize', () => win.maximize());
|
||||||
|
win.on('maximize', () => send('window-maximize'));
|
||||||
|
handle('window-unmaximize', () => win.unmaximize());
|
||||||
|
win.on('unmaximize', () => send('window-unmaximize'));
|
||||||
|
|
||||||
|
handle('image-path-to-data-url', (imagePath: string) => {
|
||||||
|
const nativeImageIcon = nativeImage.createFromPath(imagePath);
|
||||||
|
return nativeImageIcon?.toDataURL();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import is from 'electron-is';
|
import is from 'electron-is';
|
||||||
|
|
||||||
import builder from './index';
|
import { setMenuOptions } from '@/config/plugins';
|
||||||
|
|
||||||
import { setMenuOptions } from '../../config/plugins';
|
import type { InAppMenuConfig } from './index';
|
||||||
|
import type { MenuContext } from '@/types/contexts';
|
||||||
|
import type { MenuTemplate } from '@/menu';
|
||||||
|
|
||||||
export default builder.createMenu(async ({ getConfig }) => {
|
export const onMenu = async ({ getConfig }: MenuContext<InAppMenuConfig>): Promise<MenuTemplate> => {
|
||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
|
|
||||||
if (is.linux()) {
|
if (is.linux()) {
|
||||||
@ -22,4 +24,4 @@ export default builder.createMenu(async ({ getConfig }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
});
|
};
|
||||||
|
|||||||
@ -6,190 +6,187 @@ import minimizeRaw from './assets/minimize.svg?inline';
|
|||||||
import maximizeRaw from './assets/maximize.svg?inline';
|
import maximizeRaw from './assets/maximize.svg?inline';
|
||||||
import unmaximizeRaw from './assets/unmaximize.svg?inline';
|
import unmaximizeRaw from './assets/unmaximize.svg?inline';
|
||||||
|
|
||||||
import builder from './index';
|
|
||||||
|
|
||||||
import type { Menu } from 'electron';
|
import type { Menu } from 'electron';
|
||||||
|
|
||||||
|
import type { RendererContext } from '@/types/contexts';
|
||||||
|
import type { InAppMenuConfig } from '@/plugins/in-app-menu/index';
|
||||||
|
|
||||||
const isMacOS = navigator.userAgent.includes('Macintosh');
|
const isMacOS = navigator.userAgent.includes('Macintosh');
|
||||||
const isNotWindowsOrMacOS = !navigator.userAgent.includes('Windows') && !isMacOS;
|
const isNotWindowsOrMacOS = !navigator.userAgent.includes('Windows') && !isMacOS;
|
||||||
|
|
||||||
export default builder.createRenderer(({ getConfig, invoke, on }) => {
|
export const onRendererLoad = async ({ getConfig, ipc: { invoke, on } }: RendererContext<InAppMenuConfig>) => {
|
||||||
return {
|
const config = await getConfig();
|
||||||
async onLoad() {
|
|
||||||
const config = await getConfig();
|
|
||||||
|
|
||||||
const hideDOMWindowControls = config.hideDOMWindowControls;
|
const hideDOMWindowControls = config.hideDOMWindowControls;
|
||||||
|
|
||||||
let hideMenu = window.mainConfig.get('options.hideMenu');
|
let hideMenu = window.mainConfig.get('options.hideMenu');
|
||||||
const titleBar = document.createElement('title-bar');
|
const titleBar = document.createElement('title-bar');
|
||||||
const navBar = document.querySelector<HTMLDivElement>('#nav-bar-background');
|
const navBar = document.querySelector<HTMLDivElement>('#nav-bar-background');
|
||||||
let maximizeButton: HTMLButtonElement;
|
let maximizeButton: HTMLButtonElement;
|
||||||
let panelClosers: (() => void)[] = [];
|
let panelClosers: (() => void)[] = [];
|
||||||
if (isMacOS) titleBar.style.setProperty('--offset-left', '70px');
|
if (isMacOS) titleBar.style.setProperty('--offset-left', '70px');
|
||||||
|
|
||||||
const logo = document.createElement('img');
|
const logo = document.createElement('img');
|
||||||
const close = document.createElement('img');
|
const close = document.createElement('img');
|
||||||
const minimize = document.createElement('img');
|
const minimize = document.createElement('img');
|
||||||
const maximize = document.createElement('img');
|
const maximize = document.createElement('img');
|
||||||
const unmaximize = document.createElement('img');
|
const unmaximize = document.createElement('img');
|
||||||
|
|
||||||
if (window.ELECTRON_RENDERER_URL) {
|
if (window.ELECTRON_RENDERER_URL) {
|
||||||
logo.src = window.ELECTRON_RENDERER_URL + '/' + logoRaw;
|
logo.src = window.ELECTRON_RENDERER_URL + '/' + logoRaw;
|
||||||
close.src = window.ELECTRON_RENDERER_URL + '/' + closeRaw;
|
close.src = window.ELECTRON_RENDERER_URL + '/' + closeRaw;
|
||||||
minimize.src = window.ELECTRON_RENDERER_URL + '/' + minimizeRaw;
|
minimize.src = window.ELECTRON_RENDERER_URL + '/' + minimizeRaw;
|
||||||
maximize.src = window.ELECTRON_RENDERER_URL + '/' + maximizeRaw;
|
maximize.src = window.ELECTRON_RENDERER_URL + '/' + maximizeRaw;
|
||||||
unmaximize.src = window.ELECTRON_RENDERER_URL + '/' + unmaximizeRaw;
|
unmaximize.src = window.ELECTRON_RENDERER_URL + '/' + unmaximizeRaw;
|
||||||
} else {
|
} else {
|
||||||
logo.src = logoRaw;
|
logo.src = logoRaw;
|
||||||
close.src = closeRaw;
|
close.src = closeRaw;
|
||||||
minimize.src = minimizeRaw;
|
minimize.src = minimizeRaw;
|
||||||
maximize.src = maximizeRaw;
|
maximize.src = maximizeRaw;
|
||||||
unmaximize.src = unmaximizeRaw;
|
unmaximize.src = unmaximizeRaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
logo.classList.add('title-bar-icon');
|
logo.classList.add('title-bar-icon');
|
||||||
const logoClick = () => {
|
const logoClick = () => {
|
||||||
hideMenu = !hideMenu;
|
hideMenu = !hideMenu;
|
||||||
let visibilityStyle: string;
|
let visibilityStyle: string;
|
||||||
if (hideMenu) {
|
if (hideMenu) {
|
||||||
visibilityStyle = 'hidden';
|
visibilityStyle = 'hidden';
|
||||||
} else {
|
} else {
|
||||||
visibilityStyle = 'visible';
|
visibilityStyle = 'visible';
|
||||||
}
|
}
|
||||||
const menus = document.querySelectorAll<HTMLElement>('menu-button');
|
const menus = document.querySelectorAll<HTMLElement>('menu-button');
|
||||||
menus.forEach((menu) => {
|
menus.forEach((menu) => {
|
||||||
menu.style.visibility = visibilityStyle;
|
menu.style.visibility = visibilityStyle;
|
||||||
});
|
});
|
||||||
};
|
|
||||||
logo.onclick = logoClick;
|
|
||||||
|
|
||||||
on('toggle-in-app-menu', logoClick);
|
|
||||||
|
|
||||||
if (!isMacOS) titleBar.appendChild(logo);
|
|
||||||
document.body.appendChild(titleBar);
|
|
||||||
|
|
||||||
titleBar.appendChild(logo);
|
|
||||||
|
|
||||||
const addWindowControls = async () => {
|
|
||||||
|
|
||||||
// Create window control buttons
|
|
||||||
const minimizeButton = document.createElement('button');
|
|
||||||
minimizeButton.classList.add('window-control');
|
|
||||||
minimizeButton.appendChild(minimize);
|
|
||||||
minimizeButton.onclick = () => invoke('window-minimize');
|
|
||||||
|
|
||||||
maximizeButton = document.createElement('button');
|
|
||||||
if (await invoke('window-is-maximized')) {
|
|
||||||
maximizeButton.classList.add('window-control');
|
|
||||||
maximizeButton.appendChild(unmaximize);
|
|
||||||
} else {
|
|
||||||
maximizeButton.classList.add('window-control');
|
|
||||||
maximizeButton.appendChild(maximize);
|
|
||||||
}
|
|
||||||
maximizeButton.onclick = async () => {
|
|
||||||
if (await invoke('window-is-maximized')) {
|
|
||||||
// change icon to maximize
|
|
||||||
maximizeButton.removeChild(maximizeButton.firstChild!);
|
|
||||||
maximizeButton.appendChild(maximize);
|
|
||||||
|
|
||||||
// call unmaximize
|
|
||||||
await invoke('window-unmaximize');
|
|
||||||
} else {
|
|
||||||
// change icon to unmaximize
|
|
||||||
maximizeButton.removeChild(maximizeButton.firstChild!);
|
|
||||||
maximizeButton.appendChild(unmaximize);
|
|
||||||
|
|
||||||
// call maximize
|
|
||||||
await invoke('window-maximize');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeButton = document.createElement('button');
|
|
||||||
closeButton.classList.add('window-control');
|
|
||||||
closeButton.appendChild(close);
|
|
||||||
closeButton.onclick = () => invoke('window-close');
|
|
||||||
|
|
||||||
// Create a container div for the window control buttons
|
|
||||||
const windowControlsContainer = document.createElement('div');
|
|
||||||
windowControlsContainer.classList.add('window-controls-container');
|
|
||||||
windowControlsContainer.appendChild(minimizeButton);
|
|
||||||
windowControlsContainer.appendChild(maximizeButton);
|
|
||||||
windowControlsContainer.appendChild(closeButton);
|
|
||||||
|
|
||||||
// Add window control buttons to the title bar
|
|
||||||
titleBar.appendChild(windowControlsContainer);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isNotWindowsOrMacOS && !hideDOMWindowControls) await addWindowControls();
|
|
||||||
|
|
||||||
if (navBar) {
|
|
||||||
const observer = new MutationObserver((mutations) => {
|
|
||||||
mutations.forEach(() => {
|
|
||||||
titleBar.style.setProperty('--titlebar-background-color', navBar.style.backgroundColor);
|
|
||||||
document.querySelector('html')!.style.setProperty('--titlebar-background-color', navBar.style.backgroundColor);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
observer.observe(navBar, { attributes : true, attributeFilter : ['style'] });
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateMenu = async () => {
|
|
||||||
const children = [...titleBar.children];
|
|
||||||
children.forEach((child) => {
|
|
||||||
if (child !== logo) child.remove();
|
|
||||||
});
|
|
||||||
panelClosers = [];
|
|
||||||
|
|
||||||
const menu = await invoke<Menu | null>('get-menu');
|
|
||||||
if (!menu) return;
|
|
||||||
|
|
||||||
menu.items.forEach((menuItem) => {
|
|
||||||
const menu = document.createElement('menu-button');
|
|
||||||
const [, { close: closer }] = createPanel(titleBar, menu, menuItem.submenu?.items ?? []);
|
|
||||||
panelClosers.push(closer);
|
|
||||||
|
|
||||||
menu.append(menuItem.label);
|
|
||||||
titleBar.appendChild(menu);
|
|
||||||
if (hideMenu) {
|
|
||||||
menu.style.visibility = 'hidden';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (isNotWindowsOrMacOS && !hideDOMWindowControls) await addWindowControls();
|
|
||||||
};
|
|
||||||
await updateMenu();
|
|
||||||
|
|
||||||
document.title = 'Youtube Music';
|
|
||||||
|
|
||||||
on('close-all-in-app-menu-panel', () => {
|
|
||||||
panelClosers.forEach((closer) => closer());
|
|
||||||
});
|
|
||||||
on('refresh-in-app-menu', () => updateMenu());
|
|
||||||
on('window-maximize', () => {
|
|
||||||
if (isNotWindowsOrMacOS && !hideDOMWindowControls && maximizeButton.firstChild) {
|
|
||||||
maximizeButton.removeChild(maximizeButton.firstChild);
|
|
||||||
maximizeButton.appendChild(unmaximize);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
on('window-unmaximize', () => {
|
|
||||||
if (isNotWindowsOrMacOS && !hideDOMWindowControls && maximizeButton.firstChild) {
|
|
||||||
maximizeButton.removeChild(maximizeButton.firstChild);
|
|
||||||
maximizeButton.appendChild(unmaximize);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (window.mainConfig.plugins.isEnabled('picture-in-picture')) {
|
|
||||||
on('pip-toggle', () => {
|
|
||||||
updateMenu();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Increases the right margin of Navbar background when the scrollbar is visible to avoid blocking it (z-index doesn't affect it)
|
|
||||||
onPlayerApiReady() {
|
|
||||||
const htmlHeadStyle = document.querySelector('head > div > style');
|
|
||||||
if (htmlHeadStyle) {
|
|
||||||
// HACK: This is a hack to remove the scrollbar width
|
|
||||||
htmlHeadStyle.innerHTML = htmlHeadStyle.innerHTML.replace('html::-webkit-scrollbar {width: var(--ytmusic-scrollbar-width);', 'html::-webkit-scrollbar {');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
logo.onclick = logoClick;
|
||||||
|
|
||||||
|
on('toggle-in-app-menu', logoClick);
|
||||||
|
|
||||||
|
if (!isMacOS) titleBar.appendChild(logo);
|
||||||
|
document.body.appendChild(titleBar);
|
||||||
|
|
||||||
|
titleBar.appendChild(logo);
|
||||||
|
|
||||||
|
const addWindowControls = async () => {
|
||||||
|
|
||||||
|
// Create window control buttons
|
||||||
|
const minimizeButton = document.createElement('button');
|
||||||
|
minimizeButton.classList.add('window-control');
|
||||||
|
minimizeButton.appendChild(minimize);
|
||||||
|
minimizeButton.onclick = () => invoke('window-minimize');
|
||||||
|
|
||||||
|
maximizeButton = document.createElement('button');
|
||||||
|
if (await invoke('window-is-maximized')) {
|
||||||
|
maximizeButton.classList.add('window-control');
|
||||||
|
maximizeButton.appendChild(unmaximize);
|
||||||
|
} else {
|
||||||
|
maximizeButton.classList.add('window-control');
|
||||||
|
maximizeButton.appendChild(maximize);
|
||||||
|
}
|
||||||
|
maximizeButton.onclick = async () => {
|
||||||
|
if (await invoke('window-is-maximized')) {
|
||||||
|
// change icon to maximize
|
||||||
|
maximizeButton.removeChild(maximizeButton.firstChild!);
|
||||||
|
maximizeButton.appendChild(maximize);
|
||||||
|
|
||||||
|
// call unmaximize
|
||||||
|
await invoke('window-unmaximize');
|
||||||
|
} else {
|
||||||
|
// change icon to unmaximize
|
||||||
|
maximizeButton.removeChild(maximizeButton.firstChild!);
|
||||||
|
maximizeButton.appendChild(unmaximize);
|
||||||
|
|
||||||
|
// call maximize
|
||||||
|
await invoke('window-maximize');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeButton = document.createElement('button');
|
||||||
|
closeButton.classList.add('window-control');
|
||||||
|
closeButton.appendChild(close);
|
||||||
|
closeButton.onclick = () => invoke('window-close');
|
||||||
|
|
||||||
|
// Create a container div for the window control buttons
|
||||||
|
const windowControlsContainer = document.createElement('div');
|
||||||
|
windowControlsContainer.classList.add('window-controls-container');
|
||||||
|
windowControlsContainer.appendChild(minimizeButton);
|
||||||
|
windowControlsContainer.appendChild(maximizeButton);
|
||||||
|
windowControlsContainer.appendChild(closeButton);
|
||||||
|
|
||||||
|
// Add window control buttons to the title bar
|
||||||
|
titleBar.appendChild(windowControlsContainer);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isNotWindowsOrMacOS && !hideDOMWindowControls) await addWindowControls();
|
||||||
|
|
||||||
|
if (navBar) {
|
||||||
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach(() => {
|
||||||
|
titleBar.style.setProperty('--titlebar-background-color', navBar.style.backgroundColor);
|
||||||
|
document.querySelector('html')!.style.setProperty('--titlebar-background-color', navBar.style.backgroundColor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(navBar, { attributes : true, attributeFilter : ['style'] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateMenu = async () => {
|
||||||
|
const children = [...titleBar.children];
|
||||||
|
children.forEach((child) => {
|
||||||
|
if (child !== logo) child.remove();
|
||||||
|
});
|
||||||
|
panelClosers = [];
|
||||||
|
|
||||||
|
const menu = await invoke('get-menu') as Menu | null;
|
||||||
|
if (!menu) return;
|
||||||
|
|
||||||
|
menu.items.forEach((menuItem) => {
|
||||||
|
const menu = document.createElement('menu-button');
|
||||||
|
const [, { close: closer }] = createPanel(titleBar, menu, menuItem.submenu?.items ?? []);
|
||||||
|
panelClosers.push(closer);
|
||||||
|
|
||||||
|
menu.append(menuItem.label);
|
||||||
|
titleBar.appendChild(menu);
|
||||||
|
if (hideMenu) {
|
||||||
|
menu.style.visibility = 'hidden';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (isNotWindowsOrMacOS && !hideDOMWindowControls) await addWindowControls();
|
||||||
|
};
|
||||||
|
await updateMenu();
|
||||||
|
|
||||||
|
document.title = 'Youtube Music';
|
||||||
|
|
||||||
|
on('close-all-in-app-menu-panel', () => {
|
||||||
|
panelClosers.forEach((closer) => closer());
|
||||||
|
});
|
||||||
|
on('refresh-in-app-menu', () => updateMenu());
|
||||||
|
on('window-maximize', () => {
|
||||||
|
if (isNotWindowsOrMacOS && !hideDOMWindowControls && maximizeButton.firstChild) {
|
||||||
|
maximizeButton.removeChild(maximizeButton.firstChild);
|
||||||
|
maximizeButton.appendChild(unmaximize);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
on('window-unmaximize', () => {
|
||||||
|
if (isNotWindowsOrMacOS && !hideDOMWindowControls && maximizeButton.firstChild) {
|
||||||
|
maximizeButton.removeChild(maximizeButton.firstChild);
|
||||||
|
maximizeButton.appendChild(unmaximize);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.mainConfig.plugins.isEnabled('picture-in-picture')) {
|
||||||
|
on('pip-toggle', () => {
|
||||||
|
updateMenu();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const onPlayerApiReady = () => {
|
||||||
|
const htmlHeadStyle = document.querySelector('head > div > style');
|
||||||
|
if (htmlHeadStyle) {
|
||||||
|
// HACK: This is a hack to remove the scrollbar width
|
||||||
|
htmlHeadStyle.innerHTML = htmlHeadStyle.innerHTML.replace('html::-webkit-scrollbar {width: var(--ytmusic-scrollbar-width);', 'html::-webkit-scrollbar {');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user