Skip to content

Commit

Permalink
feat(basemap): Add and select basemap (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
mspivak-actionengine authored Apr 3, 2024
1 parent 21ba66e commit 5104f1f
Show file tree
Hide file tree
Showing 45 changed files with 1,341 additions and 675 deletions.
Binary file added public/icons/basemaps/arcgis-dark-gray.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/basemaps/arcgis-light-gray.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/basemaps/arcgis-streets-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/basemaps/arcgis-streets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/basemaps/custom-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/basemaps/maplibre-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/basemaps/maplibre-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/basemaps/terrain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions public/icons/custom-map.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/icons/terrain-map.png
Binary file not shown.
4 changes: 4 additions & 0 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ const THEMES: AppThemes = {
switchCheckedBackground: color_brand_tertiary,
switchCheckedBackgroundHovered: dim_brand_tertinary,
bullet: color_canvas_secondary,
dropdownArrow: hilite_canvas_secondary,
customIconBackground: color_brand_quaternary,
},
name: Theme.Dark,
},
Expand Down Expand Up @@ -132,6 +134,8 @@ const THEMES: AppThemes = {
switchCheckedBackground: color_brand_tertiary,
switchCheckedBackgroundHovered: dim_brand_tertinary,
bullet: hilite_canvas_primary,
dropdownArrow: color_brand_primary,
customIconBackground: dim_canvas_secondary,
},
name: Theme.Light,
},
Expand Down
9 changes: 6 additions & 3 deletions src/components/comparison/comparison-side/comparison-side.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
PageId,
type TilesetMetadata,
type LayoutProps,
BaseMapGroup,
} from "../../../types";
import { DeckGlWrapper } from "../../deck-gl-wrapper/deck-gl-wrapper";
import { MainToolsPanel } from "../../main-tools-panel/main-tools-panel";
Expand Down Expand Up @@ -61,7 +62,7 @@ import { useSelector } from "react-redux";
import { type RootState } from "../../../redux/store";
import { selectFiltersByAttribute } from "../../../redux/slices/symbolization-slice";
import { selectViewState } from "../../../redux/slices/view-state-slice";
import { selectSelectedBaseMapId } from "../../../redux/slices/base-maps-slice";
import { selectSelectedBaseMap } from "../../../redux/slices/base-maps-slice";
import { ArcgisWrapper } from "../../../components/arcgis-wrapper/arcgis-wrapper";

