Skip to content

Commit

Permalink
Google Fonts (#80)
Browse files Browse the repository at this point in the history
* moved validate font logic

* google fonts working

* fixes

* minor improvements

* fix linter

* fixes

* Changeset

* refactor

* refactor

* move files around

---------

Co-authored-by: Jordi Sala Morales <jordism91@gmail.com>
  • Loading branch information
Cenadros and jordisala1991 committed Apr 29, 2024
1 parent 881ccab commit 8021da2
Show file tree
Hide file tree
Showing 24 changed files with 27,113 additions and 1,581 deletions.
5 changes: 5 additions & 0 deletions .changeset/good-teachers-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"penpot-exporter": minor
---

Add support for Google Fonts
26,942 changes: 26,942 additions & 0 deletions plugin-src/gfonts.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion plugin-src/transformers/partials/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ export * from './transformFills';
export * from './transformProportion';
export * from './transformSceneNode';
export * from './transformStrokes';
export * from './transformTextStyle';
export * from './transformText';
export * from './transformVectorPaths';
89 changes: 89 additions & 0 deletions plugin-src/transformers/partials/transformText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { transformFills } from '@plugin/transformers/partials';
import {
translateFills,
translateHorizontalAlign,
translateVerticalAlign
} from '@plugin/translators';
import {
translateFontId,
translateFontStyle,
translateFontVariantId,
translateGrowType,
translateLetterSpacing,
translateLineHeight,
translateTextDecoration,
translateTextTransform
} from '@plugin/translators/text';

import { TextStyle } from '@ui/lib/types/text/textContent';
import { TextShape } from '@ui/lib/types/text/textShape';

export const transformText = (node: TextNode): Partial<TextShape> => {
const styledTextSegments = node.getStyledTextSegments([
'fontName',
'fontSize',
'fontWeight',
'lineHeight',
'letterSpacing',
'textCase',
'textDecoration',
'fills'
]);

return {
content: {
type: 'root',
verticalAlign: translateVerticalAlign(node.textAlignVertical),
children: [
{
type: 'paragraph-set',
children: [
{
type: 'paragraph',
children: styledTextSegments.map(segment => ({
fills: translateFills(segment.fills, node.width, node.height),
text: segment.characters,
...transformTextStyle(node, segment)
})),
...(styledTextSegments.length ? transformTextStyle(node, styledTextSegments[0]) : {}),
...transformFills(node)
}
]
}
]
},
growType: translateGrowType(node)
};
};

const transformTextStyle = (
node: TextNode,
segment: Pick<
StyledTextSegment,
| 'characters'
| 'start'
| 'end'
| 'fontName'
| 'fontSize'
| 'fontWeight'
| 'lineHeight'
| 'letterSpacing'
| 'textCase'
| 'textDecoration'
| 'fills'
>
): Partial<TextStyle> => {
return {
fontFamily: segment.fontName.family,
fontId: translateFontId(segment.fontName),
fontVariantId: translateFontVariantId(segment.fontName, segment.fontWeight),
fontSize: segment.fontSize.toString(),
fontStyle: translateFontStyle(segment.fontName.style),
fontWeight: segment.fontWeight.toString(),
textAlign: translateHorizontalAlign(node.textAlignHorizontal),
textDecoration: translateTextDecoration(segment),
textTransform: translateTextTransform(segment),
letterSpacing: translateLetterSpacing(segment),
lineHeight: translateLineHeight(segment)
};
};
45 changes: 0 additions & 45 deletions plugin-src/transformers/partials/transformTextStyle.ts

This file was deleted.

38 changes: 2 additions & 36 deletions plugin-src/transformers/transformTextNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,19 @@ import {
transformBlend,
transformDimensionAndPosition,
transformEffects,
transformFills,
transformProportion,
transformSceneNode,
transformStrokes,
transformTextStyle
transformText
} from '@plugin/transformers/partials';
import {
translateGrowType,
translateStyledTextSegments,
translateVerticalAlign
} from '@plugin/translators';

import { TextShape } from '@ui/lib/types/text/textShape';

export const transformTextNode = (node: TextNode, baseX: number, baseY: number): TextShape => {
const styledTextSegments = node.getStyledTextSegments([
'fontName',
'fontSize',
'fontWeight',
'lineHeight',
'letterSpacing',
'textCase',
'textDecoration',
'fills'
]);

return {
type: 'text',
name: node.name,
content: {
type: 'root',
verticalAlign: translateVerticalAlign(node.textAlignVertical),
children: [
{
type: 'paragraph-set',
children: [
{
type: 'paragraph',
children: translateStyledTextSegments(node, styledTextSegments),
...(styledTextSegments.length ? transformTextStyle(node, styledTextSegments[0]) : {}),
...transformFills(node)
}
]
}
]
},
growType: translateGrowType(node),
...transformText(node),
...transformDimensionAndPosition(node, baseX, baseY),
...transformEffects(node),
...transformSceneNode(node),
Expand Down
8 changes: 0 additions & 8 deletions plugin-src/translators/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
export * from './translateBlendMode';
export * from './translateShadowEffects';
export * from './translateFills';
export * from './translateFontStyle';
export * from './translateFontVariantId';
export * from './translateGrowType';
export * from './translateHorizontalAlign';
export * from './translateLetterSpacing';
export * from './translateLineHeight';
export * from './translateStrokes';
export * from './translateStyledTextSegments';
export * from './translateTextDecoration';
export * from './translateTextTransform';
export * from './translateVectorPaths';
export * from './translateVerticalAlign';
7 changes: 7 additions & 0 deletions plugin-src/translators/text/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export * from './translateFontIds';
export * from './translateFontStyle';
export * from './translateGrowType';
export * from './translateLetterSpacing';
export * from './translateLineHeight';
export * from './translateTextDecoration';
export * from './translateTextTransform';
60 changes: 60 additions & 0 deletions plugin-src/translators/text/translateFontIds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import slugify from 'slugify';

import { items as gfonts } from '@plugin/gfonts.json';

export const translateFontId = (fontName: FontName): string => {
if (isGfont(fontName)) {
return `gfont-${slugify(fontName.family.toLowerCase())}`;
}

// @TODO: check if source sans pro

// always send font name if not gfont or source sans pro
figma.ui.postMessage({ type: 'FONT_NAME', data: fontName.family });

// @TODO: custom font
return slugify(fontName.family.toLowerCase());
};

export const translateFontVariantId = (fontName: FontName, fontWeight: number) => {
const variantId = translateGfontVariantId(fontName, fontWeight);
if (variantId !== undefined) {
return variantId;
}

// @TODO: Custom font
// @TODO: Source Sans pro
return fontName.style.toLowerCase().replace(/\s/g, '');
};

const findGoogleFont = (fontName: FontName) => {
return gfonts.find(font => font.family === fontName.family);
};

const isGfont = (fontName: FontName): boolean => {
return findGoogleFont(fontName) !== undefined;
};

const translateGfontVariantId = (fontName: FontName, fontWeight: number): string | undefined => {
const gfont = findGoogleFont(fontName);

if (gfont === undefined) {
return;
}

// check match directly by style
const variant = gfont.variants.find(variant => variant === fontName.style.toLowerCase());
if (variant !== undefined) {
return variant;
}

// check match by style and weight
const italic = fontName.style.toLowerCase().includes('italic') ? 'italic' : '';
const variantWithWeight = gfont.variants.find(
variant => variant === `${fontWeight.toString()}${italic}`
);

if (variantWithWeight !== undefined) {
return variantWithWeight;
}
};
File renamed without changes.
3 changes: 0 additions & 3 deletions plugin-src/translators/translateFontVariantId.ts

This file was deleted.

32 changes: 0 additions & 32 deletions plugin-src/translators/translateStyledTextSegments.ts

This file was deleted.

3 changes: 2 additions & 1 deletion plugin-src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"lib": ["es6"],
"strict": true,
"typeRoots": ["../node_modules/@figma"],
"moduleResolution": "Node"
"moduleResolution": "Node",
"resolveJsonModule": true
}
}
5 changes: 4 additions & 1 deletion plugin-src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export * from './applyMatrixToPoint';
export * from './calculateAdjustment';
export * from './calculateLinearGradient';
export * from './detectMimeType';
export * from './matrixInvert';
export * from './rgbToHex';
export * from './calculateAdjustment';
8 changes: 1 addition & 7 deletions ui-src/PenpotExporter.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { useEffect, useState } from 'react';
import slugify from 'slugify';

import { createPenpotFile } from '@ui/converters';
import { PenpotDocument } from '@ui/lib/types/penpotDocument';
import { validateFont } from '@ui/validators';

import Logo from './logo.svg?react';

Expand All @@ -24,11 +22,7 @@ export const PenpotExporter = () => {

setExporting(false);
} else if (event.data.pluginMessage?.type == 'FONT_NAME') {
const fontName = event.data.pluginMessage.data as string;

if (!validateFont(fontName)) {
addFontWarning(slugify(fontName.toLowerCase()));
}
addFontWarning(event.data.pluginMessage.data as string);
}
};

Expand Down

0 comments on commit 8021da2

Please sign in to comment.