Skip to content

Commit

Permalink
Update README, fix retrieveColors/Texts which were wrong, fix small i…
Browse files Browse the repository at this point in the history
…ssue in padding calculation, update UI with revamped tabs and explanations!
  • Loading branch information
bernaferrari committed Jul 3, 2020
1 parent 84b1581 commit 6ef805d
Show file tree
Hide file tree
Showing 15 changed files with 503 additions and 17 deletions.
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<p align="center"><img src="assets/icon_256.png" alt="Figma to Code" height="128px"></p>
<!-- <p align="center"><img src="assets/icon_256.png" alt="Figma to Code" height="128px"></p> -->

![Figma to Code](assets/git_preview.png)

# Figma to Code

Expand All @@ -8,25 +10,25 @@
<a href="http://twitter.com/bernaferrari"><img src="https://img.shields.io/badge/Twitter-@bernaferrari-brightgreen.svg?style=flat" style="max-height: 300px;" alt="Twitter"/></a>
</p>



Most *design to code* plugins are bad, some are even paid. This project aims to raise the bar. This plugin generates responsive layouts in [Tailwind](https://tailwindcss.com/) and [Flutter](https://flutter.github.io/). The plan is to eventually add support for [Jetpack Compose](https://developer.android.com/jetpack/compose) and possibly standard HTML or other frameworks like [React Native](https://reactnative.dev/), [SwiftUI](https://developer.apple.com/xcode/swiftui/), [Bootstrap](https://getbootstrap.com/) or [Fluent](https://www.microsoft.com/design/fluent/). Feedback, ideas and partnerships are appreciated!
Most _design to code_ plugins are bad, some are even paid. This project aims to raise the bar by generating **responsive** layouts in [Tailwind](https://tailwindcss.com/) and [Flutter](https://flutter.github.io/). The plan is to eventually add support for [Jetpack Compose](https://developer.android.com/jetpack/compose) and possibly standard HTML or other frameworks like [React Native](https://reactnative.dev/), [SwiftUI](https://developer.apple.com/xcode/swiftui/), [Bootstrap](https://getbootstrap.com/) or [Fluent](https://www.microsoft.com/design/fluent/). Feedback, ideas and partnerships are appreciated!

![Gif showing the conversion](assets/lossy_gif.gif)

## How it works

This plugin takes an unconventional approach to improve code quality: it optimizes the layout before the conversion to code even begins. The standard Figma [Nodes](https://www.figma.com/plugin-docs/api/nodes/) (what represents each layer) was a joy to work with, but it can't modify a layer without modifying the user project. For this reason, I decided to virtualize it, remaking the official implementation and naming it `AltNodes`. During the process to convert a `Node` into an `AltNode`, the plugin does the following:
This plugin takes an unconventional approach to improve code quality: it optimizes the layout before the conversion to code even begins. The standard Figma [Nodes](https://www.figma.com/plugin-docs/api/nodes/) (what represents each layer) is a joy to work with, but it can't modify a layer without modifying the user project. For this reason, I decided to virtualize it, remaking the official implementation and naming them `AltNodes`. During the process to convert a `Node` into an `AltNode`, the plugin does the following:

![Conversion Workflow](assets/workflow.png)

That process can also be seen as an [Intermediate Representation](https://en.wikipedia.org/wiki/Intermediate_representation) and might allow this plugin to, one day, live outside Figma.

## Hard cases

When finding the unknown (a `Group` or `Frame` with more than one child and no vertical or horizontal alignment), Tailwind mode uses [insets](https://tailwindcss.com/docs/top-right-bottom-left/#app) for best cases and `left`, `top` from standard CSS for the worst cases. Flutter mode uses `Stack` and `Positioned.fill`. Both are usually not recommended and can easily defeat the responsiveness. In many scenarios, just wrapping some elements in a `Group` or `Frame` can solve:

![Conversion Workflow](assets/examples.png)

## Todo
### Todo

- Vectors (tricky in HTML, unsupported in Flutter)
- Images (they are local, how to support?)
Expand All @@ -48,11 +50,12 @@ When finding the unknown (a `Group` or `Frame` with more than one child and no v
- **Material Styles**: texts could be matched to existing Material styles (like outputting `Headline6` when text size is 20).
- **Identify FlatButtons**: the plugin could identify specific buttons and output them instead of always using `Container` or `Material`.

### How to build the project
## How to build the project

The project is configured to be built with Webpack or Rollup. The author couldn't find a way to correctly configure Svelte in Webpack, so Rollup was added. But Rollup is a lot less stable than Webpack and crashes regularly in watch mode when editing Typescript files. So, if you are going to work only Typescript, I reccommend sticking with Webpack. If you are going to make changes in the UI, you **need** to use Rollup for now.

## Issues

The Figma file for this README and icon is also open! [Check it here](https://www.figma.com/file/8buWpm6Mpq4yK9MhbkcdJB/Figma-to-Code).
It is hard to work alone. I took decisions thinking about how it would benefit the majority of people, but I can (and probably will!) be wrong many times. Found a bug? Have an idea for an improvement? Feel free to [add an issue](../../issues) or email me. Pull requests are also more than welcome.
The Figma file for this README and icon is also open and welcome to changes! [Check it here.](https://www.figma.com/file/8buWpm6Mpq4yK9MhbkcdJB/Figma-to-Code)

I took decisions thinking about how it would benefit the majority of people, but I can (and probably will!) be wrong many times. Found a bug? Have an idea for an improvement? Feel free to [add an issue](../../issues) or email me. Pull requests are also more than welcome.
Binary file added assets/git_preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icon_768.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions src/altNodes/convertToAutoLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export const convertToAutoLayout = (
node.children = reorderChildrenIfAligned(node.children);
const [direction, itemSpacing] = detectAutoLayoutDirection(node.children);

// if no direction was found, add an attribute that helps children know they should be have absolute position.
if (direction === "NONE" && node.children.length > 1) {
// catches when children is 0 or children is larger than 1
if (direction === "NONE" && node.children.length !== 1) {
return node;
}

Expand Down Expand Up @@ -221,7 +221,7 @@ const detectAutoLayoutPadding = (

// similar to [right] calculation, but using height and getting the minimum
const bottom = Math.min(
...node.children.map((d) => node.height - (d.height + d.x))
...node.children.map((d) => node.height - (d.height + d.y))
);

// return the smallest padding in each axis
Expand Down
2 changes: 1 addition & 1 deletion src/flutter/retrieveUI/retrieveColors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const convertColor = (
};

return {
hex: "#" + rgbTo6hex(fill.color),
hex: rgbTo6hex(fill.color),
contrastBlack: calculateContrastRatio(fill.color, black),
contrastWhite: calculateContrastRatio(fill.color, white),
};
Expand Down
2 changes: 1 addition & 1 deletion src/tailwind/retrieveUI/retrieveTexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const retrieveTailwindText = (
textStr.push({
name: node.name,
attr: attr.attributes,
full: `<p ${attr.attributes}>${charsWithLineBreak}</p>`,
full: `<p class="${attr.attributes}">${charsWithLineBreak}</p>`,
style: style(node),
contrastBlack: contrastBlack,
});
Expand Down
7 changes: 6 additions & 1 deletion src/ui/Main.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
import { fade, fly } from "svelte/transition";
import { Tabs, Tab, TabList, TabPanel } from "svelte-tabs";
import { Tabs, Tab, TabList, TabPanel } from "./svelte-tabs/index";
import copy from "clipboard-copy";
Expand All @@ -20,6 +20,11 @@
});
}
import { Switch } from "figma-plugin-ds-svelte";
//use bind:group, with a var to create a radio group and store the value of selected item
//set value if this var to same value as radio item to set initial selection
var switchValue;
import ScreenTailwind from "./ScreenTailwind.svelte";
import ScreenFlutter from "./ScreenFlutter.svelte";
import ScreenAbout from "./ScreenAbout.svelte";
Expand Down
136 changes: 135 additions & 1 deletion src/ui/ScreenFlutter.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,141 @@
});
</script>

<div class="px-2">
<div class="bg-gray-100 p-2 flex flex-col items-center">

<div class="flex">

<svg
class="h-8 w-1/4 m-auto"
viewBox="0 0 415 168"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path
d="M46.9871 130.148L97.7505 79.373H60.839L28.5371 111.687L46.9871
130.148Z"
fill="#39CEFD" />
<path
d="M0.844727 83.9942L60.8389 24H97.7505L19.3063 102.456L0.844727
83.9942Z"
fill="#39CEFD" />
<path
d="M60.8392 143.988H97.7508L65.4488 111.686L46.9873 130.148L60.8392
143.988Z"
fill="#03569B" />
<path
d="M28.5347 111.679L46.9967 93.2173L65.4598 111.679L46.9967
130.141L28.5347 111.679Z"
fill="#16B9FD" />
<path
d="M97.7505 79.3731L65.4485 111.687L97.7505 144H60.8389L28.5255
111.687L60.8389 79.3731H97.7505ZM60.8389 24L0.844727 83.9942L19.3063
102.456L97.7505 24H60.8389Z"
fill="url(#paint0_radial)" />
<path
d="M139.097
49.1748H179.146V57.0073H147.225V80.7044H176.043V88.4408H147.225V118.422H139.097V49.1748ZM188.837
49.1748H197.057V118.426H188.837V49.1748ZM227.131 119.974C221.2 119.974
216.644 118.233 213.461 114.75C210.387 111.245 208.85 106.377 208.85
100.145V69.0997H217.071V98.8891C217.071 103.569 218.135 107.017
220.263 109.234C222.391 111.451 225.261 112.559 228.871
112.559C231.645 112.559 234.108 111.818 236.261 110.335C238.477
108.852 240.152 106.919 241.285 104.534C242.509 102.145 243.121
99.6305 243.121
96.9901V69.1329H251.338V118.456H243.506V111.266H243.118C241.763
113.717 239.603 115.779 236.637 117.454C233.672 119.129 230.512
119.967 227.157 119.967L227.131 119.974Z"
fill="#696969" />
<path
d="M282.978 119.202C280.978 119.202 279.109 118.88 277.37
118.234C275.695 117.589 274.276 116.718 273.114 115.622C271.823
114.398 270.856 112.979 270.214 111.366C269.568 109.755 269.246
107.788 269.246
105.466V76.5482H260.637V69.1H269.246V55.1714H277.466V69.1H289.459V76.5482H277.466V103.437C277.466
106.147 277.983 108.146 279.018 109.434C280.242 110.852 282.015
111.562 284.338 111.562C286.21 111.562 288.015 111.014 289.754
109.918V117.946C288.786 118.397 287.786 118.719 286.754
118.914C285.786 119.111 284.53 119.21 282.986 119.21L282.978 119.202Z"
fill="#696969" />
<path
d="M317.841 119.202C315.841 119.202 313.971 118.88 312.232
118.234C310.557 117.589 309.139 116.718 307.976 115.622C306.685
114.398 305.719 112.979 305.076 111.366C304.431 109.755 304.108
107.788 304.108
105.466V76.5482H295.5V69.1H304.108V55.1714H312.328V69.1H324.321V76.5482H312.328V103.437C312.328
106.147 312.846 108.146 313.88 109.434C315.104 110.852 316.878 111.562
319.2 111.562C321.072 111.562 322.878 111.014 324.617
109.918V117.946C323.649 118.397 322.649 118.719 321.617
118.914C320.649 119.111 319.392 119.21 317.848 119.21L317.841 119.202Z"
fill="#696969" />
<path
d="M354.047 119.975C349.368 119.975 345.144 118.847 341.375
116.591C337.636 114.334 334.703 111.24 332.575 107.306C330.511 103.308
329.479 98.8257 329.479 93.8577C329.479 89.0868 330.445 84.7026
332.379 80.705C334.379 76.7075 337.184 73.5154 340.795 71.1287C344.406
68.7395 348.597 67.5449 353.368 67.5449C358.203 67.5449 362.394
68.6533 365.94 70.87C369.487 72.9981 372.196 75.9636 374.068
79.7666C376.002 83.572 376.969 87.9242 376.969 92.8233C376.969 93.7912
376.87 94.6287 376.673 95.3356H337.695C337.892 99.0745 338.795 102.235
340.403 104.816C342.014 107.395 344.046 109.328 346.499
110.616C349.012 111.907 351.623 112.552 354.332 112.552C360.652
112.552 365.52 109.587 368.937 103.656L375.901 107.04C373.773 111.038
370.871 114.198 367.196 116.52C363.586 118.84 359.201 120.001 354.044
120.001L354.047 119.975ZM368.264 88.5412C368.136 86.4772 367.557
84.4144 366.528 82.3528C365.493 80.2888 363.849 78.5474 361.596
77.1287C359.379 75.7099 356.608 75.0006 353.283 75.0006C349.416
75.0006 346.128 76.2567 343.418 78.7691C340.775 81.2198 339.034 84.476
338.194 88.5375H368.275L368.264 88.5412ZM386.493
69.1003H394.326V77.0326H394.714C395.682 74.3232 397.551 72.0991
400.322 70.3602C403.095 68.5548 405.997 67.6521 409.027
67.6521C411.283 67.6521 413.216 67.9747 414.827 68.62V77.5166C412.763
76.4821 410.442 75.9649 407.863 75.9649C405.474 75.9649 403.281
76.6422 401.286 77.9969C399.286 79.3516 397.685 81.189 396.483
83.5092C395.326 85.7654 394.747 88.2284 394.747
90.8984V118.46H386.527V69.1373L386.493 69.1003Z"
fill="#696969" />
</g>
<defs>
<radialGradient
id="paint0_radial"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(3.56714 32.1788) scale(146.805)">
<stop stop-color="white" stop-opacity="0.1" />
<stop offset="1" stop-color="white" stop-opacity="0" />
</radialGradient>
<clipPath id="clip0">
<rect
width="413.982"
height="168"
fill="white"
transform="translate(0.844727)" />
</clipPath>
</defs>
</svg>

<p class="mx-2 w-3/4 text-md tracking-tight leading-tight">
Flutter is Google’s UI toolkit for building applications for
<a class="text-blue-500 font-medium" href="https://tailwindcss.com/">
mobile, web, and desktop from a single codebase.
</a>
You can test your creations by pasting them here:
</p>
</div>

<a href="https://codepen.io/bernardoferrari/pen/pogpBLB" target="_blank">
<button
class="mt-2 bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2
px-4 border border-gray-400 rounded shadow">
Flutter on CodePen
</button>
</a>

</div>

<div class="px-2 pt-2">

{#if emptySelection}
<div
Expand Down
116 changes: 115 additions & 1 deletion src/ui/ScreenTailwind.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,121 @@
});
</script>

<div class="px-2">
<div>
<div class="bg-gray-100 p-2 flex flex-col items-center">

<div class="flex">
<svg
class="h-8 w-1/4 m-auto"
viewBox="0 0 273 64"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<title>Tailwind CSS</title>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M32 16C24.8 16 20.3 19.6 18.5 26.8C21.2 23.2 24.35 21.85 27.95
22.75C30.004 23.2635 31.4721 24.7536 33.0971 26.4031C35.7443 29.0901
38.8081 32.2 45.5 32.2C52.7 32.2 57.2 28.6 59 21.4C56.3 25 53.15 26.35
49.55 25.45C47.496 24.9365 46.0279 23.4464 44.4029 21.7969C41.7557
19.1099 38.6919 16 32 16ZM18.5 32.2C11.3 32.2 6.8 35.8 5 43C7.7 39.4
10.85 38.05 14.45 38.95C16.504 39.4635 17.9721 40.9536 19.5971
42.6031C22.2443 45.2901 25.3081 48.4 32 48.4C39.2 48.4 43.7 44.8 45.5
37.6C42.8 41.2 39.65 42.55 36.05 41.65C33.996 41.1365 32.5279 39.6464
30.9029 37.9969C28.2557 35.3099 25.1919 32.2 18.5 32.2Z"
fill="url(#paint0_linear)" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M85.996 29.652H81.284V38.772C81.284 41.204 82.88 41.166 85.996
41.014V44.7C79.688 45.46 77.18 43.712 77.18
38.772V29.652H73.684V25.7H77.18V20.596L81.284
19.38V25.7H85.996V29.652ZM103.958
25.7H108.062V44.7H103.958V41.964C102.514 43.978 100.272 45.194 97.308
45.194C92.14 45.194 87.846 40.824 87.846 35.2C87.846 29.538 92.14
25.206 97.308 25.206C100.272 25.206 102.514 26.422 103.958
28.398V25.7ZM97.954 41.28C101.374 41.28 103.958 38.734 103.958
35.2C103.958 31.666 101.374 29.12 97.954 29.12C94.534 29.12 91.95
31.666 91.95 35.2C91.95 38.734 94.534 41.28 97.954 41.28ZM114.902
22.85C113.458 22.85 112.28 21.634 112.28 20.228C112.28 18.784 113.458
17.606 114.902 17.606C116.346 17.606 117.524 18.784 117.524
20.228C117.524 21.634 116.346 22.85 114.902 22.85ZM112.85
44.7V25.7H116.954V44.7H112.85ZM121.704
44.7V16.96H125.808V44.7H121.704ZM152.446 25.7H156.778L150.812
44.7H146.784L142.832 31.894L138.842 44.7H134.814L128.848
25.7H133.18L136.866 38.81L140.856 25.7H144.77L148.722 38.81L152.446
25.7ZM161.87 22.85C160.426 22.85 159.248 21.634 159.248 20.228C159.248
18.784 160.426 17.606 161.87 17.606C163.314 17.606 164.492 18.784
164.492 20.228C164.492 21.634 163.314 22.85 161.87 22.85ZM159.818
44.7V25.7H163.922V44.7H159.818ZM178.666 25.206C182.922 25.206 185.962
28.094 185.962 33.034V44.7H181.858V33.452C181.858 30.564 180.186
29.044 177.602 29.044C174.904 29.044 172.776 30.64 172.776
34.516V44.7H168.672V25.7H172.776V28.132C174.03 26.156 176.082 25.206
178.666 25.206ZM205.418 18.1H209.522V44.7H205.418V41.964C203.974
43.978 201.732 45.194 198.768 45.194C193.6 45.194 189.306 40.824
189.306 35.2C189.306 29.538 193.6 25.206 198.768 25.206C201.732 25.206
203.974 26.422 205.418 28.398V18.1ZM199.414 41.28C202.834 41.28
205.418 38.734 205.418 35.2C205.418 31.666 202.834 29.12 199.414
29.12C195.994 29.12 193.41 31.666 193.41 35.2C193.41 38.734 195.994
41.28 199.414 41.28ZM223.278 45.194C217.54 45.194 213.246 40.824
213.246 35.2C213.246 29.538 217.54 25.206 223.278 25.206C227.002
25.206 230.232 27.144 231.752 30.108L228.218 32.16C227.382 30.374
225.52 29.234 223.24 29.234C219.896 29.234 217.35 31.78 217.35
35.2C217.35 38.62 219.896 41.166 223.24 41.166C225.52 41.166 227.382
39.988 228.294 38.24L231.828 40.254C230.232 43.256 227.002 45.194
223.278 45.194ZM238.592 30.944C238.592 34.402 248.814 32.312 248.814
39.342C248.814 43.142 245.508 45.194 241.404 45.194C237.604 45.194
234.868 43.484 233.652 40.748L237.186 38.696C237.794 40.406 239.314
41.432 241.404 41.432C243.228 41.432 244.634 40.824 244.634
39.304C244.634 35.922 234.412 37.822 234.412 31.02C234.412 27.448
237.49 25.206 241.366 25.206C244.482 25.206 247.066 26.65 248.396
29.158L244.938 31.096C244.254 29.614 242.924 28.93 241.366
28.93C239.884 28.93 238.592 29.576 238.592 30.944ZM256.11
30.944C256.11 34.402 266.332 32.312 266.332 39.342C266.332 43.142
263.026 45.194 258.922 45.194C255.122 45.194 252.386 43.484 251.17
40.748L254.704 38.696C255.312 40.406 256.832 41.432 258.922
41.432C260.746 41.432 262.152 40.824 262.152 39.304C262.152 35.922
251.93 37.822 251.93 31.02C251.93 27.448 255.008 25.206 258.884
25.206C262 25.206 264.584 26.65 265.914 29.158L262.456 31.096C261.772
29.614 260.442 28.93 258.884 28.93C257.402 28.93 256.11 29.576 256.11
30.944Z"
fill="#2D3748" />
<defs>
<linearGradient
id="paint0_linear"
x1="3.5"
y1="16"
x2="59"
y2="48"
gradientUnits="userSpaceOnUse">
<stop stop-color="#2298BD" />
<stop offset="1" stop-color="#0ED7B5" />

</linearGradient>
</defs>
</svg>
<p class="mx-2 w-3/4 text-md tracking-tight leading-tight">
Tailwind is a utility-first CSS framework for
<a class="text-teal-500 font-medium" href="https://tailwindcss.com/">
rapidly building custom designs and responsive pages.
</a>
You can test your creations by pasting them here:
</p>
</div>

<a href="https://codepen.io/bernardoferrari/pen/mdVBJxe" target="_blank">
<button
class="mt-2 bg-white hover:bg-gray-100 text-gray-800
font-semibold py-2 px-4 border border-gray-400 rounded shadow">
Tailwind on CodePen
</button>
</a>

</div>

</div>

<div class="px-2 pt-2">

{#if emptySelection}
<div
Expand Down
Loading

0 comments on commit 6ef805d

Please sign in to comment.