Skip to content

Commit

Permalink
feat: ability to ignore certain nodes in the document + locate node i…
Browse files Browse the repository at this point in the history
…n the doc (#30)
  • Loading branch information
stepan662 authored Apr 10, 2024
1 parent 59f77eb commit c398afb
Show file tree
Hide file tree
Showing 26 changed files with 344 additions and 137 deletions.
16 changes: 16 additions & 0 deletions src/main/endpoints/highlightNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createEndpoint } from "../utils/createEndpoint";

export type HighlightNodeProps = {
id: string;
};

export const highlightNodeEndpoint = createEndpoint(
"HIGHLIGHT_NODE",
async ({ id }: HighlightNodeProps) => {
const node = figma.getNodeById(id);

if (node) {
figma.viewport.scrollAndZoomIntoView([node]);
}
}
);
83 changes: 10 additions & 73 deletions src/main/main.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1,31 @@
import { showUI } from "@create-figma-plugin/utilities";
import { on, emit } from "@/utilities";
import { TOLGEE_PLUGIN_CONFIG_NAME } from "../constants";

import {
ConfigChangeHandler,
CurrentDocumentSettings,
CurrentPageSettings,
DocumentChangeHandler,
GlobalSettings,
ResetHandler,
ResizeHandler,
SelectionChangeHandler,
SetLanguageHandler,
SetupHandle,
SyncCompleteHandler,
TolgeeConfig,
} from "../types";
import { DEFAULT_SIZE } from "../tools/useWindowSize";
import { getScreenshotsEndpoint } from "./endpoints/getScreenshots";
import { getSelectedNodesEndpoint } from "./endpoints/getSelectedNodes";
import { getConnectedNodesEndpoint } from "./endpoints/getConnectedNodes";
import { setPageData } from "./utils/pages";
import { copyPageEndpoint } from "./endpoints/copyPage";
import { updateNodesEndpoint } from "./endpoints/updateNodes";
import { setNodesDataEndpoint } from "./endpoints/setNodesData";

const getGlobalSettings = async () => {
const pluginData = await figma.clientStorage.getAsync(
TOLGEE_PLUGIN_CONFIG_NAME
);
return pluginData ? (JSON.parse(pluginData) as Partial<GlobalSettings>) : {};
};

const setGlobalSettings = async (data: Partial<GlobalSettings>) => {
await figma.clientStorage.setAsync(
TOLGEE_PLUGIN_CONFIG_NAME,
JSON.stringify(data)
);
};

const deleteGlobalSettings = async () => {
await figma.clientStorage.deleteAsync(TOLGEE_PLUGIN_CONFIG_NAME);
};

const getDocumentData = () => {
const pluginData = figma.root.getPluginData(TOLGEE_PLUGIN_CONFIG_NAME);
return pluginData
? (JSON.parse(pluginData) as Partial<CurrentDocumentSettings>)
: {};
};

const setDocumentData = (data: Partial<CurrentDocumentSettings>) => {
figma.root.setPluginData(TOLGEE_PLUGIN_CONFIG_NAME, JSON.stringify(data));
};

const deleteDocumentData = () => {
figma.root.setPluginData(TOLGEE_PLUGIN_CONFIG_NAME, "");
};

const getPageData = (page = figma.currentPage) => {
const pluginData = page.getPluginData(TOLGEE_PLUGIN_CONFIG_NAME);
return pluginData
? (JSON.parse(pluginData) as Partial<CurrentPageSettings>)
: {};
};

const deletePageData = (page = figma.currentPage) => {
page.setPluginData(TOLGEE_PLUGIN_CONFIG_NAME, "");
};

const getPluginData = async () => {
return {
...(await getGlobalSettings()),
...getDocumentData(),
...getPageData(),
};
};

