Skip to content
This repository has been archived by the owner on Jun 4, 2023. It is now read-only.

feat: add tabs preview #346

Merged
merged 6 commits into from
Nov 9, 2019
Merged
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
1 change: 1 addition & 0 deletions src/main/dialogs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './auth';
export * from './permissions';
export * from './form-fill';
export * from './credentials';
export * from './preview';
48 changes: 48 additions & 0 deletions src/main/dialogs/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { AppWindow } from '../windows';
import { MENU_WIDTH } from '~/constants/design';
import { Dialog } from '.';
import { TAB_MAX_WIDTH } from '~/renderer/views/app/constants/tabs';

const WIDTH = MENU_WIDTH;
const HEIGHT = 128;

export class PreviewDialog extends Dialog {
public visible = false;
public tab: { id?: number; x?: number } = {};

constructor(appWindow: AppWindow) {
super(appWindow, {
name: 'preview',
bounds: {
width: TAB_MAX_WIDTH + 16,
height: HEIGHT,
y: 40,
},
hideTimeout: 300,
});
}

public show() {
this.bounds.x = Math.round(this.tab.x - 8);

super.show();

const tab = this.appWindow.viewManager.views.find(
x => x.webContents.id === this.tab.id,
);

const url = tab.webContents.getURL();
const title = tab.webContents.getTitle();

this.webContents.send('visible', true, {
id: tab.id,
url: url.startsWith('wexond-error') ? tab.errorURL : url,
title,
});
}

public hide() {
super.hide();
this.webContents.send('visible', false);
}
}
9 changes: 9 additions & 0 deletions src/main/services/messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ export const runMessagingService = (appWindow: AppWindow) => {
appWindow.searchDialog.toggle();
});

ipcMain.on(`show-tab-preview-${id}`, (e, tab) => {
appWindow.previewDialog.tab = tab;
appWindow.previewDialog.show();
});

ipcMain.on(`hide-tab-preview-${id}`, (e, tab) => {
appWindow.previewDialog.hide();
});

ipcMain.on(`update-find-info-${id}`, (e, tabId, data) =>
appWindow.findDialog.updateInfo(tabId, data),
);
Expand Down
4 changes: 4 additions & 0 deletions src/main/windows/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
AuthDialog,
FormFillDialog,
CredentialsDialog,
PreviewDialog,
} from '../dialogs';