const Container = styled.div<LayoutProps>`
Expand Down Expand Up @@ -138,9 +139,11 @@ export const ComparisonSide = ({
? selectLeftSublayers
: selectRightSublayers
);
const selectedBaseMapId = useAppSelector(selectSelectedBaseMapId);
const selectedBaseMap = useAppSelector(selectSelectedBaseMap);
const MapWrapper =
selectedBaseMapId === "ArcGis" ? ArcgisWrapper : DeckGlWrapper;
selectedBaseMap?.group === BaseMapGroup.ArcGIS
? ArcgisWrapper
: DeckGlWrapper;
const [isCompressedGeometry, setIsCompressedGeometry] =
useState<boolean>(true);
const [isCompressedTextures, setIsCompressedTextures] =
Expand Down
8 changes: 4 additions & 4 deletions src/components/debug-panel/debug-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { addIconItem } from "../../redux/slices/icon-list-slice";
import {
type IIconItem,
IconListSetName,
BaseMapGroup,
ButtonSize,
FileType,
type FileUploaded,
Expand All @@ -18,7 +19,6 @@ import { IconListPanel } from "../icon-list-panel/icon-list-panel";
import { ActionIconButton } from "../action-icon-button/action-icon-button";
import PlusIcon from "../../../public/icons/plus.svg";
import { UploadPanel } from "../upload-panel/upload-panel";

import { useAppLayout } from "../../utils/hooks/layout";
import { CloseButton } from "../close-button/close-button";
import {
Expand All @@ -35,7 +35,7 @@ import {
setDebugOptions,
selectDebugOptions,
} from "../../redux/slices/debug-options-slice";
import { selectSelectedBaseMapId } from "../../redux/slices/base-maps-slice";
import { selectSelectedBaseMap } from "../../redux/slices/base-maps-slice";

export const TEXTURE_ICON_SIZE = 54;

Expand Down Expand Up @@ -95,8 +95,8 @@ export const DebugPanel = ({ onClose }: DebugPanelProps) => {
const dispatch = useAppDispatch();
const [showFileUploadPanel, setShowFileUploadPanel] = useState(false);
const debugOptions = useAppSelector(selectDebugOptions);
const selectedBaseMapId = useAppSelector(selectSelectedBaseMapId);
const minimapDisabled = selectedBaseMapId === "ArcGis";
const selectedBaseMap = useAppSelector(selectSelectedBaseMap);
const minimapDisabled = selectedBaseMap?.group === BaseMapGroup.ArcGIS;
if (minimapDisabled && debugOptions.minimap) {
dispatch(setDebugOptions({ minimap: false }));
}
Expand Down
25 changes: 22 additions & 3 deletions src/components/deck-gl-wrapper/deck-gl-wrapper.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// Get tileset stub before Mocks. The order is important
import { getTileset3d, getTile3d } from "../../test/tile-stub";
import { getTilesetJson } from "../../test/tileset-header-stub";
import { DragMode, TilesetType, TileColoredBy } from "../../types";
import {
DragMode,
TilesetType,
TileColoredBy,
BaseMapGroup,
} from "../../types";

import { act } from "@testing-library/react";
import { DeckGlWrapper } from "./deck-gl-wrapper";
Expand Down Expand Up @@ -357,7 +362,15 @@ describe("Deck.gl I3S map component", () => {

describe("Render TerrainLayer", () => {
const store = setupStore();
store.dispatch(addBaseMap({ id: "Terrain", mapUrl: "", name: "Terrain" }));
store.dispatch(
addBaseMap({
id: "Terrain",
mapUrl: "",
name: "Terrain",
group: BaseMapGroup.Terrain,
iconId: "Dark",
})
);
it("Should render terrain", () => {
callRender(renderWithProvider, undefined, store);
expect(TerrainLayer).toHaveBeenCalled();
Expand All @@ -366,7 +379,13 @@ describe("Deck.gl I3S map component", () => {
it("Should call onTerrainTileLoad", async () => {
const store = setupStore();
store.dispatch(
addBaseMap({ id: "Terrain", mapUrl: "", name: "Terrain" })
addBaseMap({
id: "Terrain",
mapUrl: "",
name: "Terrain",
group: BaseMapGroup.Terrain,
iconId: "Terrain",
})
);
const { rerender } = callRender(renderWithProvider, undefined, store);
const { onTileLoad } = TerrainLayer.mock.lastCall[0];
Expand Down
89 changes: 89 additions & 0 deletions src/components/input-dropdown/input-dropdown.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { fireEvent } from "@testing-library/react";
import { renderWithTheme } from "../../utils/testing-utils/render-with-theme";
import { InputDropdown } from "./input-dropdown";

describe("Input Text", () => {
it("Should render InputText without label", () => {
const onChange = jest.fn();

const dom = renderWithTheme(
<InputDropdown options={["test1", "test2"]} onChange={onChange} />
);
expect(dom).toBeDefined();
if (!dom) {
return;
}
const input: HTMLSelectElement | null =
dom.container.querySelector("select");
const inputLabel: HTMLLabelElement | null =
dom.container.querySelector("label");

expect(input).toBeInTheDocument();
expect(inputLabel).not.toBeInTheDocument();
});

it("Should render InputText with label", () => {
const onChange = jest.fn();

const dom = renderWithTheme(
<InputDropdown
label="Label Text"
options={["test1", "test2"]}
onChange={onChange}
/>
);
expect(dom).toBeDefined();
if (!dom) {
return;
}
const input: HTMLSelectElement | null =
dom.container.querySelector("select");
const inputLabel: HTMLLabelElement | null =
dom.container.querySelector("label");

expect(input).toBeInTheDocument();
expect(input?.value).toBe("test1");
expect(inputLabel).toBeInTheDocument();
expect(inputLabel?.textContent).toEqual("Label Text");
});

it("Should change InputText", () => {
let changedValue = "";
const onChange = jest
.fn()
.mockImplementation((event) => (changedValue = event.target.value));

const dom = renderWithTheme(
<InputDropdown options={["test1", "test2"]} onChange={onChange} />
);
expect(dom).toBeDefined();
if (!dom) {
return;
}
const input: HTMLSelectElement | null =
dom.container.querySelector("select");
if (input) {
fireEvent.change(input, { target: { value: "test2" } });
}

expect(changedValue).toBe("test2");
expect(onChange).toHaveBeenCalledTimes(1);
});

it("Should handle value as prop", () => {
const onChange = jest.fn();

const dom = renderWithTheme(
<InputDropdown options={["test1", "test2"]} onChange={onChange} />
);
expect(dom).toBeDefined();
if (!dom) {
return;
}
const input: HTMLSelectElement | null =
dom.container.querySelector("select");

expect(input?.value).toBe("test1");
expect(onChange).toHaveBeenCalledTimes(0);
});
});
119 changes: 119 additions & 0 deletions src/components/input-dropdown/input-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { type ChangeEvent, type FC, useId } from "react";
import styled, { useTheme } from "styled-components";
import { ExpandIcon } from "../expand-icon/expand-icon";
import { CollapseDirection, ExpandState } from "../../types";

const InputWrapper = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
`;

