From 9b9d4bcf792bc7bc374ff32fb66b7ce2c2671219 Mon Sep 17 00:00:00 2001 From: Beatrice Mkumbo Date: Tue, 16 Jan 2024 09:46:43 +0300 Subject: [PATCH] chore(web): sketch layer UI implementation (#855) Co-authored-by: KaWaite <34051327+KaWaite@users.noreply.github.com> Co-authored-by: keiya sasaki Co-authored-by: nina992 <89770889+nina992@users.noreply.github.com> Co-authored-by: nina992 Co-authored-by: pyshx --- web/src/beta/components/Modal/index.tsx | 12 +- web/src/beta/components/TabMenu/index.tsx | 44 +++--- .../components/fields/SelectField/index.tsx | 2 +- .../Editor/DataSourceManager/Common/index.tsx | 10 +- .../DataSourceManager/DelimitedText/index.tsx | 8 +- .../DataSourceManager/ThreeDTiles/index.tsx | 8 +- .../DataSourceManager/VectorTiles/index.tsx | 10 +- .../DataSourceManager/WmsTiles/index.tsx | 10 +- .../CustomedProperties/index.tsx | 110 +++++++++++++++ .../SketchLayerManager/General/index.tsx | 50 +++++++ .../Editor/SketchLayerManager/index.tsx | 131 ++++++++++++++++++ .../Editor/SketchLayerManager/types.ts | 8 ++ web/src/beta/features/Editor/hooks.ts | 8 ++ web/src/beta/features/Editor/index.tsx | 13 ++ .../tabs/map/LeftPanel/GroupField/index.tsx | 3 + .../tabs/map/LeftPanel/Layers/LayerItem.tsx | 7 + .../map/LeftPanel/Layers/index.stories.tsx | 1 + .../tabs/map/LeftPanel/Layers/index.tsx | 16 ++- .../Editor/tabs/map/LeftPanel/index.tsx | 3 + web/src/beta/features/Editor/useLeftPanel.tsx | 4 + .../Editor/{DataSourceManager => }/utils.tsx | 84 +++++++++++ web/src/beta/lib/core/mantle/types/index.ts | 1 + web/src/services/i18n/translations/en.yml | 16 ++- web/src/services/i18n/translations/ja.yml | 16 ++- 24 files changed, 522 insertions(+), 53 deletions(-) create mode 100644 web/src/beta/features/Editor/SketchLayerManager/CustomedProperties/index.tsx create mode 100644 web/src/beta/features/Editor/SketchLayerManager/General/index.tsx create mode 100644 web/src/beta/features/Editor/SketchLayerManager/index.tsx create mode 100644 web/src/beta/features/Editor/SketchLayerManager/types.ts rename web/src/beta/features/Editor/{DataSourceManager => }/utils.tsx (62%) diff --git a/web/src/beta/components/Modal/index.tsx b/web/src/beta/components/Modal/index.tsx index be27701c68..a731955700 100644 --- a/web/src/beta/components/Modal/index.tsx +++ b/web/src/beta/components/Modal/index.tsx @@ -22,6 +22,7 @@ type Props = { button2?: ReactNode; children?: ReactNode; isVisible?: boolean; + isContent?: boolean; onClose?: () => void; onTabChange?: (tabId: string) => void; sidebarTabs?: SidebarTab[]; @@ -35,6 +36,7 @@ const Modal: React.FC = ({ button2, children, isVisible, + isContent, onClose, onTabChange, sidebarTabs, @@ -77,7 +79,7 @@ const Modal: React.FC = ({ )} {tabs.length > 0 && {tabs.find(tab => tab.active === true)?.content}} - {children && {children}} + {children && {children}} {button1 || button2 ? ( {tabs.find(tab => tab.active === true)?.tabButton1 ?? button1} @@ -117,9 +119,9 @@ const ContentWrapper = styled.div` flex: 1; `; -const Content = styled.div` +const Content = styled.div<{ isContent?: boolean }>` display: flex; - padding: ${({ theme }) => theme.spacing.super}px; + padding: ${({ isContent, theme }) => (isContent ? theme.spacing.normal : theme.spacing.super)}px; flex-direction: column; gap: ${({ theme }) => theme.spacing.largest}px; align-self: stretch; @@ -130,9 +132,11 @@ const ButtonWrapper = styled.div` flex-direction: row; align-self: stretch; justify-content: flex-end; - border-top: 1px solid ${({ theme }) => theme.bg[3]}; gap: ${({ theme }) => theme.spacing.normal}px; padding: ${({ theme }) => theme.spacing.normal}px; + background: ${({ theme }) => theme.bg[1]}; + border-bottom-right-radius: 8px; + border-bottom-left-radius: 8px; `; export default Modal; diff --git a/web/src/beta/components/TabMenu/index.tsx b/web/src/beta/components/TabMenu/index.tsx index f14be89026..d42ffdd228 100644 --- a/web/src/beta/components/TabMenu/index.tsx +++ b/web/src/beta/components/TabMenu/index.tsx @@ -6,10 +6,12 @@ import { styled } from "@reearth/services/theme"; import Text from "../Text"; +type menuAlignment = "top" | "left"; + export type TabObject = { id: string; name?: string; - icon: keyof typeof Icons; + icon?: keyof typeof Icons; component?: JSX.Element; }; @@ -17,27 +19,29 @@ export type Props = { tabs: TabObject[]; selectedTab: string; onSelectedTabChange: (tab: string) => void; + menuAlignment?: menuAlignment; }; -const TabMenu: FC = ({ tabs, selectedTab, onSelectedTabChange }) => { +const TabMenu: FC = ({ tabs, selectedTab, onSelectedTabChange, menuAlignment }) => { const selectedTabItem = useMemo(() => { return tabs.find(({ id }) => id === selectedTab); }, [selectedTab, tabs]); return ( - - - {tabs.map(({ id, icon }) => ( + + + {tabs.map(({ id, icon, name }) => ( onSelectedTabChange(id)} - selected={id === selectedTab}> - + selected={id === selectedTab} + menuAlignment={menuAlignment}> + {icon ? : {name}} ))} - {selectedTabItem?.name && ( + {selectedTabItem?.name && !menuAlignment && (
{selectedTabItem.name}
@@ -50,20 +54,24 @@ const TabMenu: FC = ({ tabs, selectedTab, onSelectedTabChange }) => { export default TabMenu; -const Wrapper = styled.div` - display: grid; - height: 100%; +const Wrapper = styled.div<{ menuAlignment?: menuAlignment }>` + display: ${({ menuAlignment }) => (menuAlignment === "top" ? "flex" : "grid")}; grid-template-columns: 28px 1fr; + height: 100%; + flex-flow: column nowrap; + position: relative; background: ${({ theme }) => theme.bg[1]}; + border-radius: 4px; `; -const Tabs = styled.div` +const Tabs = styled.div<{ menuAlignment?: menuAlignment }>` padding-top: 4px; - grid-column: 1/2; background: ${({ theme }) => theme.bg[0]}; + display: flex; + flex-flow: ${({ menuAlignment }) => (menuAlignment === "top" ? "row" : "column")} nowrap; `; -const TabIconWrapper = styled.div<{ selected: boolean }>` +const TabIconWrapper = styled.div<{ selected: boolean; menuAlignment?: menuAlignment }>` padding: 4px; display: flex; justify-content: center; @@ -71,6 +79,12 @@ const TabIconWrapper = styled.div<{ selected: boolean }>` cursor: pointer; color: ${({ selected, theme }) => (selected ? theme.content.main : theme.content.weak)}; background: ${props => (props.selected ? props.theme.bg[1] : "inherit")}; + border-top-right-radius: ${({ menuAlignment }) => (menuAlignment === "top" ? "4px" : "0")}; + border-top-left-radius: ${({ menuAlignment }) => (menuAlignment === "top" ? "4px" : "0")}; +`; + +const TabHeader = styled(Text)` + padding: 4px; `; const Header = styled.div` @@ -80,8 +94,6 @@ const Header = styled.div` `; const MainArea = styled.div` - grid-column: 2/-1; display: block; padding: 12px; - background: ${({ theme }) => theme.bg[1]}; `; diff --git a/web/src/beta/components/fields/SelectField/index.tsx b/web/src/beta/components/fields/SelectField/index.tsx index 93c457f67c..9acee3b581 100644 --- a/web/src/beta/components/fields/SelectField/index.tsx +++ b/web/src/beta/components/fields/SelectField/index.tsx @@ -164,7 +164,7 @@ const InputWrapper = styled.div<{ disabled: boolean }>` `; const Select = styled.div<{ open: boolean; selected: boolean }>` - padding: 7px 8px; + padding: 9px 8px; /* The width + placement of the arrow icon */ padding-right: 22px; border-radius: 4px; diff --git a/web/src/beta/features/Editor/DataSourceManager/Common/index.tsx b/web/src/beta/features/Editor/DataSourceManager/Common/index.tsx index 8c273adea1..9594dc808b 100644 --- a/web/src/beta/features/Editor/DataSourceManager/Common/index.tsx +++ b/web/src/beta/features/Editor/DataSourceManager/Common/index.tsx @@ -6,10 +6,6 @@ import URLField from "@reearth/beta/components/fields/URLField"; import RadioGroup from "@reearth/beta/components/RadioGroup"; import Toggle from "@reearth/beta/components/Toggle"; import { AcceptedFileFormat } from "@reearth/beta/features/Assets/types"; -import { DataType } from "@reearth/beta/lib/core/Map"; -import { useT } from "@reearth/services/i18n"; - -import { DataProps, DataSourceOptType, SourceType } from ".."; import { ColJustifyBetween, AssetWrapper, @@ -19,7 +15,11 @@ import { SubmitWrapper, TextArea, generateTitle, -} from "../utils"; +} from "@reearth/beta/features/Editor/utils"; +import { DataType } from "@reearth/beta/lib/core/Map"; +import { useT } from "@reearth/services/i18n"; + +import { DataProps, DataSourceOptType, SourceType } from ".."; const SelectDataType: React.FC<{ fileFormat: AcceptedFileFormat; diff --git a/web/src/beta/features/Editor/DataSourceManager/DelimitedText/index.tsx b/web/src/beta/features/Editor/DataSourceManager/DelimitedText/index.tsx index 96f246c11e..5a389381d9 100644 --- a/web/src/beta/features/Editor/DataSourceManager/DelimitedText/index.tsx +++ b/web/src/beta/features/Editor/DataSourceManager/DelimitedText/index.tsx @@ -4,9 +4,6 @@ import Button from "@reearth/beta/components/Button"; import URLField from "@reearth/beta/components/fields/URLField"; import RadioGroup from "@reearth/beta/components/RadioGroup"; import Text from "@reearth/beta/components/Text"; -import { useT } from "@reearth/services/i18n"; - -import { DataProps, SourceType, DataSourceOptType } from ".."; import { ColJustifyBetween, AssetWrapper, @@ -15,7 +12,10 @@ import { SourceTypeWrapper, SubmitWrapper, generateTitle, -} from "../utils"; +} from "@reearth/beta/features/Editor/utils"; +import { useT } from "@reearth/services/i18n"; + +import { DataProps, SourceType, DataSourceOptType } from ".."; const DelimitedText: React.FC = ({ sceneId, onSubmit, onClose }) => { const t = useT(); diff --git a/web/src/beta/features/Editor/DataSourceManager/ThreeDTiles/index.tsx b/web/src/beta/features/Editor/DataSourceManager/ThreeDTiles/index.tsx index 68afa47044..2aeef05be9 100644 --- a/web/src/beta/features/Editor/DataSourceManager/ThreeDTiles/index.tsx +++ b/web/src/beta/features/Editor/DataSourceManager/ThreeDTiles/index.tsx @@ -1,9 +1,6 @@ import { useState } from "react"; import Button from "@reearth/beta/components/Button"; -import { useT } from "@reearth/services/i18n"; - -import { DataProps } from ".."; import { ColJustifyBetween, AssetWrapper, @@ -11,7 +8,10 @@ import { Input, SubmitWrapper, generateTitle, -} from "../utils"; +} from "@reearth/beta/features/Editor/utils"; +import { useT } from "@reearth/services/i18n"; + +import { DataProps } from ".."; const ThreeDTiles: React.FC = ({ sceneId, onSubmit, onClose }) => { const t = useT(); diff --git a/web/src/beta/features/Editor/DataSourceManager/VectorTiles/index.tsx b/web/src/beta/features/Editor/DataSourceManager/VectorTiles/index.tsx index 4aec1b41ca..5cd10fc3cb 100644 --- a/web/src/beta/features/Editor/DataSourceManager/VectorTiles/index.tsx +++ b/web/src/beta/features/Editor/DataSourceManager/VectorTiles/index.tsx @@ -1,10 +1,6 @@ import { FC } from "react"; import Button from "@reearth/beta/components/Button"; -import { useT } from "@reearth/services/i18n"; - -import { DataProps } from ".."; -import useHooks from "../hooks"; import { AddLayerWrapper, AssetWrapper, @@ -15,7 +11,11 @@ import { LayerWrapper, SubmitWrapper, generateTitle, -} from "../utils"; +} from "@reearth/beta/features/Editor/utils"; +import { useT } from "@reearth/services/i18n"; + +import { DataProps } from ".."; +import useHooks from "../hooks"; const VectorTiles: FC = ({ sceneId, onSubmit, onClose }) => { const { diff --git a/web/src/beta/features/Editor/DataSourceManager/WmsTiles/index.tsx b/web/src/beta/features/Editor/DataSourceManager/WmsTiles/index.tsx index 2b9f4094be..792d40b6a5 100644 --- a/web/src/beta/features/Editor/DataSourceManager/WmsTiles/index.tsx +++ b/web/src/beta/features/Editor/DataSourceManager/WmsTiles/index.tsx @@ -1,10 +1,6 @@ import { FC } from "react"; import Button from "@reearth/beta/components/Button"; -import { useT } from "@reearth/services/i18n"; - -import { DataProps } from ".."; -import useHooks from "../hooks"; import { AddLayerWrapper, AssetWrapper, @@ -15,7 +11,11 @@ import { LayerWrapper, SubmitWrapper, generateTitle, -} from "../utils"; +} from "@reearth/beta/features/Editor/utils"; +import { useT } from "@reearth/services/i18n"; + +import { DataProps } from ".."; +import useHooks from "../hooks"; const WmsTiles: FC = ({ sceneId, onSubmit, onClose }) => { const t = useT(); diff --git a/web/src/beta/features/Editor/SketchLayerManager/CustomedProperties/index.tsx b/web/src/beta/features/Editor/SketchLayerManager/CustomedProperties/index.tsx new file mode 100644 index 0000000000..0ca0a69a1b --- /dev/null +++ b/web/src/beta/features/Editor/SketchLayerManager/CustomedProperties/index.tsx @@ -0,0 +1,110 @@ +import { useCallback, useState } from "react"; + +import Button from "@reearth/beta/components/Button"; +import { + ColJustifyBetween, + AssetWrapper, + InputGroup, + Input, + SubmitWrapper, + InputWrapper, + AddButtonWrapper, + SelectWrapper, + PropertyList, + PropertyListHeader, + StyledText, + DataTypeContent, + PropertyContent, + DataTypeText, + DeleteDataType, + PropertyContentWrapper, +} from "@reearth/beta/features/Editor/utils"; +import { useT } from "@reearth/services/i18n"; + +import { SketchProps, dataTypes } from ".."; + +const CustomedProperties: React.FC = ({ propertyList = [], setPropertyList }) => { + const t = useT(); + const [propertyName, setPropertyName] = useState(""); + const [dataType, setDataType] = useState(""); + + const handleAddToPropertyToList = useCallback(() => { + const newData = { [propertyName]: dataType }; + + setPropertyList?.([...propertyList, newData]); + setPropertyName(""); + setDataType(""); + }, [dataType, propertyName, propertyList, setPropertyList]); + + const handleDeletePropertyToList = useCallback( + (idx: number) => { + const updatedPropertiesList = [...propertyList]; + updatedPropertiesList.splice(idx, 1); + setPropertyList?.(updatedPropertiesList); + }, + [propertyList, setPropertyList], + ); + + return ( + + + + + setPropertyName(e.target.value)} + /> + + ({ key: v, label: v }))} + attachToRoot + onChange={setDataType} + /> + + +