diff --git a/web/src/beta/features/PluginPlayground/Code/hook.ts b/web/src/beta/features/PluginPlayground/Code/hook.ts index 85b4a8ebde..2d1b400751 100644 --- a/web/src/beta/features/PluginPlayground/Code/hook.ts +++ b/web/src/beta/features/PluginPlayground/Code/hook.ts @@ -2,6 +2,7 @@ import Visualizer from "@reearth/beta/features/Visualizer"; import { useNotification } from "@reearth/services/state"; import * as yaml from "js-yaml"; import { ComponentProps, useCallback, useState } from "react"; +import { v4 } from "uuid"; import { Story } from "../../Visualizer/Crust/StoryPanel/types"; import { WidgetLocation } from "../../Visualizer/Crust/Widgets/types"; @@ -121,7 +122,10 @@ export default ({ files, resetVisualizer }: Props) => { widgets: [ ...(areaAlignSystem.widgets ?? []), { - id: cur.id, + id: v4(), + name: cur.name, + extensionId: cur.id, + pluginId: ymlJson.id, __REEARTH_SOURCECODE: file.sourceCode, extended } diff --git a/web/src/beta/features/PluginPlayground/Plugins/presets/communication/extensionExtensionMessenger.ts b/web/src/beta/features/PluginPlayground/Plugins/presets/communication/extensionExtensionMessenger.ts new file mode 100644 index 0000000000..dae2023530 --- /dev/null +++ b/web/src/beta/features/PluginPlayground/Plugins/presets/communication/extensionExtensionMessenger.ts @@ -0,0 +1,247 @@ +import { FileType, PluginType } from "../../constants"; +import { PRESET_PLUGIN_COMMON_STYLE } from "../common"; + +// YAML File Definition +const yamlFile: FileType = { + id: "extension-to-extension-messenger-reearth-yml", + title: "reearth.yml", + sourceCode: `id: extension-to-extension-messenger-plugin +name: Extension To Extension Messenger +version: 1.0.0 +extensions: + - id: extension-1 + type: widget + name: Extension 1 + description: Extension 1 Widget + - id: extension-2 + type: widget + name: Extension 2 + description: Extension 2 Widget +`, + disableEdit: true, + disableDelete: true +}; + +// Extension 1 Widget Source Code +const extension1SourceCode = ` +reearth.ui.show(\` + ${PRESET_PLUGIN_COMMON_STYLE} + + +
+

Extension 1

+
+ + +
+

Received Messages

+
+
+
+
+ + +\`); + +// Handle messages from UI to send to other extension +reearth.extension.on("message", msg => { + if (msg.type === "send") { + const extensions = reearth.extension.list; + const target = extensions.find(ext => ext.extensionId === "extension-2"); + if (target) { + reearth.extension.postMessage(target.id, msg.message); + } + } +}); + +// Handle messages received from other extension +reearth.extension.on("extensionMessage", msg => { + reearth.ui.postMessage({ + type: "received", + message: msg.data + }); +});`; + +// Extension 2 Widget Source Code +const extension2SourceCode = ` +reearth.ui.show(\` + ${PRESET_PLUGIN_COMMON_STYLE} + + +
+

Extension 2

+
+ + +
+

Received Messages

+
+
+
+
+ + +\`); + +// Note: Re:Earth visualizer requires using msg.data for message content +// and extensionId for finding extensions + +// Handle messages from UI to send to other extension +reearth.extension.on("message", msg => { + if (msg.type === "send") { + const extensions = reearth.extension.list; + const target = extensions.find(ext => ext.extensionId === "extension-1"); + if (target) { + reearth.extension.postMessage(target.id, msg.message); + } + } +}); + +// Handle messages received from other extension +reearth.extension.on("extensionMessage", msg => { + reearth.ui.postMessage({ + type: "received", + message: msg.data + }); +});`; + +// Widget File Definitions +const extension1File: FileType = { + id: "extension-to-extension-messenger-extension1", + title: "extension-1.js", + sourceCode: extension1SourceCode +}; + +const extension2File: FileType = { + id: "extension-to-extension-messenger-extension2", + title: "extension-2.js", + sourceCode: extension2SourceCode +}; + +// Plugin Definition +export const extensionExtensionMessenger: PluginType = { + id: "extension-to-extension-messenger", + title: "Extension To Extension Messenger", + files: [yamlFile, extension1File, extension2File] +}; diff --git a/web/src/beta/features/PluginPlayground/Plugins/presets/ui/uiExtensionMessenger.ts b/web/src/beta/features/PluginPlayground/Plugins/presets/communication/uiExtensionMessenger.ts similarity index 67% rename from web/src/beta/features/PluginPlayground/Plugins/presets/ui/uiExtensionMessenger.ts rename to web/src/beta/features/PluginPlayground/Plugins/presets/communication/uiExtensionMessenger.ts index f732dfec20..160995ca7b 100644 --- a/web/src/beta/features/PluginPlayground/Plugins/presets/ui/uiExtensionMessenger.ts +++ b/web/src/beta/features/PluginPlayground/Plugins/presets/communication/uiExtensionMessenger.ts @@ -52,10 +52,43 @@ const widgetFile: FileType = { button:hover { background: #45a049; } + + #info-section { + margin: 20px 0; + text-align: left; + } + + #info-toggle { + padding: 6px 12px; /* Smaller button */ + background: #4CAF50; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 12px; /* Smaller text */ + } + + #info-content { + background: #f9f9f9; /* Light gray background */ + padding: 10px; + border-radius: 5px; + margin-top: 15px; /* Space between button and content */ + font-size: 14px; + line-height: 1.4; + }

Coordinate Viewer

+
+ + +

Latitude: -°

Longitude: -°

@@ -89,6 +122,14 @@ const widgetFile: FileType = { alt: 1000 // Fixed camera height for better viewing }, "*"); }); + + // Toggle info section + document.getElementById("info-toggle").addEventListener("click", () => { + const infoContent = document.getElementById("info-content"); + const isHidden = infoContent.style.display === "none"; + infoContent.style.display = isHidden ? "block" : "none"; + document.getElementById("info-toggle").textContent = isHidden ? "Hide Info" : "Show Info"; + }); \`); diff --git a/web/src/beta/features/PluginPlayground/Plugins/presets/index.ts b/web/src/beta/features/PluginPlayground/Plugins/presets/index.ts index ed98442282..e525e42eb0 100644 --- a/web/src/beta/features/PluginPlayground/Plugins/presets/index.ts +++ b/web/src/beta/features/PluginPlayground/Plugins/presets/index.ts @@ -1,5 +1,7 @@ import { PluginType } from "../constants"; +import { extensionExtensionMessenger } from "./communication/extensionExtensionMessenger"; +import { uiExtensionMessenger } from "./communication/uiExtensionMessenger"; import { myPlugin } from "./custom/myPlugin"; import { add3dTiles } from "./layers/add-3Dtiles"; import { addCsv } from "./layers/add-csv"; @@ -13,7 +15,6 @@ import { hideFlyToDeleteLayer } from "./layers/hideFlyToDeleteLayer"; import { header } from "./ui/header"; import { responsivePanel } from "./ui/responsivePanel"; import { sidebar } from "./ui/sidebar"; -import { uiExtensionMessenger } from "./ui/uiExtensionMessenger"; type PresetPluginCategory = { id: string; @@ -37,7 +38,7 @@ export const presetPlugins: PresetPlugins = [ { id: "communication", title: "Communication", - plugins: [uiExtensionMessenger] + plugins: [uiExtensionMessenger, extensionExtensionMessenger] }, { id: "viewerScene", diff --git a/web/src/beta/features/Visualizer/Crust/Plugins/Plugin/hooks/usePluginAPI.ts b/web/src/beta/features/Visualizer/Crust/Plugins/Plugin/hooks/usePluginAPI.ts index 12c849a508..b5cc6ec98c 100644 --- a/web/src/beta/features/Visualizer/Crust/Plugins/Plugin/hooks/usePluginAPI.ts +++ b/web/src/beta/features/Visualizer/Crust/Plugins/Plugin/hooks/usePluginAPI.ts @@ -116,6 +116,7 @@ export function usePluginAPI({ uiEvents.current = events(); modalEvents.current = events(); popupEvents.current = events(); + extensionEvents.current = events(); initAndMergeEvents(ctx.viewerEvents, viewerEventsRef, [ "click",