From 27ca82648c933a7d57b51b3f2dbcb0e00855dba6 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 25 Jan 2023 18:06:06 +0000 Subject: [PATCH 1/6] refactor(site): Normalize avatar components --- site/.eslintrc.yaml | 3 + site/src/components/Avatar/Avatar.tsx | 79 +++++++++++++++++++ .../Avatar}/firstLetter.test.ts | 0 .../Avatar}/firstLetter.ts | 0 site/src/components/AvatarData/AvatarData.tsx | 67 ++++++---------- .../components/BuildsTable/BuildAvatar.tsx | 28 ++----- .../components/GroupAvatar/GroupAvatar.tsx | 5 +- .../components/Resources/ResourceAvatar.tsx | 24 ++---- .../TableCellData/TableCellData.tsx | 43 ---------- .../TemplateLayout/TemplateLayout.tsx | 25 ++---- .../UserAutocomplete/AutocompleteAvatar.tsx | 36 --------- .../UserAutocomplete/UserAutocomplete.tsx | 23 +----- site/src/components/UserAvatar/UserAvatar.tsx | 18 +---- .../UserOrGroupAutocomplete.tsx | 17 +--- .../components/UsersTable/UsersTableBody.tsx | 16 +--- site/src/components/Workspace/Workspace.tsx | 13 ++- .../WorkspacesTable/WorkspacesRow.tsx | 10 +-- .../CreateWorkspacePage/SelectedTemplate.tsx | 21 +---- site/src/pages/GroupsPage/GroupPage.tsx | 1 - site/src/pages/GroupsPage/GroupsPageView.tsx | 1 - .../TemplatePermissionsPageView.tsx | 18 +---- .../pages/TemplatesPage/TemplatesPageView.tsx | 8 +- .../WorkspaceBuildPageView.tsx | 2 +- site/src/theme/overrides.ts | 4 + 24 files changed, 157 insertions(+), 305 deletions(-) create mode 100644 site/src/components/Avatar/Avatar.tsx rename site/src/{util => components/Avatar}/firstLetter.test.ts (100%) rename site/src/{util => components/Avatar}/firstLetter.ts (100%) delete mode 100644 site/src/components/TableCellData/TableCellData.tsx delete mode 100644 site/src/components/UserAutocomplete/AutocompleteAvatar.tsx diff --git a/site/.eslintrc.yaml b/site/.eslintrc.yaml index 6be87c5c80f52..e239e69df1783 100644 --- a/site/.eslintrc.yaml +++ b/site/.eslintrc.yaml @@ -96,6 +96,9 @@ rules: message: "Use path imports to avoid pulling in unused modules. See: https://material-ui.com/guides/minimizing-bundle-size/" + - name: "@material-ui/core/Avatar" + message: + "You should use the Avatar component provided on components/Avatar/Avatar" no-unused-vars: "off" "object-curly-spacing": "off" react-hooks/exhaustive-deps: warn diff --git a/site/src/components/Avatar/Avatar.tsx b/site/src/components/Avatar/Avatar.tsx new file mode 100644 index 0000000000000..7b1bb337873e3 --- /dev/null +++ b/site/src/components/Avatar/Avatar.tsx @@ -0,0 +1,79 @@ +// This is the only place MuiAvatar can be used +// eslint-disable-next-line no-restricted-imports -- Read above +import MuiAvatar, { + AvatarProps as MuiAvatarProps, +} from "@material-ui/core/Avatar" +import { makeStyles } from "@material-ui/core/styles" +import { cloneElement, FC } from "react" +import { combineClasses } from "util/combineClasses" +import { firstLetter } from "./firstLetter" + +export type AvatarProps = MuiAvatarProps & { + size?: "sm" | "md" | "xl" + colorScheme?: "light" | "darken" + fitImage?: boolean +} + +export const Avatar: FC = ({ + size = "md", + colorScheme = "light", + fitImage, + className, + children, + ...muiProps +}) => { + const styles = useStyles() + + return ( + + {/* If the children is a string, we always want to render the first letter */} + {typeof children === "string" ? firstLetter(children) : children} + + ) +} + +export const AvatarIcon: FC<{ children: JSX.Element }> = ({ children }) => { + const styles = useStyles() + return cloneElement(children, { className: styles.avatarIcon }) +} + +const useStyles = makeStyles((theme) => ({ + // Size styles + sm: { + width: theme.spacing(4), + height: theme.spacing(4), + fontSize: theme.spacing(2), + }, + // Just use the default value from theme + md: {}, + xl: { + width: theme.spacing(6), + height: theme.spacing(6), + fontSize: theme.spacing(3), + }, + // Colors + // Just use the default value from theme + light: {}, + darken: { + background: theme.palette.divider, + color: theme.palette.text.primary, + }, + // Avatar icon + avatarIcon: { + maxWidth: "50%", + }, + // Fit image + fitImage: { + "& .MuiAvatar-img": { + objectFit: "contain", + }, + }, +})) diff --git a/site/src/util/firstLetter.test.ts b/site/src/components/Avatar/firstLetter.test.ts similarity index 100% rename from site/src/util/firstLetter.test.ts rename to site/src/components/Avatar/firstLetter.test.ts diff --git a/site/src/util/firstLetter.ts b/site/src/components/Avatar/firstLetter.ts similarity index 100% rename from site/src/util/firstLetter.ts rename to site/src/components/Avatar/firstLetter.ts diff --git a/site/src/components/AvatarData/AvatarData.tsx b/site/src/components/AvatarData/AvatarData.tsx index d0118837c991e..31bb60282a1aa 100644 --- a/site/src/components/AvatarData/AvatarData.tsx +++ b/site/src/components/AvatarData/AvatarData.tsx @@ -1,71 +1,50 @@ -import Avatar from "@material-ui/core/Avatar" -import Link from "@material-ui/core/Link" -import { makeStyles } from "@material-ui/core/styles" +import { Avatar } from "components/Avatar/Avatar" import { FC, PropsWithChildren } from "react" -import { Link as RouterLink } from "react-router-dom" -import { firstLetter } from "../../util/firstLetter" -import { - TableCellData, - TableCellDataPrimary, - TableCellDataSecondary, -} from "../TableCellData/TableCellData" +import { Stack } from "components/Stack/Stack" +import { makeStyles } from "@material-ui/core/styles" export interface AvatarDataProps { title: string subtitle?: string - highlightTitle?: boolean - link?: string + src?: string avatar?: React.ReactNode } export const AvatarData: FC> = ({ title, subtitle, - link, - highlightTitle, + src, avatar, }) => { const styles = useStyles() if (!avatar) { - avatar = {firstLetter(title)} + avatar = {title} } return ( -
-
{avatar}
+ + {avatar} - {link ? ( - - - - {title} - - {subtitle && ( - {subtitle} - )} - - - ) : ( - - - {title} - - {subtitle && ( - {subtitle} - )} - - )} -
+ + {title} + {subtitle && {subtitle}} + + ) } const useStyles = makeStyles((theme) => ({ - root: { - display: "flex", - alignItems: "center", + title: { + color: theme.palette.text.primary, + fontWeight: 600, }, - avatarWrapper: { - marginRight: theme.spacing(1.5), + + subtitle: { + fontSize: 12, + color: theme.palette.text.secondary, + lineHeight: "140%", + marginTop: 2, + maxWidth: 540, }, })) diff --git a/site/src/components/BuildsTable/BuildAvatar.tsx b/site/src/components/BuildsTable/BuildAvatar.tsx index c891aeaca95be..54840c71eb6ba 100644 --- a/site/src/components/BuildsTable/BuildAvatar.tsx +++ b/site/src/components/BuildsTable/BuildAvatar.tsx @@ -1,4 +1,3 @@ -import Avatar from "@material-ui/core/Avatar" import Badge from "@material-ui/core/Badge" import { Theme, useTheme, withStyles } from "@material-ui/core/styles" import { FC } from "react" @@ -8,6 +7,7 @@ import DeleteOutlined from "@material-ui/icons/DeleteOutlined" import { WorkspaceBuild, WorkspaceTransition } from "api/typesGenerated" import { getDisplayWorkspaceBuildStatus } from "util/workspace" import { PaletteIndex } from "theme/palettes" +import { Avatar, AvatarProps } from "components/Avatar/Avatar" interface StylesBadgeProps { type: PaletteIndex @@ -25,27 +25,9 @@ const StyledBadge = withStyles((theme) => ({ }, }))(Badge) -interface StyledAvatarProps { - size?: number -} - -const StyledAvatar = withStyles((theme) => ({ - root: { - background: theme.palette.divider, - color: theme.palette.text.primary, - border: `2px solid ${theme.palette.divider}`, - width: ({ size }: StyledAvatarProps) => size, - height: ({ size }: StyledAvatarProps) => size, - - "& svg": { - width: ({ size }: StyledAvatarProps) => (size ? size / 2 : 18), - height: ({ size }: StyledAvatarProps) => (size ? size / 2 : 18), - }, - }, -}))(Avatar) - -export interface BuildAvatarProps extends StyledAvatarProps { +export interface BuildAvatarProps { build: WorkspaceBuild + size?: AvatarProps["size"] } const iconByTransition: Record = { @@ -71,9 +53,9 @@ export const BuildAvatar: FC = ({ build, size }) => { }} badgeContent={
} > - + {iconByTransition[build.transition]} - + ) } diff --git a/site/src/components/GroupAvatar/GroupAvatar.tsx b/site/src/components/GroupAvatar/GroupAvatar.tsx index ab9762050ab27..e909d41381857 100644 --- a/site/src/components/GroupAvatar/GroupAvatar.tsx +++ b/site/src/components/GroupAvatar/GroupAvatar.tsx @@ -1,9 +1,8 @@ -import Avatar from "@material-ui/core/Avatar" +import { Avatar } from "components/Avatar/Avatar" import Badge from "@material-ui/core/Badge" import { withStyles } from "@material-ui/core/styles" import Group from "@material-ui/icons/Group" import { FC } from "react" -import { firstLetter } from "util/firstLetter" const StyledBadge = withStyles((theme) => ({ badge: { @@ -38,7 +37,7 @@ export const GroupAvatar: FC = ({ name, avatarURL }) => { }} badgeContent={} > - {firstLetter(name)} + {name} ) } diff --git a/site/src/components/Resources/ResourceAvatar.tsx b/site/src/components/Resources/ResourceAvatar.tsx index dd7c38caedfb3..2e9253dfa81e1 100644 --- a/site/src/components/Resources/ResourceAvatar.tsx +++ b/site/src/components/Resources/ResourceAvatar.tsx @@ -1,11 +1,9 @@ -import Avatar from "@material-ui/core/Avatar" -import { makeStyles } from "@material-ui/core/styles" +import { Avatar, AvatarIcon } from "components/Avatar/Avatar" import { FC } from "react" import { WorkspaceResource } from "../../api/typesGenerated" const FALLBACK_ICON = "/icon/widgets.svg" -// NOTE @jsjoeio, @BrunoQuaresma // These resources (i.e. docker_image, kubernetes_deployment) map to Terraform // resource types. These are the most used ones and are based on user usage. // We may want to update from time-to-time. @@ -37,18 +35,12 @@ export type ResourceAvatarProps = { resource: WorkspaceResource } export const ResourceAvatar: FC = ({ resource }) => { const hasIcon = resource.icon && resource.icon !== "" const avatarSrc = hasIcon ? resource.icon : getIconPathResource(resource.type) - const styles = useStyles() - return + return ( + + + + + + ) } - -const useStyles = makeStyles((theme) => ({ - resourceAvatar: { - backgroundColor: theme.palette.divider, - - "& img": { - width: 18, - height: 18, - }, - }, -})) diff --git a/site/src/components/TableCellData/TableCellData.tsx b/site/src/components/TableCellData/TableCellData.tsx deleted file mode 100644 index 21e88e3f7a7f9..0000000000000 --- a/site/src/components/TableCellData/TableCellData.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { makeStyles } from "@material-ui/core/styles" -import { ReactNode, FC, PropsWithChildren } from "react" -import { Stack } from "../Stack/Stack" - -interface StyleProps { - highlight?: boolean -} - -export const TableCellData: FC<{ children: ReactNode }> = ({ children }) => { - return {children} -} - -export const TableCellDataPrimary: FC< - PropsWithChildren<{ highlight?: boolean }> -> = ({ children, highlight }) => { - const styles = useStyles({ highlight }) - - return {children} -} - -export const TableCellDataSecondary: FC> = ({ - children, -}) => { - const styles = useStyles({}) - - return {children} -} - -const useStyles = makeStyles((theme) => ({ - primary: { - color: ({ highlight }: StyleProps) => - highlight ? theme.palette.text.primary : theme.palette.text.secondary, - fontWeight: ({ highlight }: StyleProps) => (highlight ? 600 : undefined), - }, - - secondary: { - fontSize: 12, - color: theme.palette.text.secondary, - lineHeight: "140%", - marginTop: 2, - maxWidth: 540, - }, -})) diff --git a/site/src/components/TemplateLayout/TemplateLayout.tsx b/site/src/components/TemplateLayout/TemplateLayout.tsx index 29e49f54338c4..9df24df5601f3 100644 --- a/site/src/components/TemplateLayout/TemplateLayout.tsx +++ b/site/src/components/TemplateLayout/TemplateLayout.tsx @@ -1,4 +1,3 @@ -import Avatar from "@material-ui/core/Avatar" import Button from "@material-ui/core/Button" import Link from "@material-ui/core/Link" import { makeStyles } from "@material-ui/core/styles" @@ -19,7 +18,6 @@ import { useParams, } from "react-router-dom" import { combineClasses } from "util/combineClasses" -import { firstLetter } from "util/firstLetter" import { TemplateContext, templateMachine, @@ -29,6 +27,7 @@ import { Stack } from "components/Stack/Stack" import { Permissions } from "xServices/auth/authXService" import { Loader } from "components/Loader/Loader" import { usePermissions } from "hooks/usePermissions" +import { Avatar } from "components/Avatar/Avatar" const Language = { settingsButton: "Settings", @@ -139,17 +138,12 @@ export const TemplateLayout: FC<{ children?: JSX.Element }> = ({ } > -
- {hasIcon ? ( -
- -
- ) : ( - - {firstLetter(template.name)} - - )} -
+ {hasIcon ? ( + + ) : ( + {template.name} + )} +
{template.display_name.length > 0 @@ -212,11 +206,6 @@ export const useStyles = makeStyles((theme) => { pageTitle: { alignItems: "center", }, - avatar: { - width: theme.spacing(6), - height: theme.spacing(6), - fontSize: theme.spacing(3), - }, iconWrapper: { width: theme.spacing(6), height: theme.spacing(6), diff --git a/site/src/components/UserAutocomplete/AutocompleteAvatar.tsx b/site/src/components/UserAutocomplete/AutocompleteAvatar.tsx deleted file mode 100644 index 87b7da3d9a0b8..0000000000000 --- a/site/src/components/UserAutocomplete/AutocompleteAvatar.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import Avatar from "@material-ui/core/Avatar" -import { makeStyles } from "@material-ui/core/styles" -import { User } from "api/typesGenerated" -import { FC } from "react" -import { firstLetter } from "../../util/firstLetter" - -export const AutocompleteAvatar: FC<{ user: User }> = ({ user }) => { - const styles = useStyles() - - return ( -
- {user.avatar_url ? ( - {`${user.username}'s - ) : ( - {firstLetter(user.username)} - )} -
- ) -} - -export const useStyles = makeStyles((theme) => { - return { - avatarContainer: { - margin: "0px 10px", - }, - avatar: { - width: theme.spacing(4.5), - height: theme.spacing(4.5), - borderRadius: "100%", - }, - } -}) diff --git a/site/src/components/UserAutocomplete/UserAutocomplete.tsx b/site/src/components/UserAutocomplete/UserAutocomplete.tsx index 186b8841fb90c..1f4bf3ef8c79c 100644 --- a/site/src/components/UserAutocomplete/UserAutocomplete.tsx +++ b/site/src/components/UserAutocomplete/UserAutocomplete.tsx @@ -4,12 +4,12 @@ import TextField from "@material-ui/core/TextField" import Autocomplete from "@material-ui/lab/Autocomplete" import { useMachine } from "@xstate/react" import { User } from "api/typesGenerated" +import { Avatar } from "components/Avatar/Avatar" import { AvatarData } from "components/AvatarData/AvatarData" import debounce from "just-debounce-it" import { ChangeEvent, FC, useEffect, useState } from "react" import { combineClasses } from "util/combineClasses" import { searchUserMachine } from "xServices/users/searchUserXService" -import { AutocompleteAvatar } from "./AutocompleteAvatar" export type UserAutocompleteProps = { value: User | null @@ -77,16 +77,7 @@ export const UserAutocomplete: FC = ({ - ) : null - } + src={option.avatar_url} /> )} options={searchResults} @@ -103,8 +94,8 @@ export const UserAutocomplete: FC = ({ InputProps={{ ...params.InputProps, onChange: handleFilterChange, - startAdornment: ( - <>{showAvatar && value && } + startAdornment: showAvatar && value && ( + {value.username} ), endAdornment: ( <> @@ -145,12 +136,6 @@ export const useStyles = makeStyles((theme) => { padding: `${theme.spacing(0, 0.5, 0, 0.5)} !important`, }, }), - - avatar: { - width: theme.spacing(4.5), - height: theme.spacing(4.5), - borderRadius: "100%", - }, } }) diff --git a/site/src/components/UserAvatar/UserAvatar.tsx b/site/src/components/UserAvatar/UserAvatar.tsx index a238db47c4f72..8d6387e00df65 100644 --- a/site/src/components/UserAvatar/UserAvatar.tsx +++ b/site/src/components/UserAvatar/UserAvatar.tsx @@ -1,25 +1,15 @@ -import Avatar from "@material-ui/core/Avatar" +import { Avatar } from "components/Avatar/Avatar" import { FC } from "react" -import { firstLetter } from "../../util/firstLetter" export interface UserAvatarProps { username: string - className?: string avatarURL?: string } -export const UserAvatar: FC = ({ - username, - className, - avatarURL, -}) => { +export const UserAvatar: FC = ({ username, avatarURL }) => { return ( - - {avatarURL ? ( - {`${username}'s - ) : ( - firstLetter(username) - )} + + {username} ) } diff --git a/site/src/components/UserOrGroupAutocomplete/UserOrGroupAutocomplete.tsx b/site/src/components/UserOrGroupAutocomplete/UserOrGroupAutocomplete.tsx index 15810bc48a26f..34ee185a00ed2 100644 --- a/site/src/components/UserOrGroupAutocomplete/UserOrGroupAutocomplete.tsx +++ b/site/src/components/UserOrGroupAutocomplete/UserOrGroupAutocomplete.tsx @@ -77,16 +77,7 @@ export const UserOrGroupAutocomplete: React.FC< - ) : null - } + src={option.avatar_url} /> ) }} @@ -137,11 +128,5 @@ export const useStyles = makeStyles((theme) => { padding: `${theme.spacing(0, 0.5, 0, 0.5)} !important`, }, }, - - avatar: { - width: theme.spacing(4.5), - height: theme.spacing(4.5), - borderRadius: "100%", - }, } }) diff --git a/site/src/components/UsersTable/UsersTableBody.tsx b/site/src/components/UsersTable/UsersTableBody.tsx index e08b3d16ccb7a..93641cd8037ca 100644 --- a/site/src/components/UsersTable/UsersTableBody.tsx +++ b/site/src/components/UsersTable/UsersTableBody.tsx @@ -110,16 +110,7 @@ export const UsersTableBody: FC< - ) : null - } + src={user.avatar_url} /> @@ -216,11 +207,6 @@ const useStyles = makeStyles((theme) => ({ suspended: { color: theme.palette.text.secondary, }, - avatar: { - width: theme.spacing(4.5), - height: theme.spacing(4.5), - borderRadius: "100%", - }, rolePill: { backgroundColor: theme.palette.background.paperLight, borderColor: theme.palette.divider, diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index c1405e4bd079a..63d0d671efcf4 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -23,6 +23,7 @@ import { WorkspaceBuildProgress, } from "components/WorkspaceBuildProgress/WorkspaceBuildProgress" import { AgentRow } from "components/Resources/AgentRow" +import { Avatar } from "components/Avatar/Avatar" export enum WorkspaceErrors { GET_RESOURCES_ERROR = "getResourcesError", @@ -151,10 +152,11 @@ export const Workspace: FC> = ({ > {hasTemplateIcon && ( - )}
@@ -267,11 +269,6 @@ export const useStyles = makeStyles((theme) => { width: "100%", }, - templateIcon: { - width: theme.spacing(6), - height: theme.spacing(6), - }, - timelineContents: { margin: 0, }, diff --git a/site/src/components/WorkspacesTable/WorkspacesRow.tsx b/site/src/components/WorkspacesTable/WorkspacesRow.tsx index d2fa9960eb85a..8ac1aab0125c7 100644 --- a/site/src/components/WorkspacesTable/WorkspacesRow.tsx +++ b/site/src/components/WorkspacesTable/WorkspacesRow.tsx @@ -11,6 +11,7 @@ import { getDisplayWorkspaceTemplateName } from "util/workspace" import { LastUsed } from "../LastUsed/LastUsed" import { Workspace } from "api/typesGenerated" import { OutdatedHelpTooltip } from "components/Tooltips/OutdatedHelpTooltip" +import { Avatar } from "components/Avatar/Avatar" export const WorkspacesRow: FC<{ workspace: Workspace @@ -35,15 +36,12 @@ export const WorkspacesRow: FC<{ > - -
- ) : undefined + hasTemplateIcon && ( + + ) } />
diff --git a/site/src/pages/CreateWorkspacePage/SelectedTemplate.tsx b/site/src/pages/CreateWorkspacePage/SelectedTemplate.tsx index 29d1030f19ebf..7d77c9a78de92 100644 --- a/site/src/pages/CreateWorkspacePage/SelectedTemplate.tsx +++ b/site/src/pages/CreateWorkspacePage/SelectedTemplate.tsx @@ -1,9 +1,8 @@ -import Avatar from "@material-ui/core/Avatar" import { makeStyles } from "@material-ui/core/styles" import { Template, TemplateExample } from "api/typesGenerated" +import { Avatar } from "components/Avatar/Avatar" import { Stack } from "components/Stack/Stack" import { FC } from "react" -import { firstLetter } from "util/firstLetter" export interface SelectedTemplateProps { template: Template | TemplateExample @@ -19,13 +18,8 @@ export const SelectedTemplate: FC = ({ template }) => { className={styles.template} alignItems="center" > -
- {template.icon === "" ? ( - {firstLetter(template.name)} - ) : ( - - )} -
+ {template.name} + {"display_name" in template && template.display_name.length > 0 @@ -58,13 +52,4 @@ const useStyles = makeStyles((theme) => ({ fontSize: 14, color: theme.palette.text.secondary, }, - - templateIcon: { - width: theme.spacing(4), - lineHeight: 1, - - "& img": { - width: "100%", - }, - }, })) diff --git a/site/src/pages/GroupsPage/GroupPage.tsx b/site/src/pages/GroupsPage/GroupPage.tsx index 0411e35747b0d..0149bcc71f8b8 100644 --- a/site/src/pages/GroupsPage/GroupPage.tsx +++ b/site/src/pages/GroupsPage/GroupPage.tsx @@ -173,7 +173,6 @@ export const GroupPage: React.FC = () => { diff --git a/site/src/pages/GroupsPage/GroupsPageView.tsx b/site/src/pages/GroupsPage/GroupsPageView.tsx index 2d6982f276830..fb6b44d2bc6ba 100644 --- a/site/src/pages/GroupsPage/GroupsPageView.tsx +++ b/site/src/pages/GroupsPage/GroupsPageView.tsx @@ -144,7 +144,6 @@ export const GroupsPageView: FC = ({ } title={group.name} subtitle={`${group.members.length} members`} - highlightTitle /> diff --git a/site/src/pages/TemplatePage/TemplatePermissionsPage/TemplatePermissionsPageView.tsx b/site/src/pages/TemplatePage/TemplatePermissionsPage/TemplatePermissionsPageView.tsx index d9c4c74001beb..55cceb033fc27 100644 --- a/site/src/pages/TemplatePage/TemplatePermissionsPage/TemplatePermissionsPageView.tsx +++ b/site/src/pages/TemplatePage/TemplatePermissionsPage/TemplatePermissionsPageView.tsx @@ -249,7 +249,6 @@ export const TemplatePermissionsPageView: FC< } title={group.name} subtitle={getGroupSubtitle(group)} - highlightTitle /> @@ -296,16 +295,7 @@ export const TemplatePermissionsPageView: FC< - ) : null - } + src={user.avatar_url} /> @@ -363,12 +353,6 @@ export const useStyles = makeStyles((theme) => { width: 100, }, - avatar: { - width: theme.spacing(4.5), - height: theme.spacing(4.5), - borderRadius: "100%", - }, - updateSelect: { margin: 0, // Set a fixed width for the select. It avoids selects having different sizes diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index 7ca1d6b9485ca..762339ad5898c 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -41,6 +41,7 @@ import { Template } from "api/typesGenerated" import { combineClasses } from "util/combineClasses" import { colors } from "theme/colors" import ArrowForwardOutlined from "@material-ui/icons/ArrowForwardOutlined" +import { Avatar } from "components/Avatar/Avatar" export const Language = { developerCount: (activeCount: number): string => { @@ -97,13 +98,8 @@ const TemplateRow: FC<{ template: Template }> = ({ template }) => { : template.name } subtitle={template.description} - highlightTitle avatar={ - hasIcon && ( -
- -
- ) + hasIcon && } />
diff --git a/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx b/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx index 17cfb72e0c12f..f2bf9905e6608 100644 --- a/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx +++ b/site/src/pages/WorkspaceBuildPage/WorkspaceBuildPageView.tsx @@ -34,7 +34,7 @@ export const WorkspaceBuildPageView: FC = ({ {build && ( - +
Build #{build.build_number} diff --git a/site/src/theme/overrides.ts b/site/src/theme/overrides.ts index e62a41e4ad1ec..025a5c9bb6daa 100644 --- a/site/src/theme/overrides.ts +++ b/site/src/theme/overrides.ts @@ -30,6 +30,10 @@ export const getOverrides = ({ width: 36, height: 36, fontSize: 18, + + "& .MuiSvgIcon-root": { + width: "50%", + }, }, colorDefault: { backgroundColor: colors.gray[6], From 72bfda0d7435d39c2891ef08a4d17bd4f37113f7 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 25 Jan 2023 18:09:15 +0000 Subject: [PATCH 2/6] Fix template layout size --- site/src/components/TemplateLayout/TemplateLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/components/TemplateLayout/TemplateLayout.tsx b/site/src/components/TemplateLayout/TemplateLayout.tsx index 9df24df5601f3..eb8644e242ac3 100644 --- a/site/src/components/TemplateLayout/TemplateLayout.tsx +++ b/site/src/components/TemplateLayout/TemplateLayout.tsx @@ -139,7 +139,7 @@ export const TemplateLayout: FC<{ children?: JSX.Element }> = ({ > {hasIcon ? ( - + ) : ( {template.name} )} From 1cb58dac9b470ef6e56a4a350dc3a2a694b37733 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 25 Jan 2023 18:12:04 +0000 Subject: [PATCH 3/6] No need for sm styles --- site/src/components/Avatar/Avatar.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/site/src/components/Avatar/Avatar.tsx b/site/src/components/Avatar/Avatar.tsx index 7b1bb337873e3..b7c78e302965a 100644 --- a/site/src/components/Avatar/Avatar.tsx +++ b/site/src/components/Avatar/Avatar.tsx @@ -9,7 +9,7 @@ import { combineClasses } from "util/combineClasses" import { firstLetter } from "./firstLetter" export type AvatarProps = MuiAvatarProps & { - size?: "sm" | "md" | "xl" + size?: "md" | "xl" colorScheme?: "light" | "darken" fitImage?: boolean } @@ -47,11 +47,6 @@ export const AvatarIcon: FC<{ children: JSX.Element }> = ({ children }) => { const useStyles = makeStyles((theme) => ({ // Size styles - sm: { - width: theme.spacing(4), - height: theme.spacing(4), - fontSize: theme.spacing(2), - }, // Just use the default value from theme md: {}, xl: { From 900622e63f2cc503512088b2e8ef6ae1bca856cf Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 25 Jan 2023 18:23:21 +0000 Subject: [PATCH 4/6] Add storybook for Avatar --- site/src/components/Avatar/Avatar.stories.tsx | 55 +++++++++++++++++++ .../AvatarData/AvatarData.stories.tsx | 13 +---- 2 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 site/src/components/Avatar/Avatar.stories.tsx diff --git a/site/src/components/Avatar/Avatar.stories.tsx b/site/src/components/Avatar/Avatar.stories.tsx new file mode 100644 index 0000000000000..143234e41cc0c --- /dev/null +++ b/site/src/components/Avatar/Avatar.stories.tsx @@ -0,0 +1,55 @@ +import { Story } from "@storybook/react" +import { Avatar, AvatarProps } from "./Avatar" +import PauseIcon from "@material-ui/icons/PauseOutlined" + +export default { + title: "components/Avatar", + component: Avatar, +} + +const Template: Story = (args: AvatarProps) => + +export const Letter = Template.bind({}) +Letter.args = { + children: "Coder", +} + +export const LetterXL = Template.bind({}) +LetterXL.args = { + children: "Coder", + size: "xl", +} + +export const LetterDarken = Template.bind({}) +LetterDarken.args = { + children: "Coder", + colorScheme: "darken", +} + +export const Image = Template.bind({}) +Image.args = { + src: "https://avatars.githubusercontent.com/u/95932066?s=200&v=4", +} + +export const ImageXL = Template.bind({}) +ImageXL.args = { + src: "https://avatars.githubusercontent.com/u/95932066?s=200&v=4", + size: "xl", +} + +export const MuiIcon = Template.bind({}) +MuiIcon.args = { + children: , +} + +export const MuiIconDarken = Template.bind({}) +MuiIconDarken.args = { + children: , + colorScheme: "darken", +} + +export const MuiIconXL = Template.bind({}) +MuiIconXL.args = { + children: , + size: "xl", +} diff --git a/site/src/components/AvatarData/AvatarData.stories.tsx b/site/src/components/AvatarData/AvatarData.stories.tsx index a341afc5c8747..bd4fa143107c2 100644 --- a/site/src/components/AvatarData/AvatarData.stories.tsx +++ b/site/src/components/AvatarData/AvatarData.stories.tsx @@ -16,16 +16,9 @@ Example.args = { subtitle: "coder@coder.com", } -export const WithHighlightTitle = Template.bind({}) -WithHighlightTitle.args = { +export const WithImage = Template.bind({}) +WithImage.args = { title: "coder", subtitle: "coder@coder.com", - highlightTitle: true, -} - -export const WithLink = Template.bind({}) -WithLink.args = { - title: "coder", - subtitle: "coder@coder.com", - link: "/users/coder", + src: "https://avatars.githubusercontent.com/u/95932066?s=200&v=4", } From 454a1f54e4a98a70d8d037a144e5bade4960e41f Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 25 Jan 2023 18:24:16 +0000 Subject: [PATCH 5/6] Fix fmt --- site/.eslintrc.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site/.eslintrc.yaml b/site/.eslintrc.yaml index e239e69df1783..d856e9e2202b7 100644 --- a/site/.eslintrc.yaml +++ b/site/.eslintrc.yaml @@ -98,7 +98,8 @@ rules: https://material-ui.com/guides/minimizing-bundle-size/" - name: "@material-ui/core/Avatar" message: - "You should use the Avatar component provided on components/Avatar/Avatar" + "You should use the Avatar component provided on + components/Avatar/Avatar" no-unused-vars: "off" "object-curly-spacing": "off" react-hooks/exhaustive-deps: warn From 61b5f95093076f6e6296cb1f39b4928dd3153716 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Thu, 26 Jan 2023 00:41:54 +0000 Subject: [PATCH 6/6] Improvements nd fixes --- site/src/components/Avatar/Avatar.stories.tsx | 8 +++++++- site/src/components/Avatar/Avatar.tsx | 9 ++++++--- site/src/components/Resources/ResourceAvatar.tsx | 4 +--- site/src/components/UserAvatar/UserAvatar.tsx | 11 +++++++++-- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/site/src/components/Avatar/Avatar.stories.tsx b/site/src/components/Avatar/Avatar.stories.tsx index 143234e41cc0c..aedeb8d1a27ff 100644 --- a/site/src/components/Avatar/Avatar.stories.tsx +++ b/site/src/components/Avatar/Avatar.stories.tsx @@ -1,5 +1,5 @@ import { Story } from "@storybook/react" -import { Avatar, AvatarProps } from "./Avatar" +import { Avatar, AvatarIcon, AvatarProps } from "./Avatar" import PauseIcon from "@material-ui/icons/PauseOutlined" export default { @@ -53,3 +53,9 @@ MuiIconXL.args = { children: , size: "xl", } + +export const AvatarIconDarken = Template.bind({}) +AvatarIconDarken.args = { + children: , + colorScheme: "darken", +} diff --git a/site/src/components/Avatar/Avatar.tsx b/site/src/components/Avatar/Avatar.tsx index b7c78e302965a..f93e2d671d91e 100644 --- a/site/src/components/Avatar/Avatar.tsx +++ b/site/src/components/Avatar/Avatar.tsx @@ -4,7 +4,7 @@ import MuiAvatar, { AvatarProps as MuiAvatarProps, } from "@material-ui/core/Avatar" import { makeStyles } from "@material-ui/core/styles" -import { cloneElement, FC } from "react" +import { FC } from "react" import { combineClasses } from "util/combineClasses" import { firstLetter } from "./firstLetter" @@ -40,9 +40,12 @@ export const Avatar: FC = ({ ) } -export const AvatarIcon: FC<{ children: JSX.Element }> = ({ children }) => { +/** + * Use it to make an img element behaves like a MaterialUI Icon component + */ +export const AvatarIcon: FC<{ src: string }> = ({ src }) => { const styles = useStyles() - return cloneElement(children, { className: styles.avatarIcon }) + return } const useStyles = makeStyles((theme) => ({ diff --git a/site/src/components/Resources/ResourceAvatar.tsx b/site/src/components/Resources/ResourceAvatar.tsx index 2e9253dfa81e1..96c2b05f733d1 100644 --- a/site/src/components/Resources/ResourceAvatar.tsx +++ b/site/src/components/Resources/ResourceAvatar.tsx @@ -38,9 +38,7 @@ export const ResourceAvatar: FC = ({ resource }) => { return ( - - - + ) } diff --git a/site/src/components/UserAvatar/UserAvatar.tsx b/site/src/components/UserAvatar/UserAvatar.tsx index 8d6387e00df65..d5c283d01072d 100644 --- a/site/src/components/UserAvatar/UserAvatar.tsx +++ b/site/src/components/UserAvatar/UserAvatar.tsx @@ -4,11 +4,18 @@ import { FC } from "react" export interface UserAvatarProps { username: string avatarURL?: string + // It is needed to work with the AvatarGroup so it can pass the + // MuiAvatarGroup-avatar className + className?: string } -export const UserAvatar: FC = ({ username, avatarURL }) => { +export const UserAvatar: FC = ({ + username, + avatarURL, + className, +}) => { return ( - + {username} )