Skip to content

Commit 4119324

Browse files
committed
Use the new buttons in the page header
This has some *minor* styling changes that make hover and click states a wee bit more noticeable.
1 parent 5d8667e commit 4119324

File tree

8 files changed

+140
-315
lines changed

8 files changed

+140
-315
lines changed

ui/frontend/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ module.exports = {
6464
'.eslintrc.js',
6565
'BuildMenu.tsx',
6666
'ButtonSet.tsx',
67+
'Header.tsx',
6768
'PopButton.tsx',
6869
'compileActions.ts',
6970
'editor/AceEditor.tsx',

ui/frontend/.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ node_modules
1515
!.eslintrc.js
1616
!BuildMenu.tsx
1717
!ButtonSet.tsx
18+
!Header.tsx
1819
!PopButton.tsx
1920
!compileActions.ts
2021
!editor/AceEditor.tsx

ui/frontend/Header.module.css

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,12 @@
1-
.container {
1+
.container,
2+
.left,
3+
.right {
24
display: flex;
3-
padding: 1.25em 0;
4-
font-size: 12px;
5-
6-
& button:enabled {
7-
cursor: pointer;
8-
}
9-
}
10-
11-
.set {
12-
margin-right: 0.5em;
13-
14-
&:last-child {
15-
margin-right: 0;
16-
}
5+
gap: 0.5em;
176
}
187

19-
.setChannelMode {
20-
margin-right: auto;
8+
.container {
9+
font-size: 12px;
10+
padding: 1.25em 0;
11+
justify-content: space-between;
2112
}

ui/frontend/Header.tsx

Lines changed: 130 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,77 @@
1-
import React, { useCallback } from 'react';
1+
import React, { RefObject, useCallback, useRef } from 'react';
22
import { useSelector } from 'react-redux';
33

44
import AdvancedOptionsMenu from './AdvancedOptionsMenu';
55
import BuildMenu from './BuildMenu';
6+
import { ButtonSet, IconButton, IconLink, Button as OneButton, Rule } from './ButtonSet';
67
import ChannelMenu from './ChannelMenu';
78
import ConfigMenu from './ConfigMenu';
8-
import HeaderButton from './HeaderButton';
9-
import { BuildIcon, ConfigIcon, HelpIcon, MoreOptionsActiveIcon, MoreOptionsIcon } from './Icon';
9+
import {
10+
BuildIcon,
11+
ConfigIcon,
12+
ExpandableIcon,
13+
HelpIcon,
14+
MoreOptionsActiveIcon,
15+
MoreOptionsIcon,
16+
} from './Icon';
1017
import ModeMenu from './ModeMenu';
11-
import PopButton from './PopButton';
12-
import { SegmentedButton, SegmentedButtonSet, SegmentedLink } from './SegmentedButton';
18+
import PopButton, { ButtonProps } from './PopButton';
1319
import ToolsMenu from './ToolsMenu';
14-
1520
import * as actions from './actions';
16-
import * as selectors from './selectors';
1721
import { useAppDispatch } from './configureStore';
1822
import { performGistSave } from './reducers/output/gist';
23+
import * as selectors from './selectors';
1924

2025
import styles from './Header.module.css';
2126

22-
const Header: React.FC = () => (
23-
<div data-test-id="header" className={styles.container}>
24-
<HeaderSet id="build">
25-
<SegmentedButtonSet>
26-
<ExecuteButton />
27-
<BuildMenuButton />
28-
</SegmentedButtonSet>
29-
</HeaderSet>
30-
<HeaderSet id="channel-mode">
31-
<SegmentedButtonSet>
32-
<ModeMenuButton />
33-
<ChannelMenuButton />
34-
<AdvancedOptionsMenuButton />
35-
</SegmentedButtonSet>
36-
</HeaderSet>
37-
<HeaderSet id="share">
38-
<SegmentedButtonSet>
39-
<ShareButton />
40-
</SegmentedButtonSet>
41-
</HeaderSet>
42-
<HeaderSet id="tools">
43-
<SegmentedButtonSet>
44-
<ToolsMenuButton />
45-
</SegmentedButtonSet>
46-
</HeaderSet>
47-
<HeaderSet id="config">
48-
<SegmentedButtonSet>
49-
<ConfigMenuButton />
50-
</SegmentedButtonSet>
51-
</HeaderSet>
52-
<HeaderSet id="help">
53-
<SegmentedButtonSet>
54-
<HelpButton />
55-
</SegmentedButtonSet>
56-
</HeaderSet>
57-
</div>
58-
);
27+
const Header: React.FC = () => {
28+
const menuContainer = useRef<HTMLDivElement | null>(null);
5929

60-
interface HeaderSetProps {
61-
children: React.ReactNode;
62-
id: string;
63-
}
30+
return (
31+
<>
32+
<div data-test-id="header" className={styles.container}>
33+
<div className={styles.left}>
34+
<ButtonSet>
35+
<ExecuteButton />
36+
<BuildMenuButton menuContainer={menuContainer} />
37+
</ButtonSet>
38+
39+
<ButtonSet>
40+
<ModeMenuButton menuContainer={menuContainer} />
41+
<Rule />
42+
<ChannelMenuButton menuContainer={menuContainer} />
43+
<Rule />
44+
<AdvancedOptionsMenuButton menuContainer={menuContainer} />
45+
</ButtonSet>
46+
</div>
47+
48+
<div className={styles.right}>
49+
<ButtonSet>
50+
<ShareButton />
51+
</ButtonSet>
52+
53+
<ButtonSet>
54+
<ToolsMenuButton menuContainer={menuContainer} />
55+
</ButtonSet>
56+
57+
<ButtonSet>
58+
<ConfigMenuButton menuContainer={menuContainer} />
59+
</ButtonSet>
60+
61+
<ButtonSet>
62+
<HelpButton />
63+
</ButtonSet>
64+
</div>
65+
</div>
66+
67+
<div ref={menuContainer} />
68+
</>
69+
);
70+
};
6471

65-
const HeaderSet: React.FC<HeaderSetProps> = ({ id, children }) => (
66-
<div className={id == 'channel-mode' ? styles.setChannelMode : styles.set}>{children}</div>
67-
);
72+
interface PortalProps {
73+
menuContainer: RefObject<HTMLDivElement>;
74+
}
6875

6976
const ExecuteButton: React.FC = () => {
7077
const executionLabel = useSelector(selectors.getExecutionLabel);
@@ -73,102 +80,124 @@ const ExecuteButton: React.FC = () => {
7380
const execute = useCallback(() => dispatch(actions.performPrimaryAction()), [dispatch]);
7481

7582
return (
76-
<SegmentedButton isBuild onClick={execute}>
77-
<HeaderButton bold rightIcon={<BuildIcon />}>
78-
{executionLabel}
79-
</HeaderButton>
80-
</SegmentedButton>
83+
<OneButton isPrimary type="button" onClick={execute} iconRight={BuildIcon}>
84+
{executionLabel}
85+
</OneButton>
8186
);
8287
};
8388

84-
const BuildMenuButton: React.FC = () => {
85-
const Button = React.forwardRef<HTMLButtonElement, { toggle: () => void }>(({ toggle }, ref) => (
86-
<SegmentedButton title="Select what to build" ref={ref} onClick={toggle}>
87-
<HeaderButton icon={<MoreOptionsIcon />} />
88-
</SegmentedButton>
89+
const BuildMenuButton: React.FC<PortalProps> = ({ menuContainer }) => {
90+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ toggle }, ref) => (
91+
<IconButton type="button" title="Select what to build" ref={ref} onClick={toggle}>
92+
<MoreOptionsIcon />
93+
</IconButton>
8994
));
9095
Button.displayName = 'BuildMenuButton.Button';
9196

92-
return <PopButton Button={Button} Menu={BuildMenu} />;
97+
return <PopButton Button={Button} Menu={BuildMenu} menuContainer={menuContainer} />;
9398
};
9499

95-
const ModeMenuButton: React.FC = () => {
100+
const ModeMenuButton: React.FC<PortalProps> = ({ menuContainer }) => {
96101
const label = useSelector(selectors.getModeLabel);
97102

98-
const Button = React.forwardRef<HTMLButtonElement, { toggle: () => void }>(({ toggle }, ref) => (
99-
<SegmentedButton title="Mode &mdash; Choose the optimization level" ref={ref} onClick={toggle}>
100-
<HeaderButton isExpandable>{label}</HeaderButton>
101-
</SegmentedButton>
103+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ toggle }, ref) => (
104+
<OneButton
105+
type="button"
106+
title="Mode &mdash; Choose the optimization level"
107+
ref={ref}
108+
onClick={toggle}
109+
iconRight={ExpandableIcon}
110+
>
111+
{label}
112+
</OneButton>
102113
));
103114
Button.displayName = 'ModeMenuButton.Button';
104115

105-
return <PopButton Button={Button} Menu={ModeMenu} />;
116+
return <PopButton Button={Button} Menu={ModeMenu} menuContainer={menuContainer} />;
106117
};
107118

108-
const ChannelMenuButton: React.FC = () => {
119+
const ChannelMenuButton: React.FC<PortalProps> = ({ menuContainer }) => {
109120
const label = useSelector(selectors.getChannelLabel);
110121

111-
const Button = React.forwardRef<HTMLButtonElement, { toggle: () => void }>(({ toggle }, ref) => (
112-
<SegmentedButton title="Channel &mdash; Choose the Rust version" ref={ref} onClick={toggle}>
113-
<HeaderButton isExpandable>{label}</HeaderButton>
114-
</SegmentedButton>
122+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ toggle }, ref) => (
123+
<OneButton
124+
type="button"
125+
title="Channel &mdash; Choose the Rust version"
126+
ref={ref}
127+
onClick={toggle}
128+
iconRight={ExpandableIcon}
129+
>
130+
{label}
131+
</OneButton>
115132
));
116133
Button.displayName = 'ChannelMenuButton.Button';
117134

118-
return <PopButton Button={Button} Menu={ChannelMenu} />;
119-
}
135+
return <PopButton Button={Button} Menu={ChannelMenu} menuContainer={menuContainer} />;
136+
};
120137

121-
const AdvancedOptionsMenuButton: React.FC = () => {
138+
const AdvancedOptionsMenuButton: React.FC<PortalProps> = ({ menuContainer }) => {
122139
const advancedOptionsSet = useSelector(selectors.getAdvancedOptionsSet);
123140

124-
const Button = React.forwardRef<HTMLButtonElement, { toggle: () => void }>(({ toggle }, ref) => (
125-
<SegmentedButton title="Advanced compilation flags" ref={ref} onClick={toggle}>
126-
<HeaderButton icon={advancedOptionsSet ? <MoreOptionsActiveIcon /> : <MoreOptionsIcon />} />
127-
</SegmentedButton>
141+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ toggle }, ref) => (
142+
<IconButton type="button" title="Advanced compilation flags" ref={ref} onClick={toggle}>
143+
{advancedOptionsSet ? <MoreOptionsActiveIcon /> : <MoreOptionsIcon />}
144+
</IconButton>
128145
));
129146
Button.displayName = 'AdvancedOptionsMenuButton.Button';
130147

131-
return <PopButton Button={Button} Menu={AdvancedOptionsMenu} />;
132-
}
148+
return <PopButton Button={Button} Menu={AdvancedOptionsMenu} menuContainer={menuContainer} />;
149+
};
133150

134151
const ShareButton: React.FC = () => {
135152
const dispatch = useAppDispatch();
136153
const gistSave = useCallback(() => dispatch(performGistSave()), [dispatch]);
137154

138155
return (
139-
<SegmentedButton title="Create shareable links to this code" onClick={gistSave}>
140-
<HeaderButton>Share</HeaderButton>
141-
</SegmentedButton>
156+
<OneButton type="button" title="Create shareable links to this code" onClick={gistSave}>
157+
Share
158+
</OneButton>
142159
);
143160
};
144161

145-
146-
const ToolsMenuButton: React.FC = () => {
147-
const Button = React.forwardRef<HTMLButtonElement, { toggle: () => void }>(({ toggle }, ref) => (
148-
<SegmentedButton title="Run extra tools on the source code" ref={ref} onClick={toggle}>
149-
<HeaderButton isExpandable>Tools</HeaderButton>
150-
</SegmentedButton>
162+
const ToolsMenuButton: React.FC<PortalProps> = ({ menuContainer }) => {
163+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ toggle }, ref) => (
164+
<OneButton
165+
type="button"
166+
title="Run extra tools on the source code"
167+
ref={ref}
168+
onClick={toggle}
169+
iconRight={ExpandableIcon}
170+
>
171+
Tools
172+
</OneButton>
151173
));
152174
Button.displayName = 'ToolsMenuButton.Button';
153175

154-
return <PopButton Button={Button} Menu={ToolsMenu} />;
176+
return <PopButton Button={Button} Menu={ToolsMenu} menuContainer={menuContainer} />;
155177
};
156178

157-
const ConfigMenuButton: React.FC = () => {
158-
const Button = React.forwardRef<HTMLButtonElement, { toggle: () => void }>(({ toggle }, ref) => (
159-
<SegmentedButton title="Show the configuration options" ref={ref} onClick={toggle}>
160-
<HeaderButton icon={<ConfigIcon />} isExpandable>Config</HeaderButton>
161-
</SegmentedButton>
179+
const ConfigMenuButton: React.FC<PortalProps> = ({ menuContainer }) => {
180+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ toggle }, ref) => (
181+
<OneButton
182+
type="button"
183+
title="Show the configuration options"
184+
ref={ref}
185+
onClick={toggle}
186+
iconLeft={ConfigIcon}
187+
iconRight={ExpandableIcon}
188+
>
189+
Config
190+
</OneButton>
162191
));
163192
Button.displayName = 'ConfigMenuButton.Button';
164193

165-
return <PopButton Button={Button} Menu={ConfigMenu} />;
194+
return <PopButton Button={Button} Menu={ConfigMenu} menuContainer={menuContainer} />;
166195
};
167196

168197
const HelpButton: React.FC = () => (
169-
<SegmentedLink title="View help" action={actions.navigateToHelp}>
170-
<HeaderButton icon={<HelpIcon />} />
171-
</SegmentedLink>
198+
<IconLink title="View help" action={actions.navigateToHelp}>
199+
<HelpIcon />
200+
</IconLink>
172201
);
173202

174203
export default Header;

0 commit comments

Comments
 (0)