bernaferrari / FigmaToCode

Generate responsive pages and apps on HTML, Tailwind, Flutter and SwiftUI.
https://www.figma.com/community/plugin/842128343887142055
GNU General Public License v3.0
3.8k stars 303 forks source link

Add Tailwind support for Figma variables #109

Closed davestewart closed 4 months ago

davestewart commented 5 months ago

[!Note]

Check the comment thread, as the final PR also introduced new settings to determine when variables were used, as well as #110 which improved how colors are derived

This PR modifies the Tailwind color functions to support Figma variables.

This allows users to use custom variables in their design systems, such as neutral/700 or buttons/active-border which then output as classes such as bg-neutral-700 or border-buttons-active-border:

CleanShot 2024-06-28 at 17 33 34

The main update to the code is that rather than passing in a color and opacity, you pass the entire fill or color stop and the function's code returns the color name as-is if it's a variable, or looks up the nearest value if not.

Output looks like this:

<div class="w-44 h-36 relative">
  <div class="w-20 h-36 left-0 top-0 absolute">
    <div class="left-[16px] top-0 absolute text-neutral-900 text-xs font-normal font-['Inter']">Variables</div>
    <div class="w-20 h-28 left-0 top-[27px] absolute">
      <div class="w-8 h-8 left-0 top-0 absolute bg-test-dragon"></div>
      <div class="w-8 h-8 left-[44px] top-0 absolute bg-test-dragon-light/opacity-25"></div>
      <div class="w-8 h-8 left-0 top-[44px] absolute bg-gradient-to-b from-test-dragon to-test-sky"></div>
      <div class="w-8 h-8 left-[44px] top-[44px] absolute bg-gradient-to-b from-test-dragon to-test-sky"></div>
      <div class="w-8 h-8 left-[44px] top-[88px] absolute bg-gradient-to-b from-test-dragon via-green-300 to-test-sky"></div>
    </div>
  </div>
  <div class="w-20 h-24 left-[103px] top-0 absolute">
    <div class="left-[16px] top-0 absolute text-neutral-800 text-xs font-normal font-['Inter']">Colors</div>
    <div class="w-20 h-20 left-0 top-[27px] absolute">
      <div class="w-8 h-8 left-0 top-0 absolute bg-lime-400"></div>
      <div class="w-8 h-8 left-[44px] top-0 absolute bg-lime-400/opacity-25"></div>
      <div class="w-8 h-8 left-0 top-[44px] absolute bg-gradient-to-b from-lime-400 to-cyan-400"></div>
      <div class="w-8 h-8 left-[44px] top-[44px] absolute bg-gradient-to-b from-lime-400 to-cyan-400"></div>
    </div>
  </div>
</div>

Closes #107

Relates to #102

bernaferrari commented 5 months ago

will this work: bg-lime-400/opacity-25? Shouldn't it be /25? Or you created a variable that's actually 25? My biggest fear is that if someone has figma variables but don't use custom tailwind file won't be able to get benefits, but maybe I'm wrong. What do you think?

davestewart commented 5 months ago

Hey! Thanks for jumping on to this.

Looking at the docs, it appears I made a mistake with the opacity code! It was this line I refactored; did I misunderstand?

Fixed now:

CleanShot 2024-07-01 at 23 21 49

Regarding a user using variables but not a custom tailwind file, you make a fair point.

Saying that, our designer was actually quite surprised about the color being rounded in the first place.

But of course, you need to make sure things don't break going forward.

Perhaps a "Conversion" dropdown would be useful here:

