0
Fork 0
mirror of https://github.com/penpot/penpot-exporter-figma-plugin.git synced 2024-12-22 05:33:02 -05:00

Add loaders when the file is being built so we can track the progress (#172)

* Add loaders when the file is being built so we can track the progress

* add changelog

* improve

* refactor
This commit is contained in:
Jordi Sala Morales 2024-06-18 09:50:38 +02:00 committed by GitHub
parent 199984d961
commit 8697902e08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 169 additions and 80 deletions

View file

@ -0,0 +1,5 @@
---
"penpot-exporter": minor
---
Track better the progress on file creation

View file

@ -45,6 +45,7 @@ export const transformComponentNode = async (
return {
figmaId: node.id,
type: 'component'
type: 'component',
name: node.name
};
};

View file

@ -12,18 +12,21 @@ import { transformPageNode } from '.';
const downloadImages = async (): Promise<Record<string, Uint8Array>> => {
const imageToDownload = Object.entries(imagesLibrary.all());
const images: Record<string, Uint8Array> = {};
let currentImage = 1;
figma.ui.postMessage({
type: 'PROGRESS_STEP',
data: 'images'
});
if (imageToDownload.length === 0) return images;
let currentImage = 1;
figma.ui.postMessage({
type: 'PROGRESS_TOTAL_ITEMS',
data: imageToDownload.length
});
figma.ui.postMessage({
type: 'PROGRESS_STEP',
data: 'images'
});
for (const [key, image] of imageToDownload) {
const bytes = await image?.getBytesAsync();

View file

@ -25,7 +25,15 @@ const stepMessages: Record<Steps, Messages> = {
optimization: {
total: 'images optimized 📸'
},
downloading: {
building: {
total: 'pages built 🏗️',
current: 'Currently processing layer'
},
components: {
total: 'components built 🏗️',
current: 'Currently processing layer'
},
exporting: {
total: 'Generating Penpot file 🚀',
current: 'Please wait, this process might take a while...'
}
@ -51,6 +59,8 @@ const StepProgress = (): JSX.Element | null => {
case 'remote':
case 'images':
case 'optimization':
case 'building':
case 'components':
return (
<>
{processedItems} of {totalItems} {stepMessages[step].total}
@ -64,7 +74,7 @@ const StepProgress = (): JSX.Element | null => {
) : undefined}
</>
);
case 'downloading':
case 'exporting':
return (
<>
{stepMessages[step].total}

View file

@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
import { FormValues } from '@ui/components/ExportForm';
import { parse } from '@ui/parser';
import { MessageData } from '.';
import { MessageData, sendMessage } from '.';
export type UseFigmaHook = {
missingFonts: string[] | undefined;
@ -19,7 +19,14 @@ export type UseFigmaHook = {
exportPenpot: (data: FormValues) => void;
};
export type Steps = 'processing' | 'remote' | 'images' | 'optimization' | 'downloading';
export type Steps =
| 'processing'
| 'remote'
| 'images'
| 'optimization'
| 'building'
| 'components'
| 'exporting';
export const useFigma = (): UseFigmaHook => {
const [missingFonts, setMissingFonts] = useState<string[]>();
@ -44,6 +51,12 @@ export const useFigma = (): UseFigmaHook => {
switch (pluginMessage.type) {
case 'PENPOT_DOCUMENT': {
const file = await parse(pluginMessage.data);
sendMessage({
type: 'PROGRESS_STEP',
data: 'exporting'
});
const blob = await file.export();
download(blob, `${pluginMessage.data.name}.zip`);

View file

@ -16,7 +16,6 @@ export type ShapeBaseAttributes = {
id?: Uuid;
figmaId?: string; // @TODO: move to any other place
figmaRelatedId?: string; // @TODO: move to any other place
name?: string;
type?:
| 'frame'
| 'group'
@ -29,8 +28,6 @@ export type ShapeBaseAttributes = {
| 'image'
| 'component'
| 'instance';
selrect?: Selrect;
points?: Point[];
transform?: Matrix;
transformInverse?: Matrix;
parentId?: Uuid;
@ -39,7 +36,7 @@ export type ShapeBaseAttributes = {
};
export type ShapeAttributes = {
name?: string;
name: string;
componentId?: string;
componentFile?: string;
componentRoot?: boolean;

View file

@ -1,36 +0,0 @@
import { componentsLibrary } from '@plugin/ComponentLibrary';
import { PenpotFile } from '@ui/lib/types/penpotFile';
import { symbolBlendMode, symbolFills, symbolStrokes } from '@ui/parser/creators/symbols';
import { uiComponents } from '@ui/parser/libraries';
import { createItems } from '.';
export const createComponentLibrary = (file: PenpotFile) => {
uiComponents.all().forEach(uiComponent => {
const component = componentsLibrary.get(uiComponent.componentFigmaId);
if (!component) {
return;
}
const { children = [], fills, strokes, blendMode, ...rest } = component;
file.startComponent({
...rest,
fills: symbolFills(fills),
strokes: symbolStrokes(strokes),
blendMode: symbolBlendMode(blendMode),
id: uiComponent.componentId,
componentId: uiComponent.componentId,
mainInstancePage: uiComponent.mainInstancePage,
mainInstanceId: uiComponent.mainInstanceId,
componentRoot: true,
mainInstance: true,
componentFile: file.getId()
});
createItems(file, children);
file.finishComponent();
});
};

View file

@ -0,0 +1,63 @@
import { componentsLibrary } from '@plugin/ComponentLibrary';
import { sleep } from '@plugin/utils/sleep';
import { sendMessage } from '@ui/context';
import { PenpotFile } from '@ui/lib/types/penpotFile';
import { symbolBlendMode, symbolFills, symbolStrokes } from '@ui/parser/creators/symbols';
import { UiComponent, uiComponents } from '@ui/parser/libraries';
import { createItems } from '.';
export const createComponentsLibrary = async (file: PenpotFile) => {
let componentsBuilt = 1;
const components = uiComponents.all();
sendMessage({
type: 'PROGRESS_TOTAL_ITEMS',
data: components.length
});
sendMessage({
type: 'PROGRESS_STEP',
data: 'components'
});
for (const uiComponent of components) {
createComponentLibrary(file, uiComponent);
sendMessage({
type: 'PROGRESS_PROCESSED_ITEMS',
data: componentsBuilt++
});
await sleep(0);
}
};
const createComponentLibrary = async (file: PenpotFile, uiComponent: UiComponent) => {
const component = componentsLibrary.get(uiComponent.componentFigmaId);
if (!component) {
return;
}
const { children = [], fills, strokes, blendMode, ...rest } = component;
file.startComponent({
...rest,
fills: symbolFills(fills),
strokes: symbolStrokes(strokes),
blendMode: symbolBlendMode(blendMode),
id: uiComponent.componentId,
componentId: uiComponent.componentId,
mainInstancePage: uiComponent.mainInstancePage,
mainInstanceId: uiComponent.mainInstanceId,
componentRoot: true,
mainInstance: true,
componentFile: file.getId()
});
createItems(file, children);
file.finishComponent();
};

View file

@ -0,0 +1,41 @@
import { sleep } from '@plugin/utils/sleep';
import { sendMessage } from '@ui/context';
import { createFile as createPenpotFile } from '@ui/lib/penpot';
import { PenpotPage } from '@ui/lib/types/penpotPage';
import { idLibrary } from '@ui/parser';
import { createComponentsLibrary, createPage } from '@ui/parser/creators';
import { uiComponents } from '@ui/parser/libraries';
export const createFile = async (name: string, children: PenpotPage[]) => {
const file = createPenpotFile(name);
let pagesBuilt = 1;
uiComponents.init();
idLibrary.init();
sendMessage({
type: 'PROGRESS_TOTAL_ITEMS',
data: children.length
});
sendMessage({
type: 'PROGRESS_STEP',
data: 'building'
});
for (const page of children) {
await createPage(file, page);
sendMessage({
type: 'PROGRESS_PROCESSED_ITEMS',
data: pagesBuilt++
});
await sleep(0);
}
await createComponentsLibrary(file);
return file;
};

View file

@ -1,3 +1,4 @@
import { sendMessage } from '@ui/context';
import { PenpotFile } from '@ui/lib/types/penpotFile';
import { PenpotNode } from '@ui/types';
@ -20,6 +21,11 @@ export const createItems = (file: PenpotFile, nodes: PenpotNode[]) => {
};
const createItem = (file: PenpotFile, node: PenpotNode) => {
sendMessage({
type: 'PROGRESS_CURRENT_ITEM',
data: node.name
});
switch (node.type) {
case 'rect':
return createRectangle(file, node);

View file

@ -3,7 +3,8 @@ export * from './createBool';
export * from './createCircle';
export * from './createComponent';
export * from './createComponentInstance';
export * from './createComponentLibrary';
export * from './createComponentsLibrary';
export * from './createFile';
export * from './createGroup';
export * from './createItems';
export * from './createPage';

View file

@ -1,6 +1,6 @@
import { Uuid } from '@ui/lib/types/utils/uuid';
type UiComponent = {
export type UiComponent = {
componentId: Uuid;
mainInstancePage?: Uuid;
mainInstanceId: Uuid;

View file

@ -3,27 +3,29 @@ import { componentsLibrary } from '@plugin/ComponentLibrary';
import { sleep } from '@plugin/utils/sleep';
import { sendMessage } from '@ui/context';
import { createFile } from '@ui/lib/penpot';
import { createComponentLibrary, createPage } from '@ui/parser/creators';
import { uiComponents, uiImages } from '@ui/parser/libraries';
import { createFile } from '@ui/parser/creators';
import { uiImages } from '@ui/parser/libraries';
import { PenpotDocument } from '@ui/types';
import { idLibrary, parseImage } from '.';
import { parseImage } from '.';
const optimizeImages = async (images: Record<string, Uint8Array>) => {
const imagesToOptimize = Object.entries(images);
let imagesOptimized = 1;
sendMessage({
type: 'PROGRESS_STEP',
data: 'optimization'
});
if (imagesToOptimize.length === 0) return;
let imagesOptimized = 1;
sendMessage({
type: 'PROGRESS_TOTAL_ITEMS',
data: imagesToOptimize.length
});
sendMessage({
type: 'PROGRESS_STEP',
data: 'optimization'
});
for (const [key, bytes] of imagesToOptimize) {
if (bytes) {
uiImages.register(key, await parseImage(bytes));
@ -43,23 +45,5 @@ export const parse = async ({ name, children = [], components, images }: PenpotD
await optimizeImages(images);
sendMessage({
type: 'PROGRESS_STEP',
data: 'downloading'
});
await sleep(20);
uiComponents.init();
idLibrary.init();
const file = createFile(name);
for (const page of children) {
await createPage(file, page);
}
createComponentLibrary(file);
return file;
return createFile(name, children);
};

View file

@ -5,6 +5,7 @@ import { Children } from '@ui/lib/types/utils/children';
export type ComponentRoot = {
figmaId: string;
type: 'component';
name: string;
};
export type ComponentTextPropertyOverride = {