Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@
"dependencies": {
"@ecromaneli/search-engine": "^3.0.0",
"auto-launch": "^5.0.6",
"delta-move": "^1.0.0",
"electron-context-menu": "^4.1.2",
"electron-draggable": "^1.6.1",
"electron-findbar": "^3.7.0",
"electron-store": "^11.0.2",
"electron-updater": "^6.8.3",
"vue": "^3.5.32"
}
}
}
2 changes: 1 addition & 1 deletion src/data/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const Positions = {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const DefaultSettings: Record<string, any> = {};
DefaultSettings[Settings.SHOW_FRAME] = true;
DefaultSettings[Settings.SHOW_FRAME] = 'always';
DefaultSettings[Settings.BACKGROUND_COLOR] = '#171717';
DefaultSettings[Settings.FOCUS_OPACITY] = 100;
DefaultSettings[Settings.BLUR_OPACITY] = 90;
Expand Down
4 changes: 4 additions & 0 deletions src/locale/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export const de: Strings = {
clipboardUrlSessionDesc: 'Legt die Sitzung fest, die für die Zwischenablage-URL-Seite verwendet wird. Leer lassen, um die Standardsitzung zu verwenden.',

showFrame: 'Titelleiste anzeigen',
showFrameDesc: 'Steuert die Sichtbarkeit der Navigationsleiste.',
showFrameAlways: 'Immer',
showFrameNever: 'Nie',
showFrameOnHover: 'Beim Hovern',
backgroundColor: 'Hintergrundfarbe',
backgroundColorDesc: 'Hintergrundfarbe für ladende Fenster.',
focusOpacity: 'Deckkraft bei Fokus',
Expand Down
4 changes: 4 additions & 0 deletions src/locale/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ export const en = {
clipboardUrlSessionDesc: 'Set the session used by the Clipboard URL page. Leave empty to use the default session.',

showFrame: 'Show frame',
showFrameDesc: 'Controls the visibility of the navigation bar.',
showFrameAlways: 'Always',
showFrameNever: 'Never',
showFrameOnHover: 'On hover',
backgroundColor: 'Background color',
backgroundColorDesc: 'Background color for loading windows.',
focusOpacity: 'Opacity when focused',
Expand Down
4 changes: 4 additions & 0 deletions src/locale/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export const es: Strings = {
clipboardUrlSessionDesc: 'Define la sesión utilizada por la página de URL del portapapeles. Dejar vacío para usar la sesión predeterminada.',

showFrame: 'Mostrar barra de título',
showFrameDesc: 'Controla la visibilidad de la barra de navegación.',
showFrameAlways: 'Siempre',
showFrameNever: 'Nunca',
showFrameOnHover: 'Al pasar el ratón',
backgroundColor: 'Color de fondo',
backgroundColorDesc: 'Color de fondo para ventanas en carga.',
focusOpacity: 'Opacidad cuando está enfocado',
Expand Down
4 changes: 4 additions & 0 deletions src/locale/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export const fr: Strings = {
clipboardUrlSessionDesc: 'Définit la session utilisée par la page URL du presse-papiers. Laisser vide pour utiliser la session par défaut.',

showFrame: 'Afficher la barre de titre',
showFrameDesc: 'Contrôle la visibilité de la barre de navigation.',
showFrameAlways: 'Toujours',
showFrameNever: 'Jamais',
showFrameOnHover: 'Au survol',
backgroundColor: 'Couleur d\'arrière-plan',
backgroundColorDesc: 'Couleur d\'arrière-plan pour les fenêtres en chargement.',
focusOpacity: 'Opacité quand focalisé',
Expand Down
4 changes: 4 additions & 0 deletions src/locale/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export const it: Strings = {
clipboardUrlSessionDesc: 'Imposta la sessione utilizzata dalla pagina URL degli appunti. Lasciare vuoto per utilizzare la sessione predefinita.',

showFrame: 'Mostra barra del titolo',
showFrameDesc: 'Controlla la visibilità della barra di navigazione.',
showFrameAlways: 'Sempre',
showFrameNever: 'Mai',
showFrameOnHover: 'Al passaggio del mouse',
backgroundColor: 'Colore di sfondo',
backgroundColorDesc: 'Colore di sfondo per le finestre in caricamento.',
focusOpacity: 'Opacità con focus',
Expand Down
4 changes: 4 additions & 0 deletions src/locale/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export const ptBR: Strings = {
clipboardUrlSessionDesc: 'Define a sessão utilizada pela página de URL da área de transferência. Deixe vazio para usar a sessão padrão.',

showFrame: 'Mostrar barra de título',
showFrameDesc: 'Controla a visibilidade da barra de navegação.',
showFrameAlways: 'Sempre',
showFrameNever: 'Nunca',
showFrameOnHover: 'Ao passar o mouse',
backgroundColor: 'Cor de fundo',
backgroundColorDesc: 'Cor de fundo para janelas em carregamento.',
focusOpacity: 'Opacidade quando focado',
Expand Down
4 changes: 4 additions & 0 deletions src/locale/pt-PT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export const ptPT: Strings = {
clipboardUrlSessionDesc: 'Define a sessão utilizada pela página de URL da área de transferência. Deixe vazio para utilizar a sessão predefinida.',

showFrame: 'Mostrar barra de título',
showFrameDesc: 'Controla a visibilidade da barra de navegação.',
showFrameAlways: 'Sempre',
showFrameNever: 'Nunca',
showFrameOnHover: 'Ao passar o rato',
backgroundColor: 'Cor de fundo',
backgroundColorDesc: 'Cor de fundo para janelas em carregamento.',
focusOpacity: 'Opacidade com foco',
Expand Down
4 changes: 4 additions & 0 deletions src/locale/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export const ru: Strings = {
clipboardUrlSessionDesc: 'Укажите сессию, используемую страницей URL из буфера обмена. Оставьте пустым для использования сессии по умолчанию.',

showFrame: 'Показывать заголовок окна',
showFrameDesc: 'Управляет видимостью панели навигации.',
showFrameAlways: 'Всегда',
showFrameNever: 'Никогда',
showFrameOnHover: 'При наведении',
backgroundColor: 'Цвет фона',
backgroundColorDesc: 'Цвет фона для загружающихся окон.',
focusOpacity: 'Прозрачность в фокусе',
Expand Down
8 changes: 8 additions & 0 deletions src/propagator/ViewPropagator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export class ViewPropagator extends Propagator<WebContentsView> {
if (!(inp.control || inp.alt || inp.meta || inp.shift)) { return; }
this.emitCurrentEvent(wc, 'before-special-keydown', e, inp);
});
// @ts-expect-error Electron v41+ before-mouse-event
wc.on('before-mouse-event', (_e: unknown, mouseEvent: { type: string }) => {
if (mouseEvent.type === 'mouseMove') {
this.emitCurrentEvent(wc, 'mouse-enter');
} else if (mouseEvent.type === 'mouseLeave') {
this.emitCurrentEvent(wc, 'mouse-leave');
}
});
wc.on('did-navigate-in-page', () => { this.emitCurrentEvent(wc, 'did-navigate-in-page'); });
wc.on('did-start-loading', () => { this.emitCurrentEvent(wc, 'did-start-loading'); });
wc.on('did-stop-loading', () => { this.emitCurrentEvent(wc, 'did-stop-loading'); });
Expand Down
104 changes: 101 additions & 3 deletions src/service/FrameService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { getAcceleratorByEvent } from '@/util/EventKeyCapture';
import { BaseWindow, BaseWindowConstructorOptions, Event, Input, WebContents, WebContentsView, screen } from 'electron';
import { Draggable } from 'electron-draggable';
import Findbar from 'electron-findbar';
import DeltaMove from 'delta-move';
import { EventEmitter } from 'node:stream';

class FrameService {
Expand All @@ -28,6 +29,26 @@ class FrameService {
autoHideMenuBar: true,
};

private static readonly NAVBAR_HIDE_DELAY_MS = 100;
private static readonly NAVBAR_ANIMATION_DURATION_MS = 200;

private navbarVisible = false;
private hoverLeaveTimeout: NodeJS.Timeout | undefined;

private getShowFrameMode(): string {
const value = Storage.getSettings(Settings.SHOW_FRAME);
if (value === true) { return 'always'; }
if (value === false) { return 'never'; }
return value as string;
}

private clearHoverTimeout(): void {
if (this.hoverLeaveTimeout) {
clearTimeout(this.hoverLeaveTimeout);
this.hoverLeaveTimeout = undefined;
}
}

constructor() {
this.registerStateListeners();
this.registerInstanceEvents();
Expand All @@ -37,6 +58,9 @@ class FrameService {
private registerCustomViewEvents(): void {
FramePropagator.on('show', () => { ViewService.getCurrentView()!.emit('show'); });
FramePropagator.on('hide', () => { ViewService.getCurrentView()!.emit('hide'); });

ViewPropagator.onCurrentView('mouse-enter', () => this.onMouseEnterFrame());
ViewPropagator.onCurrentView('mouse-leave', () => this.onMouseLeaveFrame());
}

private getFrameOptions(): BaseWindowConstructorOptions {
Expand Down Expand Up @@ -150,8 +174,15 @@ class FrameService {

if (navbar && !frame.isFullScreen()) {
const navbarHeight = NavbarService.NAVBAR_HEIGHT;
navbar.setBounds({ x: 0, y: 0, width: size[0] - rightMargin, height: navbarHeight });
view.setBounds({ x: 0, y: navbarHeight, width: size[0] - rightMargin, height: size[1] - navbarHeight });
const showFrame = this.getShowFrameMode();

if (showFrame === 'hover' && !this.navbarVisible) {
navbar.setBounds({ x: 0, y: -navbarHeight, width: size[0] - rightMargin, height: navbarHeight });
view.setBounds({ x: 0, y: 0, width: size[0] - rightMargin, height: size[1] });
} else {
navbar.setBounds({ x: 0, y: 0, width: size[0] - rightMargin, height: navbarHeight });
view.setBounds({ x: 0, y: navbarHeight, width: size[0] - rightMargin, height: size[1] - navbarHeight });
}
} else {
view.setBounds({ x: 0, y: 0, width: size[0] - rightMargin, height: size[1] });
}
Expand Down Expand Up @@ -336,16 +367,83 @@ class FrameService {
}

public setupNavbarForCurrentPage(frame = this.getFrame()!): void {
if (!Storage.getSettings(Settings.SHOW_FRAME)) {
const showFrame = this.getShowFrameMode();

if (showFrame === 'never') {
if (NavbarService.hasView()) {
frame.contentView.removeChildView(NavbarService.getView()!);
}
NavbarService.close();
this.navbarVisible = false;
return;
}

NavbarService.hasView() || NavbarService.createView();
NavbarService.onLoadChangeView();

if (showFrame === 'hover') {
this.navbarVisible = false;
this.registerNavbarMouseEvents();
} else {
this.navbarVisible = true;
}
}

private registerNavbarMouseEvents(): void {
const navbar = NavbarService.getView();
if (!navbar) { return; }

// @ts-expect-error Electron v41+ before-mouse-event
navbar.webContents.on('before-mouse-event', (_e: unknown, mouseEvent: { type: string }) => {
if (mouseEvent.type === 'mouseMove') {
this.onMouseEnterFrame();
} else if (mouseEvent.type === 'mouseLeave') {
this.onMouseLeaveFrame();
}
});
}

private onMouseEnterFrame(): void {
if (this.getShowFrameMode() !== 'hover') { return; }
this.clearHoverTimeout();
if (!this.navbarVisible) { this.animateNavbar(true); }
}

private onMouseLeaveFrame(): void {
if (this.getShowFrameMode() !== 'hover') { return; }
this.clearHoverTimeout();
this.hoverLeaveTimeout = setTimeout(() => {
this.hoverLeaveTimeout = undefined;
if (this.navbarVisible) { this.animateNavbar(false); }
}, FrameService.NAVBAR_HIDE_DELAY_MS);
}

private animateNavbar(show: boolean): void {
const frame = this.getFrame();
const navbar = NavbarService.getView();
const view = ViewService.getCurrentView();
if (!frame || frame.isDestroyed() || !navbar || !view) { return; }

const navbarHeight = NavbarService.NAVBAR_HEIGHT;
const size = frame.getSize();
const rightMargin = OS.IS_WIN32 && frame.isMaximized()
? Storage.getSettings<number>(Settings.RIGHT_MARGIN_WHEN_MAXIMIZED)
: 0;
const width = size[0] - rightMargin;
const height = size[1];

this.navbarVisible = show;

const range: [number, number] = show ? [0, navbarHeight] : [navbarHeight, 0];

DeltaMove.animate((y) => {
if (frame.isDestroyed()) { return; }
navbar.setBounds({ x: 0, y: y - navbarHeight, width, height: navbarHeight });
view.setBounds({ x: 0, y, width, height: height - y });
}, {
id: 'navbar-hover', duration: FrameService.NAVBAR_ANIMATION_DURATION_MS,
range, effect: 'ease-out',
}).catch(() => { /* animation cancelled or replaced */ });
}

public isFocused(): boolean {
Expand Down
13 changes: 12 additions & 1 deletion web/preferences/components/settings/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ app.component('Settings', {
options.push({ label: s.screenPositions[value], value: value })
})

const showFrameRaw = await storage.getSettings(this.$const.Settings.SHOW_FRAME)
const showFrameValue = showFrameRaw === true ? 'always' : showFrameRaw === false ? 'never' : showFrameRaw

this.inputs = {
[s.general]: [
{
Expand Down Expand Up @@ -155,7 +158,15 @@ app.component('Settings', {
{
id: this.$const.Settings.SHOW_FRAME,
label: s.showFrame,
data: { type: 'bool', value: await storage.getSettings(this.$const.Settings.SHOW_FRAME) }
description: s.showFrameDesc,
data: {
type: 'select', value: showFrameValue,
options: [
{ label: s.showFrameAlways, value: 'always' },
{ label: s.showFrameOnHover, value: 'hover' },
{ label: s.showFrameNever, value: 'never' }
]
}
},
{
id: this.$const.Settings.BACKGROUND_COLOR,
Expand Down