From 843db6f22395dd16e7e20ddf666acd83f0340cb0 Mon Sep 17 00:00:00 2001 From: mspivak-actionengine Date: Thu, 30 Nov 2023 10:55:55 +0300 Subject: [PATCH 01/10] feat(arcgis): auth UI --- public/icons/download-2.svg | 4 + public/icons/esri.svg | 3 + public/icons/logout.svg | 5 ++ .../layers-panel/layers-control-panel.tsx | 32 +++++++ .../login-button/login-button.spec.tsx | 60 +++++++++++++ src/components/login-button/login-button.tsx | 85 +++++++++++++++++++ .../logout-button/logout-button.spec.tsx | 43 ++++++++++ .../logout-button/logout-button.tsx | 54 ++++++++++++ 8 files changed, 286 insertions(+) create mode 100644 public/icons/download-2.svg create mode 100644 public/icons/esri.svg create mode 100644 public/icons/logout.svg create mode 100644 src/components/login-button/login-button.spec.tsx create mode 100644 src/components/login-button/login-button.tsx create mode 100644 src/components/logout-button/logout-button.spec.tsx create mode 100644 src/components/logout-button/logout-button.tsx diff --git a/public/icons/download-2.svg b/public/icons/download-2.svg new file mode 100644 index 00000000..bdfae70b --- /dev/null +++ b/public/icons/download-2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/icons/esri.svg b/public/icons/esri.svg new file mode 100644 index 00000000..ce387d1d --- /dev/null +++ b/public/icons/esri.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/logout.svg b/public/icons/logout.svg new file mode 100644 index 00000000..b5362ebe --- /dev/null +++ b/public/icons/logout.svg @@ -0,0 +1,5 @@ + + + + diff --git a/src/components/layers-panel/layers-control-panel.tsx b/src/components/layers-panel/layers-control-panel.tsx index 1a7a2759..97b59ac5 100644 --- a/src/components/layers-panel/layers-control-panel.tsx +++ b/src/components/layers-panel/layers-control-panel.tsx @@ -5,11 +5,14 @@ import { SelectionState, LayerExample, LayerViewState, ListItemType } from "../. import { ListItem } from "./list-item/list-item"; import { PlusButton } from "../plus-button/plus-button"; +import { LoginButton } from "../login-button/login-button"; +import { LogoutButton } from "../logout-button/logout-button"; import { DeleteConfirmation } from "./delete-confirmation"; import { LayerOptionsMenu } from "./layer-options-menu/layer-options-menu"; import { handleSelectAllLeafsInGroup } from "../../utils/layer-utils"; import { ButtonSize } from "../../types"; +import { PanelHorizontalLine } from "../common"; type LayersControlPanelProps = { layers: LayerExample[]; @@ -73,6 +76,19 @@ export const LayersControlPanel = ({ const [showLayerSettings, setShowLayerSettings] = useState(false); const [layerToDeleteId, setLayerToDeleteId] = useState(""); + /// Stab { + const username = 'Michael'; + const showLogin = true; + const showLogout = true; + const showImport = true; + + const onArcGisLoginClick = () => { return true; }; + + const onArcGisLogoutClick = () => { return true; }; + + const onArcGisImportClick = () => { return true; }; +/// Stab } + const isListItemSelected = ( layer: LayerExample, parentLayer?: LayerExample @@ -184,6 +200,22 @@ export const LayersControlPanel = ({ Insert scene + + { showLogin && ( + + Login to ArcGIS + + ) } + { showImport && ( + + Import from ArcGIS + + ) } + { showLogout && ( + + {username} + + ) } ); diff --git a/src/components/login-button/login-button.spec.tsx b/src/components/login-button/login-button.spec.tsx new file mode 100644 index 00000000..1aef5918 --- /dev/null +++ b/src/components/login-button/login-button.spec.tsx @@ -0,0 +1,60 @@ +import { screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { ButtonSize } from "../../types"; +import { renderWithTheme } from "../../utils/testing-utils/render-with-theme"; +import { LoginButton } from "./login-button"; + +const onClickMock = jest.fn(); + +const callRender = (renderFunc, props) => { + return renderFunc( + + ); +}; + +describe("Login Button", () => { + it("Should render small Login button", () => { + const { container } = callRender(renderWithTheme, { children: 'Test Button' }); + expect(container).toBeInTheDocument(); + const button = screen.getByText('Test Button'); + const buttonHeight = getComputedStyle(button.previousSibling as Element).getPropertyValue( + "height" + ); + expect(buttonHeight).toEqual('24px'); + userEvent.click(button); + expect(onClickMock).toHaveBeenCalled(); + }); + + it("Should render Big Login button", () => { + const { container } = callRender(renderWithTheme, { children: 'Test Button', buttonSize: ButtonSize.Big }); + expect(container).toBeInTheDocument(); + const button = screen.getByText('Test Button'); + const buttonHeight = getComputedStyle(button.previousSibling as Element).getPropertyValue( + "height" + ); + expect(buttonHeight).toEqual('40px'); + userEvent.click(button); + expect(onClickMock).toHaveBeenCalled(); + }); + + it("Should render 'normal' (not 'grayed') Login button", () => { + callRender(renderWithTheme, { children: 'Test Button' }); + const button = screen.getByText('Test Button'); + const background = getComputedStyle(button.previousSibling as Element).getPropertyValue( + "background" + ); + expect(background).toEqual('rgba(96, 93, 236, 0.4)'); + }); + + it("Should render 'grayed' Login button", () => { + callRender(renderWithTheme, { children: 'Test Button', grayed: true }); + const button = screen.getByText('Test Button'); + const background = getComputedStyle(button.previousSibling as Element).getPropertyValue( + "background" + ); + expect(background).toEqual('rgba(128, 128, 128, 0.6)'); + }); +}); diff --git a/src/components/login-button/login-button.tsx b/src/components/login-button/login-button.tsx new file mode 100644 index 00000000..cbbc0eb1 --- /dev/null +++ b/src/components/login-button/login-button.tsx @@ -0,0 +1,85 @@ +import styled from "styled-components"; +import { color_brand_tertiary } from "../../constants/colors"; +import { ButtonSize } from "../../types"; +import DownloadIcon from "../../../public/icons/download-2.svg"; +import EsriIcon from "../../../public/icons/esri.svg"; + +type LoginButtonProps = { + children?: React.ReactNode; + buttonSize: ButtonSize; + grayed?: boolean; + onClick?: () => void; +}; + +const LoginImage = styled(DownloadIcon)` + display: flex; + position: relative; + left: 5px; + height: ${(props) => (props.buttonSize === ButtonSize.Big ? "30px" : "14px")}; + fill: ${color_brand_tertiary}; +`; + +const EsriImage = styled(EsriIcon)` + display: flex; + position: relative; + left: 5px; + height: 14px; + fill: ${({ theme }) => theme.colors.fontColor}; +`; + +const LoginImageContainer = styled.div<{ buttonSize: number, grayed?: boolean }>` + display: flex; + position: relative; + width: ${(props) => (props.buttonSize === ButtonSize.Big ? "40px" : "24px")}; + height: ${(props) => (props.buttonSize === ButtonSize.Big ? "40px" : "24px")}; + // Keep rgba format to avoid issue with opacity inheritance and pseudo elements. + background: ${(props) => (!props.grayed ? 'rgba(96, 93, 236, 0.4)' : 'rgba(128, 128, 128, 0.6)')}; + border-radius: 4px; + margin-right: 16px; + align-items: center; + `; + +const ButtonText = styled.div<{ grayed?: boolean }>` + display: flex; + position: relative; + color: ${(props) => (!props.grayed ? color_brand_tertiary : 'rgba(128, 128, 128, 0.6)')}; + align-items: center; +`; + +const Button = styled.div<{ grayed?: boolean }>` + display: flex; + cursor: pointer; + justify-content: flex-start; + align-items: center; + margin-bottom: 28px; + + &:hover { + > * { + &:first-child { + // Keep rgba format to avoid issue with opacity inheritance and pseudo elements. + background: ${(props) => (!props.grayed ? 'rgba(96, 93, 236, 0.2)' : 'rgba(128, 128, 128, 0.3)')}; + } + } + } + +`; + +export const LoginButton = ({ + children, + buttonSize, + grayed, + onClick, +}: LoginButtonProps) => { + return ( + + ); +}; + + + diff --git a/src/components/logout-button/logout-button.spec.tsx b/src/components/logout-button/logout-button.spec.tsx new file mode 100644 index 00000000..0817e165 --- /dev/null +++ b/src/components/logout-button/logout-button.spec.tsx @@ -0,0 +1,43 @@ +import { screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { ButtonSize } from "../../types"; +import { renderWithTheme } from "../../utils/testing-utils/render-with-theme"; +import { LogoutButton } from "./logout-button"; + +const onClickMock = jest.fn(); + +const callRender = (renderFunc, props) => { + return renderFunc( + + ); +}; + +describe("Logout Button", () => { + it("Should render small Logout button", () => { + const { container } = callRender(renderWithTheme, { children: 'Test Button' }); + expect(container).toBeInTheDocument(); + const button = screen.getByText('Test Button'); + const buttonHeight = getComputedStyle(button as Element).getPropertyValue( + "margin-left" + ); + expect(buttonHeight).toEqual('41px'); + userEvent.click(button); + expect(onClickMock).toHaveBeenCalled(); + }); + + it("Should render Big Logout button", () => { + const { container } = callRender(renderWithTheme, { children: 'Test Button', buttonSize: ButtonSize.Big }); + expect(container).toBeInTheDocument(); + const button = screen.getByText('Test Button'); + const buttonHeight = getComputedStyle(button as Element).getPropertyValue( + "margin-left" + ); + expect(buttonHeight).toEqual('57px'); + userEvent.click(button); + expect(onClickMock).toHaveBeenCalled(); + }); + +}); diff --git a/src/components/logout-button/logout-button.tsx b/src/components/logout-button/logout-button.tsx new file mode 100644 index 00000000..4ab2b1de --- /dev/null +++ b/src/components/logout-button/logout-button.tsx @@ -0,0 +1,54 @@ +import styled from "styled-components"; +import { ButtonSize } from "../../types"; +import LogoutIcon from "../../../public/icons/logout.svg"; + +type LogoutButtonProps = { + children?: React.ReactNode; + buttonSize: ButtonSize; + onClick?: () => void; +}; + +const LogoutImage = styled(LogoutIcon)` + display: flex; + position: relative; + height: 14px; +`; + +const ButtonText = styled.div<{ buttonSize: number }>` + color: rgba(128, 128, 128, 0.6); + margin-left: ${(props) => (props.buttonSize === ButtonSize.Big ? "57px" : "41px")}; + margin-right: 16px; +`; + +const Button = styled.div` + display: flex; + cursor: pointer; + justify-content: flex-start; + align-items: center; + margin-top: -28px; + + &:hover { + > * { + // Note: it's applied to all children, not just the first one. + // Keep rgba format to avoid issue with opacity inheritance and pseudo elements. + background: rgba(128, 128, 128, 0.3); + } + } + +`; + +export const LogoutButton = ({ + children, + buttonSize, + onClick, +}: LogoutButtonProps) => { + return ( + + ); +}; + + + From d2404c015c23ff4a2cb370ac4aa68d177bed9231 Mon Sep 17 00:00:00 2001 From: mspivak-actionengine Date: Thu, 30 Nov 2023 12:33:49 +0300 Subject: [PATCH 02/10] fix e2e-layers-panel test --- src/utils/testing-utils/e2e-layers-panel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/testing-utils/e2e-layers-panel.tsx b/src/utils/testing-utils/e2e-layers-panel.tsx index 3bece459..78501fb5 100644 --- a/src/utils/testing-utils/e2e-layers-panel.tsx +++ b/src/utils/testing-utils/e2e-layers-panel.tsx @@ -42,7 +42,7 @@ export const checkLayersPanel = async ( ); expect(insertLayerText).toBe("Insert layer"); const insertSceneText = await page.$eval( - `${panelId} > :nth-child(4) > :first-child > :nth-child(2) > :last-child :last-child`, + `${panelId} > :nth-child(4) > :first-child > :nth-child(2) > :nth-child(2) :last-child`, (node) => node.innerText ); expect(insertSceneText).toBe("Insert scene"); From 1b7302a98c6d518837548f6740da4b0f803a390e Mon Sep 17 00:00:00 2001 From: mspivak-actionengine Date: Tue, 5 Dec 2023 12:14:00 +0300 Subject: [PATCH 03/10] feat(arcgis): arcgis auth ui --- public/icons/esri.svg | 3 - public/icons/import.svg | 3 + public/icons/logout.svg | 6 +- public/icons/plus.svg | 4 +- public/images/esri.svg | 3 + src/app.tsx | 25 +++++ .../action-icon-button.spec.tsx} | 17 ++-- .../action-icon-button/action-icon-button.tsx | 92 +++++++++++++++++++ .../layers-control-panel.spec.tsx | 6 +- .../layers-panel/layers-control-panel.tsx | 83 +++++++++++------ .../layers-panel/map-options-panel.spec.tsx | 6 +- .../layers-panel/map-options-panel.tsx | 7 +- .../login-button/login-button.spec.tsx | 60 ------------ src/components/login-button/login-button.tsx | 85 ----------------- .../logout-button/logout-button.spec.tsx | 16 +--- .../logout-button/logout-button.tsx | 21 ++--- src/components/plus-button/plus-button.tsx | 75 --------------- 17 files changed, 210 insertions(+), 302 deletions(-) delete mode 100644 public/icons/esri.svg create mode 100644 public/icons/import.svg create mode 100644 public/images/esri.svg rename src/components/{plus-button/plus-button.spec.tsx => action-icon-button/action-icon-button.spec.tsx} (82%) create mode 100644 src/components/action-icon-button/action-icon-button.tsx delete mode 100644 src/components/login-button/login-button.spec.tsx delete mode 100644 src/components/login-button/login-button.tsx delete mode 100644 src/components/plus-button/plus-button.tsx diff --git a/public/icons/esri.svg b/public/icons/esri.svg deleted file mode 100644 index ce387d1d..00000000 --- a/public/icons/esri.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/public/icons/import.svg b/public/icons/import.svg new file mode 100644 index 00000000..7182f926 --- /dev/null +++ b/public/icons/import.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/logout.svg b/public/icons/logout.svg index b5362ebe..44474a58 100644 --- a/public/icons/logout.svg +++ b/public/icons/logout.svg @@ -1,5 +1,3 @@ - - - + + diff --git a/public/icons/plus.svg b/public/icons/plus.svg index fb3dfa1f..0974354b 100644 --- a/public/icons/plus.svg +++ b/public/icons/plus.svg @@ -1,3 +1,3 @@ - - + + diff --git a/public/images/esri.svg b/public/images/esri.svg new file mode 100644 index 00000000..4fb7b159 --- /dev/null +++ b/public/images/esri.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app.tsx b/src/app.tsx index 9030c74f..870184af 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -19,6 +19,7 @@ import { color_brand_secondary_dark, color_accent_primary, color_accent_tertiary, + color_brand_tertiary, } from "./constants/colors"; import * as Pages from "./pages"; import { AppThemes, ComparisonMode, Theme } from "./types"; @@ -75,6 +76,18 @@ const THEMES: AppThemes = { validateTileOk: color_brand_secondary_dark, validateTileWarning: color_accent_tertiary, filtrationImage: color_brand_quaternary, + + actionIconButtonDisabledColor: color_canvas_primary, + actionIconButtonDisabledBG: `${dim_canvas_primary}FF`, + actionIconButtonDisabledBGHover: `${dim_canvas_primary}99`, + actionIconButtonTextDisabledColor: dim_canvas_primary, + + actionIconButtonActiveColor: color_brand_tertiary, + actionIconButtonActiveBG: `${color_brand_tertiary}66`, + actionIconButtonActiveBGHover: `${color_brand_tertiary}33`, + actionIconButtonTextActiveColor: color_brand_tertiary, + + esriImageColor: color_canvas_secondary_inverted, }, name: Theme.Dark, }, @@ -106,6 +119,18 @@ const THEMES: AppThemes = { validateTileOk: color_brand_secondary, validateTileWarning: color_accent_primary, filtrationImage: color_canvas_secondary, + + actionIconButtonDisabledColor: color_canvas_secondary, + actionIconButtonDisabledBG: `${color_brand_tertiary}66`, + actionIconButtonDisabledBGHover: `${color_brand_tertiary}33`,// TODO: waiting for the design... + actionIconButtonTextDisabledColor: `${color_brand_tertiary}66`, + + actionIconButtonActiveColor: color_brand_tertiary, + actionIconButtonActiveBG: `${color_brand_tertiary}66`, + actionIconButtonActiveBGHover: `${color_brand_tertiary}33`,// TODO: waiting for the design... + actionIconButtonTextActiveColor: color_brand_tertiary, + + esriImageColor: `${color_brand_tertiary}66`, }, name: Theme.Light, }, diff --git a/src/components/plus-button/plus-button.spec.tsx b/src/components/action-icon-button/action-icon-button.spec.tsx similarity index 82% rename from src/components/plus-button/plus-button.spec.tsx rename to src/components/action-icon-button/action-icon-button.spec.tsx index 64c5895c..b79a8086 100644 --- a/src/components/plus-button/plus-button.spec.tsx +++ b/src/components/action-icon-button/action-icon-button.spec.tsx @@ -2,13 +2,16 @@ import { screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { ButtonSize } from "../../types"; import { renderWithTheme } from "../../utils/testing-utils/render-with-theme"; -import { PlusButton } from "./plus-button"; +import PlusIcon from "../../../public/icons/plus.svg"; +import { ActionIconButton } from "../action-icon-button/action-icon-button"; const onClickMock = jest.fn(); const callRender = (renderFunc, props = {}) => { return renderFunc( - @@ -20,10 +23,9 @@ describe("Plus Button", () => { const { container } = callRender(renderWithTheme, { children: 'Test Button' }); expect(container).toBeInTheDocument(); const button = screen.getByText('Test Button'); - const buttonHeight = getComputedStyle(button.previousSibling as Element).getPropertyValue( - "height" - ); + const buttonHeight = getComputedStyle(button.previousSibling as Element).getPropertyValue("height"); expect(buttonHeight).toEqual('24px'); + userEvent.click(button); expect(onClickMock).toHaveBeenCalled(); }); @@ -32,11 +34,10 @@ describe("Plus Button", () => { const { container } = callRender(renderWithTheme, { children: 'Test Button', buttonSize: ButtonSize.Big }); expect(container).toBeInTheDocument(); const button = screen.getByText('Test Button'); - const buttonHeight = getComputedStyle(button.previousSibling as Element).getPropertyValue( - "height" - ); + const buttonHeight = getComputedStyle(button.previousSibling as Element).getPropertyValue("height"); expect(buttonHeight).toEqual('40px'); userEvent.click(button); expect(onClickMock).toHaveBeenCalled(); }); + }); diff --git a/src/components/action-icon-button/action-icon-button.tsx b/src/components/action-icon-button/action-icon-button.tsx new file mode 100644 index 00000000..d1c92b32 --- /dev/null +++ b/src/components/action-icon-button/action-icon-button.tsx @@ -0,0 +1,92 @@ +import React from "react"; +import styled from "styled-components"; +import { ButtonSize } from "../../types"; +import { StyledComponent, DefaultTheme } from "styled-components"; + +type ActionIconButtonProps = { + children?: React.ReactNode; + icon: StyledComponent; + buttonSize: ButtonSize; + style?: "active" | "disabled"; + onClick?: () => void; +}; + +/* + https://developer.mozilla.org/en-US/docs/Web/CSS/opacity + + opacity applies to the element as a whole, including its contents, even though the value is not inherited by child elements. + Thus, the element and its children all have the same opacity relative to the element's background, + even if they have different opacities relative to one another. + + To change the opacity of a background only, use the background property with a color value that allows for an alpha channel. F +*/ + +const Button = styled.div<{ grayed?: boolean }>` + display: flex; + cursor: pointer; + justify-content: flex-start; + align-items: center; + margin-right: 16px; + + &:hover { + > * { + &:first-child { + background: ${({ theme, grayed }) => ( + grayed + ? theme.colors.actionIconButtonDisabledBGHover + : theme.colors.actionIconButtonActiveBGHover + )}; + } + } + } +`; + +const ButtonText = styled.div<{ grayed?: boolean }>` + color: ${({ theme, grayed }) => ( + grayed + ? theme.colors.actionIconButtonTextDisabledColor + : theme.colors.actionIconButtonTextActiveColor + )}; + `; + +const IconContainer = styled.div<{ buttonSize: number, grayed?: boolean }>` + display: flex; + position: relative; + width: ${(props) => (props.buttonSize === ButtonSize.Big ? "40px" : "24px")}; + height: ${(props) => (props.buttonSize === ButtonSize.Big ? "40px" : "24px")}; + + background: ${({ theme, grayed }) => ( + grayed + ? theme.colors.actionIconButtonDisabledBG + : theme.colors.actionIconButtonActiveBG + )}; + + border-radius: 4px; + align-items: center; + justify-content: center; + margin-right: 16px; + `; + +export const ActionIconButton = (props: ActionIconButtonProps) => { + + const grayed = props.style === "disabled"; + const StyledIcon = styled(props.icon) <{ grayed?: boolean }>` + position: absolute; + fill: ${({ theme, grayed }) => ( + grayed + ? theme.colors.actionIconButtonDisabledColor + : theme.colors.actionIconButtonActiveColor + )}; + `; + + return ( + + ); +}; + diff --git a/src/components/layers-panel/layers-control-panel.spec.tsx b/src/components/layers-panel/layers-control-panel.spec.tsx index bcd544cd..8d07588a 100644 --- a/src/components/layers-panel/layers-control-panel.spec.tsx +++ b/src/components/layers-panel/layers-control-panel.spec.tsx @@ -3,18 +3,18 @@ import { renderWithTheme } from "../../utils/testing-utils/render-with-theme"; import { LayersControlPanel } from "./layers-control-panel"; // Mocked components -import { PlusButton } from "../plus-button/plus-button"; +import { ActionIconButton } from "../action-icon-button/action-icon-button"; import { DeleteConfirmation } from "./delete-confirmation"; import { LayerOptionsMenu } from "./layer-options-menu/layer-options-menu"; import { ListItem } from "./list-item/list-item"; jest.mock("./list-item/list-item"); -jest.mock("../plus-button/plus-button"); +jest.mock("../action-icon-button/action-icon-button"); jest.mock("./delete-confirmation"); jest.mock("./layer-options-menu/layer-options-menu"); const ListItemMock = ListItem as unknown as jest.Mocked; -const PlusButtonMock = PlusButton as unknown as jest.Mocked; +const PlusButtonMock = ActionIconButton as unknown as jest.Mocked; const DeleteConfirmationMock = DeleteConfirmation as unknown as jest.Mocked; const LayerOptionsMenuMock = LayerOptionsMenu as unknown as jest.Mocked; diff --git a/src/components/layers-panel/layers-control-panel.tsx b/src/components/layers-panel/layers-control-panel.tsx index 97b59ac5..5945ba8b 100644 --- a/src/components/layers-panel/layers-control-panel.tsx +++ b/src/components/layers-panel/layers-control-panel.tsx @@ -4,8 +4,10 @@ import styled from "styled-components"; import { SelectionState, LayerExample, LayerViewState, ListItemType } from "../../types"; import { ListItem } from "./list-item/list-item"; -import { PlusButton } from "../plus-button/plus-button"; -import { LoginButton } from "../login-button/login-button"; +import PlusIcon from "../../../public/icons/plus.svg"; +import ImportIcon from "../../../public/icons/import.svg"; +import EsriImage from "../../../public/images/esri.svg"; +import { ActionIconButton } from "../action-icon-button/action-icon-button"; import { LogoutButton } from "../logout-button/logout-button"; import { DeleteConfirmation } from "./delete-confirmation"; @@ -27,6 +29,15 @@ type LayersControlPanelProps = { deleteLayer: (id: string) => void; }; +const EsriStyledImage = styled(EsriImage)` + display: flex; + position: relative; + top: 0.37px; + width: 41.9px; + height: 15.65px; + fill: ${({ theme }) => theme.colors.esriImageColor}; +`; + const LayersContainer = styled.div` display: flex; flex-direction: column; @@ -60,6 +71,14 @@ const ChildrenContainer = styled.div` padding-left: 12px; `; +const ActionIconButtonContainer = styled.div<{ bottom?: number }>` + display: flex; + flex-direction: row; + justify-content: start; + align-items: center; + margin-bottom: ${({ bottom = 0 }) => `${bottom}px`}; +`; + export const LayersControlPanel = ({ layers, type, @@ -78,16 +97,14 @@ export const LayersControlPanel = ({ /// Stab { const username = 'Michael'; - const showLogin = true; - const showLogout = true; - const showImport = true; - - const onArcGisLoginClick = () => { return true; }; - - const onArcGisLogoutClick = () => { return true; }; - + const [isLoggedIn, setIsLoggedIn] = useState(false); + const onArcGisLoginClick = () => { setIsLoggedIn(true) }; + const onArcGisLogoutClick = () => { setIsLoggedIn(false) }; const onArcGisImportClick = () => { return true; }; -/// Stab } + const showLogin = !isLoggedIn; + const showLogout = isLoggedIn; + const showImport = isLoggedIn; + /// Stab } const isListItemSelected = ( layer: LayerExample, @@ -194,28 +211,36 @@ export const LayersControlPanel = ({ {renderLayers(layers)} - + Insert layer - - + + Insert scene - + + - { showLogin && ( - - Login to ArcGIS - - ) } - { showImport && ( - - Import from ArcGIS - - ) } - { showLogout && ( - - {username} + + {showLogin && ( + + + Login to ArcGIS + + + + )} + {showImport && ( + + + Import from ArcGIS + + + + )} + {showLogout && ( + + {username} - ) } + )} ); diff --git a/src/components/layers-panel/map-options-panel.spec.tsx b/src/components/layers-panel/map-options-panel.spec.tsx index 6ee488ac..e5f2a171 100644 --- a/src/components/layers-panel/map-options-panel.spec.tsx +++ b/src/components/layers-panel/map-options-panel.spec.tsx @@ -4,7 +4,7 @@ import { renderWithThemeProviders } from "../../utils/testing-utils/render-with- import { MapOptionPanel } from "./map-options-panel"; import { BaseMapListItem } from "./base-map-list-item/base-map-list-item"; -import { PlusButton } from "../plus-button/plus-button"; +import { ActionIconButton } from "../action-icon-button/action-icon-button"; import { DeleteConfirmation } from "./delete-confirmation"; import { BaseMapOptionsMenu } from "./basemap-options-menu/basemap-options-menu"; import { setupStore } from "../../redux/store"; @@ -15,12 +15,12 @@ import { } from "../../redux/slices/base-maps-slice"; jest.mock("./base-map-list-item/base-map-list-item"); -jest.mock("../plus-button/plus-button"); +jest.mock("../action-icon-button/action-icon-button"); jest.mock("./delete-confirmation"); jest.mock("./basemap-options-menu/basemap-options-menu"); const BaseMapListItemMock = BaseMapListItem as unknown as jest.Mocked; -const PlusButtonMock = PlusButton as unknown as jest.Mocked; +const PlusButtonMock = ActionIconButton as unknown as jest.Mocked; const DeleteConfirmationMock = DeleteConfirmation as unknown as jest.Mocked; const BaseMapOptionsMenuMock = diff --git a/src/components/layers-panel/map-options-panel.tsx b/src/components/layers-panel/map-options-panel.tsx index a3ae5ddd..674bd584 100644 --- a/src/components/layers-panel/map-options-panel.tsx +++ b/src/components/layers-panel/map-options-panel.tsx @@ -1,7 +1,8 @@ import { useState, Fragment } from "react"; import styled from "styled-components"; import { BaseMapListItem } from "./base-map-list-item/base-map-list-item"; -import { PlusButton } from "../plus-button/plus-button"; +import PlusIcon from "../../../public/icons/plus.svg"; +import { ActionIconButton } from "../action-icon-button/action-icon-button"; import { DeleteConfirmation } from "./delete-confirmation"; import { SelectionState } from "../../types"; import { BaseMapOptionsMenu } from "./basemap-options-menu/basemap-options-menu"; @@ -120,9 +121,9 @@ export const MapOptionPanel = ({ insertBaseMap }: MapOptionPanelProps) => { })} - + Insert Base Map - + ); diff --git a/src/components/login-button/login-button.spec.tsx b/src/components/login-button/login-button.spec.tsx deleted file mode 100644 index 1aef5918..00000000 --- a/src/components/login-button/login-button.spec.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { ButtonSize } from "../../types"; -import { renderWithTheme } from "../../utils/testing-utils/render-with-theme"; -import { LoginButton } from "./login-button"; - -const onClickMock = jest.fn(); - -const callRender = (renderFunc, props) => { - return renderFunc( - - ); -}; - -describe("Login Button", () => { - it("Should render small Login button", () => { - const { container } = callRender(renderWithTheme, { children: 'Test Button' }); - expect(container).toBeInTheDocument(); - const button = screen.getByText('Test Button'); - const buttonHeight = getComputedStyle(button.previousSibling as Element).getPropertyValue( - "height" - ); - expect(buttonHeight).toEqual('24px'); - userEvent.click(button); - expect(onClickMock).toHaveBeenCalled(); - }); - - it("Should render Big Login button", () => { - const { container } = callRender(renderWithTheme, { children: 'Test Button', buttonSize: ButtonSize.Big }); - expect(container).toBeInTheDocument(); - const button = screen.getByText('Test Button'); - const buttonHeight = getComputedStyle(button.previousSibling as Element).getPropertyValue( - "height" - ); - expect(buttonHeight).toEqual('40px'); - userEvent.click(button); - expect(onClickMock).toHaveBeenCalled(); - }); - - it("Should render 'normal' (not 'grayed') Login button", () => { - callRender(renderWithTheme, { children: 'Test Button' }); - const button = screen.getByText('Test Button'); - const background = getComputedStyle(button.previousSibling as Element).getPropertyValue( - "background" - ); - expect(background).toEqual('rgba(96, 93, 236, 0.4)'); - }); - - it("Should render 'grayed' Login button", () => { - callRender(renderWithTheme, { children: 'Test Button', grayed: true }); - const button = screen.getByText('Test Button'); - const background = getComputedStyle(button.previousSibling as Element).getPropertyValue( - "background" - ); - expect(background).toEqual('rgba(128, 128, 128, 0.6)'); - }); -}); diff --git a/src/components/login-button/login-button.tsx b/src/components/login-button/login-button.tsx deleted file mode 100644 index cbbc0eb1..00000000 --- a/src/components/login-button/login-button.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import styled from "styled-components"; -import { color_brand_tertiary } from "../../constants/colors"; -import { ButtonSize } from "../../types"; -import DownloadIcon from "../../../public/icons/download-2.svg"; -import EsriIcon from "../../../public/icons/esri.svg"; - -type LoginButtonProps = { - children?: React.ReactNode; - buttonSize: ButtonSize; - grayed?: boolean; - onClick?: () => void; -}; - -const LoginImage = styled(DownloadIcon)` - display: flex; - position: relative; - left: 5px; - height: ${(props) => (props.buttonSize === ButtonSize.Big ? "30px" : "14px")}; - fill: ${color_brand_tertiary}; -`; - -const EsriImage = styled(EsriIcon)` - display: flex; - position: relative; - left: 5px; - height: 14px; - fill: ${({ theme }) => theme.colors.fontColor}; -`; - -const LoginImageContainer = styled.div<{ buttonSize: number, grayed?: boolean }>` - display: flex; - position: relative; - width: ${(props) => (props.buttonSize === ButtonSize.Big ? "40px" : "24px")}; - height: ${(props) => (props.buttonSize === ButtonSize.Big ? "40px" : "24px")}; - // Keep rgba format to avoid issue with opacity inheritance and pseudo elements. - background: ${(props) => (!props.grayed ? 'rgba(96, 93, 236, 0.4)' : 'rgba(128, 128, 128, 0.6)')}; - border-radius: 4px; - margin-right: 16px; - align-items: center; - `; - -const ButtonText = styled.div<{ grayed?: boolean }>` - display: flex; - position: relative; - color: ${(props) => (!props.grayed ? color_brand_tertiary : 'rgba(128, 128, 128, 0.6)')}; - align-items: center; -`; - -const Button = styled.div<{ grayed?: boolean }>` - display: flex; - cursor: pointer; - justify-content: flex-start; - align-items: center; - margin-bottom: 28px; - - &:hover { - > * { - &:first-child { - // Keep rgba format to avoid issue with opacity inheritance and pseudo elements. - background: ${(props) => (!props.grayed ? 'rgba(96, 93, 236, 0.2)' : 'rgba(128, 128, 128, 0.3)')}; - } - } - } - -`; - -export const LoginButton = ({ - children, - buttonSize, - grayed, - onClick, -}: LoginButtonProps) => { - return ( - - ); -}; - - - diff --git a/src/components/logout-button/logout-button.spec.tsx b/src/components/logout-button/logout-button.spec.tsx index 0817e165..d29b9ba5 100644 --- a/src/components/logout-button/logout-button.spec.tsx +++ b/src/components/logout-button/logout-button.spec.tsx @@ -1,6 +1,5 @@ import { screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { ButtonSize } from "../../types"; import { renderWithTheme } from "../../utils/testing-utils/render-with-theme"; import { LogoutButton } from "./logout-button"; @@ -9,14 +8,13 @@ const onClickMock = jest.fn(); const callRender = (renderFunc, props) => { return renderFunc( ); }; describe("Logout Button", () => { - it("Should render small Logout button", () => { + it("Should render Logout button", () => { const { container } = callRender(renderWithTheme, { children: 'Test Button' }); expect(container).toBeInTheDocument(); const button = screen.getByText('Test Button'); @@ -28,16 +26,4 @@ describe("Logout Button", () => { expect(onClickMock).toHaveBeenCalled(); }); - it("Should render Big Logout button", () => { - const { container } = callRender(renderWithTheme, { children: 'Test Button', buttonSize: ButtonSize.Big }); - expect(container).toBeInTheDocument(); - const button = screen.getByText('Test Button'); - const buttonHeight = getComputedStyle(button as Element).getPropertyValue( - "margin-left" - ); - expect(buttonHeight).toEqual('57px'); - userEvent.click(button); - expect(onClickMock).toHaveBeenCalled(); - }); - }); diff --git a/src/components/logout-button/logout-button.tsx b/src/components/logout-button/logout-button.tsx index 4ab2b1de..a79bf684 100644 --- a/src/components/logout-button/logout-button.tsx +++ b/src/components/logout-button/logout-button.tsx @@ -1,10 +1,8 @@ import styled from "styled-components"; -import { ButtonSize } from "../../types"; import LogoutIcon from "../../../public/icons/logout.svg"; type LogoutButtonProps = { children?: React.ReactNode; - buttonSize: ButtonSize; onClick?: () => void; }; @@ -14,9 +12,11 @@ const LogoutImage = styled(LogoutIcon)` height: 14px; `; -const ButtonText = styled.div<{ buttonSize: number }>` - color: rgba(128, 128, 128, 0.6); - margin-left: ${(props) => (props.buttonSize === ButtonSize.Big ? "57px" : "41px")}; +const ButtonText = styled.div` + color: ${({ theme }) => ( + theme.colors.actionIconButtonTextDisabledColor + )}; + margin-left: 41px; margin-right: 16px; `; @@ -25,26 +25,23 @@ const Button = styled.div` cursor: pointer; justify-content: flex-start; align-items: center; - margin-top: -28px; &:hover { > * { - // Note: it's applied to all children, not just the first one. - // Keep rgba format to avoid issue with opacity inheritance and pseudo elements. - background: rgba(128, 128, 128, 0.3); + background: ${({ theme }) => ( + theme.colors.actionIconButtonDisabledBGHover + )}; } } - `; export const LogoutButton = ({ children, - buttonSize, onClick, }: LogoutButtonProps) => { return ( ); diff --git a/src/components/plus-button/plus-button.tsx b/src/components/plus-button/plus-button.tsx deleted file mode 100644 index 5343e69f..00000000 --- a/src/components/plus-button/plus-button.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import styled from "styled-components"; -import { color_brand_tertiary } from "../../constants/colors"; -import { ButtonSize } from "../../types"; - -type PlusButtonProps = { - children?: React.ReactNode; - buttonSize: ButtonSize; - onClick?: () => void; -}; - -const Button = styled.div` - display: flex; - cursor: pointer; - justify-content: flex-start; - align-items: center; - - &:hover { - > * { - &:first-child { - // Keep rgba format to avoid issue with opacity inheritance and pseudo elements. - background: rgba(96, 93, 236, 0.2); - } - } - } -`; - -const PlusIcon = styled.div<{ buttonSize: number }>` - position: relative; - width: ${(props) => (props.buttonSize === ButtonSize.Big ? "40px" : "24px")}; - height: ${(props) => (props.buttonSize === ButtonSize.Big ? "40px" : "24px")}; - // Keep rgba format to avoid issue with opacity inheritance and pseudo elements. - background: rgba(96, 93, 236, 0.4); - cursor: pointer; - border-radius: 4px; - margin-right: 16px; - - &:after { - content: ""; - position: absolute; - transform: translate(-50%, -50%); - height: 2px; - width: 50%; - background: ${color_brand_tertiary}; - top: 50%; - left: 50%; - } - - &:before { - content: ""; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background: ${color_brand_tertiary}; - height: 50%; - width: 2px; - } -`; - -const ButtonText = styled.div` - color: ${color_brand_tertiary}; -`; - -export const PlusButton = ({ - children, - buttonSize, - onClick, -}: PlusButtonProps) => { - return ( - - ); -}; From a4efef707ac7a511a5e405364f324a0cc12937d5 Mon Sep 17 00:00:00 2001 From: mspivak-actionengine Date: Tue, 5 Dec 2023 12:20:37 +0300 Subject: [PATCH 04/10] prettier --- src/components/action-icon-button/action-icon-button.tsx | 2 +- src/components/logout-button/logout-button.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/action-icon-button/action-icon-button.tsx b/src/components/action-icon-button/action-icon-button.tsx index d1c92b32..a211e2c3 100644 --- a/src/components/action-icon-button/action-icon-button.tsx +++ b/src/components/action-icon-button/action-icon-button.tsx @@ -82,7 +82,7 @@ export const ActionIconButton = (props: ActionIconButtonProps) => { return (