const SelectDiv = styled.div`
position: relative;
width: 100%;
height: 46px;
border-radius: 8px;
background: ${({ theme }) => theme.colors.mainHiglightColor};
&:hover {
background: ${({ theme }) => theme.colors.mainDimColor};
}
magrin: 0;
`;

const Input = styled.select`
width: 100%;
padding: 13px 30px 13px 16px;
border-radius: 8px;
color: ${({ theme }) => theme.colors.secondaryFontColor};
border: 1px solid ${({ theme }) => theme.colors.mainHiglightColor};
&:hover {
border: 1px solid ${({ theme }) => theme.colors.mainDimColor};
cursor: pointer;
}
&:focus {
color: ${({ theme }) => theme.colors.fontColor};
outline: none;
}
appearance: none;
background: transparent;
magrin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;

const SelectOption = styled.option`
height: 20px;
background: ${({ theme }) => theme.colors.mainHiglightColor};
&:hover {
background-color: ${({ theme }) => theme.colors.mainDimColor};
box-shadow: 0 0 10px 100px green inset;
}
&:checked {
background-color: ${({ theme }) => theme.colors.mainDimColor};
box-shadow: 0 0 10px 100px green inset;
}
box-shadow: 0 0 10px 100px green inset;
`;

const ExpandIconWrapper = styled.div`
position: absolute;
top: 50%;
transform: translate(0, -50%);
right: 12px;
`;

const Label = styled.label`
display: block;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 19px;
margin-bottom: 8px;
color: ${({ theme }) => theme.colors.fontColor};
`;

interface InputDropdownProps {
label?: string;
options: string[];
onChange: (event: ChangeEvent<HTMLSelectElement>) => void;
}

export const InputDropdown: FC<InputDropdownProps> = ({
label,
options,
onChange,
...rest
}) => {
const inputId = useId();
const theme = useTheme();
return (
<InputWrapper>
{label && <Label htmlFor={inputId}>{label}</Label>}
<SelectDiv>
<ExpandIconWrapper>
<ExpandIcon
expandState={ExpandState.expanded}
collapseDirection={CollapseDirection.bottom}
fillExpanded={theme.colors.dropdownArrow}
onClick={() => {}}
/>
</ExpandIconWrapper>
<Input
disabled={options.length <= 1}
id={inputId}
onChange={onChange}
{...rest}
>
{options.map((item) => (
<SelectOption value={item} key={item}>
{item}
</SelectOption>
))}
</Input>
</SelectDiv>
</InputWrapper>
);
};
49 changes: 0 additions & 49 deletions src/components/layers-panel/base-map-icon/base-map-icon.spec.tsx

This file was deleted.

Loading

0 comments on commit 5104f1f

Please sign in to comment.