በFigma ውስጥ የአዶዎች ስብስብ እንዳለህ እና በReact/Vue/ምንም ሌላ ፕሮጀክት እንዳለህ ይናገሩ። ምንም አያስደንቅም፣ እነዚያን አዶዎች መጠቀም ያስፈልግዎታል። እንዴት እናስመጣቸዋለን? ግትር ከሆንክ አንድ በአንድ አውርደህ እንደ ንብረት ማከል ትችላለህ። ግን ያ አሳዛኝ መንገድ ነው። መውደድ የለም። ማዘንን ትተን በምትኩ ድንቅ እንሁን። የሚያስፈልገን ይኸውና፡- እነዚያን አዶዎች በተለያየ መጠን እና ቀለም ለመጠቀም የሚያስችል ጥሩ አካል። በአዶ ስሞች ራስ-አጠናቅቅ። አዲስ አዶ ሲታከል ቀላል ዝማኔ። *ምንም ተጨማሪ ማስደሰት የለም* እዚ ጀምር የFigma ማስመሰያ እንፈልጋለን። ይህንን እንዴት ማድረግ እንደሚቻል ማብራራት አስፈላጊ አይመስለኝም, ስለዚህ በምትኩ የእርዳታ ክፍል ይኸውና: . https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens ነባሪ ቅንጅቶች በቂ ናቸው፡ የፋይሉ ይዘት ተነባቢ-ብቻ መዳረሻ ያስፈልገናል። መታወቂያህን ስጠኝ። እንደ ምሳሌ እጠቀማለሁ። የቁሳቁስ ንድፍ አዶዎችን (ማህበረሰብ) የፋይል ቁልፍ እና ዋናው መስቀለኛ መንገድ መታወቂያ እንፈልጋለን፡ አሁን በቂ ቅድመ ሁኔታዎች ስላሉን፣ ኮድ ማድረግ እንጀምር። ስክሪፕቶቼን ከዋናው የፕሮጀክት ኮድ የተለዩ እወዳለሁ፣ ስለዚህ በስሩ ውስጥ ማህደር እና በውስጡ እፈጥራለሁ። በታይፕ ስክሪፕት ማድረግ አያስፈልግም፣ ነገር ግን ይህን ጽሁፍ ጥሩ ያደርገዋል፣ ስለዚህ አብሬው እሄዳለሁ። scripts fetch-icons.ts ሆኖም ፣ ይህ ሁለት ተጨማሪ ጥገኝነቶችን ይፈልጋል- yarn add -D tsx dotenv axios @figma/rest-api-spec የ ተለዋዋጮችን ለመጠቀም እዚህ አለ ፣ — የቲኤስ ስክሪፕቱን ለማስኬድ (የጌጥ ፣ አስታውስ?) ፣ ለአይነት ደህንነት ነው ፣ እና እሱን ስለለመድኩ ብቻ ነው። የሚፈለገው ብቻ ነው (የኤፒአይ ቁልፉን በኮዱ ላይ በማከል ጥሩ ካልሆነ በስተቀር) እና በመጨረሻው ላይ “ንፁህ” የሚለውን እትም እጨምራለሁ ። ለአሁን፣ ይህን ማዋቀር ይኖረናል፣ እና በዚህ የምንጀምረው ነገር እነሆ፡- dotenv .env tsx @figma/rest-api-spec axios dotenv 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 ፋይል ዩአርኤሎችን እናመጣለን፡ 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, ""); }; አንዳንድ ሎጎዎችን ማስመጣት ከፈለጉ ቀለሞቹን መተካት አያስፈልግዎትም ነገር ግን ለእነሱ የተለየ አመክንዮ መስራት የቤት ስራዎ ይሆናል። እንጀምር እሺ፣ እቅዳችን ይኸውና፡- የተገኘውን ፋይል ካለ ያስወግዱት። የአዶ ኖዶችን ከ Figma ያውጡ። ለነዚያ አንጓዎች አዶ ዩአርኤሎችን ያውጡ። SVGs አውርድ። በአዶ ተግባሮቻችን አዲስ ፋይል ይፍጠሩ። ሙሉውን ፋይል አላነብም - በ ላይ ማረጋገጥ ትችላለህ. ማውረዱን ራሱ እንመልከት፡- 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 አይወድዎትም። ከጀርባ በተቀበሉት ስም አዶ ማግኘት ከፈለጉ መዝገበ ቃላት መፍጠር ይችላሉ፡- 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("")); አንድ ትንሽ ነገር ዩአርኤሎቹን ከወሰዱ በኋላ አዶዎችን መደርደር ጥሩ ሀሳብ ነው፣ ይህም እንደዚህ ቀላል ነው። 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 ቁጥሮችን እንደ ስፋት/ቁመት የሲኤስኤስ ባህሪያት ተቀብሏል ነገርግን ፋየርፎክስ አላደረገም, ስለዚህ ጨምሬያለሁ. አሁን ጉዳዩ ባይሆንም እንደታሰበው እንደ መስፈርት እናቆየው። px እና እኔ ቃል የገባሁት ራስ-አጠናቅቅ ይኸውና፡- ያ ሁሉም ሰዎች ናቸው። እንደዚህ ነው የማበስለው። ጠቃሚ ሆኖ እንዳገኙት ተስፋ አደርጋለሁ። የዚህ አቀራረብ ጉዳቱ አዶዎቹ ወደ ውስጥ እንዲገቡ እና በዚህ ምክንያት እንዳይሸጎጡ ማድረጉ ነው። ይሁን እንጂ ለጥቂት ባይት ትልቅ ጉዳይ ነው ብዬ አላምንም። በተጨማሪም ፣ በማንዣበብ ላይ ያለውን ቀለም መለወጥ ፣ ሌላ ማንኛውንም ማሽከርከር ማከል ይችላሉ ፣ እና የእነዚያ አዶዎች ትንሽ የስዊስ-ሠራዊት ቢላዋ ይኖርዎታል። እንዲሁም፣ በFigma ውስጥ የተደራጀ ፋይል ያስፈልገዋል። ግን ሄይ፣ ይህን ሁሉ ኮድ መፃፍ ከቻልክ ዲዛይነሮችህን እንዲያስተካክሉ ማሳመንም ትችላለህ። React እና Vue ክፍሎችን ጨምሮ ሙሉውን ኮድ እና ጥቂት ጥገኞች ያለው የ Node.js ስሪት እዚህ ማግኘት ይችላሉ ፡ https://github.com/Smileek/fetch-icons