paint-brush
Figma-аас дүрсүүдийг хэрхэн гайхалтай аргаар импортлох вэby@smileek
Шинэ түүх

Figma-аас дүрсүүдийг хэрхэн гайхалтай аргаар импортлох вэ

by Andrei Sieedugin8m2025/03/04
Read on Terminal Reader

Хэтэрхий урт; Унших

Энэхүү гарын авлага нь React/Vue төсөл рүү Figma-аас дүрсүүдийг хэрхэн хялбархан импортлох, тэдгээрийг өөр өөр хэмжээ, өнгөөр ашиглах боломжтой бүрэлдэхүүн хэсгийг хэрхэн үүсгэхийг харуулж байна.
featured image - Figma-аас дүрсүүдийг хэрхэн гайхалтай аргаар импортлох вэ
Andrei Sieedugin HackerNoon profile picture

Танд Figma-д олон тооны дүрс, React/Vue/бусад ямар нэгэн төсөл байгаа гэж хэлээрэй. Гайхах зүйлгүй, та эдгээр дүрсийг ашиглах хэрэгтэй болно. Бид тэдгээрийг хэрхэн импортлох вэ?


Хэрэв та хангалттай зөрүүд байвал тэдгээрийг нэг нэгээр нь татаж аваад хөрөнгө болгон нэмж болно. Гэхдээ энэ бол гунигтай арга юм. Таалагдахгүй.


Гуниглахаа больж оронд нь гайхалтай байцгаая. Энд бидэнд хэрэгтэй зүйл байна:

  • Эдгээр дүрсийг өөр өөр хэмжээ, өнгөөр ашиглах боломжийг олгодог сайхан бүрэлдэхүүн хэсэг.
  • Дүрсийн нэрээр автоматаар бөглөх.
  • Шинэ дүрс нэмэхэд хялбар шинэчлэлт.


*цаашаа мэдээлэл өгөхгүй*

Эндээс эхэл

Бидэнд Figma токен хэрэгтэй болно. Үүнийг хэрхэн хийх талаар тайлбарлах шаардлагагүй гэж би бодож байна, тиймээс энд тусламжийн хэсэг байна: https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens .


Өгөгдмөл тохиргоонууд нь хангалттай сайн: бидэнд файлын агуулгад зөвхөн унших хандалт хэрэгтэй.



Надад үнэмлэхээ өгөөч

Би жишээ болгон Материалын дизайны дүрсүүдийг (Нийгэмлэг) ашиглах болно.


Бидэнд файлын түлхүүр болон үндсэн зангилааны ID хэрэгтэй болно:


Одоо бидэнд хангалттай урьдчилсан нөхцөл байгаа тул кодчилол хийж эхэлцгээе. Би төслийн үндсэн кодоос тусгаарлагдсан скриптүүддээ дуртай, тиймээс би 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; };


Эцэст нь бид олон тооны зургийн ID-тай болсон үед бид 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, ""); };


Мэдээжийн хэрэг, хэрэв та зарим лого импортлох шаардлагатай бол өнгө солих шаардлагагүй, гэхдээ тэдгээрт өөр логик хийх нь таны гэрийн даалгавар байх болно.

Эхэлцгээе

За, бидний төлөвлөгөө энд байна:

  1. Хэрэв үүссэн файл байгаа бол устгана уу.
  2. Figma-аас дүрсийн зангилаа татах.
  3. Эдгээр зангилааны дүрс URL-уудыг дуудах.
  4. SVG татаж авах.
  5. Манай дүрсний функцээр шинэ файл үүсгэ.


Би файлыг бүхэлд нь уншихгүй - та үүнийг 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` ); } } }


Энд багцлах нь чухал, учир нь өөрөөр хэлбэл, хэрэв та хэдэн мянган файлыг зэрэгцүүлэн татахаар шийдсэн бол Фигма танд таалагдахгүй.


Хэрэв та арын хэсгээс хүлээн авсан нэрээр дүрс авах шаардлагатай бол толь бичиг үүсгэж болно:

 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;


Хэмжээний нарийвчлалыг эс тооцвол энэ нь маш энгийн зүйл гэж би бодож байна: намайг анх удаа хэрэгжүүлэхэд Chrome тоонуудын өргөн/өндөр CSS шинж чанарыг хүлээн зөвшөөрсөн боловч Firefox хүлээн аваагүй тул би px нэмсэн. Хэдий тийм биш байсан ч стандартын дагуу байх ёстой байдгаараа л байя.


Миний амласан автомат бөглөх нь энд байна:

Энэ бол бүх хүмүүс

Би ингэж хоол хийж байна. Энэ нь танд хэрэг болно гэж найдаж байна.


Энэ аргын сул тал нь дүрсүүд нь доторлогоотой байх бөгөөд үүнээс болж кэш хийхгүй байх явдал юм. Гэсэн хэдий ч, энэ нь хэдэн байт нь том асуудал биш гэж бодож байна. Түүгээр ч зогсохгүй та эргэлдэх, өнгийг нь өөрчлөх гэх мэт өөр ямар ч зүйлийг нэмж, эдгээр дүрснүүдийн жижиг Швейцарийн армийн хутгатай болно.


Мөн Figma-д цэгцтэй файл хэрэгтэй болно. Гэхдээ хүүе, хэрэв та энэ бүх кодыг бичиж чадвал дизайнерууддаа үүнийг цэгцлэхийг ятгаж болно.


Та React болон Vue бүрэлдэхүүн хэсгүүд, мөн цөөн хамаарал бүхий Node.js хувилбар зэрэг бүрэн кодыг эндээс олж болно: https://github.com/Smileek/fetch-icons

L O A D I N G
. . . comments & more!

About Author

Andrei Sieedugin HackerNoon profile picture
Andrei Sieedugin@smileek
Senior frontend developer with product management experience

TAG ҮҮ

ЭНЭ ӨГҮҮЛЛИЙГ ТОЛГОЙЛУУЛСАН...