Templates Library
Build a templates library, generate previews, and load designs via a custom side panel
You can use Polotno tools and side panel customization to build your own template library with design presets.
In order to make a templates library you will need:
- Create a design in the Polotno Editor
- Use
store.toJSON()to export the design as a.jsonfile - (Optional) Use
store.saveAsImage()to save a preview image of a design - Repeat steps 1–3 as many times as you need in order to make a library of templates
- If you skipped step 3 you can use Cloud Render API to generate previews automatically
- Make a server‑side API to access a list of templates
- Create a custom side panel to display a list of templates from that API
- Use
store.loadJSON()to import design into canvas
(1–4) Making designs library
You will need to use Polotno editor to create designs. Importing designs from other software is not directly supported.
Note: if you need to import from SVG files, please contact us.
(5) Generating previews
You can use the Polotno Cloud API to generate previews with your own backend language.
import fs from 'fs';
import path from 'path';
import { createInstance } from 'polotno-node';
// we will look for local directory for templates
const FOLDER_NAME = 'templates';
async function run() {
// create working instance
const instance = await createInstance({
// this is a demo key just for that project
// (!) please don't use it in your projects
// to create your own API key please go here: https://polotno.com/cabinet
key: 'nFA5H9elEytDyPyvKL7T',
});
// read all files in the directory
const files = fs.readdirSync(FOLDER_NAME);
for (const file of files) {
// if it is not a json file - skip it
if (!file.endsWith('.json')) continue;
// load file
const data = fs.readFileSync(path.join(FOLDER_NAME, file)).toString();
const json = JSON.parse(data);
// convert JSON into image preview
const imageBase64 = await instance.run(async (json) => {
store.loadJSON(json);
await store.waitLoading();
// set width of previews (we usually don't need original size)
const maxWidth = 200;
const scale = maxWidth / store.width;
const url = await store.toDataURL({ pixelRatio: scale });
return url.split('base64,')[1];
}, json);
// save images locally into the same folder
fs.writeFileSync(
path.join(FOLDER_NAME, file.split('.')[0] + '.png'),
imageBase64,
'base64'
);
console.log(`Finished ${FOLDER_NAME} ${file}`);
}
// close instance
instance.close();
}
run();(6) Making backend API to load templates
This step is out of Polotno scope. You can use any backend stack you like. Most likely, you will need an API to get a list of available templates. For every design, you will have to share a public path to json file and png preview.
(7 and 8) Displaying templates on side panel
As soon as you have a backend API to get a list of templates, you can use Side Panel Customization to display that list on the page. In the demo we will use <ImagesGrid /> and the useInfiniteAPI hook (docs). You don't have to use them in your app, but they can save time for this use case.
import React from 'react';
import { observer } from 'mobx-react-lite';
import { useInfiniteAPI } from 'polotno/utils/use-api';
import { SectionTab } from 'polotno/side-panel';
import MdPhotoLibrary from '@meronex/icons/md/MdPhotoLibrary';
import { ImagesGrid } from 'polotno/side-panel/images-grid';
export const TemplatesPanel = observer(({ store }) => {
// load data
const { data, isLoading } = useInfiniteAPI({
getAPI: ({ page }) => `templates/page${page}.json`,
});
return (
<div style={{ height: '100%' }}>
<ImagesGrid
shadowEnabled={false}
images={data?.map((d) => d.items).flat()}
getPreview={(item) => `/templates/${item.preview}`}
isLoading={isLoading}
onSelect={async (item) => {
// download selected json
const req = await fetch(`/templates/${item.json}`);
const json = await req.json();
// inject it into store
store.loadJSON(json);
}}
rowsNumber={1}
/>
</div>
);
});
// define the new custom section
export const TemplatesSection = {
name: 'custom-templates',
Tab: (props) => (
<SectionTab name="Custom templates" {...props}>
<MdPhotoLibrary />
</SectionTab>
),
// we need observer to update component automatically on any store changes
Panel: TemplatesPanel,
};