Tailwind Export - A Figma plugin that can export element styles to Tailwind
It only took me 3 days to develop a Figma plug-in with the help of GPT4, and I didn't know any Figma plug-in development knowledge before.
2023年3月27日

本文共有1776字,预计阅读时间8分钟
Introducing GPT-4
I want to write a Figma plugin, the function is to convert the CSS style generated by the selected element into the tailwind class name and display it on the plugin panel. The plug-in panel has no elements by default, only a prompt "Please select an element". After selecting an element, the tailwind class name corresponding to its style will be displayed on the plug-in panel. There will be a copy button below. If you click on another element, continue to generate a new tailwind class name. This plug-in only needs to consider width, height and background color for the time being, and other styles can be ignored. You need to tell me how to implement this function in code.ts, and give the complete code without typescript errors.
AI's Answer
1// code.ts
2const figmaUIApi = `
3 <html>
4 <style>
5 body {
6 font-family: -apple-system, sans-serif;
7 margin: 0;
8 padding: 24px;
9 }
10
11 #info {
12 margin-bottom: 16px;
13 }
14
15 button {
16 background-color: #1669ef;
17 border: none;
18 border-radius: 4px;
19 color: white;
20 cursor: pointer;
21 font-size: 14px;
22 padding: 8px 16px;
23 }
24
25 button:hover {
26 background-color: #0d4edb;
27 }
28 </style>
29 <body>
30 <div id="info">请选择元素</div>
31 <button id="copy">复制</button>
32 <script>
33 const info = document.querySelector('#info');
34 const copyButton = document.querySelector('#copy');
35
36 copyButton.addEventListener('click', () => {
37 const tailwindClasses = info.textContent;
38 if (tailwindClasses) {
39 navigator.clipboard.writeText(tailwindClasses);
40 }
41 });
42
43 onmessage = (event) => {
44 const tailwindClasses = event.data.pluginMessage;
45 if (tailwindClasses) {
46 info.textContent = tailwindClasses;
47 } else {
48 info.textContent = '请选择元素';
49 }
50 };
51 </script>
52 </body>
53 </html>
54`;
55
56figma.showUI(figmaUIApi, { width: 300, height: 150 });
57
58function convertToTailwind(width: number, height: number, color: string): string {
59 // 宽度和高度转换
60 const widthClass = `w-${Math.round(width / 4)}`;
61 const heightClass = `h-${Math.round(height / 4)}`;
62
63 // 颜色转换
64 const colorClass = `bg-${color.replace('#', '')}`;
65
66 return `${widthClass} ${heightClass} ${colorClass}`;
67}
68
69figma.on("selectionchange", () => {
70 const node = figma.currentPage.selection[0];
71
72 if (node && node.type === "RECTANGLE") {
73 const width = node.width;
74 const height = node.height;
75 const color = node.fills[0].color;
76 const hexColor = `#${Math.round(color.r * 255).toString(16)}${Math.round(color.g * 255).toString(16)}${Math.round(color.b * 255).toString(16)}`;
77
78 const tailwindClasses = convertToTailwind(width, height, hexColor);
79 figma.ui.postMessage(tailwindClasses);
80 } else {
81 figma.ui.postMessage(null);
82 }
83});
Continue
Interface
const figmaUIApi
is the interface of the plug-in, and the ones in <style>
are temporarily ignored.copyButton.addEventListener
and onmessage
.copyButton.addEventListener
adds a listening function to the copy button, saves the content in info
to tailwindClasses
, and writes it to the clipboard if it exists;onmessage
is to judge whether there is a selection element, and if there is no selection, a prompt copy will be displayed.Plugin Logic
figma.showUI
is a method of Figma used to call out the interface of the plugin.convertToTailwind
is the simplest conversion function generated by AI for us, such as the following:1const widthClass = `w-${Math.round(width / 4)}`;
w-6
will be output here.figma.on
is to register a callback function for the specified event, and execute the function when the event occurs.1figma.on("selectionchange", () => {
2 const node = figma.currentPage.selection[0];
3
4 if (node && node.type === "RECTANGLE") {
5 const width = node.width;
6 const height = node.height;
7 const color = node.fills[0].color;
8 const hexColor = `#${Math.round(color.r * 255).toString(16)}${Math.round(color.g * 255).toString(16)}${Math.round(color.b * 255).toString(16)}`;
9
10 const tailwindClasses = convertToTailwind(width, height, hexColor);
11 figma.ui.postMessage(tailwindClasses);
12 } else {
13 figma.ui.postMessage(null);
14 }
15});
convertToTailwind()
processing function, and finally returns a string of Tailwind class name strings, which are then displayed on the interface.Add Features
1export default function Text(node: SceneNode): string {
2 const textNode = node as TextNode;
3
4 let fontSize = 'text-base';
5 let fontWeight = 'font-normal';
6 let fontColor = 'text-black';
7
8 const textAlign = ConvertTextAlign(textNode);
9
10 if (textNode.fontSize !== figma.mixed) {
11 fontSize = ConvertFontSize(textNode.fontSize);
12 }
13
14 if (textNode.fontWeight !== figma.mixed) {
15 fontWeight = ConvertFontWeight(textNode.fontWeight);
16 }
17
18 const opacity = ConvertOpacity(textNode.opacity);
19
20 if (textNode.fills !== figma.mixed) {
21 if (textNode.fills[0].type === "SOLID") {
22 fontColor = `text-${ConvertColors(textNode.fills[0].color)}`
23 }
24 }
25
26 return `${textAlign} ${fontSize} ${fontWeight} ${opacity} ${fontColor}`;
27}
1import getNumber from "./getNumber";
2
3const Sizes = {
4 'text-xs': 12,
5 'text-sm': 14,
6 'text-base': 16,
7 'text-lg': 18,
8 'text-xl': 20,
9 'text-2xl': 24,
10 'text-3xl': 30,
11 'text-4xl': 36,
12 'text-5xl': 48,
13 'text-6xl': 60,
14 'text-7xl': 72,
15 'text-8xl': 96,
16 'text-9xl': 128,
17}
18
19export default function ConvertFontSize(fontSize: number): string {
20 const fontSizeClass = getNumber(fontSize, Sizes);
21
22 return fontSizeClass;
23}
getNumber()
is to find the name closest to the first parameter in the second parameter. For example, if the font size passed in is 17, the string text-base
will be returned.Finish
align-items
, justify-content
, and gap
can all be found. So I also specially generated layout-related class names.