Skip to content

Commit e85ebf5

Browse files
committed
Fix gradient
1 parent 78d2232 commit e85ebf5

File tree

1 file changed

+148
-54
lines changed

1 file changed

+148
-54
lines changed

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

Lines changed: 148 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,11 @@ export const tailwindSolidColor = (
7373

7474
// In Tailwind v4, we always use the slash syntax for opacity
7575
// In Tailwind v3, we use opacity utilities for standard colors and slash syntax for arbitrary values
76-
if (localTailwindSettings.useTailwind4 || colorName.startsWith('[')) {
76+
if (localTailwindSettings.useTailwind4 || colorName.startsWith("[")) {
7777
// Only add opacity suffix if it's not 1.0
78-
const opacity = effectiveOpacity !== 1.0
79-
? `/${nearestOpacity(effectiveOpacity)}`
80-
: "";
81-
78+
const opacity =
79+
effectiveOpacity !== 1.0 ? `/${nearestOpacity(effectiveOpacity)}` : "";
80+
8281
return `${kind}-${colorName}${opacity}`;
8382
} else {
8483
// Tailwind v3 - use separate opacity utilities for standard colors
@@ -176,7 +175,7 @@ export const tailwindGradientFromFills = (
176175
return "";
177176
}
178177
}
179-
178+
180179
return "";
181180
};
182181

@@ -192,42 +191,48 @@ const tailwindArbitraryGradient = (cssGradient: string): string => {
192191
};
193192

194193
/**
195-
* Maps an angle to a gradient direction class for both Tailwind 3 and 4
194+
* Maps an angle to a gradient direction class
196195
* @param angle The angle in degrees
197-
* @param useTailwind4 Whether to use Tailwind 4 syntax
198196
* @returns The appropriate gradient direction class
199197
*/
200-
const directionMap: Record<number, { tailwind3: string; tailwind4: string }> = {
201-
0: { tailwind3: "bg-gradient-to-r", tailwind4: "bg-linear-to-r" },
202-
45: { tailwind3: "bg-gradient-to-br", tailwind4: "bg-linear-to-br" },
203-
90: { tailwind3: "bg-gradient-to-b", tailwind4: "bg-linear-to-b" },
204-
135: { tailwind3: "bg-gradient-to-bl", tailwind4: "bg-linear-to-bl" },
205-
"-45": { tailwind3: "bg-gradient-to-tr", tailwind4: "bg-linear-to-tr" },
206-
"-90": { tailwind3: "bg-gradient-to-t", tailwind4: "bg-linear-to-t" },
207-
"-135": { tailwind3: "bg-gradient-to-tl", tailwind4: "bg-linear-to-tl" },
208-
180: { tailwind3: "bg-gradient-to-l", tailwind4: "bg-linear-to-l" },
198+
const directionMap: Record<number, string> = {
199+
0: "bg-gradient-to-r",
200+
45: "bg-gradient-to-br",
201+
90: "bg-gradient-to-b",
202+
135: "bg-gradient-to-bl",
203+
"-45": "bg-gradient-to-tr",
204+
"-90": "bg-gradient-to-t",
205+
"-135": "bg-gradient-to-tl",
206+
180: "bg-gradient-to-l",
209207
};
210208

211-
function getGradientDirectionClass(angle: number, useTailwind4: boolean): string {
212-
let snappedAngle = nearestValue(angle, [
213-
0, 45, 90, 135, 180, -45, -90, -135, -180,
214-
]);
215-
if (snappedAngle === -180) snappedAngle = 180;
209+
function getGradientDirectionClass(
210+
angle: number,
211+
useTailwind4: boolean,
212+
): string {
213+
const angleValues = [0, 45, 90, 135, 180, -45, -90, -135, -180];
216214

217-
// Check if angle is in the map
218-
const entry = directionMap[snappedAngle];
219-
if (entry) {
220-
return useTailwind4 ? entry.tailwind4 : entry.tailwind3;
221-
}
222-
223215
// For non-standard angles in Tailwind 4, use exact angle
224216
if (useTailwind4) {
217+
const roundedAngle = Math.round(angle);
218+
if (angleValues.includes(roundedAngle)) {
219+
return directionMap[roundedAngle];
220+
}
221+
225222
const exactAngle = Math.round(((angle % 360) + 360) % 360);
226223
return `bg-linear-${exactAngle}`;
227224
}
228225

229-
// Fallback for Tailwind 3 (nearest standard direction)
230-
return snappedAngle === 180 ? "bg-gradient-to-l" : "bg-gradient-to-r";
226+
let snappedAngle = nearestValue(angle, angleValues);
227+
if (snappedAngle === -180) snappedAngle = 180;
228+
229+
// Check if angle is in the map
230+
const entry = directionMap[snappedAngle];
231+
if (entry) {
232+
return entry;
233+
}
234+
235+
return "bg-gradient-to-r";
231236
}
232237

233238
/**
@@ -253,7 +258,7 @@ const getStopPositionModifier = (
253258
stopPosition: number,
254259
expectedPosition: number,
255260
unit: string = "%",
256-
multiplier: number = 100
261+
multiplier: number = 100,
257262
): string => {
258263
if (needsPositionOverride(stopPosition, expectedPosition)) {
259264
const position = Math.round(stopPosition * multiplier);
@@ -278,7 +283,7 @@ function generateGradientStop(
278283
globalOpacity: number = 1.0,
279284
expectedPosition: number,
280285
unit: string = "%",
281-
multiplier: number = 100
286+
multiplier: number = 100,
282287
): string {
283288
const colorValue = tailwindGradientStop(stop, globalOpacity);
284289
const colorPart = `${prefix}-${colorValue}`;
@@ -292,33 +297,60 @@ function generateGradientStop(
292297
stop.position,
293298
expectedPosition,
294299
unit,
295-
multiplier
300+
multiplier,
296301
);
297-
return positionModifier ? `${colorPart} ${prefix}${positionModifier}` : colorPart;
302+
return positionModifier
303+
? `${colorPart} ${prefix}${positionModifier}`
304+
: colorPart;
298305
}
299306

300307
export const tailwindGradient = (fill: GradientPaint): string => {
301308
const globalOpacity = fill.opacity ?? 1.0;
302309
const direction = getGradientDirectionClass(
303310
gradientAngle(fill),
304-
localTailwindSettings.useTailwind4
311+
localTailwindSettings.useTailwind4,
305312
);
306313

307314
if (fill.gradientStops.length === 1) {
308-
const fromStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0);
315+
const fromStop = generateGradientStop(
316+
"from",
317+
fill.gradientStops[0],
318+
globalOpacity,
319+
0,
320+
);
309321
return [direction, fromStop].filter(Boolean).join(" ");
310322
} else if (fill.gradientStops.length === 2) {
311-
const firstStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0);
312-
const lastStop = generateGradientStop("to", fill.gradientStops[1], globalOpacity, 1);
323+
const firstStop = generateGradientStop(
324+
"from",
325+
fill.gradientStops[0],
326+
globalOpacity,
327+
0,
328+
);
329+
const lastStop = generateGradientStop(
330+
"to",
331+
fill.gradientStops[1],
332+
globalOpacity,
333+
1,
334+
);
313335
return [direction, firstStop, lastStop].filter(Boolean).join(" ");
314336
} else {
315-
const firstStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0);
316-
const viaStop = generateGradientStop("via", fill.gradientStops[1], globalOpacity, 0.5);
337+
const firstStop = generateGradientStop(
338+
"from",
339+
fill.gradientStops[0],
340+
globalOpacity,
341+
0,
342+
);
343+
const viaStop = generateGradientStop(
344+
"via",
345+
fill.gradientStops[1],
346+
globalOpacity,
347+
0.5,
348+
);
317349
const lastStop = generateGradientStop(
318350
"to",
319351
fill.gradientStops[fill.gradientStops.length - 1],
320352
globalOpacity,
321-
1
353+
1,
322354
);
323355
return [direction, firstStop, viaStop, lastStop].filter(Boolean).join(" ");
324356
}
@@ -333,23 +365,50 @@ const tailwindRadialGradient = (fill: GradientPaint): string => {
333365
const cx = Math.round(center.x * 100);
334366
const cy = Math.round(center.y * 100);
335367
const isCustomPosition = Math.abs(cx - 50) > 5 || Math.abs(cy - 50) > 5;
336-
const baseClass = isCustomPosition ? `bg-radial-[at_${cx}%_${cy}%]` : "bg-radial";
368+
const baseClass = isCustomPosition
369+
? `bg-radial-[at_${cx}%_${cy}%]`
370+
: "bg-radial";
337371

338372
if (fill.gradientStops.length === 1) {
339-
const fromStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0);
373+
const fromStop = generateGradientStop(
374+
"from",
375+
fill.gradientStops[0],
376+
globalOpacity,
377+
0,
378+
);
340379
return [baseClass, fromStop].filter(Boolean).join(" ");
341380
} else if (fill.gradientStops.length === 2) {
342-
const firstStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0);
343-
const lastStop = generateGradientStop("to", fill.gradientStops[1], globalOpacity, 1);
381+
const firstStop = generateGradientStop(
382+
"from",
383+
fill.gradientStops[0],
384+
globalOpacity,
385+
0,
386+
);
387+
const lastStop = generateGradientStop(
388+
"to",
389+
fill.gradientStops[1],
390+
globalOpacity,
391+
1,
392+
);
344393
return [baseClass, firstStop, lastStop].filter(Boolean).join(" ");
345394
} else {
346-
const firstStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0);
347-
const viaStop = generateGradientStop("via", fill.gradientStops[1], globalOpacity, 0.5);
395+
const firstStop = generateGradientStop(
396+
"from",
397+
fill.gradientStops[0],
398+
globalOpacity,
399+
0,
400+
);
401+
const viaStop = generateGradientStop(
402+
"via",
403+
fill.gradientStops[1],
404+
globalOpacity,
405+
0.5,
406+
);
348407
const lastStop = generateGradientStop(
349408
"to",
350409
fill.gradientStops[fill.gradientStops.length - 1],
351410
globalOpacity,
352-
1
411+
1,
353412
);
354413
return [baseClass, firstStop, viaStop, lastStop].filter(Boolean).join(" ");
355414
}
@@ -376,22 +435,57 @@ const tailwindConicGradient = (fill: GradientPaint): string => {
376435
}
377436

378437
if (fill.gradientStops.length === 1) {
379-
const fromStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0, "deg", 360);
438+
const fromStop = generateGradientStop(
439+
"from",
440+
fill.gradientStops[0],
441+
globalOpacity,
442+
0,
443+
"deg",
444+
360,
445+
);
380446
return [baseClass, fromStop].filter(Boolean).join(" ");
381447
} else if (fill.gradientStops.length === 2) {
382-
const firstStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0, "deg", 360);
383-
const lastStop = generateGradientStop("to", fill.gradientStops[1], globalOpacity, 1, "deg", 360);
448+
const firstStop = generateGradientStop(
449+
"from",
450+
fill.gradientStops[0],
451+
globalOpacity,
452+
0,
453+
"deg",
454+
360,
455+
);
456+
const lastStop = generateGradientStop(
457+
"to",
458+
fill.gradientStops[1],
459+
globalOpacity,
460+
1,
461+
"deg",
462+
360,
463+
);
384464
return [baseClass, firstStop, lastStop].filter(Boolean).join(" ");
385465
} else {
386-
const firstStop = generateGradientStop("from", fill.gradientStops[0], globalOpacity, 0, "deg", 360);
387-
const viaStop = generateGradientStop("via", fill.gradientStops[1], globalOpacity, 0.5, "deg", 360);
466+
const firstStop = generateGradientStop(
467+
"from",
468+
fill.gradientStops[0],
469+
globalOpacity,
470+
0,
471+
"deg",
472+
360,
473+
);
474+
const viaStop = generateGradientStop(
475+
"via",
476+
fill.gradientStops[1],
477+
globalOpacity,
478+
0.5,
479+
"deg",
480+
360,
481+
);
388482
const lastStop = generateGradientStop(
389483
"to",
390484
fill.gradientStops[fill.gradientStops.length - 1],
391485
globalOpacity,
392486
1,
393487
"deg",
394-
360
488+
360,
395489
);
396490
return [baseClass, firstStop, viaStop, lastStop].filter(Boolean).join(" ");
397491
}

0 commit comments

Comments
 (0)