Templates library

You can use Polotno tools and ability to customize side panel to make your own library of templates.

In order to make a templates library you will need:

  1. Create a design in the Polotno Editor

  2. Use store.toJSON() to save the design state on computer as .json file

  3. (Optionally) Use store.saveAsImage() to save preview file of a design

  4. Repeat 1-4 as many times as you need in order to make a library of templates

  5. If you skipped step number 3 you can use Cloud Render API to generate previews automatically

  6. Make a server-side API to access a list of templates

  7. Create a custom side panel to display a list of templates from that API

  8. 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, there are some (not public) tools for that.

(5) Generating previews​

You can use 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);
  for (const file of files) {
    // if it is not a json file - skip it
    if (file.indexOf('.json') === -1) {
      continue;
    }

    // load file
    const data = fs.readFileSync(path.join(folder, 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 there
      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, file.split('.')[0] + '.png'),
      imageBase64,
      'base64'
    );
    console.log(`Finished ${folder} ${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 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 backend API to get list of templates, you can use Side Panel Customization to display that list on the page. In the demo we will use <ImagesGrid /> component and useInfiniteAPI hook (Docs for them). You don't have to use them in your app. You can make your own implementation. But these modules may save you a lot of time, because they are designed for such use cases. Polotno uses them internally for default side panels.

The side panel may look like this:

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((data) => data.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();
          // just 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,
};

News, updates and promos – be the first to get 'em