fix #689: custom title bar on Windows

pull/1769/head
antelle 2 years ago
parent 7e2823903b
commit 0f4434a361
No known key found for this signature in database
GPG Key ID: 63C9777AAB7C563C
  1. 14
      app/scripts/comp/launcher/launcher-electron.js
  2. 5
      app/scripts/util/features.js
  3. 16
      app/scripts/views/app-view.js
  4. 2
      app/scripts/views/settings/settings-general-view.js
  5. 60
      app/scripts/views/titlebar-buttons-view.js
  6. 15
      app/styles/areas/_app.scss
  7. 19
      app/styles/areas/_titlebar-buttons.scss
  8. 4
      app/styles/base/_icon-font.scss
  9. 3
      app/styles/base/_theme-vars.scss
  10. 4
      app/styles/base/_variables.scss
  11. 1
      app/styles/main.scss
  12. 6
      app/templates/app.hbs
  13. 9
      app/templates/titlebar-buttons.hbs
  14. 6
      desktop/main.js
  15. 1
      graphics/svg/titlebar-close.svg
  16. 1
      graphics/svg/titlebar-maximize.svg
  17. 1
      graphics/svg/titlebar-minimize.svg
  18. 1
      graphics/svg/titlebar-restore.svg
  19. 5
      release-notes.md

@ -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…
Cancel
Save