export class AppWindow extends BrowserWindow {
Expand All @@ -27,6 +28,7 @@ export class AppWindow extends BrowserWindow {
public authDialog = new AuthDialog(this);
public formFillDialog = new FormFillDialog(this);
public credentialsDialog = new CredentialsDialog(this);
public previewDialog = new PreviewDialog(this);

public incognito: boolean;

Expand Down Expand Up @@ -136,6 +138,7 @@ export class AppWindow extends BrowserWindow {
this.formFillDialog.destroy();
this.credentialsDialog.destroy();
this.permissionsDialog.destroy();
this.previewDialog.destroy();

this.menuDialog = null;
this.searchDialog = null;
Expand All @@ -144,6 +147,7 @@ export class AppWindow extends BrowserWindow {
this.formFillDialog = null;
this.credentialsDialog = null;
this.permissionsDialog = null;
this.previewDialog = null;

this.viewManager.clear();

Expand Down
11 changes: 8 additions & 3 deletions src/renderer/views/app/components/Toolbar/Tab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
StyledIcon,
StyledTitle,
StyledClose,
StyledBorder,
StyledOverlay,
TabContainer,
} from './style';
Expand Down Expand Up @@ -47,10 +46,17 @@ const onMouseDown = (tab: ITab) => (e: React.MouseEvent<HTMLDivElement>) => {
store.tabs.lastScrollLeft = store.tabs.containerRef.current.scrollLeft;
};

const onMouseEnter = (tab: ITab) => () => {
const onMouseEnter = (tab: ITab) => (e: React.MouseEvent<HTMLDivElement>) => {
if (!store.tabs.isDragging) {
store.tabs.hoveredTabId = tab.id;
}

const x = e.currentTarget.getBoundingClientRect().left;

ipcRenderer.send(`show-tab-preview-${store.windowId}`, {
id: tab.id,
x,
});
};

const onMouseLeave = () => {
Expand Down Expand Up @@ -232,7 +238,6 @@ export default observer(({ tab }: { tab: ITab }) => {
onMouseLeave={onMouseLeave}
visible={tab.tabGroupId === store.tabGroups.currentGroupId}
ref={tab.ref}
title={tab.title}
>
<TabContainer
pinned={tab.isPinned}
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/views/app/components/Toolbar/Tabbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Tabs } from '../Tabs';
import store from '../../../store';
import { icons } from '~/renderer/constants';
import HorizontalScrollbar from '~/renderer/components/HorizontalScrollbar';
import { ipcRenderer } from 'electron';

const getContainer = () => store.tabs.containerRef.current;

Expand All @@ -16,12 +17,13 @@ const onMouseEnter = () => {
clearTimeout(timeout);
};

const onTabsMouseLeave = () => {
const onTabsMouseLeave = (e: React.MouseEvent) => {
store.tabs.scrollbarVisible = false;
timeout = setTimeout(() => {
store.tabs.removedTabs = 0;
store.tabs.updateTabsBounds(true);
}, 300);
ipcRenderer.send(`hide-tab-preview-${store.windowId}`);
};

const onAddTabClick = () => {
Expand Down
24 changes: 24 additions & 0 deletions src/renderer/views/preview/components/App/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react';
import { observer } from 'mobx-react-lite';
import { createGlobalStyle, ThemeProvider } from 'styled-components';
import { hot } from 'react-hot-loader/root';

import { Style } from '../../style';
import { StyledApp, Title, Domain } from './style';
import store from '../../store';

const GlobalStyle = createGlobalStyle`${Style}`;

export const App = hot(
observer(() => {
return (
<ThemeProvider theme={{ ...store.theme }}>
<StyledApp visible={store.visible}>
<Title>{store.title}</Title>
<Domain>{store.domain}</Domain>
<GlobalStyle />
</StyledApp>
</ThemeProvider>
);
}),
);
45 changes: 45 additions & 0 deletions src/renderer/views/preview/components/App/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import styled, { css } from 'styled-components';
import { ITheme } from '~/interfaces';
import { maxLines } from '~/renderer/mixins';

export const StyledApp = styled.div`
margin: 8px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
border-radius: 6px;
overflow: hidden;
position: relative;
transition: 0.2s opacity, 0.2s margin-top;
padding: 16px;
font-size: 14px;

${({ visible, theme }: { visible: boolean; theme?: ITheme }) => css`
opacity: ${visible ? 1 : 0};
margin-top: ${visible ? 0 : 7}px;
background-color: ${theme['dialog.backgroundColor']};
color: ${theme['dialog.textColor']};
`}
`;

export const Title = styled.div`
font-weight: 500;
line-height: 1.3rem;
${maxLines(2)};
`;

export const Domain = styled.div`
opacity: 0.54;
font-weight: 300;
line-height: 1.3rem;
`;

export const Subtitle = styled.div`
font-size: 13px;
opacity: 0.54;
margin-top: 8px;
`;

export const Buttons = styled.div`
display: flex;
margin-top: 16px;
float: right;
`;
35 changes: 35 additions & 0 deletions src/renderer/views/preview/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';

import { App } from './components/App';
import { fonts } from '../../constants';
import { ipcRenderer } from 'electron';

ipcRenderer.setMaxListeners(0);

const styleElement = document.createElement('style');

styleElement.textContent = `
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(${fonts.robotoRegular}) format('woff2');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(${fonts.robotoMedium}) format('woff2');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: url(${fonts.robotoLight}) format('woff2');
}
`;

document.head.appendChild(styleElement);

ReactDOM.render(<App />, document.getElementById('app'));
58 changes: 58 additions & 0 deletions src/renderer/views/preview/store/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ipcRenderer, remote } from 'electron';
import { observable, computed } from 'mobx';
import { getTheme } from '~/utils/themes';
import { ISettings } from '~/interfaces';
import { DEFAULT_SETTINGS } from '~/constants';
import { parse } from 'url';

export class Store {
@observable
public settings: ISettings = DEFAULT_SETTINGS;

@computed
public get theme() {
return getTheme(this.settings.theme);
}

@observable
public visible = false;

@observable
public id = remote.getCurrentWebContents().id;

@observable
public windowId = remote.getCurrentWindow().id;

@observable
public title = '';

@observable
public url = '';

@computed
public get domain() {
return parse(this.url).hostname;
}

public constructor() {
ipcRenderer.on('visible', (e, flag, tab) => {
this.visible = flag;
if (tab) {
this.title = tab.title;
this.url = tab.url;
}
});

ipcRenderer.send('get-settings');

ipcRenderer.on('update-settings', (e, settings: ISettings) => {
this.settings = { ...this.settings, ...settings };
});
}

public hide() {
ipcRenderer.send(`hide-${this.id}`);
}
}

export default new Store();
20 changes: 20 additions & 0 deletions src/renderer/views/preview/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { css } from 'styled-components';

import { body2 } from '~/renderer/mixins';

export const Style = css`
body {
user-select: none;
cursor: default;
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
${body2()}
}

* {
box-sizing: border-box;
}
`;
1 change: 1 addition & 0 deletions webpack.config.renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ applyEntries('app', appConfig, [
'find',
'menu',
'search',
'preview',
]);

module.exports = appConfig;