From ec88fb98f41cd460e0432aba7cef81c4a391173f Mon Sep 17 00:00:00 2001 From: Oscar Otero Date: Wed, 7 Sep 2022 17:44:24 +0200 Subject: [PATCH] missing copies --- CHANGELOG.md | 1 + manifest.json | 4 +++ package.json | 5 +++ src/main.ts | 58 +++++++++++++++--------------- src/missing-copies.ts | 76 +++++++++++++++++++++++++++++++++++++++ src/ui.tsx | 15 ++++++++ src/ui/missing-copies.tsx | 62 ++++++++++++++++++++++++++++++++ src/ui/styles.css | 8 +++++ 8 files changed, 200 insertions(+), 29 deletions(-) create mode 100644 src/missing-copies.ts create mode 100644 src/ui/missing-copies.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index ff2b2d4..5f8b897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ project adheres to [Semantic Versioning](http://semver.org/). ## [0.2.0] - 2022-09-07 ### Added - New command _Reset layer names_. +- New command _Get missing copies_. - New button to select the text layer while editing the variables. - New option to filter the empty variables. diff --git a/manifest.json b/manifest.json index 277ac73..25a73a1 100644 --- a/manifest.json +++ b/manifest.json @@ -18,6 +18,10 @@ { "name": "Reset layer names", "command": "src/reset-names.ts--default" + }, + { + "name": "Get missing copies", + "command": "src/missing-copies.ts--default" } ] } diff --git a/package.json b/package.json index 10f1780..7840561 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,11 @@ { "name": "Reset layer names", "main": "src/reset-names.ts" + }, + { + "name": "Get missing copies", + "main": "src/missing-copies.ts", + "ui": "src/ui.tsx" } ] } diff --git a/src/main.ts b/src/main.ts index 60de063..4085606 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,25 +2,25 @@ import { emit, on, showUI } from "@create-figma-plugin/utilities"; import { NodeInfo, ResizeWindowHandler, SourceCopies } from "./types"; import { getTextNodes, updateNodeCopy } from "./utils"; -export default function () { - on( - "RESIZE_WINDOW", - (windowSize: { width: number; height: number }) => { - const { width, height } = windowSize; - figma.ui.resize(width, height); - }, - ); - showUI({ - height: 400, - width: 500, - }); - - // Get the nodes from the selection or the whole document - const selection = figma.currentPage.selection.slice(); - const textNodes = selection.length - ? getTextNodes(selection) - : figma.currentPage.findAll((node) => node.type === "TEXT") as TextNode[]; +on( + "RESIZE_WINDOW", + (windowSize: { width: number; height: number }) => { + const { width, height } = windowSize; + figma.ui.resize(width, height); + }, +); +showUI({ + height: 400, + width: 500, +}); + +// Get the nodes from the selection or the whole document +const selection = figma.currentPage.selection.slice(); +const textNodes = selection.length + ? getTextNodes(selection) + : figma.currentPage.findAll((node) => node.type === "TEXT") as TextNode[]; +export default function () { // List of Nodes with copies let nodes: NodeInfo[] = []; @@ -65,17 +65,6 @@ export default function () { } }); - // Select a text node - on("SELECT_NODE", (data: NodeInfo) => { - const node = figma.currentPage.findOne((node) => - node.id === data.node.id - ) as TextNode; - if (node) { - figma.currentPage.selection = [node]; - figma.viewport.scrollAndZoomIntoView([node]); - } - }); - // Update the variables on("UPDATE_VARS", (data: NodeInfo[]) => { data.forEach((info) => { @@ -93,6 +82,17 @@ export default function () { }); } +// Select a text node +on("SELECT_NODE", (data: NodeInfo) => { + const node = figma.currentPage.findOne((node) => + node.id === data.node.id + ) as TextNode; + if (node) { + figma.currentPage.selection = [node]; + figma.viewport.scrollAndZoomIntoView([node]); + } +}); + // Close the plugin when the UI is closed on("CLOSE", () => figma.closePlugin()); diff --git a/src/missing-copies.ts b/src/missing-copies.ts new file mode 100644 index 0000000..10033bc --- /dev/null +++ b/src/missing-copies.ts @@ -0,0 +1,76 @@ +import { emit, on, showUI } from "@create-figma-plugin/utilities"; +import { SourceCopies } from "./types"; +import { getTextNodes } from "./utils"; + +export default function () { + showUI({ + height: 400, + width: 500, + }); + + // Get the nodes from the selection or the whole document + const selection = figma.currentPage.selection.slice(); + const textNodes = selection.length + ? getTextNodes(selection) + : figma.currentPage.findAll((node) => node.type === "TEXT") as TextNode[]; + + if (!textNodes.length) { + emit("COMPLETED", { + title: selection.length + ? "No text nodes found in the selection" + : "No text nodes found in the document", + }); + } else { + // Send document defaults + emit("DEFAULTS", { + url: figma.root.getPluginData("url"), + url_2: figma.root.getPluginData("url_2"), + url_3: figma.root.getPluginData("url_3"), + }); + } + + // The copies have been loaded + on("FETCHED_COPIES", (data: SourceCopies) => { + // Save document urls defaults + figma.root.setPluginData("url", data.url); + figma.root.setPluginData("url_2", data.url_2); + figma.root.setPluginData("url_3", data.url_3); + + // Search and replace the text nodes with the copies + const nodes = getUntranslatedNodes(textNodes, data.copies); + + if (nodes.length) { + // Update the copies + emit("UNTRANSLATED", { nodes }); + } else { + const title = selection.length + ? "No missing copies found in the selection" + : "No missing copies found in the document"; + emit("COMPLETED", { title }); + } + }); +} + +// Select a text node +on("SELECT_NODE", (data: { node: { id: string } }) => { + const node = figma.currentPage.findOne((node) => + node.id === data.node.id + ) as TextNode; + if (node) { + figma.currentPage.selection = [node]; + figma.viewport.scrollAndZoomIntoView([node]); + } +}); + +// Close the plugin when the UI is closed +on("CLOSE", () => figma.closePlugin()); + +/** Filter all TextNodes without translations */ +function getUntranslatedNodes( + nodes: TextNode[], + copies: Record, +): [string, string, string][] { + return nodes.filter((node) => !(node.name in copies)).map(( + node, + ) => [node.name, node.characters, node.id]); +} diff --git a/src/ui.tsx b/src/ui.tsx index d684dfc..2a7ba86 100644 --- a/src/ui.tsx +++ b/src/ui.tsx @@ -13,6 +13,7 @@ import { fetchCopies } from "./ui/utils"; import SourceForm from "./ui/source-form"; import VariablesForm from "./ui/variables-form"; import Completed from "./ui/completed"; +import MissingCopies from "./ui/missing-copies"; import "!./ui/styles.css"; import type { NodeInfo, ResizeWindowHandler, SourceUrls } from "./types"; @@ -60,6 +61,13 @@ function Main() { }); }); + on("UNTRANSLATED", (data) => { + setState({ + type: "untranslated", + data: { nodes: data.nodes }, + }); + }); + async function handleSubmitUrls(data: SourceUrls) { setState({ type: "loading", data: { title: "Loading copies..." } }); const copies = await fetchCopies(...Object.values(data)); @@ -104,6 +112,13 @@ function Main() { {state.type === "completed" && ( )} + {state.type === "untranslated" && ( + + )} ); } diff --git a/src/ui/missing-copies.tsx b/src/ui/missing-copies.tsx new file mode 100644 index 0000000..66610a4 --- /dev/null +++ b/src/ui/missing-copies.tsx @@ -0,0 +1,62 @@ +import { + Button, + IconButton, + IconPlus32, + Inline, + Text, + VerticalSpace, +} from "@create-figma-plugin/ui"; +import { h } from "preact"; + +interface Props { + onClose: () => void; + onSelectNode: (data: any) => void; + nodes: [string, string, string][]; +} + +export default function VariablesForm( + { nodes, onSelectNode, onClose }: Props, +) { + nodes.sort((a, b) => a[0].localeCompare(b[0])); + + return ( +
+ + + The following nodes are missing in the Google Spreadsheet document: + + + + + + + + + + + + + {nodes.map((node, index) => ( + + + + onSelectNode({ node: { id: node[2] } })} + > + + + + ))} + +
IdText
{node[0]}{node[1]}
+ + + + + + + +
+ ); +} diff --git a/src/ui/styles.css b/src/ui/styles.css index 56aa40c..9f3f4b1 100644 --- a/src/ui/styles.css +++ b/src/ui/styles.css @@ -16,4 +16,12 @@ } .center { text-align: center; +} +.table { + user-select: initial; + cursor: text; + font-size: var(--font-size-11); +} +.table th { + text-align: left; } \ No newline at end of file