Skip to content

Commit 9dbff52

Browse files
committed
Add a brand new UI for Linux and Windows 💅
1 parent 2b75c04 commit 9dbff52

9 files changed

Lines changed: 245 additions & 39 deletions

File tree

app/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,18 @@ app.on('ready', () => installDevExtensions(isDev).then(() => {
237237
rpc.emit('move');
238238
});
239239

240+
rpc.on('open hamburger menu', ({x, y}) => {
241+
Menu.getApplicationMenu().popup(x, y);
242+
});
243+
244+
rpc.on('minimize', () => {
245+
win.minimize();
246+
});
247+
248+
rpc.on('close', () => {
249+
win.close();
250+
});
251+
240252
const deleteSessions = () => {
241253
sessions.forEach((session, key) => {
242254
session.removeAllListeners();

assets/icons.svg

Lines changed: 20 additions & 2 deletions
Loading

lib/actions/header.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {CLOSE_TAB, CHANGE_TAB} from '../constants/tabs';
2-
import {UI_WINDOW_MAXIMIZE, UI_WINDOW_UNMAXIMIZE} from '../constants/ui';
2+
import {UI_WINDOW_MAXIMIZE, UI_WINDOW_UNMAXIMIZE, UI_OPEN_HAMBURGER_MENU, UI_WINDOW_MINIMIZE, UI_WINDOW_CLOSE} from '../constants/ui';
33
import rpc from '../rpc';
44
import {userExitTermGroup, setActiveGroup} from './term-groups';
55

@@ -48,3 +48,36 @@ export function unmaximize() {
4848
});
4949
};
5050
}
51+
52+
export function openHamburgerMenu(coordinates) {
53+
return dispatch => {
54+
dispatch({
55+
type: UI_OPEN_HAMBURGER_MENU,
56+
effect() {
57+
rpc.emit('open hamburger menu', coordinates);
58+
}
59+
});
60+
};
61+
}
62+
63+
export function minimize() {
64+
return dispatch => {
65+
dispatch({
66+
type: UI_WINDOW_MINIMIZE,
67+
effect() {
68+
rpc.emit('minimize');
69+
}
70+
});
71+
};
72+
}
73+
74+
export function close() {
75+
return dispatch => {
76+
dispatch({
77+
type: UI_WINDOW_CLOSE,
78+
effect() {
79+
rpc.emit('close');
80+
}
81+
});
82+
};
83+
}

lib/components/header.js

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ export default class Header extends Component {
1414
this.onChangeIntent = this.onChangeIntent.bind(this);
1515
this.handleHeaderClick = this.handleHeaderClick.bind(this);
1616
this.handleHeaderMouseDown = this.handleHeaderMouseDown.bind(this);
17+
this.handleHamburgerMenuClick = this.handleHamburgerMenuClick.bind(this);
18+
this.handleMaximizeClick = this.handleMaximizeClick.bind(this);
19+
this.handleMinimizeClick = this.handleMinimizeClick.bind(this);
20+
this.handleCloseClick = this.handleCloseClick.bind(this);
1721
}
1822

1923
onChangeIntent(active) {
@@ -68,6 +72,27 @@ export default class Header extends Component {
6872
}
6973
}
7074

75+
handleHamburgerMenuClick(event) {
76+
const {right: x, bottom: y} = event.currentTarget.getBoundingClientRect();
77+
this.props.openHamburgerMenu({x, y});
78+
}
79+
80+
handleMaximizeClick() {
81+
if (this.props.maximized) {
82+
this.props.unmaximize();
83+
} else {
84+
this.props.maximize();
85+
}
86+
}
87+
88+
handleMinimizeClick() {
89+
this.props.minimize();
90+
}
91+
92+
handleCloseClick() {
93+
this.props.close();
94+
}
95+
7196
componentWillUnmount() {
7297
delete this.clicks;
7398
clearTimeout(this.clickTimer);
@@ -81,11 +106,49 @@ export default class Header extends Component {
81106
onClose: this.props.onCloseTab,
82107
onChange: this.onChangeIntent
83108
});
109+
const {borderColor} = props;
110+
let title = 'Hyper';
111+
if (props.tabs.length === 1 && props.tabs[0].title) {
112+
// if there's only one tab we use its title as the window title
113+
title = props.tabs[0].title;
114+
}
84115
return (<header
85116
className={css('header', isMac && 'headerRounded')}
86117
onClick={this.handleHeaderClick}
87118
onMouseDown={this.handleHeaderMouseDown}
88119
>
120+
{
121+
!isMac && <div
122+
className={css('windowHeader', props.tabs.length > 1 && 'windowHeaderWithBorder')}
123+
style={{borderColor}}
124+
>
125+
<svg
126+
className={css('shape', 'hamburgerMenu')}
127+
onClick={this.handleHamburgerMenuClick}
128+
>
129+
<use xlinkHref="./dist/assets/icons.svg#hamburger-menu"/>
130+
</svg>
131+
<span className={css('appTitle')}>{title}</span>
132+
<svg
133+
className={css('shape', 'minimizeWindow')}
134+
onClick={this.handleMinimizeClick}
135+
>
136+
<use xlinkHref="./dist/assets/icons.svg#minimize-window"/>
137+
</svg>
138+
<svg
139+
className={css('shape', 'maximizeWindow')}
140+
onClick={this.handleMaximizeClick}
141+
>
142+
<use xlinkHref="./dist/assets/icons.svg#maximize-window"/>
143+
</svg>
144+
<svg
145+
className={css('shape', 'closeWindow')}
146+
onClick={this.handleCloseClick}
147+
>
148+
<use xlinkHref="./dist/assets/icons.svg#close-window"/>
149+
</svg>
150+
</div>
151+
}
89152
{ this.props.customChildrenBefore }
90153
<Tabs {...props}/>
91154
{ this.props.customChildren }
@@ -105,6 +168,61 @@ export default class Header extends Component {
105168
headerRounded: {
106169
borderTopLeftRadius: '4px',
107170
borderTopRightRadius: '4px'
171+
},
172+
173+
windowHeader: {
174+
height: '34px',
175+
width: '100%',
176+
position: 'fixed',
177+
top: '1px',
178+
left: '1px',
179+
right: '1px',
180+
WebkitAppRegion: 'drag',
181+
display: 'flex',
182+
justifyContent: 'center',
183+
alignItems: 'center'
184+
},
185+
186+
windowHeaderWithBorder: {
187+
borderColor: '#ccc',
188+
borderBottomStyle: 'solid',
189+
borderBottomWidth: '1px'
190+
},
191+
192+
appTitle: {
193+
fontSize: '12px',
194+
fontFamily: `-apple-system, BlinkMacSystemFont,
195+
"Segoe UI", "Roboto", "Oxygen",
196+
"Ubuntu", "Cantarell", "Fira Sans",
197+
"Droid Sans", "Helvetica Neue", sans-serif`
198+
},
199+
200+
shape: {
201+
width: '10px',
202+
height: '10px',
203+
position: 'fixed',
204+
WebkitAppRegion: 'no-drag',
205+
fill: 'currentColor'
206+
},
207+
208+
hamburgerMenu: {
209+
height: '9px', // TODO fix the SVG
210+
top: '10px',
211+
left: '10px'
212+
},
213+
214+
closeWindow: {
215+
right: '10px',
216+
stroke: 'currentColor'
217+
},
218+
219+
maximizeWindow: {
220+
right: '35px',
221+
stroke: 'currentColor'
222+
},
223+
224+
minimizeWindow: {
225+
right: '60px'
108226
}
109227
};
110228
}

lib/components/tab.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export default class Tab extends Component {
7979
onClick={this.props.onClose}
8080
>
8181
<svg className={css('shape')}>
82-
<use xlinkHref="./dist/assets/icons.svg#close"/>
82+
<use xlinkHref="./dist/assets/icons.svg#close-tab"/>
8383
</svg>
8484
</i>
8585
{ this.props.customChildren }

lib/components/tabs.js

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,37 +21,40 @@ export default class Tabs extends Component {
2121
return (<nav className={css('nav')}>
2222
{ this.props.customChildrenBefore }
2323
{
24-
tabs.length ?
25-
tabs.length === 1 ?
26-
<div className={css('title')}>{tabs[0].title}</div> :
27-
[
28-
<ul
29-
key="list"
30-
className={css('list')}
31-
>
32-
{
33-
tabs.map((tab, i) => {
34-
const {uid, title, isActive, hasActivity} = tab;
35-
const props = getTabProps(tab, this.props, {
36-
text: title === '' ? 'Shell' : title,
37-
isFirst: i === 0,
38-
isLast: tabs.length - 1 === i,
39-
borderColor,
40-
isActive,
41-
hasActivity,
42-
onSelect: onChange.bind(null, uid),
43-
onClose: onClose.bind(null, uid)
44-
});
45-
return <Tab key={`tab-${uid}`} {...props}/>;
46-
})
47-
}
48-
</ul>,
49-
isMac && <div
50-
key="shim"
51-
style={{borderColor}}
52-
className={css('borderShim')}
53-
/>
54-
] :
24+
tabs.length === 1 && isMac ?
25+
<div className={css('title')}>{tabs[0].title}</div> :
26+
null
27+
}
28+
{
29+
tabs.length > 1 ?
30+
[
31+
<ul
32+
key="list"
33+
className={css('list')}
34+
>
35+
{
36+
tabs.map((tab, i) => {
37+
const {uid, title, isActive, hasActivity} = tab;
38+
const props = getTabProps(tab, this.props, {
39+
text: title === '' ? 'Shell' : title,
40+
isFirst: i === 0,
41+
isLast: tabs.length - 1 === i,
42+
borderColor,
43+
isActive,
44+
hasActivity,
45+
onSelect: onChange.bind(null, uid),
46+
onClose: onClose.bind(null, uid)
47+
});
48+
return <Tab key={`tab-${uid}`} {...props}/>;
49+
})
50+
}
51+
</ul>,
52+
isMac && <div
53+
key="shim"
54+
style={{borderColor}}
55+
className={css('borderShim')}
56+
/>
57+
] :
5558
null
5659
}
5760
{ this.props.customChildren }
@@ -73,7 +76,7 @@ export default class Tabs extends Component {
7376
cursor: 'default',
7477
position: 'relative',
7578
WebkitUserSelect: 'none',
76-
WebkitAppRegion: 'drag'
79+
top: isMac ? '' : '34px'
7780
},
7881

7982
title: {

lib/components/terms.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {decorate, getTermGroupProps} from '../utils/plugins';
44
import TermGroup_ from './term-group';
55

66
const TermGroup = decorate(TermGroup_, 'TermGroup');
7+
const isMac = /Mac/.test(navigator.userAgent);
78

89
export default class Terms extends Component {
910

@@ -71,8 +72,9 @@ export default class Terms extends Component {
7172
}
7273

7374
template(css) {
75+
const shift = !isMac && this.props.termGroups.length > 1;
7476
return (<div
75-
className={css('terms')}
77+
className={css('terms', shift && 'termsShifted')}
7678
>
7779
{ this.props.customChildrenBefore }
7880
{
@@ -132,7 +134,12 @@ export default class Terms extends Component {
132134
right: 0,
133135
left: 0,
134136
bottom: 0,
135-
color: '#fff'
137+
color: '#fff',
138+
transition: isMac ? '' : 'margin-top 0.3s ease'
139+
},
140+
141+
termsShifted: {
142+
marginTop: '68px'
136143
},
137144

138145
termGroup: {

lib/constants/ui.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ export const UI_WINDOW_MOVE = 'UI_WINDOW_MOVE';
1313
export const UI_WINDOW_MAXIMIZE = 'UI_WINDOW_MAXIMIZE';
1414
export const UI_WINDOW_UNMAXIMIZE = 'UI_WINDOW_UNMAXIMIZE';
1515
export const UI_OPEN_FILE = 'UI_OPEN_FILE';
16+
export const UI_OPEN_HAMBURGER_MENU = 'UI_OPEN_HAMBURGER_MENU';
17+
export const UI_WINDOW_MINIMIZE = 'UI_WINDOW_MINIMIZE';
18+
export const UI_WINDOW_CLOSE = 'UI_WINDOW_CLOSE';

0 commit comments

Comments
 (0)