Skip to content

Commit 5d8667e

Browse files
committed
Reimplement the buttons used in the header
This will allow us to more easily reuse them for stdin interactions. As a bonus, the HTML structure feels much cleaner.
1 parent bc1bbb0 commit 5d8667e

File tree

5 files changed

+218
-0
lines changed

5 files changed

+218
-0
lines changed

ui/frontend/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ module.exports = {
6363
files: [
6464
'.eslintrc.js',
6565
'BuildMenu.tsx',
66+
'ButtonSet.tsx',
6667
'PopButton.tsx',
6768
'compileActions.ts',
6869
'editor/AceEditor.tsx',

ui/frontend/.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ node_modules
1414
# Slowly migrate files that we've touched
1515
!.eslintrc.js
1616
!BuildMenu.tsx
17+
!ButtonSet.tsx
1718
!PopButton.tsx
1819
!compileActions.ts
1920
!editor/AceEditor.tsx

ui/frontend/ButtonSet.module.css

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
$width: 1px;
2+
$radius: 4px;
3+
4+
.set {
5+
display: flex;
6+
}
7+
8+
.-border {
9+
border-width: $width 0;
10+
border-style: solid;
11+
12+
&:first-child {
13+
border-top-left-radius: $radius;
14+
border-bottom-left-radius: $radius;
15+
border-left-width: $width;
16+
}
17+
18+
&:last-child {
19+
border-top-right-radius: $radius;
20+
border-bottom-right-radius: $radius;
21+
border-right-width: $width;
22+
}
23+
}
24+
25+
.-button {
26+
composes: -buttonReset from './shared.module.css';
27+
display: grid;
28+
grid-auto-flow: column;
29+
gap: 0.5em;
30+
align-content: center;
31+
align-items: center;
32+
padding: 0 1.25em;
33+
height: 3em;
34+
font-weight: 600;
35+
text-decoration: none;
36+
text-transform: uppercase;
37+
white-space: nowrap;
38+
39+
&:enabled {
40+
cursor: pointer;
41+
}
42+
}
43+
44+
.primary {
45+
composes: -border -button;
46+
background-color: var(--button-primary-bg-color);
47+
border-color: var(--button-primary-border-color);
48+
color: var(--button-primary-color);
49+
font-weight: 700;
50+
51+
&:disabled {
52+
background-color: var(--button-primary-bg-color-light);
53+
border-color: var(--button-primary-border-color-light);
54+
}
55+
56+
&:hover:enabled {
57+
background-color: var(--button-primary-border-color);
58+
}
59+
60+
&:active:enabled {
61+
box-shadow: inset 0 0 5px var(--button-primary-active-color);
62+
}
63+
}
64+
65+
.secondary {
66+
composes: -border -button;
67+
background: linear-gradient(
68+
to bottom,
69+
var(--button-secondary-bg-color-top),
70+
var(--button-secondary-bg-color-bottom)
71+
);
72+
border-color: var(--button-secondary-border-color);
73+
color: var(--button-secondary-color);
74+
75+
&:disabled {
76+
background: inherit;
77+
background-color: var(--button-secondary-bg-color-light);
78+
border-color: var(--button-secondary-border-color-light);
79+
color: var(--button-secondary-color-light);
80+
}
81+
82+
&:hover:enabled {
83+
background: inherit;
84+
background-color: var(--button-secondary-border-color);
85+
}
86+
87+
&:active:enabled {
88+
box-shadow: inset 0 0 5px var(--button-secondary-active-color);
89+
}
90+
}
91+
92+
.iconLeft {
93+
transform: translate(-0.25em, 0);
94+
}
95+
96+
.iconRight {
97+
transform: translate(0.25em, 0);
98+
}
99+
100+
.rule {
101+
composes: -border;
102+
background-color: var(--button-secondary-border-color);
103+
width: 1px;
104+
border-color: var(--button-secondary-border-color);
105+
}
106+
107+
.icon {
108+
composes: secondary;
109+
padding: 0;
110+
aspect-ratio: 1/1;
111+
justify-items: center;
112+
}

ui/frontend/ButtonSet.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React from 'react';
2+
3+
import Link, { LinkProps } from './uss-router/Link';
4+
5+
import styles from './ButtonSet.module.css';
6+
7+
interface ButtonSetProps {
8+
children: React.ReactNode;
9+
}
10+
11+
export const ButtonSet: React.FC<ButtonSetProps> = ({ children }) => (
12+
<div className={styles.set}>{children}</div>
13+
);
14+
15+
type HTMLButton = JSX.IntrinsicElements['button'];
16+
17+
interface ButtonProps extends HTMLButton {
18+
isPrimary?: boolean;
19+
iconLeft?: React.FC;
20+
iconRight?: React.FC;
21+
}
22+
23+
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
24+
({ isPrimary = false, iconLeft: IconLeft, iconRight: IconRight, children, ...props }, ref) => {
25+
const iconLeft = IconLeft && (
26+
<span className={styles.iconLeft}>
27+
<IconLeft />
28+
</span>
29+
);
30+
const iconRight = IconRight && (
31+
<span className={styles.iconRight}>
32+
<IconRight />
33+
</span>
34+
);
35+
const ordinalStyle = isPrimary ? styles.primary : styles.secondary;
36+
37+
return (
38+
<button ref={ref} className={ordinalStyle} {...props}>
39+
{iconLeft}
40+
{children}
41+
{iconRight}
42+
</button>
43+
);
44+
},
45+
);
46+
Button.displayName = 'Button';
47+
48+
export const Rule: React.FC = () => <span className={styles.rule} />;
49+
50+
export const IconButton = React.forwardRef<HTMLButtonElement, HTMLButton>(
51+
({ children, ...props }, ref) => (
52+
<button ref={ref} className={styles.icon} {...props}>
53+
{children}
54+
</button>
55+
),
56+
);
57+
IconButton.displayName = 'IconButton';
58+
59+
export const IconLink = React.forwardRef<HTMLAnchorElement, LinkProps>(
60+
({ children, ...props }, ref) => (
61+
<Link ref={ref} className={styles.icon} {...props}>
62+
{children}
63+
</Link>
64+
),
65+
);
66+
IconLink.displayName = 'IconLink';

ui/frontend/index.module.css

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,44 @@
99
--header-tint: #428bca;
1010
--header-border-radius: 4px;
1111
--header-accent-border: #bdbdbd;
12+
13+
/* The big red button */
14+
15+
--button-primary-color: white;
16+
--button-primary-bg-color: var(--rust);
17+
--button-primary-border-color: var(--rust-dark);
18+
--button-primary-bg-color-light: color-mix(in hsl, var(--button-primary-bg-color), white);
19+
--button-primary-border-color-light: color-mix(in hsl, var(--button-primary-border-color), white);
20+
21+
/* Clicked */
22+
--button-primary-active-color: color-mix(in hsl, white, black 30%);
23+
24+
/* Not the big red button */
25+
26+
--button-secondary-color: #444;
27+
--button-secondary-bg-color-top: #fff;
28+
--button-secondary-bg-color-bottom: #f9f9f9;
29+
--button-secondary-border-color: color-mix(
30+
in hsl,
31+
var(--button-secondary-bg-color-bottom),
32+
black 20%
33+
);
34+
35+
/* Disabled */
36+
--button-secondary-bg-color-light: color-mix(
37+
in hsl,
38+
var(--button-secondary-bg-color-bottom),
39+
white
40+
);
41+
--button-secondary-border-color-light: color-mix(
42+
in hsl,
43+
var(--button-secondary-border-color),
44+
white
45+
);
46+
--button-secondary-color-light: color-mix(in hsl, var(--button-secondary-color), white);
47+
48+
/* Clicked */
49+
--button-secondary-active-color: color-mix(in hsl, black, white 30%);
1250
}
1351

1452
/* Modify normalized styles */

0 commit comments

Comments
 (0)