Icons: init figma icon sync & optimizer
This commit is contained in:
committed by
hsjobeki
parent
38e12781fa
commit
2b0f4fc4b8
116
pkgs/icon-update/main.ts
Executable file
116
pkgs/icon-update/main.ts
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env -S deno run --allow-env --allow-net --allow-read --allow-write
|
||||
import "jsr:@std/dotenv/load";
|
||||
import type { FigmaNodeFile } from "./figma.types.ts";
|
||||
import { optimize } from "svgo";
|
||||
|
||||
const FIGMA_ICON_FILE_ID = Deno.env.get("FIGMA_ICON_FILE_ID");
|
||||
const FIGMA_TOKEN = Deno.env.get("FIGMA_TOKEN");
|
||||
const FRAME_ID = Deno.env.get("FRAME_ID");
|
||||
const OUT_DIR = Deno.env.get("OUT_DIR");
|
||||
|
||||
if (!FIGMA_ICON_FILE_ID) {
|
||||
console.error("env: FIGMA_ICON_FILE_ID is not set.");
|
||||
Deno.exit(2);
|
||||
}
|
||||
if (!FRAME_ID) {
|
||||
console.error("env: FRAME_ID is not set.");
|
||||
Deno.exit(2);
|
||||
}
|
||||
if (!FIGMA_TOKEN) {
|
||||
console.error("env: FIGMA_TOKEN is not set.");
|
||||
Deno.exit(2);
|
||||
}
|
||||
|
||||
const raw = await fetch(
|
||||
`https://api.figma.com/v1/files/${FIGMA_ICON_FILE_ID}/nodes?ids=${FRAME_ID}`,
|
||||
{
|
||||
headers: {
|
||||
"X-FIGMA-TOKEN": FIGMA_TOKEN,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const figmaFile: FigmaNodeFile = await raw.json();
|
||||
|
||||
// @ts-ignore: could be an error response
|
||||
if (figmaFile.status) {
|
||||
console.error(`Failed to fetch`, { figmaFile });
|
||||
Deno.exit();
|
||||
}
|
||||
|
||||
const nodeId = FRAME_ID.replace("-", ":");
|
||||
const iconComponentIds = Object.keys(figmaFile.nodes[nodeId].components);
|
||||
|
||||
const images = await fetch(
|
||||
`https://api.figma.com/v1/images/${FIGMA_ICON_FILE_ID}?ids=${iconComponentIds.join(
|
||||
",",
|
||||
)}&format=svg`,
|
||||
{
|
||||
headers: {
|
||||
"X-FIGMA-TOKEN": FIGMA_TOKEN,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
type ImageResonse =
|
||||
| {
|
||||
err: null;
|
||||
images: {
|
||||
[id: string]: string | null;
|
||||
};
|
||||
}
|
||||
| {
|
||||
err: string;
|
||||
};
|
||||
const urlSet: ImageResonse = await images.json();
|
||||
|
||||
if (urlSet.err !== null) {
|
||||
console.error("Could not get image paths", { urlSet });
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
const getNamefromType = (str: string) => {
|
||||
const [_type, name] = str.split("=");
|
||||
if (!name) {
|
||||
console.error("Icon doesnt have name");
|
||||
Deno.exit(1);
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
const final = await Promise.all(
|
||||
Object.entries(urlSet.images)
|
||||
.filter(([, url]) => url !== null)
|
||||
.map(async ([id, url]) => {
|
||||
const entry = figmaFile.nodes[nodeId].components[id];
|
||||
const rawSvg = await fetch(url as string);
|
||||
let svgText = await rawSvg.text();
|
||||
const replace = /fill=["']#?[0-9a-fA-F]{3,6}["']|fill=["'][a-zA-Z]+["']/g;
|
||||
svgText = svgText.replaceAll(replace, 'fill="currentColor"');
|
||||
|
||||
const optimizedSvg = optimize(svgText, {}).data;
|
||||
return {
|
||||
name: getNamefromType(entry.name),
|
||||
file: optimizedSvg,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const path = OUT_DIR;
|
||||
if (!path) {
|
||||
console.error("OUT_DIR is not set");
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Will write icons to: ${path}/*`);
|
||||
|
||||
final.filter(Boolean).forEach((i) => {
|
||||
const icon = i!;
|
||||
Deno.mkdirSync(path, { recursive: true });
|
||||
Deno.writeTextFileSync(`${path}/${icon.name}.svg`, icon.file);
|
||||
console.log(`Wrote: ${path}/${icon.name}.svg`);
|
||||
});
|
||||
|
||||
console.info("All icons up to date");
|
||||
|
||||
export {};
|
||||
Reference in New Issue
Block a user