Skip to content

Commit 9f5a59d

Browse files
authored
feat(site): improve icon compatibility across themes (#11457)
1 parent 427afe1 commit 9f5a59d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+722
-196
lines changed

examples/examples.gen.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"url": "",
66
"name": "AWS EC2 (Devcontainer)",
77
"description": "Provision AWS EC2 VMs with a devcontainer as Coder workspaces",
8-
"icon": "/icon/aws.png",
8+
"icon": "/icon/aws.svg",
99
"tags": [
1010
"vm",
1111
"linux",
@@ -20,7 +20,7 @@
2020
"url": "",
2121
"name": "AWS EC2 (Linux)",
2222
"description": "Provision AWS EC2 VMs as Coder workspaces",
23-
"icon": "/icon/aws.png",
23+
"icon": "/icon/aws.svg",
2424
"tags": [
2525
"vm",
2626
"linux",
@@ -34,7 +34,7 @@
3434
"url": "",
3535
"name": "AWS EC2 (Windows)",
3636
"description": "Provision AWS EC2 VMs as Coder workspaces",
37-
"icon": "/icon/aws.png",
37+
"icon": "/icon/aws.svg",
3838
"tags": [
3939
"vm",
4040
"windows",

examples/templates/aws-devcontainer/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
display_name: AWS EC2 (Devcontainer)
33
description: Provision AWS EC2 VMs with a devcontainer as Coder workspaces
4-
icon: ../../../site/static/icon/aws.png
4+
icon: ../../../site/static/icon/aws.svg
55
maintainer_github: coder
66
verified: true
77
tags: [vm, linux, aws, persistent, devcontainer]

examples/templates/aws-linux/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
display_name: AWS EC2 (Linux)
33
description: Provision AWS EC2 VMs as Coder workspaces
4-
icon: ../../../site/static/icon/aws.png
4+
icon: ../../../site/static/icon/aws.svg
55
maintainer_github: coder
66
verified: true
77
tags: [vm, linux, aws, persistent-vm]

examples/templates/aws-windows/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
display_name: AWS EC2 (Windows)
33
description: Provision AWS EC2 VMs as Coder workspaces
4-
icon: ../../../site/static/icon/aws.png
4+
icon: ../../../site/static/icon/aws.svg
55
maintainer_github: coder
66
verified: true
77
tags: [vm, windows, aws]

site/src/AppRouter.tsx

+1-7
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import WorkspacesPage from "./pages/WorkspacesPage/WorkspacesPage";
2121
import UserSettingsLayout from "./pages/UserSettingsPage/Layout";
2222
import { TemplateSettingsLayout } from "./pages/TemplateSettingsPage/TemplateSettingsLayout";
2323
import { WorkspaceSettingsLayout } from "./pages/WorkspaceSettingsPage/WorkspaceSettingsLayout";
24-
import { ThemeOverride } from "contexts/ThemeProvider";
25-
import themes from "theme";
2624

2725
// Lazy load pages
2826
// - Pages that are secondary, not in the main navigation or not usually accessed
@@ -421,11 +419,7 @@ export const AppRouter: FC = () => {
421419
/>
422420
<Route
423421
path="/:username/:workspace/terminal"
424-
element={
425-
<ThemeOverride theme={themes.dark}>
426-
<TerminalPage />
427-
</ThemeOverride>
428-
}
422+
element={<TerminalPage />}
429423
/>
430424
<Route path="/cli-auth" element={<CliAuthenticationPage />} />
431425
<Route path="/icons" element={<IconsPage />} />

site/src/__mocks__/react-markdown.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FC, PropsWithChildren } from "react";
22

3-
const ReactMarkdown: FC<PropsWithChildren<unknown>> = ({ children }) => {
3+
const ReactMarkdown: FC<PropsWithChildren> = ({ children }) => {
44
return <div data-testid="markdown">{children}</div>;
55
};
66

site/src/api/queries/users.ts

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export const me = (): UseQueryOptions<User> & {
131131
queryKey: meKey,
132132
initialData: initialUserData,
133133
queryFn: API.getAuthenticatedUser,
134+
refetchOnWindowFocus: true,
134135
};
135136
};
136137

site/src/components/Avatar/Avatar.tsx

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import MuiAvatar, {
44
type AvatarProps as MuiAvatarProps,
55
} from "@mui/material/Avatar";
66
import { type FC, useId } from "react";
7-
import { css, type Interpolation, type Theme } from "@emotion/react";
7+
import { css, type Interpolation, type Theme, useTheme } from "@emotion/react";
88
import { visuallyHidden } from "@mui/utils";
9+
import { getExternalImageStylesFromUrl } from "theme/externalImages";
910

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

71+
export const ExternalAvatar: FC<AvatarProps> = (props) => {
72+
const theme = useTheme();
73+
74+
return (
75+
<Avatar
76+
css={getExternalImageStylesFromUrl(theme.externalImages, props.src)}
77+
{...props}
78+
/>
79+
);
80+
};
81+
7082
type AvatarIconProps = {
7183
src: string;
7284
alt: string;

site/src/components/AvatarCard/AvatarCard.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type ReactNode } from "react";
1+
import { type FC, type ReactNode } from "react";
22
import { Avatar } from "components/Avatar/Avatar";
33
import { type CSSObject, useTheme } from "@emotion/react";
44

@@ -12,14 +12,14 @@ type AvatarCardProps = {
1212
maxWidth?: number | "none";
1313
};
1414

15-
export function AvatarCard({
15+
export const AvatarCard: FC<AvatarCardProps> = ({
1616
header,
1717
imgUrl,
1818
altText,
1919
background,
2020
subtitle,
2121
maxWidth = "none",
22-
}: AvatarCardProps) {
22+
}) => {
2323
const theme = useTheme();
2424

2525
return (
@@ -77,4 +77,4 @@ export function AvatarCard({
7777
</Avatar>
7878
</div>
7979
);
80-
}
80+
};

site/src/components/ExternalIcon/ExternalIcon.tsx

-36
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { useTheme } from "@emotion/react";
2+
import { type ImgHTMLAttributes, forwardRef } from "react";
3+
import { getExternalImageStylesFromUrl } from "theme/externalImages";
4+
5+
export const ExternalImage = forwardRef<
6+
HTMLImageElement,
7+
ImgHTMLAttributes<HTMLImageElement>
8+
>((attrs, ref) => {
9+
const theme = useTheme();
10+
11+
return (
12+
<img
13+
ref={ref}
14+
alt=""
15+
css={getExternalImageStylesFromUrl(theme.externalImages, attrs.src)}
16+
{...attrs}
17+
/>
18+
);
19+
});

site/src/components/FullPageLayout/Topbar.tsx

+11-11
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import { css } from "@emotion/css";
22
import Button, { ButtonProps } from "@mui/material/Button";
33
import IconButton, { IconButtonProps } from "@mui/material/IconButton";
44
import { useTheme } from "@mui/material/styles";
5-
import { Avatar, AvatarProps } from "components/Avatar/Avatar";
5+
import { AvatarProps, ExternalAvatar } from "components/Avatar/Avatar";
66
import {
7-
ForwardedRef,
8-
HTMLAttributes,
9-
PropsWithChildren,
10-
ReactElement,
7+
type FC,
8+
type ForwardedRef,
9+
type HTMLAttributes,
10+
type ReactElement,
1111
cloneElement,
1212
forwardRef,
1313
} from "react";
1414

15-
export const Topbar = (props: HTMLAttributes<HTMLDivElement>) => {
15+
export const Topbar: FC<HTMLAttributes<HTMLElement>> = (props) => {
1616
const theme = useTheme();
1717

1818
return (
@@ -70,7 +70,7 @@ export const TopbarButton = forwardRef<HTMLButtonElement, ButtonProps>(
7070
},
7171
);
7272

73-
export const TopbarData = (props: HTMLAttributes<HTMLDivElement>) => {
73+
export const TopbarData: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
7474
return (
7575
<div
7676
{...props}
@@ -84,7 +84,7 @@ export const TopbarData = (props: HTMLAttributes<HTMLDivElement>) => {
8484
);
8585
};
8686

87-
export const TopbarDivider = (props: HTMLAttributes<HTMLSpanElement>) => {
87+
export const TopbarDivider: FC<HTMLAttributes<HTMLSpanElement>> = (props) => {
8888
const theme = useTheme();
8989
return (
9090
<span {...props} css={{ color: theme.palette.divider }}>
@@ -93,9 +93,9 @@ export const TopbarDivider = (props: HTMLAttributes<HTMLSpanElement>) => {
9393
);
9494
};
9595

96-
export const TopbarAvatar = (props: AvatarProps) => {
96+
export const TopbarAvatar: FC<AvatarProps> = (props) => {
9797
return (
98-
<Avatar
98+
<ExternalAvatar
9999
{...props}
100100
variant="square"
101101
fitImage
@@ -104,7 +104,7 @@ export const TopbarAvatar = (props: AvatarProps) => {
104104
);
105105
};
106106

107-
type TopbarIconProps = PropsWithChildren<HTMLAttributes<HTMLOrSVGElement>>;
107+
type TopbarIconProps = HTMLAttributes<HTMLOrSVGElement>;
108108

109109
export const TopbarIcon = forwardRef<HTMLOrSVGElement, TopbarIconProps>(
110110
(props: TopbarIconProps, ref) => {

site/src/components/GroupAvatar/GroupAvatar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const GroupAvatar: FC<GroupAvatarProps> = ({ name, avatarURL }) => {
1919
badgeContent={<Group />}
2020
classes={{ badge }}
2121
>
22-
<Avatar src={avatarURL} background>
22+
<Avatar background src={avatarURL}>
2323
{name}
2424
</Avatar>
2525
</Badge>

site/src/components/IconField/IconField.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
PopoverContent,
1313
PopoverTrigger,
1414
} from "components/Popover/Popover";
15+
import { ExternalImage } from "components/ExternalImage/ExternalImage";
1516

1617
// See: https://github.com/missive/emoji-mart/issues/51#issuecomment-287353222
1718
const urlFromUnifiedCode = (unified: string) =>
@@ -60,7 +61,7 @@ export const IconField: FC<IconFieldProps> = ({
6061
},
6162
}}
6263
>
63-
<img
64+
<ExternalImage
6465
alt=""
6566
src={textFieldProps.value}
6667
// This prevent browser to display the ugly error icon if the
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1-
import { type FC } from "react";
1+
import { type FC, useId } from "react";
2+
import { visuallyHidden } from "@mui/utils";
23
import type { WorkspaceResource } from "api/typesGenerated";
3-
import { Avatar, AvatarIcon } from "components/Avatar/Avatar";
4+
import { Avatar } from "components/Avatar/Avatar";
5+
import { ExternalImage } from "components/ExternalImage/ExternalImage";
46
import { getResourceIconPath } from "utils/workspace";
57

68
export type ResourceAvatarProps = { resource: WorkspaceResource };
79

810
export const ResourceAvatar: FC<ResourceAvatarProps> = ({ resource }) => {
911
const avatarSrc = resource.icon || getResourceIconPath(resource.type);
12+
const altId = useId();
1013

1114
return (
1215
<Avatar background>
13-
<AvatarIcon src={avatarSrc} alt={resource.name} />
16+
<ExternalImage
17+
src={avatarSrc}
18+
css={{ maxWidth: "50%" }}
19+
aria-labelledby={altId}
20+
/>
21+
<div id={altId} css={{ ...visuallyHidden }}>
22+
{resource.name}
23+
</div>
1424
</Avatar>
1525
);
1626
};

site/src/components/RichParameterInput/RichParameterInput.stories.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export const Options: Story = {
9696
name: "Third option",
9797
value: "third_option",
9898
description: "",
99-
icon: "/icon/aws.png",
99+
icon: "/icon/aws.svg",
100100
},
101101
],
102102
}),
@@ -138,7 +138,7 @@ Very big.
138138
139139
> Wow, that description is straight up large. –Some guy, probably
140140
`,
141-
icon: "/icon/aws.png",
141+
icon: "/icon/aws.svg",
142142
},
143143
],
144144
}),

site/src/components/RichParameterInput/RichParameterInput.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { TemplateVersionParameter } from "api/typesGenerated";
99
import { MemoizedMarkdown } from "components/Markdown/Markdown";
1010
import { Stack } from "components/Stack/Stack";
1111
import { MultiTextField } from "./MultiTextField";
12+
import { ExternalImage } from "components/ExternalImage/ExternalImage";
1213

1314
const isBoolean = (parameter: TemplateVersionParameter) => {
1415
return parameter.type === "bool";
@@ -106,7 +107,7 @@ const ParameterLabel: FC<ParameterLabelProps> = ({ parameter }) => {
106107
<Stack direction="row" alignItems="center">
107108
{parameter.icon && (
108109
<span css={styles.labelIconWrapper}>
109-
<img
110+
<ExternalImage
110111
css={styles.labelIcon}
111112
alt="Parameter icon"
112113
src={parameter.icon}
@@ -213,7 +214,7 @@ const RichParameterField: FC<RichParameterInputProps> = ({
213214
label={
214215
<Stack direction="row" alignItems="center">
215216
{option.icon && (
216-
<img
217+
<ExternalImage
217218
css={styles.optionIcon}
218219
src={option.icon}
219220
alt="Parameter icon"

0 commit comments

Comments
 (0)