mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: add support buttons (#20339)
Fixes: https://github.com/coder/coder/issues/16804
This commit is contained in:
Generated
+9
-1
@@ -14897,7 +14897,15 @@ const docTemplate = `{
|
||||
"enum": [
|
||||
"bug",
|
||||
"chat",
|
||||
"docs"
|
||||
"docs",
|
||||
"star"
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"navbar",
|
||||
"dropdown"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
|
||||
Generated
+5
-1
@@ -13489,7 +13489,11 @@
|
||||
"properties": {
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"enum": ["bug", "chat", "docs"]
|
||||
"enum": ["bug", "chat", "docs", "star"]
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"enum": ["navbar", "dropdown"]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
|
||||
@@ -984,9 +984,10 @@ func DefaultSupportLinks(docsURL string) []LinkConfig {
|
||||
Icon: "bug",
|
||||
},
|
||||
{
|
||||
Name: "Join the Coder Discord",
|
||||
Target: "https://coder.com/chat?utm_source=coder&utm_medium=coder&utm_campaign=server-footer",
|
||||
Icon: "chat",
|
||||
Name: "Join the Coder Discord",
|
||||
Target: "https://discord.gg/coder",
|
||||
Icon: "chat",
|
||||
Location: "navbar",
|
||||
},
|
||||
{
|
||||
Name: "Star the Repo",
|
||||
@@ -3339,7 +3340,9 @@ type SupportConfig struct {
|
||||
type LinkConfig struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Target string `json:"target" yaml:"target"`
|
||||
Icon string `json:"icon" yaml:"icon" enums:"bug,chat,docs"`
|
||||
Icon string `json:"icon" yaml:"icon" enums:"bug,chat,docs,star"`
|
||||
|
||||
Location string `json:"location,omitempty" yaml:"location,omitempty" enums:"navbar,dropdown"`
|
||||
}
|
||||
|
||||
// Validate checks cross-field constraints for deployment values.
|
||||
|
||||
Generated
+1
@@ -120,6 +120,7 @@ curl -X GET http://coder-server:8080/api/v2/appearance \
|
||||
"support_links": [
|
||||
{
|
||||
"icon": "bug",
|
||||
"location": "navbar",
|
||||
"name": "string",
|
||||
"target": "string"
|
||||
}
|
||||
|
||||
Generated
+1
@@ -473,6 +473,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
|
||||
"value": [
|
||||
{
|
||||
"icon": "bug",
|
||||
"location": "navbar",
|
||||
"name": "string",
|
||||
"target": "string"
|
||||
}
|
||||
|
||||
Generated
+20
-10
@@ -1110,6 +1110,7 @@
|
||||
"support_links": [
|
||||
{
|
||||
"icon": "bug",
|
||||
"location": "navbar",
|
||||
"name": "string",
|
||||
"target": "string"
|
||||
}
|
||||
@@ -3138,6 +3139,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
"value": [
|
||||
{
|
||||
"icon": "bug",
|
||||
"location": "navbar",
|
||||
"name": "string",
|
||||
"target": "string"
|
||||
}
|
||||
@@ -3644,6 +3646,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
"value": [
|
||||
{
|
||||
"icon": "bug",
|
||||
"location": "navbar",
|
||||
"name": "string",
|
||||
"target": "string"
|
||||
}
|
||||
@@ -4752,6 +4755,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
||||
```json
|
||||
{
|
||||
"icon": "bug",
|
||||
"location": "navbar",
|
||||
"name": "string",
|
||||
"target": "string"
|
||||
}
|
||||
@@ -4759,19 +4763,23 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|----------|--------|----------|--------------|-------------|
|
||||
| `icon` | string | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `target` | string | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|------------|--------|----------|--------------|-------------|
|
||||
| `icon` | string | false | | |
|
||||
| `location` | string | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `target` | string | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Property | Value |
|
||||
|----------|--------|
|
||||
| `icon` | `bug` |
|
||||
| `icon` | `chat` |
|
||||
| `icon` | `docs` |
|
||||
| Property | Value |
|
||||
|------------|------------|
|
||||
| `icon` | `bug` |
|
||||
| `icon` | `chat` |
|
||||
| `icon` | `docs` |
|
||||
| `icon` | `star` |
|
||||
| `location` | `navbar` |
|
||||
| `location` | `dropdown` |
|
||||
|
||||
## codersdk.ListInboxNotificationsResponse
|
||||
|
||||
@@ -7625,6 +7633,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
||||
"value": [
|
||||
{
|
||||
"icon": "bug",
|
||||
"location": "navbar",
|
||||
"name": "string",
|
||||
"target": "string"
|
||||
}
|
||||
@@ -13685,6 +13694,7 @@ None
|
||||
"value": [
|
||||
{
|
||||
"icon": "bug",
|
||||
"location": "navbar",
|
||||
"name": "string",
|
||||
"target": "string"
|
||||
}
|
||||
|
||||
@@ -201,6 +201,17 @@ func TestCustomSupportLinks(t *testing.T) {
|
||||
Target: "http://second-link-2",
|
||||
Icon: "bug",
|
||||
},
|
||||
{
|
||||
Name: "First button",
|
||||
Target: "http://first-button-1",
|
||||
Icon: "bug",
|
||||
Location: "navbar",
|
||||
},
|
||||
{
|
||||
Name: "Third link",
|
||||
Target: "http://third-link-3",
|
||||
Icon: "star",
|
||||
},
|
||||
}
|
||||
cfg := coderdtest.DeploymentValues(t)
|
||||
cfg.Support.Links = serpent.Struct[[]codersdk.LinkConfig]{
|
||||
|
||||
Generated
+1
@@ -2515,6 +2515,7 @@ export interface LinkConfig {
|
||||
readonly name: string;
|
||||
readonly target: string;
|
||||
readonly icon: string;
|
||||
readonly location?: string;
|
||||
}
|
||||
|
||||
// From codersdk/inboxnotification.go
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { buildInfo } from "api/queries/buildInfo";
|
||||
import type { LinkConfig } from "api/typesGenerated";
|
||||
import { useProxy } from "contexts/ProxyContext";
|
||||
import { useAuthenticated } from "hooks";
|
||||
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
|
||||
@@ -25,12 +26,18 @@ export const Navbar: FC = () => {
|
||||
const canViewConnectionLog =
|
||||
featureVisibility.connection_log && permissions.viewAnyConnectionLog;
|
||||
|
||||
const uniqueLinks = new Map<string, LinkConfig>();
|
||||
for (const link of appearance.support_links ?? []) {
|
||||
if (!uniqueLinks.has(link.name)) {
|
||||
uniqueLinks.set(link.name, link);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<NavbarView
|
||||
user={me}
|
||||
logo_url={appearance.logo_url}
|
||||
buildInfo={buildInfoQuery.data}
|
||||
supportLinks={appearance.support_links}
|
||||
supportLinks={Array.from(uniqueLinks.values())}
|
||||
onSignOut={signOut}
|
||||
canViewDeployment={canViewDeployment}
|
||||
canViewOrganizations={canViewOrganizations}
|
||||
|
||||
@@ -33,6 +33,7 @@ const meta: Meta<typeof NavbarView> = {
|
||||
canViewDeployment: true,
|
||||
canViewHealth: true,
|
||||
canViewOrganizations: true,
|
||||
supportLinks: [],
|
||||
},
|
||||
decorators: [withDashboardProvider],
|
||||
};
|
||||
@@ -129,3 +130,64 @@ export const IdleTasks: Story = {
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const SupportLinks: Story = {
|
||||
args: {
|
||||
user: MockUserMember,
|
||||
canViewAuditLog: false,
|
||||
canViewDeployment: false,
|
||||
canViewHealth: false,
|
||||
canViewOrganizations: false,
|
||||
supportLinks: [
|
||||
{
|
||||
name: "This is a bug",
|
||||
icon: "bug",
|
||||
target: "#",
|
||||
},
|
||||
{
|
||||
name: "This is a star",
|
||||
icon: "star",
|
||||
target: "#",
|
||||
location: "navbar",
|
||||
},
|
||||
{
|
||||
name: "This is a chat",
|
||||
icon: "chat",
|
||||
target: "#",
|
||||
location: "navbar",
|
||||
},
|
||||
{
|
||||
name: "No icon here",
|
||||
icon: "",
|
||||
target: "#",
|
||||
location: "navbar",
|
||||
},
|
||||
{
|
||||
name: "No icon here too",
|
||||
icon: "",
|
||||
target: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultSupportLinks: Story = {
|
||||
args: {
|
||||
user: MockUserMember,
|
||||
canViewAuditLog: false,
|
||||
canViewDeployment: false,
|
||||
canViewHealth: false,
|
||||
canViewOrganizations: false,
|
||||
supportLinks: [
|
||||
{ icon: "docs", name: "Documentation", target: "" },
|
||||
{ icon: "bug", name: "Report a bug", target: "" },
|
||||
{
|
||||
icon: "chat",
|
||||
name: "Join the Coder Discord",
|
||||
target: "",
|
||||
location: "navbar",
|
||||
},
|
||||
{ icon: "star", name: "Star the Repo", target: "" },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -34,6 +34,7 @@ describe("NavbarView", () => {
|
||||
canViewHealth
|
||||
canViewAuditLog
|
||||
canViewConnectionLog
|
||||
supportLinks={[]}
|
||||
/>,
|
||||
);
|
||||
const workspacesLink =
|
||||
@@ -52,6 +53,7 @@ describe("NavbarView", () => {
|
||||
canViewHealth
|
||||
canViewAuditLog
|
||||
canViewConnectionLog
|
||||
supportLinks={[]}
|
||||
/>,
|
||||
);
|
||||
const templatesLink =
|
||||
@@ -70,6 +72,7 @@ describe("NavbarView", () => {
|
||||
canViewHealth
|
||||
canViewAuditLog
|
||||
canViewConnectionLog
|
||||
supportLinks={[]}
|
||||
/>,
|
||||
);
|
||||
const deploymentMenu = await screen.findByText("Admin settings");
|
||||
@@ -89,6 +92,7 @@ describe("NavbarView", () => {
|
||||
canViewHealth
|
||||
canViewAuditLog
|
||||
canViewConnectionLog
|
||||
supportLinks={[]}
|
||||
/>,
|
||||
);
|
||||
const deploymentMenu = await screen.findByText("Admin settings");
|
||||
|
||||
@@ -21,13 +21,14 @@ import { cn } from "utils/cn";
|
||||
import { DeploymentDropdown } from "./DeploymentDropdown";
|
||||
import { MobileMenu } from "./MobileMenu";
|
||||
import { ProxyMenu } from "./ProxyMenu";
|
||||
import { SupportIcon } from "./SupportIcon";
|
||||
import { UserDropdown } from "./UserDropdown/UserDropdown";
|
||||
|
||||
interface NavbarViewProps {
|
||||
logo_url?: string;
|
||||
user: TypesGen.User;
|
||||
buildInfo?: TypesGen.BuildInfoResponse;
|
||||
supportLinks?: readonly TypesGen.LinkConfig[];
|
||||
supportLinks: readonly TypesGen.LinkConfig[];
|
||||
onSignOut: () => void;
|
||||
canViewDeployment: boolean;
|
||||
canViewOrganizations: boolean;
|
||||
@@ -71,6 +72,16 @@ export const NavbarView: FC<NavbarViewProps> = ({
|
||||
<NavItems className="ml-4" user={user} />
|
||||
|
||||
<div className="flex items-center gap-3 ml-auto">
|
||||
{supportLinks.filter(isNavbarLink).map((link) => (
|
||||
<div key={link.name} className="hidden md:block">
|
||||
<SupportButton
|
||||
name={link.name}
|
||||
target={link.target}
|
||||
icon={link.icon}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{proxyContextValue && (
|
||||
<div className="hidden md:block">
|
||||
<ProxyMenu proxyContextValue={proxyContextValue} />
|
||||
@@ -121,7 +132,7 @@ export const NavbarView: FC<NavbarViewProps> = ({
|
||||
<UserDropdown
|
||||
user={user}
|
||||
buildInfo={buildInfo}
|
||||
supportLinks={supportLinks}
|
||||
supportLinks={supportLinks?.filter((link) => !isNavbarLink(link))}
|
||||
onSignOut={onSignOut}
|
||||
/>
|
||||
</div>
|
||||
@@ -240,3 +251,36 @@ const TasksNavItem: FC<TasksNavItemProps> = ({ user }) => {
|
||||
function idleTasksLabel(count: number) {
|
||||
return `You have ${count} ${count === 1 ? "task" : "tasks"} waiting for input`;
|
||||
}
|
||||
|
||||
function isNavbarLink(link: TypesGen.LinkConfig): boolean {
|
||||
return link.location === "navbar";
|
||||
}
|
||||
|
||||
interface SupportButtonProps {
|
||||
name: string;
|
||||
target: string;
|
||||
icon: string;
|
||||
location?: string;
|
||||
}
|
||||
|
||||
const SupportButton: FC<SupportButtonProps> = ({ name, target, icon }) => {
|
||||
return (
|
||||
<Button asChild variant="outline">
|
||||
<a
|
||||
href={target}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-block"
|
||||
>
|
||||
{icon && (
|
||||
<SupportIcon
|
||||
icon={icon}
|
||||
className={"size-5 text-content-secondary"}
|
||||
/>
|
||||
)}
|
||||
{name}
|
||||
<span className="sr-only"> (link opens in new tab)</span>
|
||||
</a>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { SvgIconProps } from "@mui/material/SvgIcon";
|
||||
import { ExternalImage } from "components/ExternalImage/ExternalImage";
|
||||
import { BookOpenTextIcon, BugIcon, MessageSquareIcon } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
|
||||
interface SupportIconProps {
|
||||
icon: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const SupportIcon: FC<SupportIconProps> = ({ icon, className }) => {
|
||||
switch (icon) {
|
||||
case "bug":
|
||||
return <BugIcon className={className} />;
|
||||
case "chat":
|
||||
return <MessageSquareIcon className={className} />;
|
||||
case "docs":
|
||||
return <BookOpenTextIcon className={className} />;
|
||||
case "star":
|
||||
return <GithubStar className={className} />;
|
||||
default:
|
||||
return <ExternalImage src={icon} className={className} />;
|
||||
}
|
||||
};
|
||||
|
||||
const GithubStar: FC<SvgIconProps> = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
version="1.1"
|
||||
width="16"
|
||||
data-view-component="true"
|
||||
fill="currentColor"
|
||||
{...props}
|
||||
>
|
||||
<path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z" />
|
||||
</svg>
|
||||
);
|
||||
@@ -11,7 +11,7 @@ import { UserDropdownContent } from "./UserDropdownContent";
|
||||
interface UserDropdownProps {
|
||||
user: TypesGen.User;
|
||||
buildInfo?: TypesGen.BuildInfoResponse;
|
||||
supportLinks?: readonly TypesGen.LinkConfig[];
|
||||
supportLinks: readonly TypesGen.LinkConfig[];
|
||||
onSignOut: () => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,11 @@ describe("UserDropdownContent", () => {
|
||||
it("has the correct link for the account item", async () => {
|
||||
render(
|
||||
<Popover>
|
||||
<UserDropdownContent user={MockUserOwner} onSignOut={jest.fn()} />
|
||||
<UserDropdownContent
|
||||
user={MockUserOwner}
|
||||
onSignOut={jest.fn()}
|
||||
supportLinks={[]}
|
||||
/>
|
||||
</Popover>,
|
||||
);
|
||||
await waitForLoaderToBeRemoved();
|
||||
@@ -25,7 +29,11 @@ describe("UserDropdownContent", () => {
|
||||
const onSignOut = jest.fn();
|
||||
render(
|
||||
<Popover>
|
||||
<UserDropdownContent user={MockUserOwner} onSignOut={onSignOut} />
|
||||
<UserDropdownContent
|
||||
user={MockUserOwner}
|
||||
onSignOut={onSignOut}
|
||||
supportLinks={[]}
|
||||
/>
|
||||
</Popover>,
|
||||
);
|
||||
await waitForLoaderToBeRemoved();
|
||||
|
||||
@@ -6,24 +6,20 @@ import {
|
||||
} from "@emotion/react";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import type { SvgIconProps } from "@mui/material/SvgIcon";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import { PopoverClose } from "@radix-ui/react-popover";
|
||||
import type * as TypesGen from "api/typesGenerated";
|
||||
import { CopyButton } from "components/CopyButton/CopyButton";
|
||||
import { ExternalImage } from "components/ExternalImage/ExternalImage";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import {
|
||||
BookOpenTextIcon,
|
||||
BugIcon,
|
||||
CircleUserIcon,
|
||||
LogOutIcon,
|
||||
MessageSquareIcon,
|
||||
MonitorDownIcon,
|
||||
SquareArrowOutUpRightIcon,
|
||||
} from "lucide-react";
|
||||
import type { FC, JSX } from "react";
|
||||
import type { FC } from "react";
|
||||
import { Link } from "react-router";
|
||||
import { SupportIcon } from "../SupportIcon";
|
||||
|
||||
export const Language = {
|
||||
accountLabel: "Account",
|
||||
@@ -34,7 +30,7 @@ export const Language = {
|
||||
interface UserDropdownContentProps {
|
||||
user: TypesGen.User;
|
||||
buildInfo?: TypesGen.BuildInfoResponse;
|
||||
supportLinks?: readonly TypesGen.LinkConfig[];
|
||||
supportLinks: readonly TypesGen.LinkConfig[];
|
||||
onSignOut: () => void;
|
||||
}
|
||||
|
||||
@@ -44,26 +40,6 @@ export const UserDropdownContent: FC<UserDropdownContentProps> = ({
|
||||
supportLinks,
|
||||
onSignOut,
|
||||
}) => {
|
||||
const renderMenuIcon = (icon: string): JSX.Element => {
|
||||
switch (icon) {
|
||||
case "bug":
|
||||
return <BugIcon css={styles.menuItemIcon} />;
|
||||
case "chat":
|
||||
return <MessageSquareIcon css={styles.menuItemIcon} />;
|
||||
case "docs":
|
||||
return <BookOpenTextIcon css={styles.menuItemIcon} />;
|
||||
case "star":
|
||||
return <GithubStar css={styles.menuItemIcon} />;
|
||||
default:
|
||||
return (
|
||||
<ExternalImage
|
||||
src={icon}
|
||||
css={{ maxWidth: "20px", maxHeight: "20px" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Stack css={styles.info} spacing={0}>
|
||||
@@ -76,7 +52,7 @@ export const UserDropdownContent: FC<UserDropdownContentProps> = ({
|
||||
<Link to="/install" css={styles.link}>
|
||||
<PopoverClose asChild>
|
||||
<MenuItem css={styles.menuItem}>
|
||||
<MonitorDownIcon css={styles.menuItemIcon} />
|
||||
<MonitorDownIcon className="size-5 text-content-secondary" />
|
||||
<span css={styles.menuItemText}>Install CLI</span>
|
||||
</MenuItem>
|
||||
</PopoverClose>
|
||||
@@ -85,14 +61,14 @@ export const UserDropdownContent: FC<UserDropdownContentProps> = ({
|
||||
<Link to="/settings/account" css={styles.link}>
|
||||
<PopoverClose asChild>
|
||||
<MenuItem css={styles.menuItem}>
|
||||
<CircleUserIcon css={styles.menuItemIcon} />
|
||||
<CircleUserIcon className="size-5 text-content-secondary" />
|
||||
<span css={styles.menuItemText}>{Language.accountLabel}</span>
|
||||
</MenuItem>
|
||||
</PopoverClose>
|
||||
</Link>
|
||||
|
||||
<MenuItem css={styles.menuItem} onClick={onSignOut}>
|
||||
<LogOutIcon css={styles.menuItemIcon} />
|
||||
<LogOutIcon className="size-5 text-content-secondary" />
|
||||
<span css={styles.menuItemText}>{Language.signOutLabel}</span>
|
||||
</MenuItem>
|
||||
|
||||
@@ -109,7 +85,12 @@ export const UserDropdownContent: FC<UserDropdownContentProps> = ({
|
||||
>
|
||||
<PopoverClose asChild>
|
||||
<MenuItem css={styles.menuItem}>
|
||||
{renderMenuIcon(link.icon)}
|
||||
{link.icon && (
|
||||
<SupportIcon
|
||||
icon={link.icon}
|
||||
className="size-5 text-content-secondary"
|
||||
/>
|
||||
)}
|
||||
<span css={styles.menuItemText}>{link.name}</span>
|
||||
</MenuItem>
|
||||
</PopoverClose>
|
||||
@@ -152,21 +133,6 @@ export const UserDropdownContent: FC<UserDropdownContentProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const GithubStar: FC<SvgIconProps> = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
version="1.1"
|
||||
width="16"
|
||||
data-view-component="true"
|
||||
fill="currentColor"
|
||||
{...props}
|
||||
>
|
||||
<path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
const styles = {
|
||||
info: (theme) => [
|
||||
theme.typography.body2 as CSSObject,
|
||||
@@ -196,11 +162,6 @@ const styles = {
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
`,
|
||||
menuItemIcon: (theme) => ({
|
||||
color: theme.palette.text.secondary,
|
||||
width: 20,
|
||||
height: 20,
|
||||
}),
|
||||
menuItemText: {
|
||||
fontSize: 14,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user