开发

Tailwind Export - 导出Tailwind的Figma插件

我只花了3天时间,便借助GPT4开发完了一个Figma插件,而我之前完全没有了解过任何Figma插件开发知识。

学习开发 Figma 插件并实现将元素的 CSS 样式转换为 Tailwind 类名,界面需有复制按钮。使用代码.ts搭建基本框架,处理宽度、高度和颜色转换。尽量避免 TypeScript 类型错误。AI Copilot可提供指导和灵感。通过事件监听来更新插件界面,根据选择元素的属性生成对应的 Tailwind 类名。适时扩展至其他 CSS 属性,需自行阅读文档。最终效果可参考 GitHub。AI的辅助能加速开发,建议不要跳过基础学习。

  1. #Figma
  2. #插件开发
  3. #Tailwind CSS
  4. #AI辅助开发

1309

Figma logoFigma logo

之前一直想开发个Figma插件练练手,但畏于开发文档,也不知道做什么,就没动手。

可能是因为最近一直在用Tailwind CSS,在前两周冒出个想法:

Figma中Frame已经支持了很多类似CSS布局的设置,能否将这些设置转换成Tailwind输出呢?

在Figma上搜索了一下,有类似插件,但还没有专门用于导出Tailwind的插件。这就是个空白,可以搞。

翻了下Figma的开发文档,设计文档中元素的样式很容易拿到,只要把最基本框架搭起来,随便把什么样式获取到,转换成Tailwind到插件界面上,剩下的工作就是针对支持的属性一个个调整输出就行了。

现在的问题就是,如何把这个最基本的框架搭起来。

Introducing GPT-4

首先我测试了ChatGPT的效果,发现给出的回答并不可靠。

GPT-4会不会靠谱一点?

可我没法使用GPT-4,因为平时主要使用付费API,已经不想再买一个plus了。

还好有Poe,每天有一次机会使用GPT-4。这就意味着我必须谨慎构思prompt,不能浪费每天一次的机会。

然后我问出了给GPT-4的第一个问题:

我想写一个Figma plugin,功能是将选定的元素生成的CSS样式,转换成tailwind类名并显示在插件面板上。插件面板默认没有元素,只有一句提示语“请选择元素”,在选择元素后,其样式对应的tailwind类名将会显示在插件面板上。下方会有一个复制按钮。如果再点击其他元素 ,继续生成新的tailwind类名。这个插件暂时只需要考虑宽、高和背景颜色,其他样式可以不用管。你需要告诉我code.ts里要怎么实现这个功能,给出完整代码,不能有typescript类型错误。

AI的回答

以下是它的回答:

首先,你需要有一个基本的Figma插件项目结构。你可以参考 Figma 插件开发文档 来了解如何创建一个新的插件。

以下是一个简单的示例,演示了如何在 code.ts 中实现你所描述的功能。请注意,这个示例仅适用于处理宽度、高度和背景颜色,并将它们转换为 Tailwind CSS 类名。你可能需要根据你的需求进行调整。

typescript

// code.ts const figmaUIApi = ` <html> <style> body { font-family: -apple-system, sans-serif; margin: 0; padding: 24px; } #info { margin-bottom: 16px; } button { background-color: #1669ef; border: none; border-radius: 4px; color: white; cursor: pointer; font-size: 14px; padding: 8px 16px; } button:hover { background-color: #0d4edb; } </style> <body> <div id="info">请选择元素</div> <button id="copy">复制</button> <script> const info = document.querySelector('#info'); const copyButton = document.querySelector('#copy'); copyButton.addEventListener('click', () => { const tailwindClasses = info.textContent; if (tailwindClasses) { navigator.clipboard.writeText(tailwindClasses); } }); onmessage = (event) => { const tailwindClasses = event.data.pluginMessage; if (tailwindClasses) { info.textContent = tailwindClasses; } else { info.textContent = '请选择元素'; } }; </script> </body> </html> `; figma.showUI(figmaUIApi, { width: 300, height: 150 }); function convertToTailwind(width: number, height: number, color: string): string { // 宽度和高度转换 const widthClass = `w-${Math.round(width / 4)}`; const heightClass = `h-${Math.round(height / 4)}`; // 颜色转换 const colorClass = `bg-${color.replace('#', '')}`; return `${widthClass} ${heightClass} ${colorClass}`; } figma.on("selectionchange", () => { const node = figma.currentPage.selection[0]; if (node && node.type === "RECTANGLE") { const width = node.width; const height = node.height; const color = node.fills[0].color; const hexColor = `#${Math.round(color.r * 255).toString(16)}${Math.round(color.g * 255).toString(16)}${Math.round(color.b * 255).toString(16)}`; const tailwindClasses = convertToTailwind(width, height, hexColor); figma.ui.postMessage(tailwindClasses); } else { figma.ui.postMessage(null); } });

注意,这个示例中的 figmaUIApi 代码是一个简单的 HTML 和 JavaScript 代码,用于创建插件的 UI。它接收从 code.ts 发送的消息,并在接收到消息时更新显示的 Tailwind 类名。

这个示例中的 convertToTailwind 函数将宽度、高度和颜色转换为相应的 Tailwind 类名。你可以根据需要扩展此函数以支持更多的 CSS 属性。

请注意,这个示例仅适用于处理矩形节点。如果你需要支持其他类型的节点,你可以根据需要调整代码。

Continue

这个代码其实已经可以运行起来了,只是会有一些bug。其实你更应该把AI当成Copilot,用它给你提供灵感,就会是很好的工具。

那我们就来分析一下这段代码。

界面

const figmaUIApi跟着的那一大坨就是插件的界面,<style>内的暂时不用管。

