Building a resume editor based on NoCode
to prepare for the job fair. Various templates did not meet my satisfaction due to details, so I decided to create a simple drag-and-drop resume editor.
The distinction between NoCode
and LowCode
can be easily confused. In my understanding, NoCode
emphasizes self-programming for personal use, giving the user a sense of a more powerful and practical software, which is an upper-layer application. This means that NoCode
needs to be targeted at a very specific domain in order to be useful. On the other hand, LowCode
not only needs to consider building processes in a graphical way but also needs to expose the underlying system when expansion is required, providing stronger customization. This allows for more flexibility compared to NoCode
, which does not restrict usage scenarios as much.
For a resume editor, it falls into a very specific domain and does not require extensive code implementation for usage. It is meant to be used right out of the box as an upper-layer application. Personally, I decided to create it simply because I needed to prepare for the job fair and was not entirely satisfied with the various templates available on websites. The idea to create this editor came to me while I was taking a shower before going to bed one night, and I spent a weekend, which was just two days, to create a simple resume editor based on NoCode
.
Getting back to the point, to implement the resume editor, the following considerations need to be taken into account. Of course, since I completed it in just two days, I only implemented some basic functionalities:
PDF
and previewing pages.JSON
format.For data, a JSON
data is maintained here. There is a strict definition of the entire resume editor in TypeScript, so it is necessary to declare the component type definition in advance. Here, I declared LocalComponentConfig
as the type definition for the component. As for the entire generated JSON
, it is completed as a nested LocalComponentConfig[]
.
The resume displayed in the project is completely implemented using JSON
configuration. The data and view rendering are completely separate. This allows us to implement different resume theme templates by writing multiple JSON
configurations. If you open the mentioned Resume DEMO
, you can see a preloaded resume, and its content is obtained entirely from the JSON
configuration. Specifically, you can refer to src/components/debug/example.ts
. If the data is stored in the local storage as a string, with the key as cld-storage
, if there is no such key in the local storage, the initial resume example will be loaded. The data storage format is {origin: ${data}, expire: number | number}
, and the data can be retrieved using JSON.parse
. With this JSON
data configuration.
In this case, we actually have two sets of data structure definitions because the goal is to separate data from components. However, components also need to be defined in a specific place. Additionally, because the entire editor is expected to be detachable, each basic component is independently registered. Removing the registration part would not have any impact on the entire project. The only consequence would be that the view cannot be rendered successfully based on the JSON
configuration, resulting in an empty final effect.
The JSON
data structure that needs to be maintained is quite complex. Here we use Context + useImmerReducer
to implement state management. Of course, using reducer
or Mobx
is also possible. This is just what I think is a relatively simple solution.
The implementation of the grid layout is relatively simple and does not require the implementation of reference lines for alignment. It's sufficient to display the grid directly during dragging. Additionally, if there will be future expansion to generate PDFs of various widths, it won't cause confusion in the previous canvas layout, as it's inherently based on grid implementation and can handle width adjustments automatically. However, if mobile adaptation is needed, a set of Layout
data will still need to be created.
In practice, this grid page layout is implemented as the canvas for the entire page layout. There are many libraries in the React
ecosystem for this purpose, and I used the react-grid-layout
library for drag-and-drop. For specific usage, you can find the GitHub link in the references section of this article. This library is quite good and can be used out of the box, but there are still many details that need to be handled. Regarding the layout
configuration, since we store a JSON
data structure, we need to generate the layout
using our own defined data structure. During the generation process, if any changes to cols
or rowHeight
cause elements to exceed the original range, they need to be handled.
In the <ReferenceLine/>
component, the grid points of the grid layout are drawn using CSS
, thus achieving the function of a reference line.
With the basic canvas component in place, we need to implement various basic components. Therefore, independent editing functionality needs to be implemented for basic components, which consists of three parts: firstly, data modification, because editing ultimately needs to be reflected in the data, i.e., the JSON
data that we need to maintain. Since we have a data communication solution, here we just need to define a reducer
to write it to the corresponding component configuration props
or other fields.
Next comes the implementation of the toolbar. For the toolbar, we need to determine the name
of the selected element. After loading the toolbar, for user operations, we just need to apply them to the JSON
data based on the current selected id
through data communication, and these modifications will be applied in the view.
When it comes to the editing panel, similar to the toolbar, you can simply load the form and apply the form data changes to the JSON data using a reducer
. Since the implementation of the editor here is relatively simple, I also loaded a CSS editor. By combining with CSS, you can achieve more styling effects. Of course, by extending various component editing panel sections, you can minimize the need for custom CSS coding as much as possible.
The PDF export function leverages the browser's capability, achieved by printing (Ctrl + P) to export to PDF. Note the following when exporting:
A4
paper, expanding the editing area may result in the resume spanning multiple pages.A4
, margins to none, and select the background graphics option in order to export a complete single-page resume.The image component is used to upload and display images. As there is no backend, the images can only be stored in the JSON structure as base64 data.
The rich text component is used to edit text. Here coincidentally, I have a rich text editor component implementation that you can refer to Github | Editor DEMO.
The blank component can be used as a placeholder or can be used in conjunction with CSS to achieve background effects.