From e598cf893116f4356ea838097e0303afc546b2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20Gran=C3=A1t?= Date: Mon, 10 Jun 2024 10:56:10 +0200 Subject: [PATCH] feat: figma plugin bugs (#42) * feat: improve highlighting and pulling * fix: keys with namespaces bug * feat: preserve scrolling state * chore: fix e2e tests * feat: remove unnecessary package * fix: improve window size management * fix: improve window size management * fix: improve window size management --- cypress/e2e/pull.cy.ts | 6 +- src/main/endpoints/highlightNode.ts | 29 ++++- src/main/main.ts | 30 +++-- src/ui/components/Dialog/Dialog.css | 9 ++ src/ui/components/Dialog/Dialog.css.d.ts | 5 + src/ui/components/Dialog/Dialog.tsx | 29 +++++ .../FullPageLoading/FullPageLoading.tsx | 11 +- .../NamespaceSelect/NamespaceSelect.tsx | 6 +- src/ui/components/NodeList/NodeList.tsx | 31 +++-- src/ui/hooks/useSelectedNodes.ts | 3 +- src/ui/hooks/useWindowSize.ts | 36 ++++-- src/ui/state/GlobalState.ts | 15 ++- src/ui/state/sizes.ts | 2 + src/ui/views/CopyView/CopyView.tsx | 9 -- src/ui/views/Index/Index.tsx | 117 +++--------------- src/ui/views/Index/KeyInput.tsx | 18 +-- src/ui/views/Index/ListItem.tsx | 114 +++++++++++++++++ src/ui/views/PageSetup/PageSetup.tsx | 7 +- src/ui/views/Pull/Pull.tsx | 11 ++ src/ui/views/Router.tsx | 35 +++++- src/ui/views/Settings/ProjectSettings.tsx | 2 +- src/ui/views/Settings/Settings.tsx | 2 +- src/web/main.ts | 5 - 23 files changed, 351 insertions(+), 181 deletions(-) create mode 100644 src/ui/components/Dialog/Dialog.css create mode 100644 src/ui/components/Dialog/Dialog.css.d.ts create mode 100644 src/ui/components/Dialog/Dialog.tsx create mode 100644 src/ui/state/sizes.ts create mode 100644 src/ui/views/Index/ListItem.tsx diff --git a/cypress/e2e/pull.cy.ts b/cypress/e2e/pull.cy.ts index a177bb5..8150aa2 100644 --- a/cypress/e2e/pull.cy.ts +++ b/cypress/e2e/pull.cy.ts @@ -51,7 +51,11 @@ describe("Pull", () => { .contains("This action will replace translations in 1") .should("be.visible"); cy.iframe().contains("Missing keys").should("be.visible"); - cy.iframe().contains("nonexistant-key").should("be.visible"); + + cy.iframe() + .findDcy("dialog") + .contains("nonexistant-key") + .should("be.visible"); cy.iframe().findDcy("pull_submit_button").should("be.visible").click(); diff --git a/src/main/endpoints/highlightNode.ts b/src/main/endpoints/highlightNode.ts index 111af21..0610e9e 100644 --- a/src/main/endpoints/highlightNode.ts +++ b/src/main/endpoints/highlightNode.ts @@ -4,13 +4,40 @@ export type HighlightNodeProps = { id: string; }; +const highlitedNodes: Map = new Map(); + export const highlightNodeEndpoint = createEndpoint( "HIGHLIGHT_NODE", async ({ id }: HighlightNodeProps) => { - const node = figma.getNodeById(id); + const node = figma.getNodeById(id) as TextNode | null; if (node) { figma.viewport.scrollAndZoomIntoView([node]); } + + if (node && !highlitedNodes.has(id)) { + const paint: SolidPaint = { + type: "SOLID", + color: { r: 1, g: 0, b: 0 }, + }; + highlitedNodes.set(id, node.fills); + const original = node.fills; + node.fills = [paint]; + + setTimeout(() => { + node.fills = original; + highlitedNodes.delete(id); + }, 500); + } } ); + +export const cleanUp = () => { + highlitedNodes.forEach((value, id) => { + const node = figma.getNodeById(id) as TextNode | null; + if (node) { + node.fills = value; + highlitedNodes.delete(id); + } + }); +}; diff --git a/src/main/main.ts b/src/main/main.ts index 13a20b6..a5ed166 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -24,8 +24,8 @@ import { getPluginData, setPluginData, } from "./utils/settingsTools"; -import { DEFAULT_SIZE } from "@/ui/hooks/useWindowSize"; -import { highlightNodeEndpoint } from "./endpoints/highlightNode"; +import { cleanUp, highlightNodeEndpoint } from "./endpoints/highlightNode"; +import { DEFAULT_SIZE } from "@/ui/state/sizes"; const getAllPages = () => { const document = figma.root; @@ -33,22 +33,30 @@ const getAllPages = () => { return document.children.filter((node) => node.type === "PAGE"); }; +const isOnlyProperty = (e: NodeChangeEvent, property: string) => { + return e.nodeChanges.every((ch) => { + return ( + ch.type === "PROPERTY_CHANGE" && + ch.properties.every((p) => p === property) + ); + }); +}; + export default async function () { figma.on("selectionchange", () => { emit("SELECTION_CHANGE"); }); figma.currentPage.on("nodechange", (e) => { - if ( - !e.nodeChanges.every((ch) => { - return ( - ch.type === "PROPERTY_CHANGE" && - ch.properties.every((p) => p === "pluginData") - ); - }) - ) { - emit("DOCUMENT_CHANGE"); + if (isOnlyProperty(e, "pluginData") || isOnlyProperty(e, "fills")) { + return; } + + emit("DOCUMENT_CHANGE"); + }); + + figma.on("close", () => { + cleanUp(); }); figma.on("currentpagechange", async () => { diff --git a/src/ui/components/Dialog/Dialog.css b/src/ui/components/Dialog/Dialog.css new file mode 100644 index 0000000..d3829c2 --- /dev/null +++ b/src/ui/components/Dialog/Dialog.css @@ -0,0 +1,9 @@ +.dialogBody { + z-index: 1300; + position: fixed; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + background: var(--figma-color-bg); +} diff --git a/src/ui/components/Dialog/Dialog.css.d.ts b/src/ui/components/Dialog/Dialog.css.d.ts new file mode 100644 index 0000000..686ea00 --- /dev/null +++ b/src/ui/components/Dialog/Dialog.css.d.ts @@ -0,0 +1,5 @@ +declare const styles: { + readonly "dialogBody": string; +}; +export = styles; + diff --git a/src/ui/components/Dialog/Dialog.tsx b/src/ui/components/Dialog/Dialog.tsx new file mode 100644 index 0000000..d2514fd --- /dev/null +++ b/src/ui/components/Dialog/Dialog.tsx @@ -0,0 +1,29 @@ +import { ComponentChildren, h } from "preact"; +import { useEffect, useRef } from "preact/hooks"; +import styles from "./Dialog.css"; +import { useWindowSize } from "@/ui/hooks/useWindowSize"; +import { DEFAULT_SIZE } from "@/ui/state/sizes"; + +type Props = { + onClose: () => void; + children: ComponentChildren; +}; + +export const Dialog = ({ children, onClose }: Props) => { + const ref = useRef(null); + + useWindowSize(DEFAULT_SIZE); + + useEffect(() => { + const handler = () => onClose(); + ref.current?.focus(); + ref.current?.addEventListener("keydown", handler); + return () => ref.current?.removeEventListener("keydown", handler); + }, []); + + return ( +
+
{children}
+
+ ); +}; diff --git a/src/ui/components/FullPageLoading/FullPageLoading.tsx b/src/ui/components/FullPageLoading/FullPageLoading.tsx index a80139c..63c59a2 100644 --- a/src/ui/components/FullPageLoading/FullPageLoading.tsx +++ b/src/ui/components/FullPageLoading/FullPageLoading.tsx @@ -5,11 +5,18 @@ import styles from "./FullPageLoading.css"; type Props = { text?: string; + blocking?: boolean; }; -export const FullPageLoading: FunctionalComponent = ({ text }) => { +export const FullPageLoading: FunctionalComponent = ({ + text, + blocking = true, +}) => { return ( -
+
diff --git a/src/ui/components/NamespaceSelect/NamespaceSelect.tsx b/src/ui/components/NamespaceSelect/NamespaceSelect.tsx index 6cba360..8b4c6db 100644 --- a/src/ui/components/NamespaceSelect/NamespaceSelect.tsx +++ b/src/ui/components/NamespaceSelect/NamespaceSelect.tsx @@ -12,7 +12,7 @@ import styles from "./NamespaceSelect.css"; type Props = { namespaces: string[]; - initialValue: string; + value: string; onChange: (value: string) => void; selectProps?: h.JSX.HTMLAttributes; }; @@ -20,21 +20,19 @@ type Props = { const ADD_NEW_VALUE = Number.MAX_VALUE; export const NamespaceSelect: FunctionComponent = ({ - initialValue, + value, namespaces, selectProps, onChange, }) => { const [modalOpen, setModalOpen] = useState(false); const [nsName, setNsName] = useState(""); - const [value, _setValue] = useState(initialValue); const handleModalClose = () => { setModalOpen(false); }; function setValue(value: string) { - _setValue(value); onChange(value); } diff --git a/src/ui/components/NodeList/NodeList.tsx b/src/ui/components/NodeList/NodeList.tsx index 0dd4cfc..9cd806c 100644 --- a/src/ui/components/NodeList/NodeList.tsx +++ b/src/ui/components/NodeList/NodeList.tsx @@ -1,4 +1,4 @@ -import { ComponentChildren, h } from "preact"; +import { ComponentChildren, Fragment, h } from "preact"; import styles from "./NodeList.css"; import { NodeRow } from "./NodeRow"; @@ -11,7 +11,7 @@ type Props = { nsComponent?: (item: T) => ComponentChildren; compact?: boolean; onClick?: (item: T) => void; - onBottomReached?: () => void; + row?: (node: T) => ComponentChildren; }; export function NodeList({ @@ -21,22 +21,27 @@ export function NodeList({ nsComponent, compact, onClick, + row, }: Props) { const containerRef = useRef(null); return (
- {items?.map((item) => ( - onClick?.(item) : undefined} - /> - ))} + {items?.map((item) => + row ? ( + {row(item)} + ) : ( + onClick?.(item) : undefined} + /> + ) + )}
); } diff --git a/src/ui/hooks/useSelectedNodes.ts b/src/ui/hooks/useSelectedNodes.ts index 0838f92..5bb4844 100644 --- a/src/ui/hooks/useSelectedNodes.ts +++ b/src/ui/hooks/useSelectedNodes.ts @@ -8,7 +8,8 @@ import { useQuery } from "react-query"; export const useSelectedNodes = () => { const result = useQuery( [getSelectedNodesEndpoint.name], - delayed(() => getSelectedNodesEndpoint.call()) + delayed(() => getSelectedNodesEndpoint.call()), + { keepPreviousData: true } ); useEffect(() => { diff --git a/src/ui/hooks/useWindowSize.ts b/src/ui/hooks/useWindowSize.ts index cfb6669..f28dc86 100644 --- a/src/ui/hooks/useWindowSize.ts +++ b/src/ui/hooks/useWindowSize.ts @@ -1,18 +1,36 @@ -import { emit } from "@/utilities"; -import { useEffect } from "preact/hooks"; +import { useEffect, useRef } from "preact/hooks"; -import { ResizeHandler } from "@/types"; -export const DEFAULT_SIZE = { width: 500, height: 400 }; -export const COMPACT_SIZE = { width: 500, height: 160 }; +import { useGlobalActions, useGlobalState } from "../state/GlobalState"; type WindowSize = { width: number; height: number; }; -export const useWindowSize = (size: WindowSize) => { +export const useWindowSize = (newSize: WindowSize) => { + const lastSize = useRef(); + const { setSizeStack } = useGlobalActions(); + const sizeStack = useGlobalState((c) => c.sizeStack); useEffect(() => { - emit("RESIZE", size); - return () => emit("RESIZE", DEFAULT_SIZE); - }, [size]); + const addedSize = { ...newSize }; + if (sizeStack.includes(lastSize.current!)) { + setSizeStack((stack) => + stack.map((i) => { + if (i === lastSize.current) { + return addedSize; + } + return i; + }) + ); + } else { + setSizeStack((stack) => [...stack, addedSize]); + } + lastSize.current = addedSize; + }, [newSize.width, newSize.height]); + + useEffect(() => { + return () => { + setSizeStack((stack) => stack.filter((i) => i !== lastSize.current)); + }; + }, []); }; diff --git a/src/ui/state/GlobalState.ts b/src/ui/state/GlobalState.ts index 37631ba..f633094 100644 --- a/src/ui/state/GlobalState.ts +++ b/src/ui/state/GlobalState.ts @@ -5,12 +5,15 @@ import { ConfigChangeHandler, NodeInfo, ResetHandler, + ResizeHandler, SetLanguageHandler, SetupHandle, TolgeeConfig, + WindowSize, } from "@/types"; -import { Route } from "../views/routes"; +import type { Route } from "../views/routes"; import { createProvider } from "@/tools/createProvider"; +import { DEFAULT_SIZE } from "./sizes"; type Props = { initialConfig: Partial | null; @@ -28,6 +31,13 @@ export const [GlobalState, useGlobalActions, useGlobalState] = createProvider( const [globalError, setGlobalError] = useState( undefined ); + const [sizeStack, setSizeStack] = useState([]); + + useEffect(() => { + const size = sizeStack[sizeStack.length - 1] ?? DEFAULT_SIZE; + emit("RESIZE", size); + return () => emit("RESIZE", DEFAULT_SIZE); + }, [sizeStack]); const [editedKeys, setEditedKeys] = useState>({}); @@ -44,6 +54,7 @@ export const [GlobalState, useGlobalActions, useGlobalState] = createProvider( config, globalError, editedKeys, + sizeStack, }; const actions = { @@ -65,6 +76,7 @@ export const [GlobalState, useGlobalActions, useGlobalState] = createProvider( resetConfig() { emit("RESET"); }, + setSizeStack, setGlobalError, }; @@ -73,3 +85,4 @@ export const [GlobalState, useGlobalActions, useGlobalState] = createProvider( return [data, actions]; } ); +export { DEFAULT_SIZE }; diff --git a/src/ui/state/sizes.ts b/src/ui/state/sizes.ts new file mode 100644 index 0000000..9be4361 --- /dev/null +++ b/src/ui/state/sizes.ts @@ -0,0 +1,2 @@ +export const DEFAULT_SIZE = { width: 500, height: 400 }; +export const COMPACT_SIZE = { width: 500, height: 160 }; diff --git a/src/ui/views/CopyView/CopyView.tsx b/src/ui/views/CopyView/CopyView.tsx index 4d7ce67..ae93776 100644 --- a/src/ui/views/CopyView/CopyView.tsx +++ b/src/ui/views/CopyView/CopyView.tsx @@ -10,11 +10,6 @@ import { import { useGlobalState } from "@/ui/state/GlobalState"; import { useApiMutation } from "@/ui/client/useQueryApi"; import { FullPageLoading } from "@/ui/components/FullPageLoading/FullPageLoading"; -import { - COMPACT_SIZE, - DEFAULT_SIZE, - useWindowSize, -} from "@/ui/hooks/useWindowSize"; import { NodeList } from "../../components/NodeList/NodeList"; import { TopBar } from "../../components/TopBar/TopBar"; @@ -63,10 +58,6 @@ export const CopyView = () => { await updateNodesLoadalbe.mutateAsync({ nodes: changedNodes }); }; - useWindowSize( - !selection || selection.length < 2 ? COMPACT_SIZE : DEFAULT_SIZE - ); - if ( translationsLoadable.isLoading || connectedNodesLoadable.isLoading || diff --git a/src/ui/views/Index/Index.tsx b/src/ui/views/Index/Index.tsx index a53ff29..590ff5d 100644 --- a/src/ui/views/Index/Index.tsx +++ b/src/ui/views/Index/Index.tsx @@ -1,5 +1,5 @@ import { Fragment, h } from "preact"; -import { useEffect, useMemo, useState } from "preact/hooks"; +import { useEffect, useState } from "preact/hooks"; import { Banner, Button, @@ -10,36 +10,25 @@ import { VerticalSpace, } from "@create-figma-plugin/ui"; -import { NodeInfo } from "@/types"; -import { Settings, InsertLink } from "@/ui/icons/SvgIcons"; +import { Settings } from "@/ui/icons/SvgIcons"; import { useApiQuery } from "@/ui/client/useQueryApi"; import { getConflictingNodes } from "@/tools/getConflictingNodes"; import { FullPageLoading } from "@/ui/components/FullPageLoading/FullPageLoading"; import { useGlobalActions, useGlobalState } from "@/ui/state/GlobalState"; -import { NamespaceSelect } from "@/ui/components/NamespaceSelect/NamespaceSelect"; -import { - COMPACT_SIZE, - DEFAULT_SIZE, - useWindowSize, -} from "@/ui/hooks/useWindowSize"; -import { LocateNodeButton } from "@/ui/components/LocateNodeButton/LocateNodeButton"; +import { useWindowSize } from "@/ui/hooks/useWindowSize"; import { useSelectedNodes } from "@/ui/hooks/useSelectedNodes"; import { NodeList } from "../../components/NodeList/NodeList"; import { TopBar } from "../../components/TopBar/TopBar"; import styles from "./Index.css"; -import { KeyInput } from "./KeyInput"; -import { useSetNodesDataMutation } from "@/ui/hooks/useSetNodesDataMutation"; +import { ListItem } from "./ListItem"; +import { COMPACT_SIZE, DEFAULT_SIZE } from "@/ui/state/sizes"; export const Index = () => { const selectionLoadable = useSelectedNodes(); const selection = selectionLoadable.data?.items || []; const [error, setError] = useState(); - const defaultNamespace = useGlobalState((c) => c.config?.namespace); - const namespacesDisabled = useGlobalState( - (c) => c.config?.namespacesDisabled - ); const languagesLoadable = useApiQuery({ url: "/v2/projects/languages", @@ -51,21 +40,7 @@ export const Index = () => { method: "get", }); - const setNodesDataMutation = useSetNodesDataMutation(); - const languages = languagesLoadable.data?._embedded?.languages; - const namespaces = useMemo( - () => - Array.from( - new Set([ - ...(namespacesLoadable.data?._embedded?.namespaces || []).map( - (ns) => ns.name || "" - ), - defaultNamespace || "", - ]) - ), - [namespacesLoadable.data, defaultNamespace] - ); const language = useGlobalState((c) => c.config?.language) || languages?.[0]?.tag || ""; @@ -80,13 +55,13 @@ export const Index = () => { } }; + const defaultNamespace = useGlobalState((c) => c.config?.namespace); + const handlePush = () => { - const subjectNodes = /*nothingSelected ? allNodes :*/ selection.map( - (node) => ({ - ...node, - ns: node.ns ?? defaultNamespace, - }) - ); + const subjectNodes = selection.map((node) => ({ + ...node, + ns: node.ns ?? defaultNamespace, + })); const conflicts = getConflictingNodes(subjectNodes); if (conflicts.length > 0) { const keys = Array.from(new Set(conflicts.map((n) => n.key))); @@ -110,18 +85,6 @@ export const Index = () => { setRoute("create_copy"); }; - const handleConnect = (node: NodeInfo) => { - setRoute("connect", { node }); - }; - - const handleKeyChange = (node: NodeInfo) => (value: string) => { - setNodesDataMutation.mutate({ nodes: [{ ...node, key: value }] }); - }; - - const handleNsChange = (node: NodeInfo) => (value: string) => { - setNodesDataMutation.mutate({ nodes: [{ ...node, ns: value }] }); - }; - useEffect(() => { setError(undefined); }, [selection]); @@ -151,7 +114,6 @@ export const Index = () => { className={styles.languageContainer} value={language} placeholder="Language" - disabled={!nothingSelected} onChange={(e) => { handleLanguageChange( (e.target as HTMLInputElement).value @@ -223,57 +185,12 @@ export const Index = () => { ) : ( - !node.connected && ( - - ) - } - nsComponent={(node) => - !node.connected && - !namespacesDisabled && ( -
- -
- ) - } - actionCallback={(node) => { - return ( -
- - -
handleConnect(node)} - className={styles.connectButton} - > - {node.connected ? ( - - ) : ( - - )} -
-
- ); - }} + row={(node) => ( + + )} /> )}
diff --git a/src/ui/views/Index/KeyInput.tsx b/src/ui/views/Index/KeyInput.tsx index f7e9ca9..bbfa718 100644 --- a/src/ui/views/Index/KeyInput.tsx +++ b/src/ui/views/Index/KeyInput.tsx @@ -1,29 +1,19 @@ import { Textbox } from "@create-figma-plugin/ui"; import { h } from "preact"; -import { useState } from "preact/hooks"; -import { useDebouncedCallback } from "use-debounce"; type Props = { - initialValue: string; - onDebouncedChange: (value: string) => void; + value: string; + onChange: (value: string) => void; }; -export const KeyInput = ({ initialValue, onDebouncedChange }: Props) => { - const [value, setValue] = useState(initialValue); - - const debouncedcallback = useDebouncedCallback( - (value: string) => onDebouncedChange(value), - 100 - ); - +export const KeyInput = ({ value, onChange }: Props) => { return ( { - setValue(e.currentTarget.value); - debouncedcallback(e.currentTarget.value); + onChange(e.currentTarget.value); }} variant="border" style={{ diff --git a/src/ui/views/Index/ListItem.tsx b/src/ui/views/Index/ListItem.tsx new file mode 100644 index 0000000..20a89dc --- /dev/null +++ b/src/ui/views/Index/ListItem.tsx @@ -0,0 +1,114 @@ +import { h } from "preact"; +import { useMemo, useState } from "preact/hooks"; +import { NodeInfo } from "@/types"; +import { NodeRow } from "@/ui/components/NodeList/NodeRow"; +import { KeyInput } from "./KeyInput"; +import { useSetNodesDataMutation } from "@/ui/hooks/useSetNodesDataMutation"; +import { NamespaceSelect } from "@/ui/components/NamespaceSelect/NamespaceSelect"; +import styles from "./Index.css"; +import { useGlobalActions, useGlobalState } from "@/ui/state/GlobalState"; +import { components } from "@/ui/client/apiSchema.generated"; +import { LocateNodeButton } from "@/ui/components/LocateNodeButton/LocateNodeButton"; +import { InsertLink } from "@/ui/icons/SvgIcons"; + +type UsedNamespaceModel = components["schemas"]["UsedNamespaceModel"]; + +type Props = { + node: NodeInfo; + loadedNamespaces: UsedNamespaceModel[] | undefined; +}; + +export const ListItem = ({ node, loadedNamespaces }: Props) => { + const [keyName, setKeyName] = useState(node.key); + const [namespace, setNamespace] = useState(node.ns); + + const setNodesDataMutation = useSetNodesDataMutation(); + + const { setRoute } = useGlobalActions(); + + const namespacesDisabled = useGlobalState( + (c) => c.config?.namespacesDisabled + ); + const defaultNamespace = useGlobalState((c) => c.config?.namespace); + + const handleConnect = (node: NodeInfo) => { + setRoute("connect", { node }); + }; + + const namespaces = useMemo( + () => + Array.from( + new Set([ + ...(loadedNamespaces?.map((ns) => ns.name || "") || []), + defaultNamespace || "", + ]) + ), + [loadedNamespaces, defaultNamespace] + ); + + const handleKeyChange = (node: NodeInfo) => (value: string) => { + setKeyName(value); + setNodesDataMutation.mutate({ + nodes: [{ ...node, key: value, ns: namespace }], + }); + }; + + const handleNsChange = (node: NodeInfo) => (value: string) => { + setNamespace(value); + setNodesDataMutation.mutate({ + nodes: [{ ...node, key: keyName, ns: value }], + }); + }; + + return ( + + ) + } + nsComponent={ + !node.connected && + !namespacesDisabled && ( +
+ +
+ ) + } + action={ +
+ + +
handleConnect(node)} + className={styles.connectButton} + > + {node.connected ? ( + + ) : ( + + )} +
+
+ } + /> + ); +}; diff --git a/src/ui/views/PageSetup/PageSetup.tsx b/src/ui/views/PageSetup/PageSetup.tsx index eb49393..1c1e71b 100644 --- a/src/ui/views/PageSetup/PageSetup.tsx +++ b/src/ui/views/PageSetup/PageSetup.tsx @@ -3,7 +3,6 @@ import { ActionsBottom } from "@/ui/components/ActionsBottom/ActionsBottom"; import { FullPageLoading } from "@/ui/components/FullPageLoading/FullPageLoading"; import { TopBar } from "@/ui/components/TopBar/TopBar"; import { useGlobalActions, useGlobalState } from "@/ui/state/GlobalState"; -import { COMPACT_SIZE, useWindowSize } from "@/ui/hooks/useWindowSize"; import { CurrentPageSettings } from "@/types"; import { VerticalSpace, @@ -15,11 +14,15 @@ import { } from "@create-figma-plugin/ui"; import { Fragment, FunctionComponent, h } from "preact"; import { useState } from "preact/hooks"; +import { useWindowSize } from "@/ui/hooks/useWindowSize"; +import { COMPACT_SIZE } from "@/ui/state/sizes"; export const PageSetup: FunctionComponent = () => { const config = useGlobalState((c) => c.config) || {}; const { setRoute, setConfig } = useGlobalActions(); + useWindowSize(COMPACT_SIZE); + const [settings, setSettings] = useState< Partial | undefined >({ language: "" }); @@ -46,8 +49,6 @@ export const PageSetup: FunctionComponent = () => { const validated = Boolean(settings?.language); - useWindowSize(COMPACT_SIZE); - if (languagesLoadable.isLoading) { return ; } diff --git a/src/ui/views/Pull/Pull.tsx b/src/ui/views/Pull/Pull.tsx index cfb4fdd..e847959 100644 --- a/src/ui/views/Pull/Pull.tsx +++ b/src/ui/views/Pull/Pull.tsx @@ -21,6 +21,7 @@ import styles from "./Pull.css"; import { useConnectedNodes } from "@/ui/hooks/useConnectedNodes"; import { useUpdateNodesMutation } from "@/ui/hooks/useUpdateNodesMutation"; import { useHighlightNodeMutation } from "@/ui/hooks/useHighlightNodeMutation"; +import { useSetNodesDataMutation } from "@/ui/hooks/useSetNodesDataMutation"; type Props = RouteParam<"pull">; @@ -50,6 +51,7 @@ export const Pull: FunctionalComponent = ({ lang }) => { }); const updateNodeLoadable = useUpdateNodesMutation(); + const setNodesDataMutation = useSetNodesDataMutation(); const { changedNodes, missingKeys } = useMemo(() => { return getPullChanges( @@ -63,6 +65,15 @@ export const Pull: FunctionalComponent = ({ lang }) => { if (changedNodes.length !== 0) { await updateNodeLoadable.mutateAsync({ nodes: changedNodes }); } + await setNodesDataMutation.mutateAsync({ + nodes: + selectedNodes.data?.items + .filter((n) => !n.connected) + .map((n) => ({ + ...n, + connected: true, + })) ?? [], + }); setLanguage(lang); setRoute("index"); }; diff --git a/src/ui/views/Router.tsx b/src/ui/views/Router.tsx index 714979a..f05e9ec 100644 --- a/src/ui/views/Router.tsx +++ b/src/ui/views/Router.tsx @@ -11,12 +11,10 @@ import { Connect } from "./Connect/Connect"; import { PageSetup } from "./PageSetup/PageSetup"; import { CreateCopy } from "./CreateCopy/CreateCopy"; import { CopyView } from "./CopyView/CopyView"; +import { Dialog } from "../components/Dialog/Dialog"; -const getPage = ([routeKey, routeData]: Route) => { +const getDialogPage = ([routeKey, routeData]: Route) => { switch (routeKey) { - case "index": - return ; - case "settings": return ; @@ -31,7 +29,34 @@ const getPage = ([routeKey, routeData]: Route) => { case "create_copy": return ; + + default: + return null; + } +}; + +type PageProps = { + route: Route; + setRoute: (...route: Route) => void; +}; + +const Page = ({ route: [routeKey, routeData], setRoute }: PageProps) => { + if (routeKey === "settings") { + return ; } + + const dialogPage = getDialogPage([routeKey, routeData] as Route); + + return ( + +
+ +
+ {dialogPage && ( + setRoute("index")}>{dialogPage} + )} +
+ ); }; export const Router = () => { @@ -68,7 +93,7 @@ export const Router = () => { ) : !pageInfo ? ( ) : ( - getPage(route) + )} ); diff --git a/src/ui/views/Settings/ProjectSettings.tsx b/src/ui/views/Settings/ProjectSettings.tsx index acb09aa..9c6247c 100644 --- a/src/ui/views/Settings/ProjectSettings.tsx +++ b/src/ui/views/Settings/ProjectSettings.tsx @@ -128,7 +128,7 @@ export const ProjectSettings: FunctionComponent = ({
setSettings((settings) => ({ diff --git a/src/ui/views/Settings/Settings.tsx b/src/ui/views/Settings/Settings.tsx index 9c38154..8e711ff 100644 --- a/src/ui/views/Settings/Settings.tsx +++ b/src/ui/views/Settings/Settings.tsx @@ -19,8 +19,8 @@ import { ActionsBottom } from "@/ui/components/ActionsBottom/ActionsBottom"; import { TopBar } from "../../components/TopBar/TopBar"; import styles from "./Settings.css"; import { ProjectSettings } from "./ProjectSettings"; -import { useWindowSize } from "@/ui/hooks/useWindowSize"; import { useQueryClient } from "react-query"; +import { useWindowSize } from "@/ui/hooks/useWindowSize"; const DEFAULT_TOLGEE_URL = "https://app.tolgee.io"; diff --git a/src/web/main.ts b/src/web/main.ts index 3e007c3..3ed9475 100644 --- a/src/web/main.ts +++ b/src/web/main.ts @@ -30,11 +30,6 @@ function main() { const state = getUrlConfig(); - window.addEventListener("message", (e) => { - // print incoming messages - console.log(...e.data.pluginMessage); - }); - function updateNodes(changes: NodeInfo[], notify: boolean) { const changed = { allNodesChanged: false, selectionChanged: false };