diff --git a/README.md b/README.md index e1c2a07c..4c323c01 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Sky Strife is broken into several sub-packages. Here are the packages that are e ```sh copy git clone https://github.com/latticexyz/skystrife-public.git - cd skystrife + cd skystrife-public pnpm install cd packages/contracts pnpm build diff --git a/packages/client/src/app/ui/PluginManager/AddPlugin.tsx b/packages/client/src/app/ui/PluginManager/AddPlugin.tsx new file mode 100644 index 00000000..0a9fe3f8 --- /dev/null +++ b/packages/client/src/app/ui/PluginManager/AddPlugin.tsx @@ -0,0 +1,160 @@ +import { useMUD } from "../../../useMUD"; +import { Button } from "../Theme/SkyStrife/Button"; +import { Input } from "../Theme/SkyStrife/Input"; +import { Body } from "../Theme/SkyStrife/Typography"; +import { ChainIcon } from "./ChainIcon"; +import { PLUGIN_DOCS_URL, convertTsPluginToJs } from "./PluginManager"; +import { TerminalIcon } from "./TerminalIcon"; +import { PluginData } from "./types"; +import { useState } from "react"; +import { twMerge } from "tailwind-merge"; + +function ImportPluginForm({ + setPlugin, + setManagerState, +}: { + setPlugin: (pluginKey: string, data: Partial) => void; + setManagerState: (state: "open" | "adding") => void; +}) { + const { + networkLayer: { + utils: { sendAnalyticsEvent }, + }, + } = useMUD(); + + const [newPluginName, setNewPluginName] = useState(""); + const [pluginUrl, setPluginUrl] = useState(""); + const [newPluginError, setNewPluginError] = useState(null); + + return ( +
+ + + + +
+ + + + {newPluginError &&
{newPluginError}
} +
+ ); +} + +export function AddPlugin({ + setPlugin, + setManagerState, +}: { + setPlugin: (pluginKey: string, data: Partial) => void; + setManagerState: (state: "open" | "adding") => void; +}) { + const [addMethod, setAddMethod] = useState<"dev" | "remote">("remote"); + const [chosenAddMethod, setChosenAddMethod] = useState<"dev" | "remote" | null>(null); + + const chooseAddMethodForm = ( + <> +
{ + setAddMethod("remote"); + }} + className={twMerge( + "flex flex-col grow items-center justify-around w-full h-[128px] rounded-md", + "border border-[#DDDAD0] bg-white hover:border-[#1A6CBC] hover:bg-blue-300/30 cursor-pointer", + addMethod === "remote" && "border-[#1A6CBC] bg-blue-300/30" + )} + > +
+
+ + Import a plugin +
+
+ Import a plugin from an external URL. +
+
+ +
{ + setAddMethod("dev"); + }} + className={twMerge( + "flex flex-col grow items-center justify-around w-full h-[128px] rounded-md", + "border border-[#DDDAD0] bg-white hover:border-[#1A6CBC] hover:bg-blue-300/30 cursor-pointer", + addMethod === "dev" && "border-[#1A6CBC] bg-blue-300/30" + )} + > +
+
+ + Create plugins locally +
+
+ Run the Sky Strife plugin dev server on your local machine. +
+
+ +
+ + + + ); + + const addRemoteForm = ; + const addDevForm =
Not implemented
; + const addForm = addMethod === "remote" ? addRemoteForm : addDevForm; + + return
{chosenAddMethod ? addForm : chooseAddMethodForm}
; +} diff --git a/packages/client/src/app/ui/PluginManager/ChainIcon.tsx b/packages/client/src/app/ui/PluginManager/ChainIcon.tsx new file mode 100644 index 00000000..ba76043e --- /dev/null +++ b/packages/client/src/app/ui/PluginManager/ChainIcon.tsx @@ -0,0 +1,13 @@ +export function ChainIcon() { + return ( + + + + ); +} diff --git a/packages/client/src/app/ui/PluginManager/PluginItem.tsx b/packages/client/src/app/ui/PluginManager/PluginItem.tsx index aded0752..b93809ac 100644 --- a/packages/client/src/app/ui/PluginManager/PluginItem.tsx +++ b/packages/client/src/app/ui/PluginManager/PluginItem.tsx @@ -1,3 +1,4 @@ +import { useMUD } from "../../../useMUD"; import { Button } from "../Theme/SkyStrife/Button"; import { OverlineSmall } from "../Theme/SkyStrife/Typography"; import { TrashIcon } from "./TrashIcon"; @@ -16,6 +17,12 @@ export function PluginItem({ deletePlugin: () => void; plugins: Plugins; }) { + const { + networkLayer: { + utils: { sendAnalyticsEvent }, + }, + } = useMUD(); + const { active, code: pluginCode } = pluginData; return ( @@ -38,7 +45,13 @@ export function PluginItem({
{ - confirm(`Are you sure you want to delete plugin: ${pluginKey}?`) && deletePlugin(); + const confirmDelete = confirm(`Are you sure you want to delete plugin: ${pluginKey}?`); + if (confirmDelete) { + deletePlugin(); + sendAnalyticsEvent("plugin-delete", { + ...pluginData, + }); + } }} > @@ -62,6 +75,11 @@ export function PluginItem({ setPlugin(pluginKey, { active: !active, }); + + sendAnalyticsEvent("plugin-toggle", { + ...pluginData, + active: !active, + }); }} > {active ? "Stop" : "Run"} diff --git a/packages/client/src/app/ui/PluginManager/PluginManager.tsx b/packages/client/src/app/ui/PluginManager/PluginManager.tsx index 9ed30b62..4dd4884e 100644 --- a/packages/client/src/app/ui/PluginManager/PluginManager.tsx +++ b/packages/client/src/app/ui/PluginManager/PluginManager.tsx @@ -18,10 +18,13 @@ import uiExampleCode from "plugins/dev/uiExample?raw"; import playerDetailsCode from "plugins/dev/playerDetails?raw"; import { DocsIcon } from "./DocsIcon"; import { CrossIcon } from "../Theme/CrossIcon"; +import { useMUD } from "../../../useMUD"; +import { AddPlugin } from "./AddPlugin"; const PLUGIN_DEV_SERVER_URL = "http://localhost:1993"; +export const PLUGIN_DOCS_URL = "https://github.com/latticexyz/skystrife-public/tree/main/packages/plugins/README.md"; -function convertTsPluginToJs(tsCode: string) { +export function convertTsPluginToJs(tsCode: string) { const jsOutput = transpileModule(tsCode.replace(/import.*?;/g, ""), { compilerOptions: { module: ModuleKind.ES2015, target: ScriptTarget.ES2015 }, }); @@ -34,9 +37,7 @@ export function PluginManager() { }); const [showManager, setShowManager] = useState(false); const [managerState, setManagerState] = useState<"open" | "adding">("open"); - const [newPluginName, setNewPluginName] = useState(""); - const [pluginUrl, setPluginUrl] = useState(""); - const [newPluginError, setNewPluginError] = useState(null); + const [devServerConnected, setDevServerConnected] = useState(false); const [lastRefreshedPlugin, setLastRefreshedPlugin] = useState<{ pluginKey: string; @@ -101,26 +102,30 @@ export function PluginManager() { }, []); useEffect(() => { - const ws = new WebSocket("ws://localhost:1993"); - ws.onopen = function () { - console.log("Plugin Dev Server connected."); - setDevServerConnected(true); - }; - - ws.onmessage = function (e) { - const message = JSON.parse(e.data); - console.log(`File changed: ${message.path}, Event Type: ${message.eventType}`); - if (message.path) refreshPlugin(message.path); - }; - - ws.onerror = function (e) { - console.error("WebSocket Error: ", e); - }; - - ws.onclose = function (e) { - console.log("WebSocket connection closed", e); - setDevServerConnected(false); - }; + try { + const ws = new WebSocket("ws://localhost:1993"); + ws.onopen = function () { + console.log("Plugin Dev Server connected."); + setDevServerConnected(true); + }; + + ws.onmessage = function (e) { + const message = JSON.parse(e.data); + console.log(`File changed: ${message.path}, Event Type: ${message.eventType}`); + if (message.path) refreshPlugin(message.path); + }; + + ws.onerror = function (e) { + console.error("WebSocket Error: ", e); + }; + + ws.onclose = function (e) { + console.log("WebSocket connection closed", e); + setDevServerConnected(false); + }; + } catch (e) { + console.warn("No plugin dev server connected."); + } }, [refreshPlugin]); const pluginList = useMemo(() => { @@ -135,12 +140,12 @@ export function PluginManager() { }} className="text-ss-text-light text-center grow flex flex-col justify-around" > -

+

No plugins found
setManagerState("adding")}> Add your first plugin
-

+
@@ -209,9 +214,6 @@ export function PluginManager() { - - {newPluginError &&
{newPluginError}
} -
- )} + {managerState === "adding" && }
@@ -303,7 +260,7 @@ export function PluginManager() {
- +