mirror of https://github.com/keeweb/keeweb
fix #689: custom title bar on Windows
This commit is contained in:
parent
7e2823903b
commit
0f4434a361
|
@ -312,6 +312,18 @@ const Launcher = {
|
|||
},
|
||||
setGlobalShortcuts(appSettings) {
|
||||
this.remoteApp().setGlobalShortcuts(appSettings);
|
||||
},
|
||||
minimizeMainWindow() {
|
||||
this.getMainWindow().minimize();
|
||||
},
|
||||
maximizeMainWindow() {
|
||||
this.getMainWindow().maximize();
|
||||
},
|
||||
restoreMainWindow() {
|
||||
this.getMainWindow().restore();
|
||||
},
|
||||
mainWindowMaximized() {
|
||||
return this.getMainWindow().isMaximized();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -319,6 +331,8 @@ Events.on('launcher-exit-request', () => {
|
|||
setTimeout(() => Launcher.exit(), 0);
|
||||
});
|
||||
Events.on('launcher-minimize', () => setTimeout(() => Events.emit('app-minimized'), 0));
|
||||
Events.on('launcher-maximize', () => setTimeout(() => Events.emit('app-maximized'), 0));
|
||||
Events.on('launcher-unmaximize', () => setTimeout(() => Events.emit('app-unmaximized'), 0));
|
||||
Events.on('launcher-started-minimized', () => setTimeout(() => Launcher.minimizeApp(), 0));
|
||||
Events.on('start-profile', (data) => StartProfiler.reportAppProfile(data));
|
||||
Events.on('log', (e) => new Logger(e.category || 'remote-app')[e.method || 'info'](e.message));
|
||||
|
|
|
@ -18,7 +18,10 @@ const Features = {
|
|||
isLocal: location.origin.indexOf('localhost') >= 0,
|
||||
|
||||
supportsTitleBarStyles() {
|
||||
return this.isMac;
|
||||
return isDesktop && (this.isMac || this.isWindows);
|
||||
},
|
||||
renderCustomTitleBar() {
|
||||
return isDesktop && this.isWindows;
|
||||
},
|
||||
hasUnicodeFlags() {
|
||||
return this.isMac;
|
||||
|
|
|
@ -25,6 +25,7 @@ import { OpenView } from 'views/open-view';
|
|||
import { SettingsView } from 'views/settings/settings-view';
|
||||
import { TagView } from 'views/tag-view';
|
||||
import { ImportCsvView } from 'views/import-csv-view';
|
||||
import { TitlebarButtonsView } from 'views/titlebar-buttons-view';
|
||||
import template from 'templates/app.hbs';
|
||||
|
||||
class AppView extends View {
|
||||
|
@ -45,6 +46,9 @@ class AppView extends View {
|
|||
|
||||
constructor(model) {
|
||||
super(model);
|
||||
|
||||
this.titlebarStyle = this.model.settings.titlebarStyle;
|
||||
|
||||
this.views.menu = new MenuView(this.model.menu, { ownParent: true });
|
||||
this.views.menuDrag = new DragView('x', { parent: '.app__menu-drag' });
|
||||
this.views.footer = new FooterView(this.model, { ownParent: true });
|
||||
|
@ -54,12 +58,13 @@ class AppView extends View {
|
|||
this.views.list.dragView = this.views.listDrag;
|
||||
this.views.details = new DetailsView(undefined, { ownParent: true });
|
||||
this.views.details.appModel = this.model;
|
||||
if (this.titlebarStyle !== 'default' && Features.renderCustomTitleBar()) {
|
||||
this.views.titlebarButtons = new TitlebarButtonsView(this.model);
|
||||
}
|
||||
|
||||
this.views.menu.listenDrag(this.views.menuDrag);
|
||||
this.views.list.listenDrag(this.views.listDrag);
|
||||
|
||||
this.titlebarStyle = this.model.settings.titlebarStyle;
|
||||
|
||||
this.listenTo(this.model.settings, 'change:theme', this.setTheme);
|
||||
this.listenTo(this.model.settings, 'change:locale', this.setLocale);
|
||||
this.listenTo(this.model.settings, 'change:fontSize', this.setFontSize);
|
||||
|
@ -120,6 +125,9 @@ class AppView extends View {
|
|||
}
|
||||
if (this.titlebarStyle !== 'default') {
|
||||
document.body.classList.add('titlebar-' + this.titlebarStyle);
|
||||
if (Features.renderCustomTitleBar()) {
|
||||
document.body.classList.add('titlebar-custom');
|
||||
}
|
||||
}
|
||||
if (Features.isMobile) {
|
||||
document.body.classList.add('mobile');
|
||||
|
@ -129,7 +137,8 @@ class AppView extends View {
|
|||
render() {
|
||||
super.render({
|
||||
beta: this.model.isBeta,
|
||||
titlebarStyle: this.titlebarStyle
|
||||
titlebarStyle: this.titlebarStyle,
|
||||
customTitlebar: Features.renderCustomTitleBar()
|
||||
});
|
||||
this.panelEl = this.$el.find('.app__panel:first');
|
||||
this.views.listWrap.render();
|
||||
|
@ -139,6 +148,7 @@ class AppView extends View {
|
|||
this.views.list.render();
|
||||
this.views.listDrag.render();
|
||||
this.views.details.render();
|
||||
this.views.titlebarButtons?.render();
|
||||
this.showLastOpenFile();
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ class SettingsGeneralView extends View {
|
|||
directAutotype: AppSettingsModel.directAutotype,
|
||||
fieldLabelDblClickAutoType: AppSettingsModel.fieldLabelDblClickAutoType,
|
||||
useLegacyAutoType: AppSettingsModel.useLegacyAutoType,
|
||||
supportsTitleBarStyles: Launcher && Features.supportsTitleBarStyles(),
|
||||
supportsTitleBarStyles: Features.supportsTitleBarStyles(),
|
||||
titlebarStyle: AppSettingsModel.titlebarStyle,
|
||||
storageProviders,
|
||||
showReloadApp: Features.isStandalone,
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import { View } from 'framework/views/view';
|
||||
import { Events } from 'framework/events';
|
||||
import { Launcher } from 'comp/launcher';
|
||||
import template from 'templates/titlebar-buttons.hbs';
|
||||
|
||||
class TitlebarButtonsView extends View {
|
||||
parent = '.app__titlebar';
|
||||
|
||||
template = template;
|
||||
|
||||
events = {
|
||||
'click .titlebar-buttons-minimize': 'clickMinimize',
|
||||
'click .titlebar-buttons-maximize': 'clickMaximize',
|
||||
'click .titlebar-buttons-restore': 'clickRestore',
|
||||
'click .titlebar-buttons-close': 'clickClose'
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.maximized = Launcher.mainWindowMaximized();
|
||||
|
||||
this.listenTo(Events, 'app-maximized', this.appMaximized);
|
||||
this.listenTo(Events, 'app-unmaximized', this.appUnmaximized);
|
||||
}
|
||||
|
||||
render() {
|
||||
super.render({
|
||||
maximized: this.maximized
|
||||
});
|
||||
}
|
||||
|
||||
clickMinimize() {
|
||||
Launcher.minimizeMainWindow();
|
||||
}
|
||||
|
||||
clickMaximize() {
|
||||
Launcher.maximizeMainWindow();
|
||||
}
|
||||
|
||||
clickRestore() {
|
||||
Launcher.restoreMainWindow();
|
||||
}
|
||||
|
||||
clickClose() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
appMaximized() {
|
||||
this.maximized = true;
|
||||
this.render();
|
||||
}
|
||||
|
||||
appUnmaximized() {
|
||||
this.maximized = false;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
export { TitlebarButtonsView };
|
|
@ -28,6 +28,18 @@
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
&__titlebar {
|
||||
.titlebar-custom & {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
-webkit-app-region: drag;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
&__menu {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
|
@ -123,6 +135,9 @@
|
|||
display: flex;
|
||||
}
|
||||
}
|
||||
.titlebar-custom & {
|
||||
margin-top: $custom-titlebar-height;
|
||||
}
|
||||
}
|
||||
|
||||
&__panel {
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
.titlebar-buttons {
|
||||
font-size: 0;
|
||||
|
||||
> .fa {
|
||||
-webkit-app-region: no-drag;
|
||||
font-size: 16px;
|
||||
padding: 4px 16px;
|
||||
height: $custom-titlebar-height;
|
||||
box-sizing: border-box;
|
||||
&:hover {
|
||||
background: var(--titlebar-button-background-color);
|
||||
}
|
||||
&.fa-titlebar-close {
|
||||
&:hover {
|
||||
background: $titlebar-close-button-background-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -196,3 +196,7 @@ $fa-var-at: next-fa-glyph();
|
|||
$fa-var-usb-token: next-fa-glyph();
|
||||
$fa-var-bell: next-fa-glyph();
|
||||
$fa-var-fingerprint: next-fa-glyph();
|
||||
$fa-var-titlebar-close: next-fa-glyph();
|
||||
$fa-var-titlebar-maximize: next-fa-glyph();
|
||||
$fa-var-titlebar-minimize: next-fa-glyph();
|
||||
$fa-var-titlebar-restore: next-fa-glyph();
|
||||
|
|
|
@ -69,7 +69,8 @@
|
|||
selectable-on-secondary-item-color:
|
||||
mix(map-get($t, medium-color), map-get($t, background-color), 14%),
|
||||
clickable-on-secondary-color:
|
||||
mix(map-get($t, medium-color), map-get($t, background-color), 75%)
|
||||
mix(map-get($t, medium-color), map-get($t, background-color), 75%),
|
||||
titlebar-button-background-color: rgba(map-get($t, text-color), 0.085)
|
||||
),
|
||||
$t
|
||||
);
|
||||
|
|
|
@ -84,3 +84,7 @@ $z-index-modal: 100000;
|
|||
// Screen sizes
|
||||
$tablet-width: 736px;
|
||||
$mobile-width: 620px;
|
||||
|
||||
// Title bar and window buttons
|
||||
$custom-titlebar-height: 32px;
|
||||
$titlebar-close-button-background-color: #d71525;
|
||||
|
|
|
@ -38,3 +38,4 @@ $fa-font-path: '~font-awesome/fonts';
|
|||
@import 'areas/open';
|
||||
@import 'areas/settings';
|
||||
@import 'areas/import-csv';
|
||||
@import 'areas/titlebar-buttons';
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<div class="app">
|
||||
{{#if beta}}<div class="app__beta"><i class="fa fa-exclamation-triangle"></i> {{res 'appBeta'}}</div>{{/if}}
|
||||
{{#ifeq titlebarStyle 'hidden'}}<div class="app__titlebar-drag"></div>{{/ifeq}}
|
||||
{{#if customTitlebar}}
|
||||
<div class="app__titlebar"></div>
|
||||
{{else}}
|
||||
{{#ifeq titlebarStyle 'hidden'}}<div class="app__titlebar-drag"></div>{{/ifeq}}
|
||||
{{/if}}
|
||||
<div class="app__body">
|
||||
<div class="app__menu"></div>
|
||||
<div class="app__menu-drag"></div>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<div class="titlebar-buttons">
|
||||
<i class="fa fa-titlebar-minimize titlebar-buttons-minimize"></i>
|
||||
{{#if maximized}}
|
||||
<i class="fa fa-titlebar-restore titlebar-buttons-restore"></i>
|
||||
{{else}}
|
||||
<i class="fa fa-titlebar-maximize titlebar-buttons-maximize"></i>
|
||||
{{/if}}
|
||||
<i class="fa fa-titlebar-close titlebar-buttons-close"></i>
|
||||
</div>
|
|
@ -263,6 +263,9 @@ function createMainWindow() {
|
|||
theme = selectDarkOrLightTheme(theme);
|
||||
}
|
||||
const bgColor = themeBgColors[theme] || defaultBgColor;
|
||||
const frameless =
|
||||
process.platform === 'win32' &&
|
||||
['hidden', 'hidden-inset'].includes(appSettings.titlebarStyle);
|
||||
const windowOptions = {
|
||||
show: false,
|
||||
width: 1000,
|
||||
|
@ -270,6 +273,7 @@ function createMainWindow() {
|
|||
minWidth: 700,
|
||||
minHeight: 400,
|
||||
titleBarStyle: appSettings.titlebarStyle,
|
||||
frame: !frameless,
|
||||
backgroundColor: bgColor,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
|
@ -324,9 +328,11 @@ function createMainWindow() {
|
|||
});
|
||||
mainWindow.on('maximize', () => {
|
||||
mainWindowMaximized = true;
|
||||
emitRemoteEvent('launcher-maximize');
|
||||
});
|
||||
mainWindow.on('unmaximize', () => {
|
||||
mainWindowMaximized = false;
|
||||
emitRemoteEvent('launcher-unmaximize');
|
||||
});
|
||||
mainWindow.on('leave-full-screen', () => {
|
||||
emitRemoteEvent('leave-full-screen');
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="512" height="512"><path d="M445 500l-285 -285l55 -55l285 285l285 -285l55 55l-285 285l285 285l-55 55l-285 -285l-285 285l-55 -55z"/></svg>
|
After Width: | Height: | Size: 208 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="512" height="512"><path d="M188 813v-625h625v625h-625zM750 250h-500v500h500v-500z"/></svg>
|
After Width: | Height: | Size: 162 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="512" height="512"><path d="M875 500v-62h-687v62h687z"/></svg>
|
After Width: | Height: | Size: 133 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="512" height="512"><path d="M188 688v-563h562v563h-562zM688 188h-438v437h438v-437zM313 688h62v62h438v-437h-63v-63h125v563h-562v-125z"/></svg>
|
After Width: | Height: | Size: 212 B |
|
@ -2,11 +2,12 @@ Release notes
|
|||
-------------
|
||||
##### v1.17.0 (TBD)
|
||||
`+` opening files with Touch ID on macOS
|
||||
`+` password quality warnings
|
||||
`+` password quality warnings
|
||||
`+` "Have I Been Pwned" service integration (opt-in)
|
||||
`+` automatically switching between dark and light theme
|
||||
`+` custom title bar on Windows
|
||||
`*` new updater capable to upgrade major versions
|
||||
`+` clear searchbox button
|
||||
`+` clear searchbox button
|
||||
`+` more options for auto-lock timeout
|
||||
`+` favicon download improvements
|
||||
`+` auto-type field selection dropdown improvements
|
||||
|
|
Loading…
Reference in New Issue