mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
Typescript - Fix some issues with custom title bar, loading screen & screen snippet
This commit is contained in:
parent
02c4dd4319
commit
a923da3667
@ -12,7 +12,7 @@ Typically you'll want to set background-image: url(""); and background-size: cov
|
||||
```
|
||||
|
||||
*/
|
||||
#title-bar {
|
||||
.title-bar {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
background: rgba(74,74,74,1);
|
||||
@ -62,7 +62,7 @@ Typically you'll want to set content: url("") and adjust the width property
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#hamburger-menu-button {
|
||||
.hamburger-menu-button {
|
||||
color: rgba(255,255,255,1);
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
@ -77,11 +77,11 @@ Typically you'll want to set content: url("") and adjust the width property
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#hamburger-menu-button:focus {
|
||||
.hamburger-menu-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#title-container {
|
||||
.title-container {
|
||||
height: 32px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
@ -91,7 +91,7 @@ Typically you'll want to set content: url("") and adjust the width property
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#title-bar-title {
|
||||
.title-bar-title {
|
||||
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||
color: white;
|
||||
margin: 0;
|
||||
|
@ -28,7 +28,8 @@ gulp.task('less', function () {
|
||||
gulp.task('copy', function () {
|
||||
return gulp.src([
|
||||
'./src/renderer/assets/*',
|
||||
'./src/renderer/*.html'
|
||||
'./src/renderer/*.html',
|
||||
'./src/locale/*'
|
||||
], {
|
||||
"base": "./src"
|
||||
}).pipe(gulp.dest('lib/src'))
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Symphony",
|
||||
"productName": "Symphony-dev",
|
||||
"productName": "Symphony",
|
||||
"version": "4.5.0",
|
||||
"clientVersion": "1.55.0",
|
||||
"buildNumber": "0",
|
||||
@ -12,7 +12,7 @@
|
||||
"compile": "npm run lint && gulp build",
|
||||
"lint": "tslint --project tsconfig.json",
|
||||
"start": "npm run compile && npm run browserify-preload && cross-env ELECTRON_DEV=true electron .",
|
||||
"prebuild": "npm run rebuild && npm run browserify-preload",
|
||||
"prebuild": "npm run compile && npm run rebuild && npm run browserify-preload",
|
||||
"browserify-preload": "browserify -o lib/src/renderer/_preload-main.js -x electron --insert-global-vars=__filename,__dirname lib/src/renderer/preload-main.js",
|
||||
"rebuild": "electron-rebuild -f",
|
||||
"dev": "npm run prebuild && cross-env ELECTRON_DEV=true electron .",
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { BrowserWindow, WebContents } from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { parse as parseQuerystring } from 'querystring';
|
||||
import { format, parse, Url } from 'url';
|
||||
import { isWindowsOS } from '../common/env';
|
||||
import { getGuid } from '../common/utils';
|
||||
import { enterFullScreen, leaveFullScreen, throttledWindowChanges } from './window-actions';
|
||||
import { monitorWindowActions, removeWindowEventListener } from './window-actions';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
import { getBounds, preventWindowNavigation } from './window-utils';
|
||||
import { getBounds, injectStyles, preventWindowNavigation } from './window-utils';
|
||||
|
||||
const DEFAULT_POP_OUT_WIDTH = 300;
|
||||
const DEFAULT_POP_OUT_HEIGHT = 600;
|
||||
@ -95,7 +93,7 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
newWinOptions.frame = true;
|
||||
newWinOptions.winKey = newWinKey;
|
||||
|
||||
const childWebContents = newWinOptions.webContents;
|
||||
const childWebContents: WebContents = newWinOptions.webContents;
|
||||
// Event needed to hide native menu bar
|
||||
childWebContents.once('did-start-loading', () => {
|
||||
const browserWin = BrowserWindow.fromWebContents(childWebContents);
|
||||
@ -104,38 +102,25 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
}
|
||||
});
|
||||
|
||||
childWebContents.once('did-finish-load', () => {
|
||||
const browserWin = BrowserWindow.fromWebContents(childWebContents) as ICustomBrowserWindow;
|
||||
childWebContents.once('did-finish-load', async () => {
|
||||
const browserWin: ICustomBrowserWindow = BrowserWindow.fromWebContents(childWebContents) as ICustomBrowserWindow;
|
||||
if (!browserWin) return;
|
||||
windowHandler.addWindow(newWinKey, browserWin);
|
||||
browserWin.webContents.send('page-load', { isWindowsOS });
|
||||
browserWin.webContents.insertCSS(
|
||||
fs.readFileSync(path.join(__dirname, '..', '/renderer/styles/snack-bar.css'), 'utf8').toString(),
|
||||
);
|
||||
// Inserts css on to the window
|
||||
await injectStyles(browserWin, false);
|
||||
browserWin.winName = frameName;
|
||||
browserWin.setAlwaysOnTop(mainWindow.isAlwaysOnTop());
|
||||
|
||||
// prevents window from navigating
|
||||
preventWindowNavigation(browserWin, true);
|
||||
// Monitor window for events
|
||||
const eventNames = [ 'move', 'resize', 'maximize', 'unmaximize' ];
|
||||
eventNames.forEach((e: string) => {
|
||||
// @ts-ignore
|
||||
if (this.mainWindow) this.mainWindow.on(e, throttledWindowChanges);
|
||||
});
|
||||
browserWin.on('enter-full-screen', enterFullScreen);
|
||||
browserWin.on('leave-full-screen', leaveFullScreen);
|
||||
|
||||
// Remove the attached event listeners when the window is about to close
|
||||
browserWin.once('close', () => {
|
||||
browserWin.removeListener('close', throttledWindowChanges);
|
||||
browserWin.removeListener('resize', throttledWindowChanges);
|
||||
browserWin.removeListener('maximize', throttledWindowChanges);
|
||||
browserWin.removeListener('unmaximize', throttledWindowChanges);
|
||||
browserWin.removeListener('enter-full-screen', leaveFullScreen);
|
||||
browserWin.removeListener('leave-full-screen', leaveFullScreen);
|
||||
// Monitor window actions
|
||||
monitorWindowActions(browserWin);
|
||||
// Remove all attached event listeners
|
||||
browserWin.on('close', () => {
|
||||
removeWindowEventListener(browserWin);
|
||||
});
|
||||
|
||||
// TODO: handle Permission Requests & setCertificateVerifyProc
|
||||
});
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { app } from 'electron';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
@ -104,6 +104,9 @@ class ScreenSnippet {
|
||||
*/
|
||||
private async convertFileToData(): Promise<IScreenSnippet> {
|
||||
try {
|
||||
if (!this.outputFileName) {
|
||||
return { message: 'output file name is required', type: 'ERROR' };
|
||||
}
|
||||
const data = await readFile(this.outputFileName);
|
||||
if (!data) {
|
||||
return { message: `no file data provided`, type: 'ERROR' };
|
||||
@ -122,13 +125,15 @@ class ScreenSnippet {
|
||||
}
|
||||
} finally {
|
||||
// remove tmp file (async)
|
||||
fs.unlink(this.outputFileName, (removeErr) => {
|
||||
// note: node complains if calling async
|
||||
// func without callback.
|
||||
if (removeErr) {
|
||||
logger.error(`ScreenSnippet: error removing temp snippet file: ${this.outputFileName}, err: ${removeErr}`);
|
||||
}
|
||||
});
|
||||
if (this.outputFileName) {
|
||||
fs.unlink(this.outputFileName, (removeErr) => {
|
||||
// note: node complains if calling async
|
||||
// func without callback.
|
||||
if (removeErr) {
|
||||
logger.error(`ScreenSnippet: error removing temp snippet file: ${this.outputFileName}, err: ${removeErr}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,3 +123,35 @@ export const handleKeyPress = (key: number): void => {
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Monitors window actions
|
||||
*
|
||||
* @param window {BrowserWindow}
|
||||
*/
|
||||
export const monitorWindowActions = (window: BrowserWindow): void => {
|
||||
if (!window || window.isDestroyed()) return;
|
||||
const eventNames = [ 'move', 'resize', 'maximize', 'unmaximize' ];
|
||||
eventNames.forEach((event: string) => {
|
||||
// @ts-ignore
|
||||
if (window) window.on(event, throttledWindowChanges);
|
||||
});
|
||||
window.on('enter-full-screen', enterFullScreen);
|
||||
window.on('leave-full-screen', leaveFullScreen);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes attached event listeners
|
||||
*
|
||||
* @param window
|
||||
*/
|
||||
export const removeWindowEventListener = (window: BrowserWindow): void => {
|
||||
if (!window || window.isDestroyed()) return;
|
||||
const eventNames = [ 'move', 'resize', 'maximize', 'unmaximize' ];
|
||||
eventNames.forEach((event: string) => {
|
||||
// @ts-ignore
|
||||
if (window) window.removeListener(event, throttledWindowChanges);
|
||||
});
|
||||
window.removeListener('enter-full-screen', enterFullScreen);
|
||||
window.removeListener('leave-full-screen', leaveFullScreen);
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
import * as electron from 'electron';
|
||||
import { BrowserWindow, crashReporter, ipcMain } from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { format, parse } from 'url';
|
||||
|
||||
@ -14,8 +13,8 @@ import { AppMenu } from './app-menu';
|
||||
import { config, IConfig } from './config-handler';
|
||||
import { showNetworkConnectivityError } from './dialog-handler';
|
||||
import { handleChildWindow } from './pop-out-window-handler';
|
||||
import { enterFullScreen, leaveFullScreen, throttledWindowChanges } from './window-actions';
|
||||
import { createComponentWindow, getBounds, handleDownloadManager } from './window-utils';
|
||||
import { monitorWindowActions } from './window-actions';
|
||||
import { createComponentWindow, getBounds, handleDownloadManager, injectStyles } from './window-utils';
|
||||
|
||||
interface ICustomBrowserWindowConstructorOpts extends Electron.BrowserWindowConstructorOptions {
|
||||
winKey: string;
|
||||
@ -200,7 +199,7 @@ export class WindowHandler {
|
||||
|
||||
// loads the main window with url from config/cmd line
|
||||
this.mainWindow.loadURL(this.url);
|
||||
this.mainWindow.webContents.on('did-finish-load', () => {
|
||||
this.mainWindow.webContents.on('did-finish-load', async () => {
|
||||
|
||||
// Displays a dialog if network connectivity has been lost
|
||||
const retry = () => {
|
||||
@ -210,33 +209,34 @@ export class WindowHandler {
|
||||
};
|
||||
if (!this.isOnline && this.mainWindow) showNetworkConnectivityError(this.mainWindow, this.url, retry);
|
||||
|
||||
// early exit if the window has already been destroyed
|
||||
if (!this.mainWindow || this.mainWindow.isDestroyed()) return;
|
||||
this.url = this.mainWindow.webContents.getURL();
|
||||
|
||||
// Injects custom title bar css into the webContents
|
||||
await injectStyles(this.mainWindow, this.isCustomTitleBarAndWindowOS);
|
||||
this.mainWindow.webContents.send('initiate-custom-title-bar');
|
||||
this.mainWindow.webContents.send('page-load', {
|
||||
isWindowsOS,
|
||||
locale: i18n.getLocale(),
|
||||
resources: i18n.loadedResources,
|
||||
});
|
||||
this.appMenu = new AppMenu();
|
||||
|
||||
// close the loading window when
|
||||
// the main windows finished loading
|
||||
if (this.loadingWindow) {
|
||||
this.loadingWindow.destroy();
|
||||
this.loadingWindow = null;
|
||||
}
|
||||
// early exit if the window has already been destroyed
|
||||
if (!this.mainWindow || this.mainWindow.isDestroyed()) return;
|
||||
this.url = this.mainWindow.webContents.getURL();
|
||||
|
||||
// Injects custom title bar css into the webContents
|
||||
if (this.mainWindow && this.isCustomTitleBarAndWindowOS) {
|
||||
this.mainWindow.webContents.insertCSS(
|
||||
fs.readFileSync(path.join(__dirname, '..', '/renderer/styles/title-bar.css'), 'utf8').toString(),
|
||||
);
|
||||
this.mainWindow.webContents.send('initiate-custom-title-bar');
|
||||
}
|
||||
this.mainWindow.webContents.insertCSS(
|
||||
fs.readFileSync(path.join(__dirname, '..', '/renderer/styles/snack-bar.css'), 'utf8').toString(),
|
||||
);
|
||||
this.mainWindow.webContents.send('page-load', { isWindowsOS, locale: i18n.getLocale(), resources: i18n.loadedResources });
|
||||
this.appMenu = new AppMenu();
|
||||
this.monitorWindowActions();
|
||||
// Ready to show the window
|
||||
this.mainWindow.show();
|
||||
});
|
||||
|
||||
// Start monitoring window actions
|
||||
monitorWindowActions(this.mainWindow);
|
||||
|
||||
// Download manager
|
||||
this.mainWindow.webContents.session.on('will-download', handleDownloadManager);
|
||||
|
||||
@ -372,7 +372,7 @@ export class WindowHandler {
|
||||
* @param id {number}
|
||||
*/
|
||||
public createScreenSharingIndicatorWindow(screenSharingWebContents: Electron.webContents, displayId: string, id: number): void {
|
||||
const indicatorScreen = (displayId && electron.screen.getAllDisplays().filter((d) => displayId.includes(d.id.toString()))[0]) || electron.screen.getPrimaryDisplay();
|
||||
const indicatorScreen = (displayId && electron.screen.getAllDisplays().filter((d) => displayId.includes(d.id.toString()))[ 0 ]) || electron.screen.getPrimaryDisplay();
|
||||
const screenRect = indicatorScreen.workArea;
|
||||
let opts = WindowHandler.getScreenSharingIndicatorOpts();
|
||||
if (opts.width && opts.height) {
|
||||
@ -485,21 +485,6 @@ export class WindowHandler {
|
||||
delete this.windows[ key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the main window bounds
|
||||
*/
|
||||
private monitorWindowActions(): void {
|
||||
const eventNames = [ 'move', 'resize', 'maximize', 'unmaximize' ];
|
||||
eventNames.forEach((event: string) => {
|
||||
// @ts-ignore
|
||||
if (this.mainWindow) this.mainWindow.on(event, throttledWindowChanges);
|
||||
});
|
||||
if (this.mainWindow) {
|
||||
this.mainWindow.on('enter-full-screen', enterFullScreen);
|
||||
this.mainWindow.on('leave-full-screen', leaveFullScreen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main window opts
|
||||
*/
|
||||
|
@ -1,15 +1,16 @@
|
||||
import * as electron from 'electron';
|
||||
import { app, BrowserWindow, nativeImage } from 'electron';
|
||||
import * as filesize from 'filesize';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as url from 'url';
|
||||
|
||||
import { isMac } from '../common/env';
|
||||
import { isDevEnv, isMac } from '../common/env';
|
||||
import { i18n, LocaleType } from '../common/i18n';
|
||||
import { logger } from '../common/logger';
|
||||
import { getGuid } from '../common/utils';
|
||||
import { screenSnippet } from './screen-snippet-handler';
|
||||
import { windowHandler } from './window-handler';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
|
||||
const checkValidWindow = true;
|
||||
|
||||
@ -65,9 +66,10 @@ export const createComponentWindow = (
|
||||
},
|
||||
};
|
||||
|
||||
const browserWindow = new BrowserWindow(options);
|
||||
const browserWindow: ICustomBrowserWindow = new BrowserWindow(options) as ICustomBrowserWindow;
|
||||
browserWindow.on('ready-to-show', () => browserWindow.show());
|
||||
browserWindow.webContents.once('did-finish-load', () => {
|
||||
if (!browserWindow || browserWindow.isDestroyed()) return;
|
||||
browserWindow.webContents.send('set-locale-resource', { locale: i18n.getLocale(), resource: i18n.loadedResources });
|
||||
});
|
||||
browserWindow.setMenu(null as any);
|
||||
@ -282,3 +284,46 @@ export const handleDownloadManager = (_event, item: Electron.DownloadItem, webCo
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts css in to the window
|
||||
*
|
||||
* @param window {BrowserWindow}
|
||||
* @param paths {string[]}
|
||||
*/
|
||||
const readAndInsertCSS = async (window, paths): Promise<void> => {
|
||||
return paths.map((filePath) => window.webContents.insertCSS(fs.readFileSync(filePath, 'utf8').toString()));
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts all the required css on to the specified windows
|
||||
*
|
||||
* @param mainWindow {BrowserWindow}
|
||||
* @param isCustomTitleBarAndWindowOS {boolean} - whether custom title bar enabled
|
||||
*/
|
||||
export const injectStyles = async (mainWindow: BrowserWindow, isCustomTitleBarAndWindowOS: boolean): Promise<void> => {
|
||||
const paths: string[] = [];
|
||||
if (isCustomTitleBarAndWindowOS) {
|
||||
let titleBarStylesPath;
|
||||
const stylesFileName = path.join('config', 'titleBarStyles.css');
|
||||
if (isDevEnv) {
|
||||
titleBarStylesPath = path.join(app.getAppPath(), stylesFileName);
|
||||
} else {
|
||||
const execPath = path.dirname(app.getPath('exe'));
|
||||
titleBarStylesPath = path.join(execPath, stylesFileName);
|
||||
}
|
||||
// Window custom title bar styles
|
||||
if (fs.existsSync(titleBarStylesPath)) {
|
||||
paths.push(titleBarStylesPath);
|
||||
} else {
|
||||
paths.push(path.join(__dirname, '..', '/renderer/styles/title-bar.css'));
|
||||
}
|
||||
} else {
|
||||
paths.push(path.join(__dirname, '..', '/renderer/styles/title-bar.css'));
|
||||
}
|
||||
|
||||
// Snack bar styles
|
||||
paths.push(path.join(__dirname, '..', '/renderer/styles/snack-bar.css'));
|
||||
|
||||
return await readAndInsertCSS(mainWindow, paths);
|
||||
};
|
||||
|
@ -13,7 +13,7 @@ export default class LoadingScreen extends React.PureComponent {
|
||||
const appName = remote.app.getName() || 'Symphony';
|
||||
return (
|
||||
<div className='LoadingScreen'>
|
||||
<img className='LoadingScreen-logo' src='../assets/symphony-logo.png' />
|
||||
<img className='LoadingScreen-logo' src='../renderer/assets/symphony-logo.png' />
|
||||
<span className='LoadingScreen-name'>{appName}</span>
|
||||
<svg width='100%' height='100%' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 200' preserveAspectRatio='xMidYMid'>
|
||||
<circle cx='50' cy='50' fill='none' ng-attr-stroke='{{config.color}}' ng-attr-stroke-width='{{config.width}}' ng-attr-r='{{config.radius}}' ng-attr-stroke-dasharray='{{config.dasharray}}' stroke='#ffffff' stroke-width='10' r='35' stroke-dasharray='164.93361431346415 56.97787143782138' transform='rotate(59.6808 50 50)'>
|
||||
|
@ -119,6 +119,7 @@ export default class WindowsTitleBar extends React.Component<{}, IState> {
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div className='branding-logo' />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -39,19 +39,15 @@ const createAPI = () => {
|
||||
createAPI();
|
||||
|
||||
// When the window is completely loaded
|
||||
ipcRenderer.on('page-load', (_event, { isWindowsOS, locale, resources }) => {
|
||||
ipcRenderer.on('page-load', (_event, { locale, resources }) => {
|
||||
|
||||
i18n.setResource(locale, resources);
|
||||
|
||||
if (isWindowsOS) {
|
||||
// injects custom window title bar
|
||||
const titleBar = React.createElement(WindowsTitleBar);
|
||||
ReactDOM.render(titleBar, document.body.appendChild(document.createElement( 'div' )));
|
||||
}
|
||||
|
||||
// injects snack bar
|
||||
const snackBar = React.createElement(SnackBar);
|
||||
ReactDOM.render(snackBar, document.body.appendChild(document.createElement( 'div' )));
|
||||
const snackBarContainer = document.createElement( 'div' );
|
||||
document.body.appendChild(snackBarContainer);
|
||||
ReactDOM.render(snackBar, snackBarContainer);
|
||||
|
||||
// injects download manager contents
|
||||
const downloadManager = React.createElement(DownloadManager);
|
||||
@ -64,5 +60,7 @@ ipcRenderer.on('page-load', (_event, { isWindowsOS, locale, resources }) => {
|
||||
// Creates a custom tile bar for Windows
|
||||
ipcRenderer.on('initiate-custom-title-bar', () => {
|
||||
const element = React.createElement(WindowsTitleBar);
|
||||
ReactDOM.render(element, document.body);
|
||||
const div = document.createElement( 'div' );
|
||||
document.body.appendChild(div);
|
||||
ReactDOM.render(element, div);
|
||||
});
|
@ -1,111 +0,0 @@
|
||||
.title-bar {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
background: rgba(74,74,74,1);
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding-left: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
box-sizing: content-box;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.hamburger-menu-button {
|
||||
color: rgba(255,255,255,1);
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
height: 32px;
|
||||
background: none;
|
||||
border: none;
|
||||
border-image: initial;
|
||||
display: inline-grid;
|
||||
border-radius: 0;
|
||||
padding: 11px;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.hamburger-menu-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.title-container {
|
||||
height: 32px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.title-bar-title {
|
||||
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||
color: white;
|
||||
margin: 0;
|
||||
padding-left: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.title-bar-button-container {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
right: 0;
|
||||
color: rgba(255,255,255,1);
|
||||
-webkit-app-region: no-drag;
|
||||
text-align: center;
|
||||
width: 45px;
|
||||
height: 32px;
|
||||
background: rgba(74,74,74,1);
|
||||
margin: 0;
|
||||
box-sizing: border-box !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.title-bar-button {
|
||||
color: rgba(255,255,255,1);
|
||||
text-align: center;
|
||||
width: 45px;
|
||||
height: 32px;
|
||||
background: none;
|
||||
border: none;
|
||||
border-image: initial;
|
||||
display: inline-grid;
|
||||
border-radius: 0;
|
||||
padding: 10px 15px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.title-bar-button:hover {
|
||||
background-color: rgba(51,51,51,1);
|
||||
}
|
||||
|
||||
.title-bar-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.title-bar-button-container:hover {
|
||||
background-color: rgba(51,51,51,1);
|
||||
}
|
||||
|
||||
.window-border {
|
||||
border-left: 1px solid rgba(74,74,74,1);
|
||||
border-right: 1px solid rgba(74,74,74,1);
|
||||
}
|
||||
|
||||
.bottom-window-border {
|
||||
position: fixed;
|
||||
border-bottom: 1px solid rgba(74,74,74,1);
|
||||
width: 100%;
|
||||
z-index: 3000;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.symphony-logo {
|
||||
content: url("../src/renderer/assets/symphony-title-bar-logo.png");
|
||||
}
|
116
src/renderer/styles/title-bar.less
Normal file
116
src/renderer/styles/title-bar.less
Normal file
@ -0,0 +1,116 @@
|
||||
@color_1: rgba(255, 255, 255, 1);
|
||||
@color_2: white;
|
||||
@font_family_1: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||
@background_color_1: rgba(51, 51, 51, 1);
|
||||
|
||||
.title-bar {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
background: rgba(74, 74, 74, 1);
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding-left: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
box-sizing: content-box;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.hamburger-menu-button {
|
||||
color: @color_1;
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
height: 32px;
|
||||
background: none;
|
||||
border: none;
|
||||
border-image: initial;
|
||||
display: inline-grid;
|
||||
border-radius: 0;
|
||||
padding: 11px;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.title-container {
|
||||
height: 32px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.title-bar-title {
|
||||
font-family: @font_family_1;
|
||||
color: @color_2;
|
||||
margin: 0;
|
||||
padding-left: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.title-bar-button-container {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
right: 0;
|
||||
color: @color_1;
|
||||
-webkit-app-region: no-drag;
|
||||
text-align: center;
|
||||
width: 45px;
|
||||
height: 32px;
|
||||
background: rgba(74, 74, 74, 1);
|
||||
margin: 0;
|
||||
box-sizing: border-box !important;
|
||||
cursor: default;
|
||||
|
||||
&:hover {
|
||||
background-color: @background_color_1;
|
||||
}
|
||||
}
|
||||
|
||||
.title-bar-button {
|
||||
color: @color_1;
|
||||
text-align: center;
|
||||
width: 45px;
|
||||
height: 32px;
|
||||
background: none;
|
||||
border: none;
|
||||
border-image: initial;
|
||||
display: inline-grid;
|
||||
border-radius: 0;
|
||||
padding: 10px 15px;
|
||||
cursor: default;
|
||||
|
||||
&:hover {
|
||||
background-color: @background_color_1;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.window-border {
|
||||
border-left: 1px solid rgba(74, 74, 74, 1);
|
||||
border-right: 1px solid rgba(74, 74, 74, 1);
|
||||
}
|
||||
|
||||
.bottom-window-border {
|
||||
position: fixed;
|
||||
border-bottom: 1px solid rgba(74, 74, 74, 1);
|
||||
width: 100%;
|
||||
z-index: 3000;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.symphony-logo {
|
||||
background-image: url("../src/renderer/assets/symphony-title-bar-logo.png");
|
||||
}
|
Loading…
Reference in New Issue
Block a user