Skip to content

Commit dffd795

Browse files
fix(site): Minor UI fixes related to avatar components (#6019)
1 parent 6c90701 commit dffd795

File tree

12 files changed

+108
-110
lines changed

12 files changed

+108
-110
lines changed

site/src/components/Avatar/Avatar.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { combineClasses } from "util/combineClasses"
99
import { firstLetter } from "./firstLetter"
1010

1111
export type AvatarProps = MuiAvatarProps & {
12-
size?: "md" | "xl"
12+
size?: "sm" | "md" | "xl"
1313
colorScheme?: "light" | "darken"
1414
fitImage?: boolean
1515
}
@@ -50,6 +50,11 @@ export const AvatarIcon: FC<{ src: string }> = ({ src }) => {
5050

5151
const useStyles = makeStyles((theme) => ({
5252
// Size styles
53+
sm: {
54+
width: theme.spacing(3),
55+
height: theme.spacing(3),
56+
fontSize: theme.spacing(1.5),
57+
},
5358
// Just use the default value from theme
5459
md: {},
5560
xl: {

site/src/components/SearchBarWithFilter/SearchBarWithFilter.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ interface StyleProps {
156156
const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
157157
root: {
158158
marginBottom: theme.spacing(2),
159+
160+
"&:has(button) .MuiInputBase-root": {
161+
borderTopLeftRadius: 0,
162+
borderBottomLeftRadius: 0,
163+
},
159164
},
160165
// necessary to expand the textField
161166
// the length of the page (within the bordered filterContainer)
@@ -174,7 +179,6 @@ const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
174179
inputStyles: {
175180
height: "100%",
176181
width: "100%",
177-
borderRadius: `0px ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px 0px`,
178182
color: theme.palette.primary.contrastText,
179183
backgroundColor: theme.palette.background.paper,
180184

@@ -189,7 +193,7 @@ const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
189193
paddingTop: "inherit",
190194
paddingBottom: "inherit",
191195
// The same as the button
192-
minHeight: 42,
196+
minHeight: 40,
193197
},
194198
},
195199
searchIcon: {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Story } from "@storybook/react"
2+
import { MockUser } from "testHelpers/entities"
3+
import { UserAutocomplete, UserAutocompleteProps } from "./UserAutocomplete"
4+
5+
export default {
6+
title: "components/UserAutocomplete",
7+
component: UserAutocomplete,
8+
}
9+
10+
const Template: Story<UserAutocompleteProps> = (
11+
args: UserAutocompleteProps,
12+
) => <UserAutocomplete {...args} />
13+
14+
export const Example = Template.bind({})
15+
Example.args = {
16+
value: MockUser,
17+
label: "User",
18+
}
19+
20+
export const NoLabel = Template.bind({})
21+
NoLabel.args = {
22+
value: MockUser,
23+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import CircularProgress from "@material-ui/core/CircularProgress"
2-
import { makeStyles, Theme } from "@material-ui/core/styles"
2+
import { makeStyles } from "@material-ui/core/styles"
33
import TextField from "@material-ui/core/TextField"
44
import Autocomplete from "@material-ui/lab/Autocomplete"
55
import { useMachine } from "@xstate/react"
@@ -8,29 +8,22 @@ import { Avatar } from "components/Avatar/Avatar"
88
import { AvatarData } from "components/AvatarData/AvatarData"
99
import debounce from "just-debounce-it"
1010
import { ChangeEvent, FC, useEffect, useState } from "react"
11-
import { combineClasses } from "util/combineClasses"
1211
import { searchUserMachine } from "xServices/users/searchUserXService"
1312

1413
export type UserAutocompleteProps = {
1514
value: User | null
1615
onChange: (user: User | null) => void
1716
label?: string
18-
inputMargin?: "none" | "dense" | "normal"
19-
inputStyles?: string
2017
className?: string
21-
showAvatar?: boolean
2218
}
2319

2420
export const UserAutocomplete: FC<UserAutocompleteProps> = ({
2521
value,
2622
onChange,
27-
className,
2823
label,
29-
inputMargin,
30-
inputStyles,
31-
showAvatar = false,
24+
className,
3225
}) => {
33-
const styles = useStyles({ showAvatar })
26+
const styles = useStyles()
3427
const [isAutocompleteOpen, setIsAutocompleteOpen] = useState(false)
3528
const [searchState, sendSearch] = useMachine(searchUserMachine)
3629
const { searchResults } = searchState.context
@@ -53,6 +46,9 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
5346

5447
return (
5548
<Autocomplete
49+
className={className}
50+
options={searchResults}
51+
loading={searchState.matches("searching")}
5652
value={value}
5753
id="user-autocomplete"
5854
open={isAutocompleteOpen}
@@ -80,22 +76,21 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
8076
src={option.avatar_url}
8177
/>
8278
)}
83-
options={searchResults}
84-
loading={searchState.matches("searching")}
85-
className={combineClasses([styles.autocomplete, className])}
8679
renderInput={(params) => (
8780
<TextField
8881
{...params}
82+
fullWidth
8983
variant="outlined"
90-
margin={inputMargin ?? "normal"}
9184
label={label ?? undefined}
9285
placeholder="User email or username"
93-
className={inputStyles}
86+
className={styles.textField}
9487
InputProps={{
9588
...params.InputProps,
9689
onChange: handleFilterChange,
97-
startAdornment: showAvatar && value && (
98-
<Avatar src={value.avatar_url}>{value.username}</Avatar>
90+
startAdornment: value && (
91+
<Avatar size="sm" src={value.avatar_url}>
92+
{value.username}
93+
</Avatar>
9994
),
10095
endAdornment: (
10196
<>
@@ -105,61 +100,24 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
105100
{params.InputProps.endAdornment}
106101
</>
107102
),
103+
classes: {
104+
root: styles.inputRoot,
105+
},
108106
}}
109107
/>
110108
)}
111109
/>
112110
)
113111
}
114112

115-
interface styleProps {
116-
showAvatar: boolean
117-
}
118-
119-
export const useStyles = makeStyles<Theme, styleProps>((theme) => {
120-
return {
121-
autocomplete: (props) => ({
122-
width: "100%",
123-
124-
"& .MuiFormControl-root": {
125-
width: "100%",
126-
},
127-
128-
"& .MuiInputBase-root": {
129-
width: "100%",
130-
// Match button small height
131-
height: props.showAvatar ? 60 : 40,
132-
},
133-
134-
"& input": {
135-
fontSize: 16,
136-
padding: `${theme.spacing(0, 0.5, 0, 0.5)} !important`,
137-
},
138-
}),
139-
}
140-
})
141-
142-
export const UserAutocompleteInline: React.FC<UserAutocompleteProps> = (
143-
props,
144-
) => {
145-
const style = useInlineStyle()
146-
147-
return <UserAutocomplete {...props} className={style.inline} />
148-
}
149-
150-
export const useInlineStyle = makeStyles(() => {
151-
return {
152-
inline: {
153-
width: "300px",
154-
155-
"& .MuiFormControl-root": {
156-
margin: 0,
157-
},
158-
159-
"& .MuiInputBase-root": {
160-
// Match button small height
161-
height: 36,
162-
},
113+
export const useStyles = makeStyles((theme) => ({
114+
textField: {
115+
"&:not(:has(label))": {
116+
margin: 0,
163117
},
164-
}
165-
})
118+
},
119+
inputRoot: {
120+
paddingLeft: `${theme.spacing(1.75)}px !important`, // Same padding left as input
121+
gap: theme.spacing(0.5),
122+
},
123+
}))

site/src/components/Workspace/Workspace.tsx

+8-10
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
9292
const styles = useStyles()
9393
const navigate = useNavigate()
9494
const serverVersion = buildInfo?.version || ""
95-
const hasTemplateIcon =
96-
workspace.template_icon && workspace.template_icon !== ""
9795

9896
const buildError = Boolean(workspaceErrors[WorkspaceErrors.BUILD_ERROR]) && (
9997
<AlertBanner
@@ -159,14 +157,14 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
159157
}
160158
>
161159
<Stack direction="row" spacing={3} alignItems="center">
162-
{hasTemplateIcon && (
163-
<Avatar
164-
size="xl"
165-
src={workspace.template_icon}
166-
variant="square"
167-
fitImage
168-
/>
169-
)}
160+
<Avatar
161+
size="xl"
162+
src={workspace.template_icon}
163+
variant={workspace.template_icon ? "square" : undefined}
164+
fitImage={Boolean(workspace.template_icon)}
165+
>
166+
{workspace.name}
167+
</Avatar>
170168
<div>
171169
<PageHeaderTitle>
172170
{workspace.name}

site/src/components/WorkspacesTable/WorkspacesRow.tsx

+10-22
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import TableRow from "@material-ui/core/TableRow"
44
import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"
55
import { AvatarData } from "components/AvatarData/AvatarData"
66
import { WorkspaceStatusBadge } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge"
7-
import { useClickable } from "hooks/useClickable"
87
import { FC } from "react"
98
import { useNavigate, Link as RouterLink } from "react-router-dom"
109
import { getDisplayWorkspaceTemplateName } from "util/workspace"
@@ -15,6 +14,7 @@ import { Avatar } from "components/Avatar/Avatar"
1514
import { Stack } from "components/Stack/Stack"
1615
import TemplateLinkIcon from "@material-ui/icons/OpenInNewOutlined"
1716
import Link from "@material-ui/core/Link"
17+
import { useClickableTableRow } from "hooks/useClickableTableRow"
1818

1919
export const WorkspacesRow: FC<{
2020
workspace: Workspace
@@ -23,20 +23,13 @@ export const WorkspacesRow: FC<{
2323
const styles = useStyles()
2424
const navigate = useNavigate()
2525
const workspacePageLink = `/@${workspace.owner_name}/${workspace.name}`
26-
const hasTemplateIcon =
27-
workspace.template_icon && workspace.template_icon !== ""
2826
const displayTemplateName = getDisplayWorkspaceTemplateName(workspace)
29-
const clickable = useClickable(() => {
27+
const clickable = useClickableTableRow(() => {
3028
navigate(workspacePageLink)
3129
})
3230

3331
return (
34-
<TableRow
35-
className={styles.row}
36-
hover
37-
data-testid={`workspace-${workspace.id}`}
38-
{...clickable}
39-
>
32+
<TableRow data-testid={`workspace-${workspace.id}`} {...clickable}>
4033
<TableCell>
4134
<AvatarData
4235
title={
@@ -53,9 +46,13 @@ export const WorkspacesRow: FC<{
5346
}
5447
subtitle={workspace.owner_name}
5548
avatar={
56-
hasTemplateIcon && (
57-
<Avatar src={workspace.template_icon} variant="square" fitImage />
58-
)
49+
<Avatar
50+
src={workspace.template_icon}
51+
variant={workspace.template_icon ? "square" : undefined}
52+
fitImage={Boolean(workspace.template_icon)}
53+
>
54+
{workspace.name}
55+
</Avatar>
5956
}
6057
/>
6158
</TableCell>
@@ -95,15 +92,6 @@ export const WorkspacesRow: FC<{
9592
}
9693

9794
const useStyles = makeStyles((theme) => ({
98-
row: {
99-
cursor: "pointer",
100-
101-
"&:focus": {
102-
outline: `1px solid ${theme.palette.secondary.dark}`,
103-
outlineOffset: -1,
104-
},
105-
},
106-
10795
arrowRight: {
10896
color: theme.palette.text.secondary,
10997
width: 20,

site/src/hooks/useClickableTableRow.ts

+5
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,10 @@ const useStyles = makeStyles((theme) => ({
2727
outline: `1px solid ${theme.palette.secondary.dark}`,
2828
outlineOffset: -1,
2929
},
30+
31+
"&:last-of-type": {
32+
borderBottomLeftRadius: theme.shape.borderRadius,
33+
borderBottomRightRadius: theme.shape.borderRadius,
34+
},
3035
},
3136
}))

site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,6 @@ export const CreateWorkspacePageView: FC<
215215
value={props.owner}
216216
onChange={props.setOwner}
217217
label={t("ownerLabel")}
218-
inputMargin="dense"
219-
showAvatar
220218
/>
221219
</Stack>
222220
</div>

site/src/pages/CreateWorkspacePage/SelectedTemplate.stories.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ const Template: Story<SelectedTemplateProps> = (args) => (
1313

1414
export const WithIcon = Template.bind({})
1515
WithIcon.args = {
16-
template: MockTemplate,
16+
template: {
17+
...MockTemplate,
18+
icon: "/icon/docker.png",
19+
},
1720
}
1821

1922
export const WithoutIcon = Template.bind({})

site/src/pages/CreateWorkspacePage/SelectedTemplate.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ export const SelectedTemplate: FC<SelectedTemplateProps> = ({ template }) => {
1818
className={styles.template}
1919
alignItems="center"
2020
>
21-
<Avatar src={template.icon}>{template.name}</Avatar>
21+
<Avatar
22+
variant={template.icon ? "square" : undefined}
23+
fitImage={Boolean(template.icon)}
24+
src={template.icon}
25+
>
26+
{template.name}
27+
</Avatar>
2228

2329
<Stack direction="column" spacing={0.5}>
2430
<span className={styles.templateName}>

0 commit comments

Comments
 (0)