Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google Fonts #80

Merged
merged 10 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
};
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
Loading