2024-04-09 03:15:21 -05:00
|
|
|
import { useEffect, useState } from 'react';
|
2024-04-09 02:52:51 -05:00
|
|
|
import slugify from 'slugify';
|
|
|
|
|
2024-04-12 09:52:36 -05:00
|
|
|
import { createPenpotFile } from '@ui/converters';
|
|
|
|
import { PenpotDocument } from '@ui/lib/types/penpotDocument';
|
|
|
|
import { validateFont } from '@ui/validators';
|
2024-04-09 02:52:51 -05:00
|
|
|
|
2024-04-12 11:52:19 -05:00
|
|
|
import Logo from './logo.svg?react';
|
|
|
|
|
2024-04-09 03:15:21 -05:00
|
|
|
export const PenpotExporter = () => {
|
|
|
|
const [missingFonts, setMissingFonts] = useState(new Set<string>());
|
|
|
|
const [exporting, setExporting] = useState(false);
|
2024-04-09 02:52:51 -05:00
|
|
|
|
2024-04-09 03:15:21 -05:00
|
|
|
const addFontWarning = (font: string) => {
|
|
|
|
setMissingFonts(missingFonts => missingFonts.add(font));
|
2024-04-09 02:52:51 -05:00
|
|
|
};
|
|
|
|
|
2024-04-12 06:55:42 -05:00
|
|
|
const onMessage = (event: MessageEvent<{ pluginMessage: { type: string; data: unknown } }>) => {
|
2024-04-15 03:57:50 -05:00
|
|
|
if (event.data.pluginMessage?.type == 'FIGMAFILE') {
|
2024-04-12 06:55:42 -05:00
|
|
|
const document = event.data.pluginMessage.data as PenpotDocument;
|
|
|
|
const file = createPenpotFile(document);
|
2024-04-09 03:15:21 -05:00
|
|
|
|
2024-04-12 06:55:42 -05:00
|
|
|
file.export();
|
2024-04-09 03:15:21 -05:00
|
|
|
|
|
|
|
setExporting(false);
|
2024-04-15 03:57:50 -05:00
|
|
|
} else if (event.data.pluginMessage?.type == 'FONT_NAME') {
|
2024-04-12 06:55:42 -05:00
|
|
|
const fontName = event.data.pluginMessage.data as string;
|
|
|
|
|
|
|
|
if (!validateFont(fontName)) {
|
|
|
|
addFontWarning(slugify(fontName.toLowerCase()));
|
|
|
|
}
|
2024-04-09 02:52:51 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-04-09 03:15:21 -05:00
|
|
|
const onCreatePenpot = () => {
|
|
|
|
setExporting(true);
|
|
|
|
|
|
|
|
parent.postMessage({ pluginMessage: { type: 'export' } }, '*');
|
|
|
|
};
|
|
|
|
|
|
|
|
const onCancel = () => {
|
|
|
|
parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*');
|
|
|
|
};
|
|
|
|
|
|
|
|
const setDimensions = () => {
|
|
|
|
const isMissingFonts = missingFonts.size > 0;
|
2024-04-09 02:52:51 -05:00
|
|
|
|
|
|
|
let width = 300;
|
|
|
|
let height = 280;
|
|
|
|
|
|
|
|
if (isMissingFonts) {
|
2024-04-09 03:15:21 -05:00
|
|
|
height += missingFonts.size * 20;
|
2024-04-09 02:52:51 -05:00
|
|
|
width = 400;
|
|
|
|
parent.postMessage({ pluginMessage: { type: 'resize', width: width, height: height } }, '*');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-04-09 03:15:21 -05:00
|
|
|
useEffect(() => {
|
|
|
|
window.addEventListener('message', onMessage);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
window.removeEventListener('message', onMessage);
|
|
|
|
};
|
|
|
|
}, []);
|
2024-04-09 02:52:51 -05:00
|
|
|
|
2024-04-09 03:15:21 -05:00
|
|
|
useEffect(() => {
|
|
|
|
setDimensions();
|
|
|
|
}, [missingFonts]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<main>
|
|
|
|
<header>
|
2024-04-12 11:52:19 -05:00
|
|
|
<Logo />
|
2024-04-09 03:15:21 -05:00
|
|
|
<h2>Penpot Exporter</h2>
|
|
|
|
</header>
|
|
|
|
<section>
|
|
|
|
<div style={{ display: missingFonts.size > 0 ? 'inline' : 'none' }}>
|
|
|
|
<div id="missing-fonts">
|
|
|
|
{missingFonts.size} non-default font
|
|
|
|
{missingFonts.size > 1 ? 's' : ''}:{' '}
|
|
|
|
</div>
|
|
|
|
<small>Ensure fonts are installed in Penpot before importing.</small>
|
|
|
|
<div id="missing-fonts-list">
|
|
|
|
<ul>
|
|
|
|
{Array.from(missingFonts).map(font => (
|
|
|
|
<li key={font}>{font}</li>
|
|
|
|
))}
|
|
|
|
</ul>
|
2024-04-09 02:52:51 -05:00
|
|
|
</div>
|
2024-04-09 03:15:21 -05:00
|
|
|
</div>
|
|
|
|
</section>
|
|
|
|
<footer>
|
|
|
|
<button className="brand" disabled={exporting} onClick={onCreatePenpot}>
|
|
|
|
{exporting ? 'Exporting...' : 'Export to Penpot'}
|
|
|
|
</button>
|
|
|
|
<button onClick={onCancel}>Cancel</button>
|
|
|
|
</footer>
|
|
|
|
</main>
|
|
|
|
);
|
|
|
|
};
|