Label Behaviour Output Comment
Exact Passes arbitrary hex value to Tailwind to generate new rule bg-[#bef260] Solves #102
Closest Rounds to closest Tailwind default color bg-lime-300 Current behaviour
Custom Uses variables to indicate custom token name bg-success Solves #107

Saying that, maybe that doesn't work, as we would only need to decide what happens with variable, rounding happens anyway, so perhaps it's a kind of blended mix of the three?

Also, I don't know enough about the UI element of figma panels to know where this would go. I see there is the debug UI; I assume that is where it happens?

FWIW, this was our designer's reaction to seeing custom tokens:

image

bernaferrari commented 4 months ago

I wish the user had only to choose between two options, but in that case seems fair. I don't know if I have a 3 option switch. Will probably be similar to swiftui scaffold x etc thing. I'll take a look

davestewart commented 4 months ago

I wonder if two checkboxes could do it?

Results would be:

Round colors Var names Description
. . Arbitrary colors for everything
x . Rounded colors for everything
. x Arbitrary colors for fills and custom tokens for variables
x x Rounded colors for fills and custom tokens for variables

Vs Dropdown:

Option Description
Exact Arbitrary colors for everything
Rounded Rounded colors for everything
Custom Rounded colors for fills and custom tokens for variables

Just trying to think through the problem...

bernaferrari commented 4 months ago

Yeah, could make sense... Most people would use the round color but not use variable. I think I like this.

davestewart commented 4 months ago

OK, updates made.

Preferences

CleanShot 2024-07-10 at 14 15 39

I added two new preferences, and disambiguated the one for values / sizes:

  roundTailwindValues: boolean;
  roundTailwindColors: boolean,
  customTailwindColors: boolean,

I also made the labels less ambiguous (and perhaps in a future update we could update the UI to UI3?)

Colors

A couple of points to take into account:

CleanShot 2024-07-10 at 15 43 39

  1. I've aligned with the way value-rounding works for colors, so both values and colors automatically show Tailwind tokens (lime-300) rather than arbitrary values (bg-[#bef264]) if they match Tailwind config.

  2. It's a bit tricky to get the color color names right just now, as they are within common/retrieveUi/retrieveColors. However, #110 has already done the work to simplify this, so if you're happy to wait I can look to marry the preferences and color output values in that PR.

If we can get this merged sooner rather than later, I'll merge these changes into #110 and #113 then things will be looking pretty rosy!

bernaferrari commented 4 months ago

I'm happy. I think just the label could be shorter. Maybe use a popover to explain more, maybe I don't know. What do you think? Do you like this? I think it is just consuming too much space.

davestewart commented 4 months ago

I wondered the same.

Your custom UI is quite bulky compared to the built-in one:

CleanShot 2024-07-10 at 19 31 54

But then even that looks like a lot of text.

Here's the checkboxes in case you want to play around:

[ ] React (JSX)
[ ] Optimize layout
[ ] Include layer names in classes
[ ] Round pixel values to Tailwind defaults
[ ] Round color values to Tailwind defaults
[ ] Use variables as custom color tokens

Or, shorter (this is probably the quickest win):

[ ] React (JSX)
[ ] Optimize layout
[ ] Include layer names
[ ] Round pixel values
[ ] Round color values
[ ] Custom color variables

I wonder if groups might help? Though I know it's only Tailwind which has the majority of the options right now.

Layout:

[ ] React (JSX)
[ ] Optimize layout
[ ] Include layer names in classes

Values:

[ ] Round pixel values to Tailwind defaults
[ ] Round color values to Tailwind defaults
[ ] Use variables as custom color tokens

Or, shorter:

Layout:

[ ] React (JSX)
[ ] Optimize layout
[ ] Include layer names

Tailwind:

[ ] Round pixel values
[ ] Round color values
[ ] Custom color variables

??

bernaferrari commented 4 months ago

Could be something like "optimize" and opens a pop-up where you can select what you want to optimize, I don't know.. Or "round values...", you click, and can choose which value you want. A dropdown could work.

davestewart commented 4 months ago

Could be something like "optimize" and opens a pop-up where you can select what you want to optimize

I kind of see what you mean, but as they are preferences, aren't they all "optimizations"? And maybe users might want to change per-component, so might be good to make it really accessible.

Just seeing if there are any examples of Figma already doing this:

image

Maybe:

Layout

[ ] React (JSX)
    Use className instead of class
[ ] Optimize layout
    I still don't know what this is
[ ] Include layer names
    Include layer names in list of Tailwind classes

Tailwind

[ ] Round pixel values
    Round pixel values to configured Tailwind pixel values
[ ] Round color values
    Round color values to configured Tailwind color values
[ ] Custom color variables
    Use Figma variable names in place of Tailwind color names

Looks bulky as hell there, but would be smaller font size and dropped-back color.

I think maybe at this stage just have the extra checkboxes and make improving the Plugin UI a separate ticket.

Could combine aligning it with the Figma UI3.

bernaferrari commented 4 months ago

what if we did something like an accordion/collapsible https://ui.shadcn.com/docs/components/collapsible where you have the "advanced features" there? Not sure we have enough, but could work...

Optimize layout works like this: you have a frame with two rectangles inside, everything using absolute position. If you press shift+a, figma is going to make an auto layout for you automatically. Inferred try to guess that and if it is possible to make an autolayout automatically, it will do.

davestewart commented 4 months ago

By "advanced features"  you mean the rounding / variables options?

Also, would need to work out how the UI would look with an accordian.

How would that look? I think the checkboxes would need to be block not inline if that was the case.

bernaferrari commented 4 months ago

Yes. You would have a block section, that expands with inline things. But that's just an idea. I'm open for other ideas too. As long as the UI is easy, feel free to think on anything

davestewart commented 4 months ago

OK, I took a quick stab at shorter labels and title props:

CleanShot 2024-07-10 at 23 49 57

Second option was longer labels but simpler checkboxes:

CleanShot 2024-07-11 at 00 01 59

Third option, simpler checkboxes and smaller labels with longer descriptions:

CleanShot 2024-07-11 at 00 07 42

My feelings about a dropdown are:

Of the above screenshots:

Also, probably lose all the backgrounds and borders (they just make it look busy for no reason):

CleanShot 2024-07-11 at 00 16 34

Anyway. Heading to bed now. Would love to move ahead on this tomorrow!

bernaferrari commented 4 months ago

I think I like the most the first. Which one did you like the most?

davestewart commented 4 months ago

I prefer the last one with the simpler UI that paves the way for something UI3-compatible.

But I've updated the code with the shorter labels and tooltips, so that's effectively ready to go now.

CleanShot 2024-07-11 at 13 16 15

bernaferrari commented 4 months ago

I like the last one, but I think there are too many options before the user sees the code which is the main part. Thanks. Should I merge already?

davestewart commented 4 months ago

before the user sees the code which is the main part

Yeah, I suppose the last 3 options are probably the ones which the user would be most interested in.

I think better groups as outlined earlier would be the best solution to this, but think that should be a separate ticket, and as mentioned taking a look at implementing a UI3 theme.

So for now, I think yeah, get this merged 🫡

bernaferrari commented 4 months ago

Ok, perfect. Thanks!

davestewart commented 4 months ago

OK. On to the next PR!