Skip to content

feat(site): improve icon compatibility across themes #11457

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix a bunch of icons
  • Loading branch information
aslilac committed Jan 5, 2024
commit fd12d430cc31f32e0868a7c0ef726f806b71d3f6
14 changes: 13 additions & 1 deletion site/src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import MuiAvatar, {
type AvatarProps as MuiAvatarProps,
} from "@mui/material/Avatar";
import { type FC, useId } from "react";
import { css, type Interpolation, type Theme } from "@emotion/react";
import { css, type Interpolation, type Theme, useTheme } from "@emotion/react";
import { visuallyHidden } from "@mui/utils";
import { getExternalImageStylesFromUrl } from "theme/externalImages";

export type AvatarProps = MuiAvatarProps & {
size?: "xs" | "sm" | "md" | "xl";
Expand Down Expand Up @@ -67,6 +68,17 @@ export const Avatar: FC<AvatarProps> = ({
);
};

export const ExternalAvatar: FC<AvatarProps> = (props) => {
const theme = useTheme();

return (
<Avatar
css={getExternalImageStylesFromUrl(theme.externalImages, props.src)}
{...props}
/>
);
};

type AvatarIconProps = {
src: string;
alt: string;
Expand Down
8 changes: 4 additions & 4 deletions site/src/components/AvatarCard/AvatarCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type ReactNode } from "react";
import { type FC, type ReactNode } from "react";
import { Avatar } from "components/Avatar/Avatar";
import { type CSSObject, useTheme } from "@emotion/react";

Expand All @@ -12,14 +12,14 @@ type AvatarCardProps = {
maxWidth?: number | "none";
};

export function AvatarCard({
export const AvatarCard: FC<AvatarCardProps> = ({
header,
imgUrl,
altText,
background,
subtitle,
maxWidth = "none",
}: AvatarCardProps) {
}) => {
const theme = useTheme();

return (
Expand Down Expand Up @@ -77,4 +77,4 @@ export function AvatarCard({
</Avatar>
</div>
);
}
};
36 changes: 0 additions & 36 deletions site/src/components/ExternalIcon/ExternalIcon.tsx

This file was deleted.

19 changes: 19 additions & 0 deletions site/src/components/ExternalImage/ExternalImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useTheme } from "@emotion/react";
import { type ImgHTMLAttributes, forwardRef } from "react";
import { getExternalImageStylesFromUrl } from "theme/externalImages";

export const ExternalImage = forwardRef<
HTMLImageElement,
ImgHTMLAttributes<HTMLImageElement>
>((attrs, ref) => {
const theme = useTheme();

return (
<img
ref={ref}
alt=""
css={getExternalImageStylesFromUrl(theme.externalImages, attrs.src)}
{...attrs}
/>
);
});
22 changes: 11 additions & 11 deletions site/src/components/FullPageLayout/Topbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { css } from "@emotion/css";
import Button, { ButtonProps } from "@mui/material/Button";
import IconButton, { IconButtonProps } from "@mui/material/IconButton";
import { useTheme } from "@mui/material/styles";
import { Avatar, AvatarProps } from "components/Avatar/Avatar";
import { AvatarProps, ExternalAvatar } from "components/Avatar/Avatar";
import {
ForwardedRef,
HTMLAttributes,
PropsWithChildren,
ReactElement,
type FC,
type ForwardedRef,
type HTMLAttributes,
type ReactElement,
cloneElement,
forwardRef,
} from "react";

export const Topbar = (props: HTMLAttributes<HTMLDivElement>) => {
export const Topbar: FC<HTMLAttributes<HTMLElement>> = (props) => {
const theme = useTheme();

return (
Expand Down Expand Up @@ -70,7 +70,7 @@ export const TopbarButton = forwardRef<HTMLButtonElement, ButtonProps>(
},
);

export const TopbarData = (props: HTMLAttributes<HTMLDivElement>) => {
export const TopbarData: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
return (
<div
{...props}
Expand All @@ -84,7 +84,7 @@ export const TopbarData = (props: HTMLAttributes<HTMLDivElement>) => {
);
};

export const TopbarDivider = (props: HTMLAttributes<HTMLSpanElement>) => {
export const TopbarDivider: FC<HTMLAttributes<HTMLSpanElement>> = (props) => {
const theme = useTheme();
return (
<span {...props} css={{ color: theme.palette.divider }}>
Expand All @@ -93,9 +93,9 @@ export const TopbarDivider = (props: HTMLAttributes<HTMLSpanElement>) => {
);
};

export const TopbarAvatar = (props: AvatarProps) => {
export const TopbarAvatar: FC<AvatarProps> = (props) => {
return (
<Avatar
<ExternalAvatar
{...props}
variant="square"
fitImage
Expand All @@ -104,7 +104,7 @@ export const TopbarAvatar = (props: AvatarProps) => {
);
};

type TopbarIconProps = PropsWithChildren<HTMLAttributes<HTMLOrSVGElement>>;
type TopbarIconProps = HTMLAttributes<HTMLOrSVGElement>;

export const TopbarIcon = forwardRef<HTMLOrSVGElement, TopbarIconProps>(
(props: TopbarIconProps, ref) => {
Expand Down
2 changes: 1 addition & 1 deletion site/src/components/GroupAvatar/GroupAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const GroupAvatar: FC<GroupAvatarProps> = ({ name, avatarURL }) => {
badgeContent={<Group />}
classes={{ badge }}
>
<Avatar src={avatarURL} background>
<Avatar background src={avatarURL}>
{name}
</Avatar>
</Badge>
Expand Down
3 changes: 2 additions & 1 deletion site/src/components/IconField/IconField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PopoverContent,
PopoverTrigger,
} from "components/Popover/Popover";
import { ExternalImage } from "components/ExternalImage/ExternalImage";

// See: https://github.com/missive/emoji-mart/issues/51#issuecomment-287353222
const urlFromUnifiedCode = (unified: string) =>
Expand Down Expand Up @@ -60,7 +61,7 @@ export const IconField: FC<IconFieldProps> = ({
},
}}
>
<img
<ExternalImage
alt=""
src={textFieldProps.value}
// This prevent browser to display the ugly error icon if the
Expand Down
14 changes: 12 additions & 2 deletions site/src/components/Resources/ResourceAvatar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { type FC } from "react";
import { type FC, useId } from "react";
import { visuallyHidden } from "@mui/utils";
import type { WorkspaceResource } from "api/typesGenerated";
import { Avatar, AvatarIcon } from "components/Avatar/Avatar";
import { ExternalImage } from "components/ExternalImage/ExternalImage";

const FALLBACK_ICON = "/icon/widgets.svg";

Expand All @@ -27,10 +29,18 @@ export type ResourceAvatarProps = { resource: WorkspaceResource };

export const ResourceAvatar: FC<ResourceAvatarProps> = ({ resource }) => {
const avatarSrc = resource.icon || getIconPathResource(resource.type);
const altId = useId();

return (
<Avatar background>
<AvatarIcon src={avatarSrc} alt={resource.name} />
<ExternalImage
src={avatarSrc}
css={{ maxWidth: "50%" }}
aria-labelledby={altId}
/>
<div id={altId} css={{ ...visuallyHidden }}>
{resource.name}
</div>
</Avatar>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Meta, StoryObj } from "@storybook/react";
import { chromatic } from "testHelpers/chromatic";
import {
MockTemplateExample,
MockTemplateExample2,
} from "testHelpers/entities";
import { TemplateExampleCard } from "./TemplateExampleCard";

const meta: Meta<typeof TemplateExampleCard> = {
title: "components/TemplateExampleCard",
parameters: { chromatic },
component: TemplateExampleCard,
args: {
example: MockTemplateExample,
},
};

export default meta;
type Story = StoryObj<typeof TemplateExampleCard>;

export const Example: Story = {};

export const ByTag: Story = {
args: {
activeTag: "cloud",
},
};

export const LotsOfTags: Story = {
args: {
example: {
...MockTemplateExample2,
tags: ["omg", "so many tags", "look at all these", "so cool"],
},
},
};
29 changes: 21 additions & 8 deletions site/src/components/TemplateExampleCard/TemplateExampleCard.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { type Interpolation, type Theme } from "@emotion/react";
import Button from "@mui/material/Button";
import Link from "@mui/material/Link";
import type { TemplateExample } from "api/typesGenerated";
import { ExternalImage } from "components/ExternalImage/ExternalImage";
import { Pill } from "components/Pill/Pill";
import { HTMLProps } from "react";
import { type FC, type HTMLAttributes } from "react";
import { Link as RouterLink } from "react-router-dom";

type TemplateExampleCardProps = {
type TemplateExampleCardProps = HTMLAttributes<HTMLDivElement> & {
example: TemplateExample;
activeTag?: string;
} & HTMLProps<HTMLDivElement>;
};

export const TemplateExampleCard = (props: TemplateExampleCardProps) => {
const { example, activeTag, ...divProps } = props;
export const TemplateExampleCard: FC<TemplateExampleCardProps> = ({
example,
activeTag,
...divProps
}) => {
return (
<div
css={(theme) => ({
Expand Down Expand Up @@ -43,14 +48,20 @@ export const TemplateExampleCard = (props: TemplateExampleCardProps) => {
height: 32,
}}
>
<img
<ExternalImage
src={example.icon}
alt=""
css={{ width: "100%", height: "100%", objectFit: "contain" }}
/>
</div>

<div css={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
<div
css={{
display: "flex",
flexWrap: "wrap",
gap: 8,
justifyContent: "end",
}}
>
{example.tags.map((tag) => {
const isActive = activeTag === tag;

Expand Down Expand Up @@ -122,3 +133,5 @@ export const TemplateExampleCard = (props: TemplateExampleCardProps) => {
</div>
);
};

const styles = {} satisfies Record<string, Interpolation<Theme>>;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Stack } from "components/Stack/Stack";
import { Link } from "react-router-dom";
import { ErrorAlert } from "components/Alert/ErrorAlert";
import type { TemplateExample } from "api/typesGenerated";
import { ExternalImage } from "components/ExternalImage/ExternalImage";

export interface StarterTemplatePageViewProps {
starterTemplate?: TemplateExample;
Expand Down Expand Up @@ -78,7 +79,7 @@ export const StarterTemplatePageView: FC<StarterTemplatePageViewProps> = ({
},
}}
>
<img src={starterTemplate.icon} alt="" />
<ExternalImage src={starterTemplate.icon} />
</div>
<div>
<PageHeaderTitle>{starterTemplate.name}</PageHeaderTitle>
Expand Down
7 changes: 6 additions & 1 deletion site/src/pages/TemplateSettingsPage/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SidebarHeader,
SidebarNavItem,
} from "components/Sidebar/Sidebar";
import { ExternalImage } from "components/ExternalImage/ExternalImage";

interface SidebarProps {
template: Template;
Expand All @@ -19,7 +20,11 @@ export const Sidebar: FC<SidebarProps> = ({ template }) => {
return (
<BaseSidebar>
<SidebarHeader
avatar={<Avatar src={template.icon} variant="square" fitImage />}
avatar={
<Avatar variant="square" fitImage>
<ExternalImage src={template.icon} css={{ width: "100%" }} />
</Avatar>
}
title={template.display_name || template.name}
linkTo={`/templates/${template.name}`}
subtitle={template.name}
Expand Down
9 changes: 7 additions & 2 deletions site/src/pages/TemplatesPage/TemplatesPageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ import { EmptyTemplates } from "./EmptyTemplates";
import { useClickableTableRow } from "hooks/useClickableTableRow";
import type { Template, TemplateExample } from "api/typesGenerated";
import ArrowForwardOutlined from "@mui/icons-material/ArrowForwardOutlined";
import { Avatar } from "components/Avatar/Avatar";
import { ExternalAvatar } from "components/Avatar/Avatar";
import { ErrorAlert } from "components/Alert/ErrorAlert";
import { docs } from "utils/docs";
import Skeleton from "@mui/material/Skeleton";
import { AvatarDataSkeleton } from "components/AvatarData/AvatarDataSkeleton";
import { DeprecatedBadge } from "components/Badges/Badges";
import { ExternalImage } from "components/ExternalImage/ExternalImage";

export const Language = {
developerCount: (activeCount: number): string => {
Expand Down Expand Up @@ -108,7 +109,11 @@ const TemplateRow: FC<TemplateRowProps> = ({ template }) => {
}
subtitle={template.description}
avatar={
hasIcon && <Avatar src={template.icon} variant="square" fitImage />
hasIcon && (
<ExternalAvatar variant="square" fitImage>
<ExternalImage src={template.icon} css={{ maxWidth: "100%" }} />
</ExternalAvatar>
)
}
/>
</TableCell>
Expand Down
Loading