diff --git a/src/components/organisms/EarthEditor/core/CanvasArea/hooks.ts b/src/components/organisms/EarthEditor/core/CanvasArea/hooks.ts index edf0acbd93..68569209fc 100644 --- a/src/components/organisms/EarthEditor/core/CanvasArea/hooks.ts +++ b/src/components/organisms/EarthEditor/core/CanvasArea/hooks.ts @@ -2,8 +2,8 @@ import { useMemo, useEffect, useCallback } from "react"; import { config } from "@reearth/config"; import type { Alignment, Location } from "@reearth/core/Crust"; -import { convertLegacyLayer } from "@reearth/core/mantle"; -import type { Cluster, Layer } from "@reearth/core/Map"; +import { type ComputedLayer, convertLegacyLayer } from "@reearth/core/mantle"; +import type { Cluster, Layer, LayerSelectionReason } from "@reearth/core/Map"; import { useGetLayersQuery, useGetEarthWidgetsQuery, @@ -102,7 +102,14 @@ export default (isBuilt?: boolean) => { // convert data const selectedLayerId = useMemo( - () => (selected?.type === "layer" ? { layerId: selected.layerId } : undefined), + () => + selected?.type === "layer" + ? { layerId: selected.layerId, featureId: selected.featureId } + : undefined, + [selected], + ); + const layerSelectionReason = useMemo( + () => (selected?.type === "layer" ? selected.layerSelectionReason : undefined), [selected], ); @@ -136,7 +143,12 @@ export default (isBuilt?: boolean) => { ); const selectLayer = useCallback( - (id?: string) => select(id ? { layerId: id, type: "layer" } : undefined), + ( + id?: string, + featureId?: string, + _layer?: () => Promise, + layerSelectionReason?: LayerSelectionReason, + ) => select(id ? { layerId: id, featureId, layerSelectionReason, type: "layer" } : undefined), [select], ); @@ -300,6 +312,7 @@ export default (isBuilt?: boolean) => { selectedWidgetArea, widgetAlignEditorActivated, engineMeta, + layerSelectionReason, selectLayer, selectBlock, onBlockChange, diff --git a/src/components/organisms/EarthEditor/core/CanvasArea/index.tsx b/src/components/organisms/EarthEditor/core/CanvasArea/index.tsx index 57a0e20d2f..93c9c061d2 100644 --- a/src/components/organisms/EarthEditor/core/CanvasArea/index.tsx +++ b/src/components/organisms/EarthEditor/core/CanvasArea/index.tsx @@ -31,6 +31,7 @@ const CanvasArea: React.FC = ({ isBuilt, inEditor }) => { selectedWidgetArea, widgetAlignEditorActivated, engineMeta, + layerSelectionReason, selectLayer, selectBlock, onBlockChange, @@ -80,6 +81,7 @@ const CanvasArea: React.FC = ({ isBuilt, inEditor }) => { pluginBaseUrl={config()?.plugins} widgetAlignSystemEditing={widgetAlignEditorActivated} meta={engineMeta} + layerSelectionReason={layerSelectionReason} onLayerSelect={selectLayer} onCameraChange={onCameraChange} onWidgetLayoutUpdate={onWidgetUpdate} diff --git a/src/core/Visualizer/hooks.ts b/src/core/Visualizer/hooks.ts index dd68e63193..a75c538687 100644 --- a/src/core/Visualizer/hooks.ts +++ b/src/core/Visualizer/hooks.ts @@ -3,6 +3,7 @@ import { useWindowSize } from "react-use"; import { type DropOptions, useDrop } from "@reearth/util/use-dnd"; +import type { Block } from "../Crust"; import type { ComputedFeature, Feature } from "../mantle"; import type { Ref as MapRef, @@ -11,6 +12,7 @@ import type { ComputedLayer, SceneProperty, LayerEditEvent, + OverriddenInfobox, } from "../Map"; import { useOverriddenProperty } from "../Map"; @@ -106,6 +108,22 @@ export default function useHooks({ [], ); + // Infobox + const overriddenInfobox = selectedLayer.reason?.overriddenInfobox; + const infobox = useMemo( + () => + selectedLayer + ? { + title: overriddenInfobox?.title || selectedLayer.layer?.layer?.title, + isEditable: !overriddenInfobox && !!selectedLayer.layer?.layer?.infobox, + visible: !!selectedLayer.layer?.layer?.infobox, + property: selectedLayer.layer?.layer.infobox?.property?.default, + blocks: overridenInfoboxBlocks(overriddenInfobox), + } + : undefined, + [selectedLayer, overriddenInfobox], + ); + // scene const [overriddenSceneProperty, overrideSceneProperty] = useOverriddenProperty(sceneProperty); @@ -148,6 +166,7 @@ export default function useHooks({ isMobile, overriddenSceneProperty, isDroppable, + infobox, handleLayerSelect, handleBlockSelect: selectBlock, handleCameraChange: changeCamera, @@ -179,3 +198,25 @@ function useValue( return [state, handleOnChange]; } + +function overridenInfoboxBlocks( + overriddenInfobox: OverriddenInfobox | undefined, +): Block[] | undefined { + return overriddenInfobox && Array.isArray(overriddenInfobox?.content) + ? [ + { + id: "content", + pluginId: "reearth", + extensionId: "dlblock", + property: { + items: overriddenInfobox.content.map((c, i) => ({ + id: i, + item_title: c.key, + item_datastr: String(c.value), + item_datatype: "string", + })), + }, + }, + ] + : undefined; +} diff --git a/src/core/Visualizer/index.tsx b/src/core/Visualizer/index.tsx index 6a14136303..ac4770ab9f 100644 --- a/src/core/Visualizer/index.tsx +++ b/src/core/Visualizer/index.tsx @@ -66,6 +66,7 @@ export type Props = { layerId?: string; featureId?: string; }; + layerSelectionReason?: LayerSelectionReason; selectedWidgetArea?: WidgetAreaType; hiddenLayers?: string[]; zoomedLayerId?: string; @@ -132,6 +133,7 @@ export default function Visualizer({ pluginBaseUrl, pluginProperty, zoomedLayerId, + layerSelectionReason, onLayerDrag, onLayerDrop, onLayerSelect, @@ -160,6 +162,7 @@ export default function Visualizer({ isMobile, overriddenSceneProperty, isDroppable, + infobox, handleLayerSelect, handleBlockSelect, handleCameraChange, @@ -187,11 +190,11 @@ export default function Visualizer({ tags={tags} viewport={viewport} isBuilt={isBuilt} - isEditable={isEditable} + isEditable={isEditable && infobox?.isEditable} inEditor={inEditor} sceneProperty={overriddenSceneProperty} overrideSceneProperty={overrideSceneProperty} - blocks={selectedLayer?.layer?.layer.infobox?.blocks} + blocks={infobox?.blocks} camera={camera} isMobile={isMobile} selectedWidgetArea={selectedWidgetArea} @@ -199,9 +202,9 @@ export default function Visualizer({ selectedFeature={selectedFeature} selectedComputedFeature={selectedComputedFeature} selectedReason={selectedLayer.reason} - infoboxProperty={selectedLayer?.layer?.layer.infobox?.property?.default} - infoboxTitle={selectedLayer?.layer?.layer.title} - infoboxVisible={!!selectedLayer?.layer?.layer.infobox} + infoboxProperty={infobox?.property} + infoboxTitle={infobox?.title} + infoboxVisible={!!infobox?.visible} selectedBlockId={selectedBlock} selectedLayerId={{ layerId: selectedLayer.layerId, featureId: selectedLayer.featureId }} widgetAlignSystem={widgetAlignSystem} @@ -239,6 +242,7 @@ export default function Visualizer({ // overrides={overrides} // not used for now property={overriddenSceneProperty} selectedLayerId={selectedLayerId} + layerSelectionReason={layerSelectionReason} small={small} ready={ready} onCameraChange={handleCameraChange} diff --git a/src/state/index.ts b/src/state/index.ts index 0edeb45e8c..19f4c3c0b1 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -1,6 +1,7 @@ import { atom, useAtom } from "jotai"; import { Clock } from "@reearth/components/molecules/Visualizer/Plugin/types"; +import { LayerSelectionReason } from "@reearth/core/Map"; import { Camera } from "@reearth/util/value"; // useError is needed for Apollo provider error only. Handle other errors with useNotification directly. @@ -36,7 +37,12 @@ export const useSelectedWidgetArea = () => useAtom(selectedWidgetArea); export type Selected = | { type: "scene" } - | { type: "layer"; layerId: string } + | { + type: "layer"; + layerId: string; + featureId?: string; + layerSelectionReason?: LayerSelectionReason; + } | { type: "widgets" } | { type: "cluster"; clusterId: string } | { type: "widget"; widgetId?: string; pluginId: string; extensionId: string }