界面相关代码最重要的部分就是copyButton.addEventListeneronmessage

copyButton.addEventListener是给复制按钮添加了一个监听函数,将info里的内容保存到tailwindClasses里,如果存在则向剪贴板写入;

onmessage的作用是判断是否有选择元素,如果没有选择,会显示一个提示文案。

插件逻辑

figma.showUI是Figma的一个方法,用于召唤出插件的界面。

function convertToTailwind是AI为我们生成的一个最简单的转换函数,比如下面这个:

typescript

const widthClass = `w-${Math.round(width / 4)}`;

它的效果是将元素的宽度获取到,除以4,四舍五入取整,在前面加一个前缀。

假如宽度是24,这里就会输出w-6

当然Tailwind的宽度并不能这么简单的四舍五入,但我们有了框架,细化就只是时间问题,并不存在什么难题。

剩下的颜色函数也是同理,并不能直接用,但你可以知道逻辑。

figma.on的作用是为指定事件注册一个回调函数,当这个事件发生的时候,执行该函数。

AI为我们生成了一个在选择元素发生变化时,针对矩形元素的一个处理:

typescript

figma.on("selectionchange", () => { const node = figma.currentPage.selection[0]; if (node && node.type === "RECTANGLE") { const width = node.width; const height = node.height; const color = node.fills[0].color; const hexColor = `#${Math.round(color.r * 255).toString(16)}${Math.round(color.g * 255).toString(16)}${Math.round(color.b * 255).toString(16)}`; const tailwindClasses = convertToTailwind(width, height, hexColor); figma.ui.postMessage(tailwindClasses); } else { figma.ui.postMessage(null); } });

当选择了Figma元素时,该函数触发,如果节点类型为矩形,将属性提取出来,传入convertToTailwind()处理函数,最终返回一串Tailwind类名字符串,然后将其显示到界面上。

其实中间还有一些小bug需要处理,我这里就不说了。

增加功能

基本的框架已经打好,暂时也没有GPT-4的帮助,剩下的只能靠自己和GPT-3.5了。

接下来的工作就是阅读Figma Plugin文档,找出支持的属性,再考虑如何转成对应的Tailwind类名。

比如对于文字类型:

typescript

export default function Text(node: SceneNode): string { const textNode = node as TextNode; let fontSize = 'text-base'; let fontWeight = 'font-normal'; let fontColor = 'text-black'; const textAlign = ConvertTextAlign(textNode); if (textNode.fontSize !== figma.mixed) { fontSize = ConvertFontSize(textNode.fontSize); } if (textNode.fontWeight !== figma.mixed) { fontWeight = ConvertFontWeight(textNode.fontWeight); } const opacity = ConvertOpacity(textNode.opacity); if (textNode.fills !== figma.mixed) { if (textNode.fills[0].type === "SOLID") { fontColor = `text-${ConvertColors(textNode.fills[0].color)}` } } return `${textAlign} ${fontSize} ${fontWeight} ${opacity} ${fontColor}`; }

先将文字的属性一个个提取出来,再分别传入对应的处理函数。

拿字号转换函数为例:

typescript

import getNumber from "./getNumber"; const Sizes = { 'text-xs': 12, 'text-sm': 14, 'text-base': 16, 'text-lg': 18, 'text-xl': 20, 'text-2xl': 24, 'text-3xl': 30, 'text-4xl': 36, 'text-5xl': 48, 'text-6xl': 60, 'text-7xl': 72, 'text-8xl': 96, 'text-9xl': 128, } export default function ConvertFontSize(fontSize: number): string { const fontSizeClass = getNumber(fontSize, Sizes); return fontSizeClass; }

这个函数收到字号后,会再调用一个函数,这个getNumber()的作用就是在第二个参数中寻找与第一个参数最接近的名称。比如传入的字号是17,就会返回字符串text-base

剩下的处理逻辑也都类似,都是在一个预设的参数中找到与入参最接近的,返回类名。

当然也有个别比较麻烦的,比如颜色。如何在一堆预设颜色中找出与指定颜色最接近的那个呢?

关于颜色如何进行对比还是将来另起一篇介绍比较好。让我们先继续。

完工

接下来你需要继续增加宽度高度、圆角半径、透明度、padding乃至布局的转换,方法都差不多,额外提一下布局。

熟悉CSS的人肯定会发现,Autolayout的设计跟CSS中Flexbox布局很相似,align-itemsjustify-contentgap都可以找到对应。所以我也特地生成了布局相关的类名。

插件的最终效果就是这样,详细代码可以访问Github查看。

The image is a screenshot of a Microsoft Word document with the "File" tab open, and the "Open" button is clicked. The document is in a new document window, and the text editor is open. The text editor is displaying the text in a blue box, and the text editor is highlighted. The text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dotThe image is a screenshot of a Microsoft Word document with the "File" tab open, and the "Open" button is clicked. The document is in a new document window, and the text editor is open. The text editor is displaying the text in a blue box, and the text editor is highlighted. The text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot. The text editor is highlighted with a blue box, and the text editor is highlighted with a red dot

还可以搞些什么

整个过程体验下来,我认为AI还不能让零基础的人实现开发,但可以让略懂的人更快的实现自己的想法。

你可能已经看到不少说法,说GPT-4已经可以完全帮你写代码了,但我还是建议你不要跳过基础的学习。刚开始可能你会欣喜于成功运行起demo,但随着实现的功能越来越复杂,你还是需要亲自写一些逻辑。完全不懂的话会无从下手,或者不知道如何提问题。

对于我来说,有了AI加持,我终于敢开发一些之前仅停留在脑海里的想法了。下一步可能搞一个OnlyFans原图下载插件,存一些艺术照。