283 lines
6.8 KiB
TypeScript
283 lines
6.8 KiB
TypeScript
|
/**
|
||
|
* External dependencies
|
||
|
*/
|
||
|
import apiFetch from '@wordpress/api-fetch';
|
||
|
import { resolveSelect } from '@wordpress/data';
|
||
|
|
||
|
/**
|
||
|
* Internal dependencies
|
||
|
*/
|
||
|
import {
|
||
|
FontFace,
|
||
|
FontFamiliesToInstall,
|
||
|
FontFamily,
|
||
|
} from '~/customize-store/types/font';
|
||
|
import { FONT_FAMILIES_TO_INSTALL } from '../sidebar/global-styles/font-pairing-variations/constants';
|
||
|
|
||
|
export type FontCollectionsResponse = Array< {
|
||
|
slug: string;
|
||
|
description: string;
|
||
|
name: string;
|
||
|
} >;
|
||
|
|
||
|
export type FontCollectionResponse = {
|
||
|
slug: string;
|
||
|
name: string;
|
||
|
font_families: Array< {
|
||
|
font_family_settings: FontFamily;
|
||
|
categories: Array< string >;
|
||
|
} >;
|
||
|
};
|
||
|
|
||
|
const getInstalledFontFamilyByNameFontFamily = (
|
||
|
installedFontFamilies: Array< {
|
||
|
id: number;
|
||
|
font_family_settings: FontFamily;
|
||
|
font_face: Array< FontFace >;
|
||
|
} >,
|
||
|
nameFontFamily: string
|
||
|
) => {
|
||
|
return installedFontFamilies.find(
|
||
|
( { font_family_settings } ) =>
|
||
|
font_family_settings.slug === nameFontFamily
|
||
|
);
|
||
|
};
|
||
|
|
||
|
const getFontFamiliesToInstall = (
|
||
|
fontCollection: FontCollectionResponse,
|
||
|
slugFontFamily: string,
|
||
|
fontFamilyToInstall: FontFamiliesToInstall[ 'slug' ]
|
||
|
) => {
|
||
|
const fontFromCollection = fontCollection.font_families.find(
|
||
|
( { font_family_settings } ) =>
|
||
|
font_family_settings.slug === slugFontFamily
|
||
|
);
|
||
|
|
||
|
if ( ! fontFromCollection ) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
const fontFace = fontFromCollection?.font_family_settings.fontFace.filter(
|
||
|
( { fontWeight } ) =>
|
||
|
fontFamilyToInstall.fontWeights.includes( fontWeight )
|
||
|
);
|
||
|
|
||
|
const fontFamilyWithFontFace = {
|
||
|
...fontFromCollection?.font_family_settings,
|
||
|
fontFace,
|
||
|
};
|
||
|
|
||
|
return fontFamilyWithFontFace;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Retrieves font families and font faces to install based on a provided font collection and a list of installed font families.
|
||
|
* The fontFamilyWithFontFaceToInstall include fontFamilies with font faces that are not installed yet.
|
||
|
* The fontFaceToInstall include font faces that are not installed yet, but already have the font family installed.
|
||
|
*
|
||
|
* @param fontCollection - The complete font collection containing all available font data.
|
||
|
* @param installedFontFamilies - An array of installed font families with associated font faces and settings.
|
||
|
* @return An object containing font families with font faces to install and individual font faces to install.
|
||
|
*/
|
||
|
export const getFontFamiliesAndFontFaceToInstall = (
|
||
|
fontCollection: FontCollectionResponse,
|
||
|
installedFontFamilies: Array< {
|
||
|
id: number;
|
||
|
font_face: Array< FontFace >;
|
||
|
font_family_settings: FontFamily;
|
||
|
} >
|
||
|
) => {
|
||
|
return Object.entries( FONT_FAMILIES_TO_INSTALL ).reduce(
|
||
|
( acc, [ slug, fontData ] ) => {
|
||
|
const fontFamilyWithFontFaceToInstall = getFontFamiliesToInstall(
|
||
|
fontCollection,
|
||
|
slug,
|
||
|
fontData
|
||
|
);
|
||
|
|
||
|
if ( ! fontFamilyWithFontFaceToInstall ) {
|
||
|
return acc;
|
||
|
}
|
||
|
|
||
|
const fontFamily = getInstalledFontFamilyByNameFontFamily(
|
||
|
installedFontFamilies,
|
||
|
fontFamilyWithFontFaceToInstall.slug
|
||
|
);
|
||
|
|
||
|
if ( ! fontFamily ) {
|
||
|
return {
|
||
|
...acc,
|
||
|
fontFamiliesWithFontFacesToInstall: [
|
||
|
...acc.fontFamiliesWithFontFacesToInstall,
|
||
|
fontFamilyWithFontFaceToInstall,
|
||
|
],
|
||
|
};
|
||
|
}
|
||
|
|
||
|
const fontFace = fontFamily.font_face.filter( ( { fontWeight } ) =>
|
||
|
fontData.fontWeights.includes( fontWeight )
|
||
|
);
|
||
|
|
||
|
return {
|
||
|
...acc,
|
||
|
fontFacesToInstall: [
|
||
|
...acc.fontFacesToInstall,
|
||
|
...fontFace.map( ( face ) => ( {
|
||
|
...face,
|
||
|
fontFamilyId: fontFamily.id,
|
||
|
} ) ),
|
||
|
],
|
||
|
};
|
||
|
},
|
||
|
{
|
||
|
fontFamiliesWithFontFacesToInstall: [],
|
||
|
fontFacesToInstall: [],
|
||
|
} as {
|
||
|
fontFamiliesWithFontFacesToInstall: Array< FontFamily >;
|
||
|
fontFacesToInstall: Array<
|
||
|
FontFace & {
|
||
|
fontFamilyId: number;
|
||
|
}
|
||
|
>;
|
||
|
}
|
||
|
);
|
||
|
};
|
||
|
|
||
|
export const installFontFamily = ( data: FontFamily ) => {
|
||
|
const config = {
|
||
|
path: '/wp/v2/font-families',
|
||
|
method: 'POST',
|
||
|
data: {
|
||
|
font_family_settings: JSON.stringify( {
|
||
|
name: data.name,
|
||
|
slug: data.slug,
|
||
|
fontFamily: data.fontFamily,
|
||
|
preview: data.preview,
|
||
|
} ),
|
||
|
},
|
||
|
};
|
||
|
|
||
|
return apiFetch< {
|
||
|
id: number;
|
||
|
font_family_settings: string;
|
||
|
} >( config );
|
||
|
};
|
||
|
|
||
|
async function downloadFontFaceAssets( src: string ) {
|
||
|
try {
|
||
|
const fontBlob = await ( await fetch( new Request( src ) ) ).blob();
|
||
|
const fileName = src.split( '/' ).pop() as string;
|
||
|
return new File( [ fontBlob ], fileName, {
|
||
|
type: fontBlob.type,
|
||
|
} );
|
||
|
} catch ( error ) {
|
||
|
throw new Error( `Error downloading font face asset from ${ src }` );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function makeFontFacesFormData(
|
||
|
fontFaceFile: File,
|
||
|
formData: FormData,
|
||
|
index: number
|
||
|
) {
|
||
|
const fileId = `file-${ index }`;
|
||
|
formData.append( fileId, fontFaceFile, fontFaceFile.name );
|
||
|
return fileId;
|
||
|
}
|
||
|
|
||
|
export const installFontFace = async (
|
||
|
data: FontFace & {
|
||
|
fontFamilyId: number;
|
||
|
},
|
||
|
index: number
|
||
|
) => {
|
||
|
const { fontFamilyId, ...font } = data;
|
||
|
const fontFaceAssets = await downloadFontFaceAssets(
|
||
|
Array.isArray( font.src ) ? font.src[ 0 ] : font.src
|
||
|
);
|
||
|
const formData = new FormData();
|
||
|
|
||
|
const fontFile = await makeFontFacesFormData(
|
||
|
fontFaceAssets,
|
||
|
formData,
|
||
|
index
|
||
|
);
|
||
|
|
||
|
formData.append(
|
||
|
'font_face_settings',
|
||
|
JSON.stringify( { ...font, src: fontFile } )
|
||
|
);
|
||
|
const config = {
|
||
|
path: `/wp/v2/font-families/${ data.fontFamilyId }/font-faces/`,
|
||
|
method: 'POST',
|
||
|
body: formData,
|
||
|
};
|
||
|
|
||
|
return apiFetch( config );
|
||
|
};
|
||
|
|
||
|
export const installFontFamilies = async () => {
|
||
|
const installedFontFamily = ( await resolveSelect(
|
||
|
'core'
|
||
|
).getEntityRecords( 'postType', 'wp_font_family', {
|
||
|
per_page: -1,
|
||
|
} ) ) as Array< {
|
||
|
id: number;
|
||
|
font_faces: Array< number >;
|
||
|
font_family_settings: FontFamily;
|
||
|
} >;
|
||
|
|
||
|
const installedFontFamiliesWithFontFaces = await Promise.all(
|
||
|
installedFontFamily.map( async ( fontFamily ) => {
|
||
|
const fontFaces = await apiFetch< Array< FontFace > >( {
|
||
|
path: `/wp/v2/font-families/${ fontFamily.id }/font-faces`,
|
||
|
method: 'GET',
|
||
|
} );
|
||
|
|
||
|
return {
|
||
|
...fontFamily,
|
||
|
font_face: fontFaces,
|
||
|
};
|
||
|
} )
|
||
|
);
|
||
|
|
||
|
const fontCollection = await apiFetch< FontCollectionResponse >( {
|
||
|
path: `/wp/v2/font-collections/google-fonts`,
|
||
|
method: 'GET',
|
||
|
} );
|
||
|
|
||
|
const { fontFacesToInstall, fontFamiliesWithFontFacesToInstall } =
|
||
|
getFontFamiliesAndFontFaceToInstall(
|
||
|
fontCollection,
|
||
|
installedFontFamiliesWithFontFaces
|
||
|
);
|
||
|
|
||
|
const fontFamiliesWithFontFaceToInstallPromises =
|
||
|
fontFamiliesWithFontFacesToInstall.map( async ( fontFamily ) => {
|
||
|
const fontFamilyResponse = await installFontFamily( fontFamily );
|
||
|
return Promise.all(
|
||
|
fontFamily.fontFace.map( async ( fontFace, index ) => {
|
||
|
return installFontFace(
|
||
|
{
|
||
|
...fontFace,
|
||
|
fontFamilyId: fontFamilyResponse.id,
|
||
|
},
|
||
|
index
|
||
|
);
|
||
|
} )
|
||
|
);
|
||
|
} );
|
||
|
|
||
|
const fontFacesToInstallPromises =
|
||
|
fontFacesToInstall.map( installFontFace );
|
||
|
|
||
|
return ( await Promise.all( [
|
||
|
...fontFamiliesWithFontFaceToInstallPromises,
|
||
|
...fontFacesToInstallPromises,
|
||
|
] ) ) as Array<
|
||
|
Array< {
|
||
|
font_face_settings: FontFace;
|
||
|
} >
|
||
|
>;
|
||
|
};
|