Skip to content

Commit 378bd93

Browse files
Enhance Tailwind Configuration and Color Handling (#143)
- Added checks for pure black and white colors in getColorInfo function to return appropriate Tailwind color names and hex values. - Introduced fontWeight and fontFamily configurations in tailwindConfig for better management of font styles. - Refactored fontWeight and fontFamily methods in TailwindTextBuilder to utilize the new configuration. - Improved shadow handling in tailwindShadow to support various shadow types and conditions, including custom shadow values. These changes streamline the Tailwind class generation process and enhance the overall functionality of the Figma plugin. Co-authored-by: Mario <[email protected]>
1 parent 3db5f61 commit 378bd93

File tree

5 files changed

+184
-72
lines changed

5 files changed

+184
-72
lines changed

packages/backend/src/tailwind/builderImpl/tailwindShadow.ts

Lines changed: 111 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,120 @@
55
export const tailwindShadow = (node: BlendMixin): string[] => {
66
// [when testing] node.effects can be undefined
77
if (node.effects && node.effects.length > 0) {
8-
const dropShadow = node.effects.filter(
9-
(d) => d.type === "DROP_SHADOW" && d.visible,
10-
);
11-
let boxShadow = "";
12-
// simple shadow from tailwind
13-
if (dropShadow.length > 0) {
14-
boxShadow = "shadow";
15-
}
8+
const EPSILON = 0.0001; // Small tolerance for floating-point comparison
169

17-
const innerShadow =
18-
node.effects.filter((d) => d.type === "INNER_SHADOW").length > 0
19-
? "shadow-inner"
20-
: "";
10+
const dropShadow = node.effects.map((d) => {
11+
if (d.type === "DROP_SHADOW") {
12+
if (
13+
d.offset?.x === 0 &&
14+
d.offset?.y === 1 &&
15+
d.radius === 2 &&
16+
d.spread === 0 &&
17+
d.color?.r === 0 &&
18+
d.color?.g === 0 &&
19+
d.color?.b === 0 &&
20+
Math.abs(d.color?.a - 0.05) < EPSILON
21+
) {
22+
return "shadow-sm";
23+
} else if (
24+
d.offset?.x === 0 &&
25+
d.offset?.y === 1 &&
26+
d.radius === 3 &&
27+
d.spread === 0 &&
28+
d.color?.r === 0 &&
29+
d.color?.g === 0 &&
30+
d.color?.b === 0 &&
31+
Math.abs(d.color?.a - 0.1) < EPSILON
32+
) {
33+
return "shadow";
34+
} else if (
35+
d.offset?.x === 0 &&
36+
d.offset?.y === 4 &&
37+
d.radius === 6 &&
38+
d.spread === -1 &&
39+
d.color?.r === 0 &&
40+
d.color?.g === 0 &&
41+
d.color?.b === 0 &&
42+
Math.abs(d.color?.a - 0.1) < EPSILON
43+
) {
44+
return "shadow-md";
45+
} else if (
46+
d.offset?.x === 0 &&
47+
d.offset?.y === 10 &&
48+
d.radius === 15 &&
49+
d.spread === -3 &&
50+
d.color?.r === 0 &&
51+
d.color?.g === 0 &&
52+
d.color?.b === 0 &&
53+
Math.abs(d.color?.a - 0.1) < EPSILON
54+
) {
55+
return "shadow-lg";
56+
} else if (
57+
d.offset?.x === 0 &&
58+
d.offset?.y === 20 &&
59+
d.radius === 25 &&
60+
d.spread === -5 &&
61+
d.color?.r === 0 &&
62+
d.color?.g === 0 &&
63+
d.color?.b === 0 &&
64+
Math.abs(d.color?.a - 0.1) < EPSILON
65+
) {
66+
return "shadow-xl";
67+
} else if (
68+
d.offset?.x === 0 &&
69+
d.offset?.y === 25 &&
70+
d.radius === 50 &&
71+
d.spread === -12 &&
72+
d.color?.r === 0 &&
73+
d.color?.g === 0 &&
74+
d.color?.b === 0 &&
75+
Math.abs(d.color?.a - 0.25) < EPSILON
76+
) {
77+
return "shadow-2xl";
78+
} else {
79+
const offsetX = d.offset?.x || 0;
80+
const offsetY = d.offset?.y || 0;
81+
const radius = d.radius || 0;
82+
const spread = d.spread || 0;
83+
const r = Math.round((d.color?.r || 0) * 255);
84+
const g = Math.round((d.color?.g || 0) * 255);
85+
const b = Math.round((d.color?.b || 0) * 255);
86+
const a = (d.color?.a || 0).toFixed(2); // Limit alpha to 2 decimal, otherwise we will get values like 0.12356587999
87+
return `shadow-[${offsetX}px_${offsetY}px_${radius}px_${spread}px_rgba(${r},${g},${b},${a})]`;
88+
}
89+
}
90+
return "";
91+
}).filter(Boolean);
2192

22-
return [boxShadow, innerShadow];
93+
const innerShadow = node.effects.map((d) => {
94+
if (d.type === "INNER_SHADOW") {
95+
if (
96+
d.offset?.x === 0 &&
97+
d.offset?.y === 2 &&
98+
d.radius === 4 &&
99+
d.spread === 0 &&
100+
d.color?.r === 0 &&
101+
d.color?.g === 0 &&
102+
d.color?.b === 0 &&
103+
Math.abs(d.color?.a - 0.05) < EPSILON
104+
) {
105+
return "shadow-inner";
106+
} else {
107+
const offsetX = d.offset?.x || 0;
108+
const offsetY = d.offset?.y || 0;
109+
const radius = d.radius || 0;
110+
const spread = d.spread || 0;
111+
const r = Math.round((d.color?.r || 0) * 255);
112+
const g = Math.round((d.color?.g || 0) * 255);
113+
const b = Math.round((d.color?.b || 0) * 255);
114+
const a = (d.color?.a || 0).toFixed(2); // Limit alpha to 2 decimal, otherwise we will get values like 0.12356587999
115+
return `shadow-[inset_${offsetX}px_${offsetY}px_${radius}px_${spread}px_rgba(${r},${g},${b},${a})]`;
116+
}
117+
}
118+
return "";
119+
}).filter(Boolean);
23120

24-
// todo customize the shadow
25-
// TODO layer blur, shadow-outline
121+
return [...dropShadow, ...innerShadow];
26122
}
27123
return [];
28124
};

packages/backend/src/tailwind/conversionTables.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,25 @@ export function getColorInfo(fill: SolidPaint | ColorStop) {
132132
let hex: string = "#" + rgbTo6hex(fill.color);
133133
let meta: string = "";
134134

135+
// Check for pure black/white first
136+
if (fill.color.r === 0 && fill.color.g === 0 && fill.color.b === 0) {
137+
return {
138+
colorType: "tailwind",
139+
colorName: "black",
140+
hex: "#000000",
141+
meta: ''
142+
};
143+
}
144+
145+
if (fill.color.r === 1 && fill.color.g === 1 && fill.color.b === 1) {
146+
return {
147+
colorType: "tailwind",
148+
colorName: "white",
149+
hex: "#ffffff",
150+
meta: ''
151+
};
152+
}
153+
135154
// variable
136155
if (
137156
localTailwindSettings.customTailwindColors &&

packages/backend/src/tailwind/tailwindConfig.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const letterSpacing = {
9090
const blur = {
9191
0: "none",
9292
4: "sm",
93-
8: "",
93+
8: "blur", // This is not the official Tailwind class name suffix, but currently needed for the blurValue variable to work.
9494
12: "md",
9595
16: "lg",
9696
24: "xl",
@@ -347,6 +347,48 @@ const color: Record<string, string> = {
347347
"#4c0519": "rose-950",
348348
};
349349

350+
const fontWeight: Record<number, string> = {
351+
100: "thin",
352+
200: "extralight",
353+
300: "light",
354+
400: "normal",
355+
500: "medium",
356+
600: "semibold",
357+
700: "bold",
358+
800: "extrabold",
359+
900: "black"
360+
};
361+
362+
const fontFamily = {
363+
sans: [
364+
'ui-sans-serif',
365+
'system-ui',
366+
'sans-serif',
367+
'Apple Color Emoji',
368+
'Segoe UI Emoji',
369+
'Segoe UI Symbol',
370+
'Noto Color Emoji'
371+
],
372+
serif: [
373+
'ui-serif',
374+
'Georgia',
375+
'Cambria',
376+
'Times New Roman',
377+
'Times',
378+
'serif'
379+
],
380+
mono: [
381+
'ui-monospace',
382+
'SFMono-Regular',
383+
'Menlo',
384+
'Monaco',
385+
'Consolas',
386+
'Liberation Mono',
387+
'Courier New',
388+
'monospace'
389+
]
390+
};
391+
350392
export const config = {
351393
layoutSize,
352394
borderRadius,
@@ -356,4 +398,6 @@ export const config = {
356398
blur,
357399
opacity,
358400
color,
401+
fontWeight,
402+
fontFamily,
359403
};

packages/backend/src/tailwind/tailwindDefaultBuilder.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,9 @@ export class TailwindDefaultBuilder {
216216
if (blur) {
217217
const blurValue = pxToBlur(blur.radius);
218218
if (blurValue) {
219-
this.addAttributes(`blur${blurValue ? `-${blurValue}` : ""}`);
219+
this.addAttributes(
220+
blurValue === "blur" ? "blur" : `blur-${blurValue}`
221+
); // If blur value is 8, it will be "blur". Otherwise, it will be "blur-sm", "blur-md", etc. or "blur-[Xpx]"
220222
}
221223
}
222224

packages/backend/src/tailwind/tailwindTextBuilder.ts

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
pxToLineHeight,
1111
} from "./conversionTables";
1212
import { TailwindDefaultBuilder } from "./tailwindDefaultBuilder";
13+
import { config } from "./tailwindConfig";
1314

1415
export class TailwindTextBuilder extends TailwindDefaultBuilder {
1516
getTextSegments(id: string): { style: string; text: string }[] {
@@ -65,28 +66,8 @@ export class TailwindTextBuilder extends TailwindDefaultBuilder {
6566
};
6667

6768
fontWeight = (fontWeight: number): string => {
68-
switch (fontWeight) {
69-
case 100:
70-
return "font-thin";
71-
case 200:
72-
return "font-extralight";
73-
case 300:
74-
return "font-light";
75-
case 400:
76-
return "font-normal";
77-
case 500:
78-
return "font-medium";
79-
case 600:
80-
return "font-semibold";
81-
case 700:
82-
return "font-bold";
83-
case 800:
84-
return "font-extrabold";
85-
case 900:
86-
return "font-black";
87-
default:
88-
return "";
89-
}
69+
const weight = config.fontWeight[fontWeight];
70+
return weight ? `font-${weight}` : "";
9071
};
9172

9273
indentStyle = (indentation: number) => {
@@ -97,43 +78,13 @@ export class TailwindTextBuilder extends TailwindDefaultBuilder {
9778
};
9879

9980
fontFamily = (fontName: FontName): string => {
100-
const sansSerif = [
101-
'ui-sans-serif',
102-
'system-ui',
103-
'sans-serif',
104-
'Apple Color Emoji',
105-
'Segoe UI Emoji',
106-
'Segoe UI Symbol',
107-
'Noto Color Emoji'
108-
];
109-
110-
const serif = [
111-
'ui-serif',
112-
'Georgia',
113-
'Cambria',
114-
'Times New Roman',
115-
'Times',
116-
'serif'
117-
];
118-
119-
const mono = [
120-
'ui-monospace',
121-
'SFMono-Regular',
122-
'Menlo',
123-
'Monaco',
124-
'Consolas',
125-
'Liberation Mono',
126-
'Courier New',
127-
'monospace'
128-
];
129-
130-
if (sansSerif.includes(fontName.family)) {
81+
if (config.fontFamily.sans.includes(fontName.family)) {
13182
return 'font-sans';
13283
}
133-
if (serif.includes(fontName.family)) {
84+
if (config.fontFamily.serif.includes(fontName.family)) {
13485
return 'font-serif';
13586
}
136-
if (mono.includes(fontName.family)) {
87+
if (config.fontFamily.mono.includes(fontName.family)) {
13788
return 'font-mono';
13889
}
13990

0 commit comments

Comments
 (0)