mirror of
https://github.com/penpot/penpot-exporter-figma-plugin.git
synced 2024-12-22 05:33:02 -05:00
parent
23e97fb3d7
commit
3118d36f0a
14 changed files with 153 additions and 133 deletions
|
@ -1,4 +1,4 @@
|
|||
import { translateFills } from '@plugin/translators';
|
||||
import { translateFills } from '@plugin/translators/fills';
|
||||
|
||||
import { ShapeAttributes } from '@ui/lib/types/shapes/shape';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
transformStrokes
|
||||
} from '@plugin/transformers/partials';
|
||||
import { createLineGeometry, translateVectorPath, translateVectorPaths } from '@plugin/translators';
|
||||
import { translateFills } from '@plugin/translators';
|
||||
import { translateFills } from '@plugin/translators/fills';
|
||||
|
||||
import { PathAttributes } from '@ui/lib/types/shapes/pathShape';
|
||||
import { PathShape } from '@ui/lib/types/shapes/pathShape';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { transformChildren } from '@plugin/transformers/partials';
|
||||
import { translatePageFill } from '@plugin/translators';
|
||||
import { translatePageFill } from '@plugin/translators/fills';
|
||||
|
||||
import { PenpotPage } from '@ui/lib/types/penpotPage';
|
||||
|
||||
|
|
2
plugin-src/translators/fills/gradients/index.ts
Normal file
2
plugin-src/translators/fills/gradients/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from './translateGradientLinearFill';
|
||||
export * from './translateGradientRadialFill';
|
|
@ -0,0 +1,24 @@
|
|||
import { calculateLinearGradient, rgbToHex } from '@plugin/utils';
|
||||
|
||||
import { Fill } from '@ui/lib/types/utils/fill';
|
||||
|
||||
export const translateGradientLinearFill = (fill: GradientPaint): Fill => {
|
||||
const points = calculateLinearGradient(fill.gradientTransform);
|
||||
|
||||
return {
|
||||
fillColorGradient: {
|
||||
type: 'linear',
|
||||
startX: points.start[0],
|
||||
startY: points.start[1],
|
||||
endX: points.end[0],
|
||||
endY: points.end[1],
|
||||
width: 1,
|
||||
stops: fill.gradientStops.map(stop => ({
|
||||
color: rgbToHex(stop.color),
|
||||
offset: stop.position,
|
||||
opacity: stop.color.a * (fill.opacity ?? 1)
|
||||
}))
|
||||
},
|
||||
fillOpacity: !fill.visible ? 0 : fill.opacity
|
||||
};
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import { calculateRadialGradient, rgbToHex } from '@plugin/utils';
|
||||
|
||||
import { Fill } from '@ui/lib/types/utils/fill';
|
||||
|
||||
export const translateGradientRadialFill = (fill: GradientPaint): Fill => {
|
||||
const points = calculateRadialGradient(fill.gradientTransform);
|
||||
|
||||
return {
|
||||
fillColorGradient: {
|
||||
type: 'radial',
|
||||
startX: points.start[0],
|
||||
startY: points.start[1],
|
||||
endX: points.end[0],
|
||||
endY: points.end[1],
|
||||
width: 1,
|
||||
stops: fill.gradientStops.map(stop => ({
|
||||
color: rgbToHex(stop.color),
|
||||
offset: stop.position,
|
||||
opacity: stop.color.a * (fill.opacity ?? 1)
|
||||
}))
|
||||
},
|
||||
fillOpacity: !fill.visible ? 0 : fill.opacity
|
||||
};
|
||||
};
|
3
plugin-src/translators/fills/index.ts
Normal file
3
plugin-src/translators/fills/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './translateFills';
|
||||
export * from './translateImageFill';
|
||||
export * from './translateSolidFill';
|
49
plugin-src/translators/fills/translateFills.ts
Normal file
49
plugin-src/translators/fills/translateFills.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { translateImageFill, translateSolidFill } from '@plugin/translators/fills';
|
||||
import {
|
||||
translateGradientLinearFill,
|
||||
translateGradientRadialFill
|
||||
} from '@plugin/translators/fills/gradients';
|
||||
import { rgbToHex } from '@plugin/utils';
|
||||
|
||||
import { Fill } from '@ui/lib/types/utils/fill';
|
||||
|
||||
export const translateFill = async (fill: Paint): Promise<Fill | undefined> => {
|
||||
switch (fill.type) {
|
||||
case 'SOLID':
|
||||
return translateSolidFill(fill);
|
||||
case 'GRADIENT_LINEAR':
|
||||
return translateGradientLinearFill(fill);
|
||||
case 'GRADIENT_RADIAL':
|
||||
return translateGradientRadialFill(fill);
|
||||
case 'IMAGE':
|
||||
return await translateImageFill(fill);
|
||||
}
|
||||
|
||||
console.error(`Unsupported fill type: ${fill.type}`);
|
||||
};
|
||||
|
||||
export const translateFills = async (
|
||||
fills: readonly Paint[] | typeof figma.mixed
|
||||
): Promise<Fill[]> => {
|
||||
const figmaFills = fills === figma.mixed ? [] : fills;
|
||||
const penpotFills: Fill[] = [];
|
||||
|
||||
for (const fill of figmaFills) {
|
||||
const penpotFill = await translateFill(fill);
|
||||
if (penpotFill) {
|
||||
// fills are applied in reverse order in Figma, that's why we unshift
|
||||
penpotFills.unshift(penpotFill);
|
||||
}
|
||||
}
|
||||
|
||||
return penpotFills;
|
||||
};
|
||||
|
||||
export const translatePageFill = (fill: Paint): string | undefined => {
|
||||
switch (fill.type) {
|
||||
case 'SOLID':
|
||||
return rgbToHex(fill.color);
|
||||
}
|
||||
|
||||
console.error(`Unsupported page fill type: ${fill.type}`);
|
||||
};
|
36
plugin-src/translators/fills/translateImageFill.ts
Normal file
36
plugin-src/translators/fills/translateImageFill.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { detectMimeType } from '@plugin/utils';
|
||||
|
||||
import { Fill } from '@ui/lib/types/utils/fill';
|
||||
import { ImageColor } from '@ui/lib/types/utils/imageColor';
|
||||
|
||||
export const translateImageFill = async (fill: ImagePaint): Promise<Fill | undefined> => {
|
||||
const fillImage = await translateImage(fill.imageHash);
|
||||
if (!fillImage) return;
|
||||
|
||||
return {
|
||||
fillOpacity: !fill.visible ? 0 : fill.opacity,
|
||||
fillImage: fillImage
|
||||
};
|
||||
};
|
||||
|
||||
const translateImage = async (imageHash: string | null): Promise<ImageColor | undefined> => {
|
||||
if (!imageHash) return;
|
||||
|
||||
const image = figma.getImageByHash(imageHash);
|
||||
if (!image) return;
|
||||
|
||||
const bytes = await image.getBytesAsync();
|
||||
const size = await image.getSizeAsync();
|
||||
const b64 = figma.base64Encode(bytes);
|
||||
const mimeType = detectMimeType(b64);
|
||||
const dataUri = `data:${mimeType};base64,${b64}`;
|
||||
|
||||
return {
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
mtype: mimeType,
|
||||
keepAspectRatio: true,
|
||||
dataUri: dataUri,
|
||||
id: '00000000-0000-0000-0000-000000000000'
|
||||
};
|
||||
};
|
10
plugin-src/translators/fills/translateSolidFill.ts
Normal file
10
plugin-src/translators/fills/translateSolidFill.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { rgbToHex } from '@plugin/utils';
|
||||
|
||||
import { Fill } from '@ui/lib/types/utils/fill';
|
||||
|
||||
export const translateSolidFill = (fill: SolidPaint): Fill => {
|
||||
return {
|
||||
fillColor: rgbToHex(fill.color),
|
||||
fillOpacity: !fill.visible ? 0 : fill.opacity
|
||||
};
|
||||
};
|
|
@ -1,6 +1,5 @@
|
|||
export * from './translateBlendMode';
|
||||
export * from './translateBlurEffects';
|
||||
export * from './translateFills';
|
||||
export * from './translateShadowEffects';
|
||||
export * from './translateStrokes';
|
||||
export * from './translateVectorPaths';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { translateFills } from '@plugin/translators';
|
||||
import { translateFills } from '@plugin/translators/fills';
|
||||
import { translateFontId } from '@plugin/translators/text/font';
|
||||
import { StyleTextSegment, translateParagraphProperties } from '@plugin/translators/text/paragraph';
|
||||
import {
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
import { calculateRadialGradient, detectMimeType, rgbToHex } from '@plugin/utils';
|
||||
import { calculateLinearGradient } from '@plugin/utils/calculateLinearGradient';
|
||||
|
||||
import { Fill } from '@ui/lib/types/utils/fill';
|
||||
import { ImageColor } from '@ui/lib/types/utils/imageColor';
|
||||
|
||||
export const translateFill = async (fill: Paint): Promise<Fill | undefined> => {
|
||||
switch (fill.type) {
|
||||
case 'SOLID':
|
||||
return translateSolidFill(fill);
|
||||
case 'GRADIENT_LINEAR':
|
||||
return translateGradientLinearFill(fill);
|
||||
case 'GRADIENT_RADIAL':
|
||||
return translateGradientRadialFill(fill);
|
||||
case 'IMAGE':
|
||||
return await translateImageFill(fill);
|
||||
}
|
||||
|
||||
console.error(`Unsupported fill type: ${fill.type}`);
|
||||
};
|
||||
|
||||
export const translateFills = async (
|
||||
fills: readonly Paint[] | typeof figma.mixed
|
||||
): Promise<Fill[]> => {
|
||||
const figmaFills = fills === figma.mixed ? [] : fills;
|
||||
const penpotFills: Fill[] = [];
|
||||
|
||||
for (const fill of figmaFills) {
|
||||
const penpotFill = await translateFill(fill);
|
||||
if (penpotFill) {
|
||||
// fills are applied in reverse order in Figma, that's why we unshift
|
||||
penpotFills.unshift(penpotFill);
|
||||
}
|
||||
}
|
||||
|
||||
return penpotFills;
|
||||
};
|
||||
|
||||
export const translatePageFill = (fill: Paint): string | undefined => {
|
||||
switch (fill.type) {
|
||||
case 'SOLID':
|
||||
return rgbToHex(fill.color);
|
||||
}
|
||||
|
||||
console.error(`Unsupported page fill type: ${fill.type}`);
|
||||
};
|
||||
|
||||
const translateImage = async (imageHash: string | null): Promise<ImageColor | undefined> => {
|
||||
if (!imageHash) return;
|
||||
|
||||
const image = figma.getImageByHash(imageHash);
|
||||
if (!image) return;
|
||||
|
||||
const bytes = await image.getBytesAsync();
|
||||
const size = await image.getSizeAsync();
|
||||
const b64 = figma.base64Encode(bytes);
|
||||
const mimeType = detectMimeType(b64);
|
||||
const dataUri = `data:${mimeType};base64,${b64}`;
|
||||
|
||||
return {
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
mtype: mimeType,
|
||||
keepAspectRatio: true,
|
||||
dataUri: dataUri,
|
||||
id: '00000000-0000-0000-0000-000000000000'
|
||||
};
|
||||
};
|
||||
|
||||
const translateImageFill = async (fill: ImagePaint): Promise<Fill | undefined> => {
|
||||
const fillImage = await translateImage(fill.imageHash);
|
||||
if (!fillImage) return;
|
||||
|
||||
return {
|
||||
fillOpacity: !fill.visible ? 0 : fill.opacity,
|
||||
fillImage: fillImage
|
||||
};
|
||||
};
|
||||
|
||||
const translateSolidFill = (fill: SolidPaint): Fill => {
|
||||
return {
|
||||
fillColor: rgbToHex(fill.color),
|
||||
fillOpacity: !fill.visible ? 0 : fill.opacity
|
||||
};
|
||||
};
|
||||
|
||||
const translateGradientLinearFill = (fill: GradientPaint): Fill => {
|
||||
const points = calculateLinearGradient(fill.gradientTransform);
|
||||
|
||||
return {
|
||||
fillColorGradient: {
|
||||
type: 'linear',
|
||||
startX: points.start[0],
|
||||
startY: points.start[1],
|
||||
endX: points.end[0],
|
||||
endY: points.end[1],
|
||||
width: 1,
|
||||
stops: fill.gradientStops.map(stop => ({
|
||||
color: rgbToHex(stop.color),
|
||||
offset: stop.position,
|
||||
opacity: stop.color.a * (fill.opacity ?? 1)
|
||||
}))
|
||||
},
|
||||
fillOpacity: !fill.visible ? 0 : fill.opacity
|
||||
};
|
||||
};
|
||||
|
||||
const translateGradientRadialFill = (fill: GradientPaint): Fill => {
|
||||
const points = calculateRadialGradient(fill.gradientTransform);
|
||||
|
||||
return {
|
||||
fillColorGradient: {
|
||||
type: 'radial',
|
||||
startX: points.start[0],
|
||||
startY: points.start[1],
|
||||
endX: points.end[0],
|
||||
endY: points.end[1],
|
||||
width: 1,
|
||||
stops: fill.gradientStops.map(stop => ({
|
||||
color: rgbToHex(stop.color),
|
||||
offset: stop.position,
|
||||
opacity: stop.color.a * (fill.opacity ?? 1)
|
||||
}))
|
||||
},
|
||||
fillOpacity: !fill.visible ? 0 : fill.opacity
|
||||
};
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
import { translateFill } from '@plugin/translators/translateFills';
|
||||
import { translateFill } from '@plugin/translators/fills';
|
||||
|
||||
import { Stroke, StrokeAlignment, StrokeCaps } from '@ui/lib/types/utils/stroke';
|
||||
|
||||
|
|
Loading…
Reference in a new issue