Waxaad dhahdaa waxaad ku leedahay jaantusyada Figma iyo mashruuc ku jira React/Vue/wax kasta oo kale. La yaab ma leh, waxaad u baahan doontaa inaad isticmaasho calaamadahaas. Sideen u soo dhoofsan karnaa?
Haddii aad madax-adayg kugu filan tahay, waxaad mid mid u soo dejisan kartaa oo aad ku dari kartaa hanti ahaan. Laakiin taasi waa hab murugo leh. No likey.
Aan joojinno murugada oo aan noqonno kuwo cajiib ah. Waa kuwan waxa aan u baahanahay:
*Wax kale oo laguma siin*
Waxaan u baahan doonaa calaamada Figma. Uma maleynayo inay lama huraan tahay in la sharaxo sida tan loo sameeyo, markaa halkan waa qaybta caawinta bedelkeeda: https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens .
Dejinta caadiga ah ayaa ku filan: waxaan u baahanahay akhri-kaliya gelitaanka macluumaadka faylka.
Waxaan tusaale ahaan u isticmaali doonaa Astaamaha Nakhshad Walxaha (Community) .
Waxaan u baahan doonaa furaha faylka iyo idamka noode ee ugu muhiimsan:
Hadda oo aan haysano shuruudo ku filan, aan bilowno codaynta. Waxaan jeclahay qoraalladayda oo laga soocay koodhka mashruuca ee ugu muhiimsan, markaa waxaan samayn doonaa galka scripts
ee xididka iyo fetch-icons.ts
dhexdeeda. Looma baahna in lagu sameeyo TypeScript, laakiin waxay ka dhigaysaa maqaalkan mid qurux badan, markaa waan raaci doonaa.
Si kastaba ha ahaatee, tani waxay u baahan doontaa dhowr ku-tiirsanaan dheeraad ah:
yarn add -D tsx dotenv axios @figma/rest-api-spec
dotenv
waxa uu halkan u joogaa in uu isticmaalo doorsoomayaasha .env
, tsx
— si loo socodsiiyo qoraalka TS (macnaha, xasuuso?), @figma/rest-api-spec
waxa loogu talagalay badbaadada nooca, iyo axios
waa sababtoo ah waa la qabsaday. Midka kaliya ee loo baahan yahay waa dotenv
(ilaa aad ku fiican tahay inaad ku darto furaha API ee koodhka), oo waxaan ku dari doonaa nooca " saafi ah" dhamaadka. Hadda, waxa aanu yeelan doonaa habayntan, waana tan waxa aan ku bilaabayno:
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
Marka hore, waxaanu heli doonaa xogta badan ee qaabka guud:
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; };
Waxay soo celin doontaa macluumaadka ku saabsan carruurteeda. Kuwani waxay noqon karaan sawiro (noockoodu wuxuu noqon doonaa INSTANCE
) ama meerisyo kale oo aan si isdaba joog ah u kala saari doono:
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; };
Ugu dambeyntii, marka aan haysano farabadan aqoonsiga sawirka, waxaan soo qaadan doonaa URL-yada faylka SVG:
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; };
Oo waxaynu ku dhamayn doonaa soo diyaarin walxahan oo kale ah:
{ name: 'CheckBox', url: 'https://figma-alpha-api.s3.us-west-2.amazonaws.com/images/7dd5bc31-4f26-4701-b155-7bf7dea45824' }
Sida aad horeba u qiyaastay, dhamaantood waanu soo dejin doonaa, laakiin taasi maaha qaybta ugu xiisaha badan.
Mar kasta oo aan soo qaadanno SVG, waxaan helnaa wax sidan oo kale ah:
<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>
Waxaan ka saari doonaa summada svg
maadaama ay isku mid yihiin calaamad kasta (waxaan u maleynayaa inay la mid yihiin fududaynta). Laakiin waxa ka sii xiiso badan ayaa ah inaan ku beddelno dhammaan fill=”black”
ku beddele meeleeyaha qaab qaabaysan, natiijaduna waxaynu yeelan doonnaa shaqadan:
export const IconToggleOn = (color: string) => `<path d="M17 6H7C3.69 [...] 9 17 9Z" fill="${color}"/>`;
Waa kan sida aan ku helno:
const cleanupSvg = (data: string): string => { const svgTags = /<\/?svg.*?>/g; const colorFills = /fill=["'].+?["']/g; return data .replace(svgTags, "") .replace(colorFills, 'fill="${color}"') .replace(/\n/g, ""); };
Sida iska cad, uma baahnid inaad beddesho midabada haddii aad u baahan tahay inaad soo dejiso calaamado, laakiin samaynta macquul ka duwan iyaga waxay noqon doontaa shaqada gurigaaga.
Hagaag, waa kan qorshahayagu:
Ma akhrin doono faylka oo dhan - waxaad ka hubin kartaa GitHub . Bal aynu eegno soo dejinta lafteeda:
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` ); } } }
Isku-dubbaridu waa muhiim halkan sababtoo ah haddii kale, Figma kuma jeclayn haddii aad go'aansato inaad soo dejiso dhowr kun oo faylal ah oo isku mid ah.
Haddii aad u baahan tahay in aad hesho calaamad magaca aad ka heshay dhabarka dambe, waxa kale oo aad samayn kartaa qaamuus:
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` );
Habkani wuu ka sii daran yahay maaddaama dhammaan set oo dhan lagu dari doono xidhmada xitaa haddii aad isticmaasho hal calaamad oo qaamuus ah, laakiin mararka qaarkood, waa inaad samaysaa wax aan fiicnayn. Sidoo kale, dhammaan \r\n
iyo boosasku waxay halkan u joogaan si aan uga farxiyo ESLint-kayga: waxa laga yaabaa inaad u baahato inaad hagaajiso qaddarkooda.
Waa tan tilaabadii u dambaysay; aan samayno fayl cusub:
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(""));
Waa fikrad wanaagsan in la kala saaro astaanta ka dib marka la keeno URL-yada, taas oo u fudud sidan:
iconsData.sort((a, b) => a.name.localeCompare(b.name));
Liis la soocay ayaa fududaan doona in la akhriyo, iyo, waxa ka sii muhiimsan, waxaan yeelan doonaa kala duwanaansho la akhriyi karo mar kasta oo aan helno astaamo cusub. Haddii kale, dalabku lama dammaanad qaadayo, iyo ku darida hal calaamad ayaa wax walba khalkhal gelin karta.
Waxaan u baahanahay qaybta aqbasha xadhkaha sumadda, midabka, iyo cabbirka sida wax-soo-jiidashada oo u sawirta wax macaan:
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;
Waxaan aaminsanahay inay si toos ah u qumman tahay, marka laga reebo hagaajinta cabbirka: markii aan hirgeliyay markii ugu horreysay, Chrome wuxuu aqbalay nambarada sida ballac / dhererka guryaha CSS, laakiin Firefox ma uusan dhicin, sidaas darteed waxaan ku daray px
. Xataa haddaysan ahayn kiis dambe, aynu u ilaalino sidii ay ahayd inay ahaato mid waafaqsan heerarka.
Oo waa kan autocomplete ee aan ballan qaaday:
Sidan ayaan u kariyaa Waxaan rajeynayaa inaad faa'iido u heli doonto.
Cilad-xumada habkan ayaa ah in calaamadaha lagu dhejiyo oo aan la kaydin sababtoo ah taas. Si kastaba ha ahaatee, uma maleynayo inay wax weyn tahay dhowr bytes. Intaa waxaa dheer, waxaad ku dari kartaa wareeg, bedelida midabka on dul heehaabaya, wax kasta oo kale, oo waxaad yeelan doontaa in yar oo mindi-ciidan Swiss ah calaamadahaas.
Sidoo kale, waxay u baahan doontaa fayl habaysan gudaha Figma. Laakiin hey, haddii aad qori karto dhammaan koodkan, waxaad sidoo kale ku qancin kartaa naqshadeeyayaashaada inay xalliyaan.
Waxaad ka heli kartaa koodka buuxa, oo ay ku jiraan qaybaha React iyo Vue, iyo nooca Node.js oo leh ku-tiirsanaan yar halkan: https://github.com/Smileek/fetch-icons