const setPluginData = async (data: Partial<TolgeeConfig>) => {
const { apiKey, apiUrl, language, namespace, namespacesDisabled } = data;
await setGlobalSettings({ apiKey, apiUrl });
setDocumentData({
apiKey,
apiUrl,
namespace,
namespacesDisabled,
documentInfo: true,
});
setPageData({ language, pageInfo: true });
emit<ConfigChangeHandler>("CONFIG_CHANGE", await getPluginData());
};
import {
deleteDocumentData,
deleteGlobalSettings,
deletePageData,
getPluginData,
setPluginData,
} from "./utils/settingsTools";
import { DEFAULT_SIZE } from "@/ui/hooks/useWindowSize";
import { highlightNodeEndpoint } from "./endpoints/highlightNode";

const getAllPages = () => {
const document = figma.root;
Expand Down Expand Up @@ -156,6 +92,7 @@ export default async function () {
copyPageEndpoint.register();
updateNodesEndpoint.register();
setNodesDataEndpoint.register();
highlightNodeEndpoint.register();

const config = await getPluginData();

Expand Down
44 changes: 29 additions & 15 deletions src/main/utils/nodeTools.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TOLGEE_NODE_INFO } from "@/constants";
import { NodeInfo } from "@/types";
import { CurrentDocumentSettings, NodeInfo } from "@/types";
import { getDocumentData } from "./settingsTools";

export const getNodeInfo = (node: TextNode): NodeInfo => {
const pluginData = JSON.parse(
Expand All @@ -15,27 +16,40 @@ export const getNodeInfo = (node: TextNode): NodeInfo => {
};
};

export function* findTextNodesGenerator(
nodes: readonly SceneNode[]
): Generator<TextNode> {
const toExplore = [...nodes].reverse();
let node: SceneNode | undefined;
while ((node = toExplore.pop())) {
function shouldIncludeNode(
node: TextNode,
settings: Partial<CurrentDocumentSettings>
) {
if (settings.ignoreNumbers && /^\d+$/.test(node.characters)) {
return false;
}
if (settings.ignorePrefix && node.name.startsWith(settings.ignorePrefix)) {
return false;
}
if (node.characters.trim().length === 0) {
return false;
}
return true;
}

export const findTextNodes = (nodes: readonly SceneNode[]): TextNode[] => {
const documentSettings = getDocumentData();
const result: TextNode[] = [];
for (const node of nodes) {
if (node.type === "TEXT") {
yield node;
if (shouldIncludeNode(node, documentSettings)) {
result.push(node);
}
}
// @ts-ignore
if (node.children) {
// @ts-ignore
[...(node.children as SceneNode[])].reverse().forEach((value) => {
toExplore.push(value);
});
findTextNodes(node.children as SceneNode[]).forEach((n) =>
result.push(n)
);
}
}
}

export const findTextNodes = (nodes: readonly SceneNode[]): TextNode[] => {
return [...findTextNodesGenerator(nodes)];
return result;
};

export const findTextNodesInfo = (nodes: readonly SceneNode[]): NodeInfo[] => {
Expand Down
92 changes: 92 additions & 0 deletions src/main/utils/settingsTools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { TOLGEE_PLUGIN_CONFIG_NAME } from "@/constants";
import {
ConfigChangeHandler,
CurrentDocumentSettings,
CurrentPageSettings,
GlobalSettings,
TolgeeConfig,
} from "@/types";
import { emit } from "@create-figma-plugin/utilities";
import { setPageData } from "./pages";

const getGlobalSettings = async () => {
const pluginData = await figma.clientStorage.getAsync(
TOLGEE_PLUGIN_CONFIG_NAME
);
return pluginData ? (JSON.parse(pluginData) as Partial<GlobalSettings>) : {};
};

const setGlobalSettings = async (data: Partial<GlobalSettings>) => {
await figma.clientStorage.setAsync(
TOLGEE_PLUGIN_CONFIG_NAME,
JSON.stringify(data)
);
};

export const deleteGlobalSettings = async () => {
await figma.clientStorage.deleteAsync(TOLGEE_PLUGIN_CONFIG_NAME);
};

export const getDocumentData = (): Partial<CurrentDocumentSettings> => {
const pluginData = figma.root.getPluginData(TOLGEE_PLUGIN_CONFIG_NAME);
const result = pluginData
? (JSON.parse(pluginData) as Partial<CurrentDocumentSettings>)
: {};

return {
ignorePrefix: "_",
ignoreNumbers: true,
...result,
};
};

const setDocumentData = (data: Partial<CurrentDocumentSettings>) => {
figma.root.setPluginData(TOLGEE_PLUGIN_CONFIG_NAME, JSON.stringify(data));
};

export const deleteDocumentData = () => {
figma.root.setPluginData(TOLGEE_PLUGIN_CONFIG_NAME, "");
};

const getPageData = (page = figma.currentPage) => {
const pluginData = page.getPluginData(TOLGEE_PLUGIN_CONFIG_NAME);
return pluginData
? (JSON.parse(pluginData) as Partial<CurrentPageSettings>)
: {};
};

export const deletePageData = (page = figma.currentPage) => {
page.setPluginData(TOLGEE_PLUGIN_CONFIG_NAME, "");
};

export const getPluginData = async () => {
return {
...(await getGlobalSettings()),
...getDocumentData(),
...getPageData(),
};
};

export const setPluginData = async (data: Partial<TolgeeConfig>) => {
const {
apiKey,
apiUrl,
language,
namespace,
namespacesDisabled,
ignorePrefix,
ignoreNumbers,
} = data;
await setGlobalSettings({ apiKey, apiUrl, ignorePrefix, ignoreNumbers });
setDocumentData({
apiKey,
apiUrl,
namespace,
namespacesDisabled,
ignorePrefix,
ignoreNumbers,
documentInfo: true,
});
setPageData({ language, pageInfo: true });
emit<ConfigChangeHandler>("CONFIG_CHANGE", await getPluginData());
};
2 changes: 1 addition & 1 deletion src/tools/getPushChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const getPushChanges = (
compareNs(t.keyNamespace, node.ns) &&
t.translations[language]?.text
);
const change = {
const change: KeyChangeValue = {
key: node.key,
ns: node.ns,
oldValue: key?.translations[language]?.text,
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export type PartialNodeInfo = Partial<NodeInfo> & {
export type GlobalSettings = {
apiUrl: string;
apiKey: string;
ignorePrefix: string;
ignoreNumbers: boolean;
};

export type CurrentDocumentSettings = GlobalSettings & {
Expand Down
1 change: 1 addition & 0 deletions src/ui/components/ActionsBottom/ActionsBottom.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
flex-direction: column;
align-items: flex-end;
background-color: var(--figma-color-bg);
z-index: 1000;
}

.actions {
Expand Down
9 changes: 9 additions & 0 deletions src/ui/components/LocateNodeButton/LocateNodeButton.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.highlightButton {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
width: 20px;
height: 20px;
color: var(--figma-color-text-secondary);
}
5 changes: 5 additions & 0 deletions src/ui/components/LocateNodeButton/LocateNodeButton.css.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare const styles: {
readonly "highlightButton": string;
};
export = styles;

29 changes: 29 additions & 0 deletions src/ui/components/LocateNodeButton/LocateNodeButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useHighlightNodeMutation } from "@/ui/hooks/useHighlightNodeMutation";
import { h } from "preact";

import styles from "./LocateNodeButton.css";
import { MyLocation } from "@/ui/icons/SvgIcons";

type Props = {
nodeId: string;
};

export const LocateNodeButton = ({ nodeId }: Props) => {
const highlightMutation = useHighlightNodeMutation();

const handleHighlight = () => {
highlightMutation.mutate({ id: nodeId });
};

return (
<div
data-cy="index_highlight_button"
role="button"
title="Locate on the page"
onClick={handleHighlight}
className={styles.highlightButton}
>
<MyLocation width={16} height={16} />
</div>
);
};
Loading

0 comments on commit c398afb

Please sign in to comment.