mirror of
https://github.com/penpot/penpot-exporter-figma-plugin.git
synced 2025-01-03 05:10:13 -05:00
Local Fonts (#81)
* moved validate font logic * google fonts working * fixes * minor improvements * fix linter * local fonts * fixes * Changeset * changeset * refactor * refactor * update branch * minor fix * move files around * try to refactor * refactor * add todo * refactor * refactor * refactor * refactor * refactor * refactor * refactor move files to their concrete location --------- Co-authored-by: Jordi Sala Morales <jordism91@gmail.com>
This commit is contained in:
parent
8021da2623
commit
58f7b0ab2c
21 changed files with 249 additions and 75 deletions
5
.changeset/sweet-months-speak.md
Normal file
5
.changeset/sweet-months-speak.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"penpot-exporter": minor
|
||||
---
|
||||
|
||||
Added support for Source Sans Pro font (penpot local font)
|
|
@ -1,18 +1,15 @@
|
|||
import { transformFills } from '@plugin/transformers/partials';
|
||||
import {
|
||||
translateFills,
|
||||
translateHorizontalAlign,
|
||||
translateVerticalAlign
|
||||
} from '@plugin/translators';
|
||||
import { translateFills } from '@plugin/translators';
|
||||
import {
|
||||
translateFontId,
|
||||
translateFontStyle,
|
||||
translateFontVariantId,
|
||||
translateGrowType,
|
||||
translateHorizontalAlign,
|
||||
translateLetterSpacing,
|
||||
translateLineHeight,
|
||||
translateTextDecoration,
|
||||
translateTextTransform
|
||||
translateTextTransform,
|
||||
translateVerticalAlign
|
||||
} from '@plugin/translators/text';
|
||||
|
||||
import { TextStyle } from '@ui/lib/types/text/textContent';
|
||||
|
@ -74,9 +71,8 @@ const transformTextStyle = (
|
|||
>
|
||||
): Partial<TextStyle> => {
|
||||
return {
|
||||
...translateFontId(segment.fontName, segment.fontWeight),
|
||||
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(),
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
export * from './translateBlendMode';
|
||||
export * from './translateShadowEffects';
|
||||
export * from './translateFills';
|
||||
export * from './translateHorizontalAlign';
|
||||
export * from './translateStrokes';
|
||||
export * from './translateVectorPaths';
|
||||
export * from './translateVerticalAlign';
|
||||
|
|
1
plugin-src/translators/text/custom/index.ts
Normal file
1
plugin-src/translators/text/custom/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './translateCustomFont';
|
17
plugin-src/translators/text/custom/translateCustomFont.ts
Normal file
17
plugin-src/translators/text/custom/translateCustomFont.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import slugify from 'slugify';
|
||||
|
||||
import { FontId } from '@ui/lib/types/text/textContent';
|
||||
|
||||
/**
|
||||
* @TODO: implement custom font loading for Penpot
|
||||
*/
|
||||
export const translateCustomFont = (fontName: FontName): FontId | undefined => {
|
||||
// For now display a message in the UI, so the user knows
|
||||
// that the file is using a custom font not present in Penpot
|
||||
figma.ui.postMessage({ type: 'FONT_NAME', data: fontName.family });
|
||||
|
||||
return {
|
||||
fontId: slugify(fontName.family.toLowerCase()),
|
||||
fontVariantId: fontName.style.toLowerCase().replace(/\s/g, '')
|
||||
};
|
||||
};
|
11
plugin-src/translators/text/gfonts/googleFont.ts
Normal file
11
plugin-src/translators/text/gfonts/googleFont.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
export type GoogleFont = {
|
||||
family: string;
|
||||
variants?: string[];
|
||||
subsets?: string[];
|
||||
version: string;
|
||||
lastModified: string;
|
||||
files?: { [key: string]: string | undefined };
|
||||
category: string;
|
||||
kind: string;
|
||||
menu: string;
|
||||
};
|
3
plugin-src/translators/text/gfonts/index.ts
Normal file
3
plugin-src/translators/text/gfonts/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './googleFont';
|
||||
export * from './translateGoogleFont';
|
||||
export * from './translateFontVariantId';
|
20
plugin-src/translators/text/gfonts/translateFontVariantId.ts
Normal file
20
plugin-src/translators/text/gfonts/translateFontVariantId.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { GoogleFont } from './googleFont';
|
||||
|
||||
export const translateFontVariantId = (
|
||||
googleFont: GoogleFont,
|
||||
fontName: FontName,
|
||||
fontWeight: number
|
||||
) => {
|
||||
// check match directly by style
|
||||
const variant = googleFont.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 = googleFont.variants?.find(
|
||||
variant => variant === `${fontWeight.toString()}${italic}`
|
||||
);
|
||||
|
||||
if (variantWithWeight !== undefined) return variantWithWeight;
|
||||
};
|
23
plugin-src/translators/text/gfonts/translateGoogleFont.ts
Normal file
23
plugin-src/translators/text/gfonts/translateGoogleFont.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import slugify from 'slugify';
|
||||
|
||||
import { translateFontVariantId } from '@plugin/translators/text/gfonts';
|
||||
|
||||
import { FontId } from '@ui/lib/types/text/textContent';
|
||||
|
||||
import { items as gfonts } from './gfonts.json';
|
||||
import { GoogleFont } from './googleFont';
|
||||
|
||||
export const translateGoogleFont = (fontName: FontName, fontWeight: number): FontId | undefined => {
|
||||
const googleFont = getGoogleFont(fontName);
|
||||
|
||||
if (googleFont === undefined) return;
|
||||
|
||||
return {
|
||||
fontId: `gfont-${slugify(fontName.family.toLowerCase())}`,
|
||||
fontVariantId: translateFontVariantId(googleFont, fontName, fontWeight)
|
||||
};
|
||||
};
|
||||
|
||||
const getGoogleFont = (fontName: FontName): GoogleFont | undefined => {
|
||||
return gfonts.find(font => font.family === fontName.family);
|
||||
};
|
|
@ -1,7 +1,9 @@
|
|||
export * from './translateFontIds';
|
||||
export * from './translateFontId';
|
||||
export * from './translateFontStyle';
|
||||
export * from './translateGrowType';
|
||||
export * from './translateHorizontalAlign';
|
||||
export * from './translateLetterSpacing';
|
||||
export * from './translateLineHeight';
|
||||
export * from './translateTextDecoration';
|
||||
export * from './translateTextTransform';
|
||||
export * from './translateVerticalAlign';
|
||||
|
|
3
plugin-src/translators/text/local/index.ts
Normal file
3
plugin-src/translators/text/local/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './localFont';
|
||||
export * from './translateLocalFont';
|
||||
export * from './translateFontVariantId';
|
14
plugin-src/translators/text/local/localFont.ts
Normal file
14
plugin-src/translators/text/local/localFont.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
export type LocalFont = {
|
||||
id: string;
|
||||
name: string;
|
||||
family: string;
|
||||
variants?: Variant[];
|
||||
};
|
||||
|
||||
type Variant = {
|
||||
id: string;
|
||||
name: string;
|
||||
weight: string;
|
||||
style: string;
|
||||
suffix?: string;
|
||||
};
|
75
plugin-src/translators/text/local/localFonts.json
Normal file
75
plugin-src/translators/text/local/localFonts.json
Normal file
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "sourcesanspro",
|
||||
"name": "Source Sans Pro",
|
||||
"family": "sourcesanspro",
|
||||
"variants": [
|
||||
{
|
||||
"id": "200",
|
||||
"name": "200",
|
||||
"weight": "200",
|
||||
"style": "normal",
|
||||
"suffix": "extralight"
|
||||
},
|
||||
{
|
||||
"id": "200italic",
|
||||
"name": "200 (italic)",
|
||||
"weight": "200",
|
||||
"style": "italic",
|
||||
"suffix": "extralightitalic"
|
||||
},
|
||||
{
|
||||
"id": "300",
|
||||
"name": "300",
|
||||
"weight": "300",
|
||||
"style": "normal",
|
||||
"suffix": "light"
|
||||
},
|
||||
{
|
||||
"id": "300italic",
|
||||
"name": "300 (italic)",
|
||||
"weight": "300",
|
||||
"style": "italic",
|
||||
"suffix": "lightitalic"
|
||||
},
|
||||
{
|
||||
"id": "regular",
|
||||
"name": "regular",
|
||||
"weight": "400",
|
||||
"style": "normal"
|
||||
},
|
||||
{
|
||||
"id": "italic",
|
||||
"name": "italic",
|
||||
"weight": "400",
|
||||
"style": "italic"
|
||||
},
|
||||
{
|
||||
"id": "bold",
|
||||
"name": "bold",
|
||||
"weight": "bold",
|
||||
"style": "normal"
|
||||
},
|
||||
{
|
||||
"id": "bolditalic",
|
||||
"name": "bold (italic)",
|
||||
"weight": "bold",
|
||||
"style": "italic"
|
||||
},
|
||||
{
|
||||
"id": "black",
|
||||
"name": "black",
|
||||
"weight": "900",
|
||||
"style": "normal"
|
||||
},
|
||||
{
|
||||
"id": "blackitalic",
|
||||
"name": "black (italic)",
|
||||
"weight": "900",
|
||||
"style": "italic"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
30
plugin-src/translators/text/local/translateFontVariantId.ts
Normal file
30
plugin-src/translators/text/local/translateFontVariantId.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { LocalFont } from './localFont';
|
||||
|
||||
export const translateFontVariantId = (
|
||||
localFont: LocalFont,
|
||||
fontName: FontName,
|
||||
fontWeight: number
|
||||
): string | undefined => {
|
||||
// check match by style and weight
|
||||
const italic = fontName.style.toLowerCase().includes('italic');
|
||||
const variantWithStyleWeight = localFont.variants?.find(
|
||||
variant =>
|
||||
variant.weight === fontWeight.toString() && variant.style === (italic ? 'italic' : 'normal')
|
||||
);
|
||||
|
||||
if (variantWithStyleWeight !== undefined) return variantWithStyleWeight.id;
|
||||
|
||||
// check match directly by suffix if exists
|
||||
const variant = localFont.variants?.find(
|
||||
variant => variant.suffix === fontName.style.toLowerCase().replace(/\s/g, '')
|
||||
);
|
||||
|
||||
if (variant !== undefined) return variant.id;
|
||||
|
||||
// check match directly by id
|
||||
const variantById = localFont.variants?.find(
|
||||
variant => variant.id === fontName.style.toLowerCase().replace(/\s/g, '')
|
||||
);
|
||||
|
||||
if (variantById !== undefined) return variantById.id;
|
||||
};
|
20
plugin-src/translators/text/local/translateLocalFont.ts
Normal file
20
plugin-src/translators/text/local/translateLocalFont.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { LocalFont, translateFontVariantId } from '@plugin/translators/text/local';
|
||||
|
||||
import { FontId } from '@ui/lib/types/text/textContent';
|
||||
|
||||
import { items as localFonts } from './localFonts.json';
|
||||
|
||||
export const translateLocalFont = (fontName: FontName, fontWeight: number): FontId | undefined => {
|
||||
const localFont = getLocalFont(fontName);
|
||||
|
||||
if (localFont === undefined) return;
|
||||
|
||||
return {
|
||||
fontId: localFont.id,
|
||||
fontVariantId: translateFontVariantId(localFont, fontName, fontWeight)
|
||||
};
|
||||
};
|
||||
|
||||
const getLocalFont = (fontName: FontName): LocalFont | undefined => {
|
||||
return localFonts.find(localFont => localFont.name === fontName.family);
|
||||
};
|
13
plugin-src/translators/text/translateFontId.ts
Normal file
13
plugin-src/translators/text/translateFontId.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { FontId } from '@ui/lib/types/text/textContent';
|
||||
|
||||
import { translateCustomFont } from './custom';
|
||||
import { translateGoogleFont } from './gfonts';
|
||||
import { translateLocalFont } from './local';
|
||||
|
||||
export const translateFontId = (fontName: FontName, fontWeight: number): FontId | undefined => {
|
||||
return (
|
||||
translateGoogleFont(fontName, fontWeight) ??
|
||||
translateLocalFont(fontName, fontWeight) ??
|
||||
translateCustomFont(fontName)
|
||||
);
|
||||
};
|
|
@ -1,60 +0,0 @@
|
|||
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;
|
||||
}
|
||||
};
|
9
ui-src/lib/types/text/textContent.d.ts
vendored
9
ui-src/lib/types/text/textContent.d.ts
vendored
|
@ -28,10 +28,8 @@ type TextNode = {
|
|||
key?: string;
|
||||
} & TextStyle;
|
||||
|
||||
type TextStyle = {
|
||||
fontId?: string;
|
||||
type TextStyle = FontId & {
|
||||
fontFamily?: string;
|
||||
fontVariantId?: string;
|
||||
fontSize?: string;
|
||||
fontStyle?: TextFontStyle;
|
||||
fontWeight?: string;
|
||||
|
@ -46,3 +44,8 @@ type TextStyle = {
|
|||
textDirection?: 'ltr' | 'rtl' | 'auto';
|
||||
fills?: Fill[];
|
||||
};
|
||||
|
||||
export type FontId = {
|
||||
fontId?: string;
|
||||
fontVariantId?: string;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue