diff --git a/src/interfaces/design.ts b/src/interfaces/design.ts new file mode 100644 index 0000000..fc61752 --- /dev/null +++ b/src/interfaces/design.ts @@ -0,0 +1,12 @@ +interface DOMRectangle { + readonly width: number; + readonly height: number; + readonly top: number; + readonly bottom: number; + readonly left: number; + readonly right: number; + readonly x: number; + readonly y: number; + + toJSON(): any; +} diff --git a/src/main/dialogs/dialog.ts b/src/main/dialogs/dialog.ts new file mode 100644 index 0000000..39c23f5 --- /dev/null +++ b/src/main/dialogs/dialog.ts @@ -0,0 +1,64 @@ +import { enable } from '@electron/remote/main'; +import { app, BrowserView, BrowserWindow, ipcMain, Rectangle } from 'electron'; +import { join } from 'path'; +import { IDialog } from '../interfaces/dialog'; + +export class Dialog { + + public browserWindow: BrowserWindow; + public readonly browserView: BrowserView; + + public readonly name: string; + + public bounds: Rectangle = { + width: 0, + height: 0, + x: 0, + y: 0 + }; + + public constructor(window: BrowserWindow, { name, bounds, onWindowBoundsUpdate, webPreferences }: IDialog) { + this.browserView = new BrowserView({ + webPreferences: { + preload: join(app.getAppPath(), 'build', 'dialog.js'), + nodeIntegration: true, + contextIsolation: false, + javascript: true, + ...webPreferences + } + }); + + this.browserWindow = window; + + this.bounds = { ...this.bounds, ...bounds }; + + this.name = name; + + if (onWindowBoundsUpdate) { + window.on('resize', () => onWindowBoundsUpdate('resize')); + window.on('move', () => onWindowBoundsUpdate('move')); + } + + enable(this.browserView.webContents); + + ipcMain.handle(`dialog-hide-${this.browserView.webContents.id}`, () => this.hide()); + } + + public show() { + this.browserWindow.addBrowserView(this.browserView); + this.browserWindow.setTopBrowserView(this.browserView); + this.browserView.setBounds(this.bounds); + this.browserView.webContents.focus(); + } + + public hide() { + this.browserWindow.removeBrowserView(this.browserView); + this.browserWindow.setTopBrowserView(this.browserWindow.getBrowserViews()[0]); + } + + public destroy() { + this.hide(); + // @ts-ignore + this.browserView.webContents.destroy(); + } +} diff --git a/src/main/dialogs/histories.ts b/src/main/dialogs/histories.ts new file mode 100644 index 0000000..2086a4e --- /dev/null +++ b/src/main/dialogs/histories.ts @@ -0,0 +1,36 @@ +import { app, BrowserWindow } from 'electron'; +import { join } from 'path'; +import { Main } from '../main'; +import { Dialog } from './dialog'; + +export const showHistoriesDialog = (browserWindow: BrowserWindow, x: number, y: number) => { + const dialogManager = Main.dialogManager; + + const bounds = { + width: 330, + height: 630, + x: x - 285, + y: y + }; + + const dynamicDialog = dialogManager.getDynamic('histories'); + if (dynamicDialog) { + dynamicDialog.browserWindow = browserWindow; + dynamicDialog.bounds = bounds; + dialogManager.show(dynamicDialog); + } else { + const dialog = dialogManager.show( + new Dialog( + browserWindow, + { + name: 'histories', + bounds, + onWindowBoundsUpdate: () => dialog.hide() + } + ) + ); + + dialog.browserView.webContents.loadFile(join(app.getAppPath(), 'build', 'internal-histories.html')); + dialog.browserView.webContents.openDevTools(); + } +}; diff --git a/src/main/interfaces/dialog.ts b/src/main/interfaces/dialog.ts new file mode 100644 index 0000000..bc4738d --- /dev/null +++ b/src/main/interfaces/dialog.ts @@ -0,0 +1,10 @@ +import { Rectangle, WebPreferences } from 'electron'; + +type BoundsDisposition = 'move' | 'resize'; + +export interface IDialog { + name: string; + bounds?: Partial; + onWindowBoundsUpdate?: (disposition: BoundsDisposition) => void; + webPreferences?: WebPreferences; +} diff --git a/src/main/manager/dialog.ts b/src/main/manager/dialog.ts new file mode 100644 index 0000000..841e9a4 --- /dev/null +++ b/src/main/manager/dialog.ts @@ -0,0 +1,30 @@ +import { Dialog } from '../dialogs/dialog'; + +export class DialogManager { + + public constructor() { + + } + + private _dialogs: Dialog[] = []; + + public get dialogs() { + return this._dialogs; + } + + public show(dialog: Dialog) { + if (!this.getDynamic(dialog.name)) + this._dialogs.push(dialog); + dialog.show(); + return dialog; + } + + public hide(dialog: Dialog) { + dialog.hide(); + return dialog; + } + + public getDynamic(name: string) { + return this._dialogs.find((dialog) => dialog.name === name); + } +} diff --git a/src/preloads/dialog.ts b/src/preloads/dialog.ts new file mode 100644 index 0000000..dd53289 --- /dev/null +++ b/src/preloads/dialog.ts @@ -0,0 +1,6 @@ +import { getCurrentWebContents } from '@electron/remote'; +import { ipcRenderer } from 'electron'; + +window.addEventListener('blur', () => { + ipcRenderer.invoke(`dialog-hide-${getCurrentWebContents().id}`); +}); diff --git a/src/renderer/views/internal-histories/components/App/index.tsx b/src/renderer/views/internal-histories/components/App/index.tsx new file mode 100644 index 0000000..04ea3b8 --- /dev/null +++ b/src/renderer/views/internal-histories/components/App/index.tsx @@ -0,0 +1,26 @@ +import React, { Fragment } from 'react'; +import { UserConfigProvider, useUserConfigContext } from '../../../../contexts/config'; +import { GlobalStyles } from '../../../../themes'; +import { SidebarHistories } from '../../../app/components/SidebarContent'; +import { StyledApp } from './styles'; + +const Content = () => { + const { config } = useUserConfigContext(); + + return ( + + + + ); +}; + +export const App = () => { + return ( + + + + + + + ); +}; diff --git a/src/renderer/views/internal-histories/components/App/styles.ts b/src/renderer/views/internal-histories/components/App/styles.ts new file mode 100644 index 0000000..e082007 --- /dev/null +++ b/src/renderer/views/internal-histories/components/App/styles.ts @@ -0,0 +1,10 @@ +import styled from 'styled-components'; + +export const StyledApp = styled.div` + width: calc(100% - 30px); + height: calc(100% - 20px); + margin: 0 15px 20px; + background-color: #fff; + box-shadow: 0 12px 16px rgba(0, 0, 0, .12), 0 8px 10px rgba(0, 0, 0, .16); + border-radius: 4px; +`; diff --git a/src/renderer/views/internal-histories/index.tsx b/src/renderer/views/internal-histories/index.tsx new file mode 100644 index 0000000..4656a33 --- /dev/null +++ b/src/renderer/views/internal-histories/index.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import '../../../../static/fonts/style.css'; +import { render } from '../../utils'; +import { App } from './components/App'; + +render();