ඔබට Figma හි අයිකන කට්ටලයක් සහ React/Vue/වෙනත් ඕනෑම දෙයක ව්යාපෘතියක් ඇතැයි සිතමු. පුදුමයක් නොවේ, ඔබට එම අයිකන භාවිතා කිරීමට සිදුවනු ඇත. අපට ඒවා ආයාත කළ හැක්කේ කෙසේද?
ඔයා මුරණ්ඩු නම්, ඔයාට ඒවා එකින් එක බාගත කරගෙන වත්කම් ලෙස එකතු කරන්න පුළුවන්. නමුත් ඒක දුකක්. එහෙම වෙන්න බෑ.
අපි දුක් වෙන එක නවත්තලා සුපිරි වෙමු. මෙන්න අපිට අවශ්ය දේවල්:
*තවත් කතා අවශ්ය නැත*
අපිට Figma ටෝකනයක් අවශ්ය වෙයි. මේක කරන්නේ කොහොමද කියලා පැහැදිලි කරන්න අවශ්ය නැහැ කියලා මම හිතනවා, ඒ නිසා මෙන්න උදව් අංශයක්: https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens .
පෙරනිමි සැකසුම් ප්රමාණවත් තරම් හොඳයි: අපට ගොනු අන්තර්ගතයට කියවීමට පමණක් ප්රවේශය අවශ්ය වේ.
මම උදාහරණයක් ලෙස ද්රව්ය නිර්මාණ අයිකන (ප්රජාව) භාවිතා කරමි.
අපට ගොනු යතුරක් සහ ප්රධාන නෝඩ් හැඳුනුම්පත අවශ්ය වනු ඇත:
දැන් අපිට ඇති තරම් පූර්ව අවශ්යතා තියෙන නිසා, අපි කේතනය කරන්න පටන් ගනිමු. මගේ ස්ක්රිප්ට් ප්රධාන ව්යාපෘති කේතයෙන් වෙන් කරලා තියෙන එක මට හොඳයි, ඒ නිසා මම root එකේ scripts
ෆෝල්ඩරයක් සහ ඒකේ fetch-icons.ts
එකක් හදන්නම්. TypeScript වලින් ඒක හදන්න අවශ්ය නැහැ, නමුත් ඒක නිසා මේ ලිපිය ටිකක් අලංකාරයි, ඒ නිසා මම ඒක කරන්නම්.
කෙසේ වෙතත්, මේ සඳහා තවත් යැපීම් කිහිපයක් අවශ්ය වනු ඇත:
yarn add -D tsx dotenv axios @figma/rest-api-spec
dotenv
මෙතන තියෙන්නේ .env
විචල්යයන් භාවිතා කරන්න, tsx
— TS ස්ක්රිප්ට් එක ක්රියාත්මක කරන්න (විසිතුරු, මතකද?), @figma/rest-api-spec
ටයිප් ආරක්ෂාව සඳහා වන අතර axios
මම ඒකට පුරුදු වෙලා ඉන්න නිසා පමණයි. අවශ්ය එකම එක dotenv
(ඔබ කේතයට API යතුර එකතු කිරීමට කැමති නැතිනම්), මම අවසානයේ “පිරිසිදු” අනුවාදය එකතු කරන්නම්. දැනට, අපට මෙම සැකසුම ඇත, අපි ආරම්භ කරන්නේ මෙන්න:
import * as dotenv from "dotenv"; dotenv.config(); const PERSONAL_ACCESS_TOKEN = String( process.env.VITE_FIGMA_PERSONAL_ACCESS_TOKEN ); // I've added my Figma token to the .env file, and so should you const FIGMA_API_URL = "https://api.figma.com/v1"; const FILE_KEY = "v50KJO82W9bBJUppE8intT"; // this one is from the URL const NODE_ID = "2402-2207"; // node-id query param, also from the URL
පළමුව, අපි ප්රධාන රාමුව සඳහා මෙටා දත්ත ලබා ගනිමු:
import { GetFileNodesResponse, GetImagesResponse, HasChildrenTrait, } from "@figma/rest-api-spec"; // ... const fetchFrameData = async ( nodeId: string ): Promise<HasChildrenTrait> => { const { data } = await axios.get<GetFileNodesResponse>( `${FIGMA_API_URL}/files/${FILE_KEY}/nodes?ids=${nodeId}`, getConfig() ); return data.nodes[nodeId].document as HasChildrenTrait; };
එය එහි දරුවන් පිළිබඳ තොරතුරු ආපසු ලබා දෙනු ඇත. ඒවා රූප (ඒවායේ වර්ගය INSTANCE
වනු ඇත) හෝ අපි පුනරාවර්තන ලෙස විග්රහ කරන වෙනත් රාමු විය හැකිය:
const getImageNodes = ( frameData: HasChildrenTrait ): Record<string, string> => { const nodes: Record<string, string> = {}; for (const image of frameData.children.filter( (node) => node.type === 'INSTANCE' )) { // normalizeName simply converts 'check-box' to 'CheckBox' const name = normalizeName(image.name); const id = image.id; nodes[id] = name; } for (const frame of frameData.children.filter( (node) => node.type === 'FRAME' )) { Object.assign(nodes, getImageNodes(frame)); } return nodes; };
අවසාන වශයෙන්, අපට රූප හැඳුනුම්පත් රාශියක් ඇති විට, අපි SVG ගොනු URL ලබා ගනිමු:
const fetchImageUrls = async ( nodeIds: string[] ): Promise<GetImagesResponse> => { const { data } = await axios.get<GetImagesResponse>( `${FIGMA_API_URL}/images/${FILE_KEY}?ids=${nodeIds.join(",")}&format=svg`, getConfig() ); return data; };
තවද අපට එවැනි වස්තූන් පෙළක් ලැබෙනු ඇත:
{ name: 'CheckBox', url: 'https://figma-alpha-api.s3.us-west-2.amazonaws.com/images/7dd5bc31-4f26-4701-b155-7bf7dea45824' }
ඔබ දැනටමත් අනුමාන කර ඇති පරිදි, අපි ඒවා සියල්ලම බාගත කරන්නෙමු, නමුත් එය වඩාත්ම සිත්ගන්නා සුළු කොටස නොවේ.
අපි SVG එකක් ලබා ගන්නා සෑම අවස්ථාවකම, අපට මෙවැනි දෙයක් ලැබේ:
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17 6H7C3.69 6 1 8.69 [...] 9 17 9Z" fill="black" /> </svg>
අපි svg
ටැග් ඉවත් කරන්නෙමු, මන්ද ඒවා සෑම නිරූපකයකටම සමාන වේ (සරල බව සඳහා ඒවා එකම ප්රමාණය යැයි මම උපකල්පනය කරමි). නමුත් වඩාත් සිත්ගන්නා කරුණ නම්, අපි සියලු fill=”black”
අච්චුවක ස්ථාන රඳවනයකින් ප්රතිස්ථාපනය කරන අතර එහි ප්රතිඵලයක් ලෙස අපට මෙවැනි ශ්රිතයක් ලැබෙනු ඇත:
export const IconToggleOn = (color: string) => `<path d="M17 6H7C3.69 [...] 9 17 9Z" fill="${color}"/>`;
අපි එය ලබා ගන්නේ මෙහෙමයි:
const cleanupSvg = (data: string): string => { const svgTags = /<\/?svg.*?>/g; const colorFills = /fill=["'].+?["']/g; return data .replace(svgTags, "") .replace(colorFills, 'fill="${color}"') .replace(/\n/g, ""); };
නිසැකවම, ඔබට සමහර ලාංඡන ආනයනය කිරීමට අවශ්ය නම් වර්ණ ප්රතිස්ථාපනය කිරීමට අවශ්ය නොවනු ඇත, නමුත් ඒවා සඳහා වෙනස් තර්කනයක් සෑදීම ඔබේ ගෙදර වැඩ වනු ඇත.
හරි, මෙන්න අපේ සැලැස්ම:
මම සම්පූර්ණ ගොනුවම කියවන්නේ නැහැ—ඔබට එය GitHub හි පරීක්ෂා කළ හැකිය. බාගත කිරීම දෙස බලමු:
const FILE_BATCH_SIZE = 10; const fileContent: string[] = []; const getPromise = async (item: IconData) => { try { const { data } = await axios.get<string>( item.url, getConfig("image/svg+xml") // returns necessary options and headers ); return { name: item.name, data }; } catch (err) { console.error(err); } }; for (let i = 0; i < iconsData.length; i += FILE_BATCH_SIZE) { const batch = await Promise.allSettled( iconsData.slice(i, i + FILE_BATCH_SIZE).map(getPromise) ); for (const icon of batch) { if (icon?.status === "fulfilled" && icon.value) { const iconName = `Icon${icon.value.name}`; const svgData = cleanupSvg(icon.value.data); fileContent.push( `export const ${iconName} = (color: string) =>\n \`${svgData}\`;\n` ); } } }
එසේ නොමැතිනම්, ඔබ එකවර ගොනු දහස් ගණනක් බාගත කිරීමට තීරණය කළහොත් Figma ඔබට කැමති නොවනු ඇති නිසා, Batching මෙහිදී වැදගත් වේ.
ඔබට පසුබිමෙන් ලැබෙන නමින් නිරූපකයක් ලබා ගැනීමට අවශ්ය නම්, ඔබට ශබ්ද කෝෂයක් ද නිර්මාණය කළ හැකිය:
const iconArray: string[] = []; // ... for (const icon of batch) { if (icon?.status === "fulfilled" && icon.value) { const iconName = `Icon${icon.value.name}`; const svgData = cleanupSvg(icon.value.data); fileContent.push( `export const ${iconName} = (color: string) =>\n \`${svgData}\`;\n` ); iconArray.push(iconName); // <-- we added this } } // ... when all files are processed fileContent.push( `\r\nexport const iconDictionary: Record<string, (color: string) => string> = {\r\n ${iconArray.join( ",\r\n " )}\r\n};\r\n` );
මෙම ප්රවේශය වඩාත් නරක ය, මන්ද ඔබ ශබ්දකෝෂය හරහා එක් නිරූපකයක් පමණක් භාවිතා කළත් මුළු කට්ටලයම බණ්ඩලයට එකතු වන නමුත් සමහර විට ඔබට අප්රසන්න දෙයක් කිරීමට සිදුවේ. එසේම, මගේ ESLint සතුටු කිරීම සඳහා සියලු \r\n
සහ අවකාශයන් මෙහි ඇත: ඔබට ඒවායේ ප්රමාණය සකස් කිරීමට අවශ්ය විය හැකිය.
මෙන්න අවසාන පියවර; අපි නව ගොනුවක් සාදමු:
import path from "path"; import { fileURLToPath } from "url"; // ... const PATH_TO_ICONS = "../src/assets/icons"; const currentPath = fileURLToPath(import.meta.url); const currentDirectory = path.dirname(currentPath); const fileName = "index.ts"; const filePath = path.join( path.resolve(currentDirectory, PATH_TO_ICONS), fileName ); // ... fs.writeFileSync(filePath, fileContent.join(""));
URL ලබා ගැනීමෙන් පසු අයිකන වර්ග කිරීම හොඳ අදහසකි, එය මේ තරම් සරලයි:
iconsData.sort((a, b) => a.name.localeCompare(b.name));
වර්ග කළ ලැයිස්තුවක් කියවීමට පහසු වනු ඇති අතර, වඩා වැදගත් දෙය නම්, අපට නව අයිකන ලැබෙන සෑම විටම කියවිය හැකි වෙනසක් ලැබෙනු ඇත. එසේ නොමැතිනම්, ඇණවුම සහතික නොවන අතර, එක් නිරූපකයක් එකතු කිරීමෙන් සියල්ල අවුල් විය හැක.
අපට අයිකන තන්තුව, වර්ණය සහ ප්රමාණය ආධාරක ලෙස පිළිගන්නා සහ මිහිරි දෙයක් අඳින සංරචකය අවශ්ය වේ:
import React, { useMemo } from "react"; import { IconSvg } from "../types/IconSvg"; interface IconProps { svg: IconSvg; // type IconSvg = (color: string) => string; color?: string; size?: number | string; } const refine = (x: string | number) => { return typeof x === "number" || !/\D+/.test(x) ? `${x}px` : x; }; const MyIcon: React.FC<IconProps> = ({ svg, color, size, }) => { const iconColor = useMemo(() => color ?? "black", [color]); const refinedSize = useMemo(() => refine(size ?? 24), [size]); const currentIcon = useMemo(() => svg(currentColor), [svg, currentColor]); return ( <svg viewBox="0 0 24 24" // make sure it's the same as in Figma dangerouslySetInnerHTML={{ __html: currentIcon }} style={{ width: refinedSize, minWidth: refinedSize, height: refinedSize, minHeight: refinedSize, }} ></svg> ); }; export default MyIcon;
ප්රමාණය පිරිපහදු කිරීම හැරුණු විට එය තරමක් සරල බව මම විශ්වාස කරමි: මම එය පළමු වරට ක්රියාත්මක කළ විට, ක්රෝම් පළල/උස CSS ගුණාංග ලෙස අංක පිළිගත්තේය, නමුත් ෆයර්ෆොක්ස් එසේ නොකළ නිසා මම px
එකතු කළෙමි. එය තවදුරටත් නඩුවක් නොවුනත්, එය ප්රමිතීන්ට අනුව විය යුතු ආකාරයටම තබා ගනිමු.
මම පොරොන්දු වූ ස්වයං සම්පූර්ණ කිරීම මෙන්න:
මම මේක උයන්නේ මෙහෙමයි. ඔයාලට මේක ප්රයෝජනවත් වෙයි කියලා මම හිතනවා.
මෙම ප්රවේශයේ ඇති අවාසිය නම්, අයිකන ඉන්ලයින් කර ඇති අතර එම නිසා හැඹිලිගත නොවීමයි. කෙසේ වෙතත්, බයිට් කිහිපයක් සඳහා එය විශාල දෙයක් යැයි මම නොසිතමි. එපමණක් නොව, ඔබට භ්රමණය, සැරිසැරීමේදී වර්ණය වෙනස් කිරීම වැනි වෙනත් ඕනෑම දෙයක් එකතු කළ හැකි අතර, ඔබට එම අයිකන වලින් කුඩා ස්විස් හමුදා පිහියක් ලැබෙනු ඇත.
ඒ වගේම, ඒකට Figma වල සංවිධානාත්මක ගොනුවක් අවශ්ය වෙනවා. නමුත් මේ ඔක්කොම කේත ලියන්න පුළුවන් නම්, ඒක විසඳන්න ඔයාගේ නිර්මාණකරුවන්ට ඒත්තු ගන්වන්නත් පුළුවන්.
React සහ Vue සංරචක ඇතුළුව සම්පූර්ණ කේතය සහ අඩු පරායත්තතා සහිත Node.js අනුවාදයක් ඔබට මෙතැනින් සොයාගත හැකිය: https://github.com/Smileek/fetch-icons