diff --git a/src/renderer/components/+catalog/catalog-entity-details.module.css b/src/renderer/components/+catalog/catalog-entity-details.module.css index 27b2c69701..bc66de6566 100644 --- a/src/renderer/components/+catalog/catalog-entity-details.module.css +++ b/src/renderer/components/+catalog/catalog-entity-details.module.css @@ -33,9 +33,8 @@ margin-right: calc(var(--margin) * 3); .avatar { - :global(.MuiAvatar-root) { - font-size: 3ch; - } + font-size: 3ch; + cursor: pointer; } .hint { diff --git a/src/renderer/components/+catalog/catalog-entity-details.tsx b/src/renderer/components/+catalog/catalog-entity-details.tsx index 40bc63fdee..b3c9fc73c2 100644 --- a/src/renderer/components/+catalog/catalog-entity-details.tsx +++ b/src/renderer/components/+catalog/catalog-entity-details.tsx @@ -27,10 +27,10 @@ import type { CatalogCategory, CatalogEntity } from "../../../common/catalog"; import { Icon } from "../icon"; import { CatalogEntityDrawerMenu } from "./catalog-entity-drawer-menu"; import { CatalogEntityDetailRegistry } from "../../../extensions/registries"; -import { HotbarIcon } from "../hotbar/hotbar-icon"; import type { CatalogEntityItem } from "./catalog-entity-item"; import { isDevelopment } from "../../../common/vars"; import { cssNames } from "../../utils"; +import { Avatar } from "../avatar"; interface Props { item: CatalogEntityItem | null | undefined; @@ -60,19 +60,18 @@ export class CatalogEntityDetails extends Component
- item.onRun()} + colorHash={`${item.name}-${item.source}`} size={128} + src={item.entity.spec.icon?.src} data-testid="detail-panel-hot-bar-icon" + background={item.entity.spec.icon?.background} + onClick={() => item.onRun()} className={styles.avatar} - /> + > + {item.entity.spec.icon?.material && } + {item?.enabled && (
Click to open diff --git a/src/renderer/components/+catalog/catalog.module.css b/src/renderer/components/+catalog/catalog.module.css index 2e6c7c7004..5682878219 100644 --- a/src/renderer/components/+catalog/catalog.module.css +++ b/src/renderer/components/+catalog/catalog.module.css @@ -140,3 +140,7 @@ background-color: var(--blue); --color-active: white; } + +.catalogAvatar { + font-size: 1.2ch; +} \ No newline at end of file diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index fff6fd045e..bb39419ed3 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -41,10 +41,10 @@ import { createStorage, prevDefault } from "../../utils"; import { CatalogEntityDetails } from "./catalog-entity-details"; import { browseCatalogTab, catalogURL, CatalogViewRouteParam } from "../../../common/routes"; import { CatalogMenu } from "./catalog-menu"; -import { HotbarIcon } from "../hotbar/hotbar-icon"; import { RenderDelay } from "../render-delay/render-delay"; import { Icon } from "../icon"; import { HotbarToggleMenuItem } from "./hotbar-toggle-menu-item"; +import { Avatar } from "../avatar"; export const previousActiveTab = createStorage("catalog-previous-active-tab", browseCatalogTab); @@ -213,15 +213,16 @@ export class Catalog extends React.Component { return ( <> - + > + {item.entity.spec.icon?.material && } + {item.name} { } @@ -96,11 +96,12 @@ export class EntitySettings extends React.Component { return ( <>
-
{this.entity.metadata.name} diff --git a/src/renderer/components/avatar/__tests__/avatar.test.tsx b/src/renderer/components/avatar/__tests__/avatar.test.tsx new file mode 100644 index 0000000000..9dd25c8b14 --- /dev/null +++ b/src/renderer/components/avatar/__tests__/avatar.test.tsx @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import React from "react"; +import "@testing-library/jest-dom/extend-expect"; +import { render } from "@testing-library/react"; +import { Avatar } from "../avatar"; +import { Icon } from "../../icon"; + +describe("", () => { + test("renders w/o errors", () => { + const { container } = render(); + + expect(container).toBeInstanceOf(HTMLElement); + }); + + test("shows capital letters from title", () => { + const { getByText } = render(); + + expect(getByText("JF")).toBeInTheDocument(); + }); + + test("shows custom icon passed as children", () => { + const { getByTestId } = render(); + + expect(getByTestId("alarm-icon")).toBeInTheDocument(); + }); + + test("shows element if src prop passed", () => { + const { getByAltText } = render(); + + expect(getByAltText("John Ferguson")).toBeInTheDocument(); + }); +}); diff --git a/src/renderer/components/avatar/avatar.module.css b/src/renderer/components/avatar/avatar.module.css new file mode 100644 index 0000000000..1c1b9234ad --- /dev/null +++ b/src/renderer/components/avatar/avatar.module.css @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +.Avatar { + background-color: hsl(0deg, 0%, 45%); + text-transform: uppercase; + color: white; + font-size: 1.6ch; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.circle { + border-radius: 50%; +} + +.rounded { + border-radius: 4px; +} + +.disabled { + opacity: 0.5; + filter: grayscale(0.7); +} \ No newline at end of file diff --git a/src/renderer/components/avatar/avatar.tsx b/src/renderer/components/avatar/avatar.tsx index 3de76af7ab..605652e99a 100644 --- a/src/renderer/components/avatar/avatar.tsx +++ b/src/renderer/components/avatar/avatar.tsx @@ -19,20 +19,22 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React, { DOMAttributes } from "react"; +import styles from "./avatar.module.css"; + +import React, { HTMLAttributes, ImgHTMLAttributes } from "react"; import randomColor from "randomcolor"; import GraphemeSplitter from "grapheme-splitter"; -import { Avatar as MaterialAvatar, AvatarTypeMap } from "@material-ui/core"; -import { iter } from "../../utils"; +import { cssNames, iter } from "../../utils"; -interface Props extends DOMAttributes, Partial { +export interface AvatarProps extends HTMLAttributes { title: string; colorHash?: string; - width?: number; - height?: number; + size?: number; src?: string; - className?: string; background?: string; + variant?: "circle" | "rounded" | "square"; + imgProps?: ImgHTMLAttributes; + disabled?: boolean; } function getNameParts(name: string): string[] { @@ -51,7 +53,7 @@ function getNameParts(name: string): string[] { return name.split(/@+/); } -function getIconString(title: string) { +function getLabelFromTitle(title: string) { if (!title) { return "??"; } @@ -69,37 +71,32 @@ function getIconString(title: string) { ].filter(Boolean).join(""); } -export function Avatar(props: Props) { - const { title, width = 32, height = 32, colorHash, children, background, ...settings } = props; +export function Avatar(props: AvatarProps) { + const { title, variant = "rounded", size = 32, colorHash, children, background, imgProps, src, className, disabled, ...rest } = props; const getBackgroundColor = () => { - if (background) { - return background; - } - - if (settings.src) { - return "transparent"; - } - - return randomColor({ seed: colorHash, luminosity: "dark" }); + return background || randomColor({ seed: colorHash, luminosity: "dark" }); }; - const generateAvatarStyle = (): React.CSSProperties => { - return { - backgroundColor: getBackgroundColor(), - width, - height, - textTransform: "uppercase", - }; + const renderContents = () => { + if (src) { + return {title}/; + } + + return children || getLabelFromTitle(title); }; return ( - - {children || getIconString(title)} - + {renderContents()} +
); } diff --git a/src/renderer/components/avatar/index.ts b/src/renderer/components/avatar/index.ts new file mode 100644 index 0000000000..38d3bff65b --- /dev/null +++ b/src/renderer/components/avatar/index.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +export * from "./avatar"; diff --git a/src/renderer/components/cluster-settings/components/cluster-icon-settings.tsx b/src/renderer/components/cluster-settings/components/cluster-icon-settings.tsx index 980ba88633..4fb37dc1a2 100644 --- a/src/renderer/components/cluster-settings/components/cluster-icon-settings.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-icon-settings.tsx @@ -24,10 +24,10 @@ import type { Cluster } from "../../../../main/cluster"; import { boundMethod } from "../../../utils"; import { observable } from "mobx"; import { observer } from "mobx-react"; -import { HotbarIcon } from "../../hotbar/hotbar-icon"; import type { KubernetesCluster } from "../../../../common/catalog-entities"; import { FilePicker, OverSizeLimitStyle } from "../../file-picker"; import { MenuActions, MenuItem } from "../../menu"; +import { Avatar } from "../../avatar"; enum GeneralInputStatus { CLEAN = "clean", @@ -86,10 +86,9 @@ export class ClusterIconSetting extends React.Component { diff --git a/src/renderer/components/hotbar/hotbar-entity-icon.module.css b/src/renderer/components/hotbar/hotbar-entity-icon.module.css new file mode 100644 index 0000000000..2c34f30fed --- /dev/null +++ b/src/renderer/components/hotbar/hotbar-entity-icon.module.css @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +.led { + position: absolute; + left: 3px; + top: 3px; + background-color: var(--layoutBackground); + border: 1px solid var(--clusterMenuBackground); + border-radius: 50%; + padding: 0px; + width: 8px; + height: 8px; + + &.online { + background-color: var(--primary); + box-shadow: 0 0 5px var(--clusterMenuBackground), 0 0 5px var(--primary); + } +} + +.badge { + position: absolute; + right: -2px; + bottom: -3px; + margin: -8px; + font-size: var(--font-size-small); + background: var(--clusterMenuBackground); + color: var(--textColorAccent); + padding: 0px; + border-radius: 50%; + border: 2px solid var(--clusterMenuBackground); + width: 15px; + height: 15px; + + svg { + width: 13px; + } +} diff --git a/src/renderer/components/hotbar/hotbar-entity-icon.tsx b/src/renderer/components/hotbar/hotbar-entity-icon.tsx index 8ab35ae6ae..e889306c41 100644 --- a/src/renderer/components/hotbar/hotbar-entity-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-entity-icon.tsx @@ -19,7 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React, { DOMAttributes } from "react"; +import styles from "./hotbar-entity-icon.module.css"; + +import React, { HTMLAttributes } from "react"; import { makeObservable, observable } from "mobx"; import { observer } from "mobx-react"; @@ -32,10 +34,9 @@ import { Icon } from "../icon"; import { HotbarIcon } from "./hotbar-icon"; import { LensKubernetesClusterStatus } from "../../../common/catalog-entities/kubernetes-cluster"; -interface Props extends DOMAttributes { +interface Props extends HTMLAttributes { entity: CatalogEntity; index: number; - className?: IClassName; errorClass?: IClassName; add: (item: CatalogEntity, index: number) => void; remove: (uid: string) => void; @@ -55,7 +56,7 @@ export class HotbarEntityIcon extends React.Component { } get kindIcon() { - const className = "badge"; + const className = styles.badge; const category = catalogCategoryRegistry.getCategoryForEntity(this.props.entity); if (!category) { @@ -74,7 +75,7 @@ export class HotbarEntityIcon extends React.Component { return null; } - const className = cssNames("led", { online: this.props.entity.status.phase === LensKubernetesClusterStatus.CONNECTED }); // TODO: make it more generic + const className = cssNames(styles.led, { [styles.online]: this.props.entity.status.phase === LensKubernetesClusterStatus.CONNECTED }); // TODO: make it more generic return
; } @@ -83,34 +84,25 @@ export class HotbarEntityIcon extends React.Component { return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId(); } + async onMenuOpen() { + const menuItems: CatalogEntityContextMenu[] = []; + + menuItems.unshift({ + title: "Remove from Hotbar", + onClick: () => this.props.remove(this.props.entity.metadata.uid), + }); + + this.contextMenu.menuItems = menuItems; + + await this.props.entity.onContextMenuOpen(this.contextMenu); + } + render() { if (!this.contextMenu) { return null; } - const { - entity, errorClass, add, remove, - index, children, ...elemProps - } = this.props; - const className = cssNames("HotbarEntityIcon", this.props.className, { - interactive: true, - active: this.isActive(entity), - disabled: !entity, - }); - - const onOpen = async () => { - const menuItems: CatalogEntityContextMenu[] = []; - - menuItems.unshift({ - title: "Remove from Hotbar", - onClick: () => remove(entity.metadata.uid), - }); - - this.contextMenu.menuItems = menuItems; - - await entity.onContextMenuOpen(this.contextMenu); - }; - const isActive = this.isActive(entity); + const { entity, errorClass, add, remove, index, children, ...elemProps } = this.props; return ( { src={entity.spec.icon?.src} material={entity.spec.icon?.material} background={entity.spec.icon?.background} - className={className} - active={isActive} - onMenuOpen={onOpen} + className={this.props.className} + active={this.isActive(entity)} + onMenuOpen={() => this.onMenuOpen()} + disabled={!entity} menuItems={this.contextMenu.menuItems} tooltip={`${entity.metadata.name} (${entity.metadata.source})`} {...elemProps} diff --git a/src/renderer/components/hotbar/hotbar-icon.module.css b/src/renderer/components/hotbar/hotbar-icon.module.css new file mode 100644 index 0000000000..5bed4d351b --- /dev/null +++ b/src/renderer/components/hotbar/hotbar-icon.module.css @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +.HotbarIcon { + --iconActiveShadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px var(--textColorAccent); + --iconHoverShadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px #ffffff50; + + display: flex; + cursor: pointer; + position: relative; + border-radius: 6px; + transition: box-shadow 0.1s ease-in-out; + + &:not(.active):hover { + box-shadow: var(--iconHoverShadow); + } +} + +.contextMenuAvailable { + cursor: context-menu; +} + +.avatar { + border-radius: 6px; +} + +.active { + box-shadow: var(--iconActiveShadow); +} \ No newline at end of file diff --git a/src/renderer/components/hotbar/hotbar-icon.scss b/src/renderer/components/hotbar/hotbar-icon.scss deleted file mode 100644 index e713b20432..0000000000 --- a/src/renderer/components/hotbar/hotbar-icon.scss +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -.HotbarMenu { - .HotbarIconMenu { - left: 30px; - min-width: 250px; - - li.MenuItem { - font-size: 0.9em; - } - } -} - -.HotbarIcon { - --iconActiveShadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px var(--textColorAccent); - --iconHoverShadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px #ffffff50; - - border-radius: 6px; - user-select: none; - cursor: pointer; - transition: none; - text-shadow: 0 0 4px #0000008f; - position: relative; - z-index: 0; // allows to catch state of :active pseudo-selector - - &:active .MuiAvatar-root { - box-shadow: var(--iconActiveShadow) !important; - } - - div.MuiAvatar-colorDefault { - font-weight:500; - text-transform: uppercase; - border-radius: 6px; - } - - &.disabled { - opacity: 0.4; - cursor: default; - filter: grayscale(0.7); - - &.contextMenuAvailable { - cursor: context-menu; - } - - &:hover { - &:not(.active) { - box-shadow: none; - } - } - } - - &.isDragging { - box-shadow: none; - } - - .MuiAvatar-root { - width: var(--size); - height: var(--size); - border-radius: 6px; - - &.active { - box-shadow: var(--iconActiveShadow); - } - - &.interactive:not(.active):hover { - box-shadow: var(--iconHoverShadow); - } - } - - .led { - position: absolute; - left: 3px; - top: 3px; - background-color: var(--layoutBackground); - border: 1px solid var(--clusterMenuBackground); - border-radius: 50%; - padding: 0px; - width: 8px; - height: 8px; - - &.online { - background-color: var(--primary); - box-shadow: 0 0 5px var(--clusterMenuBackground), 0 0 5px var(--primary); - } - } - - .badge { - position: absolute; - right: -2px; - bottom: -3px; - margin: -8px; - font-size: var(--font-size-small); - background: var(--clusterMenuBackground); - color: var(--textColorAccent); - padding: 0px; - border-radius: 50%; - border: 2px solid var(--clusterMenuBackground); - width: 15px; - height: 15px; - - svg { - width: 13px; - } - } - - .materialIcon { - margin-left: 1px; - margin-top: 1px; - text-shadow: none; - font-size: 180%; - } -} diff --git a/src/renderer/components/hotbar/hotbar-icon.tsx b/src/renderer/components/hotbar/hotbar-icon.tsx index e14b0618b1..0cd746b72f 100644 --- a/src/renderer/components/hotbar/hotbar-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-icon.tsx @@ -19,32 +19,27 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import "./hotbar-icon.scss"; +import styles from "./hotbar-icon.module.css"; -import React, { DOMAttributes, useState } from "react"; +import React, { useState } from "react"; import type { CatalogEntityContextMenu } from "../../../common/catalog"; -import { cssNames, IClassName } from "../../utils"; +import { cssNames } from "../../utils"; import { ConfirmDialog } from "../confirm-dialog"; import { Menu, MenuItem } from "../menu"; import { observer } from "mobx-react"; -import { Avatar } from "../avatar/avatar"; +import { Avatar, AvatarProps } from "../avatar"; import { Icon } from "../icon"; import { Tooltip } from "../tooltip"; -export interface HotbarIconProps extends DOMAttributes { +export interface Props extends AvatarProps { uid: string; - title: string; source: string; - src?: string; material?: string; onMenuOpen?: () => void; - className?: IClassName; active?: boolean; menuItems?: CatalogEntityContextMenu[]; disabled?: boolean; - size?: number; - background?: string; tooltip?: string; } @@ -65,7 +60,7 @@ function onMenuItemClick(menuItem: CatalogEntityContextMenu) { } } -export const HotbarIcon = observer(({ menuItems = [], size = 40, tooltip, ...props }: HotbarIconProps) => { +export const HotbarIcon = observer(({ menuItems = [], size = 40, tooltip, ...props }: Props) => { const { uid, title, src, material, active, className, source, disabled, onMenuOpen, onClick, children, ...rest } = props; const id = `hotbarIcon-${uid}`; const [menuOpen, setMenuOpen] = useState(false); @@ -75,33 +70,25 @@ export const HotbarIcon = observer(({ menuItems = [], size = 40, tooltip, ...pro }; return ( -
0 })}> +
0 })}> {tooltip && {tooltip}} -
{ - if (!disabled) { - onClick?.(event); - } - }} + title={title} + colorHash={`${title}-${source}`} + className={cssNames(styles.avatar, { [styles.active]: active })} + disabled={disabled} + size={size} + src={src} + onClick={(event) => !disabled && onClick?.(event)} > - - {material && } - - {children} -
+ {material && } + + {children} div { animation: click .1s; } } diff --git a/src/renderer/components/layout/setting-layout.scss b/src/renderer/components/layout/setting-layout.scss index 1008ef6259..03472f5579 100644 --- a/src/renderer/components/layout/setting-layout.scss +++ b/src/renderer/components/layout/setting-layout.scss @@ -120,10 +120,6 @@ } } } - - .HotbarIcon { - margin: 0 11px; - } } } diff --git a/src/renderer/components/layout/sidebar-cluster.tsx b/src/renderer/components/layout/sidebar-cluster.tsx index f2015a0063..baa77f168e 100644 --- a/src/renderer/components/layout/sidebar-cluster.tsx +++ b/src/renderer/components/layout/sidebar-cluster.tsx @@ -26,7 +26,7 @@ import { HotbarStore } from "../../../common/hotbar-store"; import { broadcastMessage } from "../../../common/ipc"; import type { CatalogEntity, CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../api/catalog-entity"; import { IpcRendererNavigationEvents } from "../../navigation/events"; -import { Avatar } from "../avatar/avatar"; +import { Avatar } from "../avatar"; import { Icon } from "../icon"; import { navigate } from "../../navigation"; import { Menu, MenuItem } from "../menu"; @@ -108,8 +108,7 @@ export function SidebarCluster({ clusterEntity }: { clusterEntity: CatalogEntity