Getting started
In this guide, we’ll be using a combination of AdminJS, Next.js, React, and Postgres to build a blog. These tools are all top-notch when it comes to creating dynamic and functional websites, so you can be sure that your blog will be looking great while very easy to manage. You will be able to customize the design, add features, and publish content with ease, all thanks to AdminJS. The entire project folder structure will look like this:
.
├── backend
│ ├── index.ts
│ └── package.json
│ └── tsconfig.json
└── frontend
├── package.json
└── pages
├── _app.js
├── components
│ ├── AnimatedText.component.js
│ ├── Cards.component.js
│ └── Menu.components.js
├── index.js
├── public
│ └── favicon.ico
└── styles
├── globals.css
└── styles.mui.js
The repository for this article can be found here: https://github.com/AdamFrydrychRST/BlogArticle
Setting up the database
Postgres is the database choice due to its great integration with AdminJS. We’ve recently released a SQL adapter that fetches the schema from the database on its own.
We’re going to use docker-compose to deploy the Postgres database. Create a ‘stack.yml’ file.
Once created, run the docker-compose command to bring the container to life.
$ docker-compose -f stack.yml up
We’re going to use Adminer to set up the database tables. In order to log into Adminer, head over to localhost:8080. Set the System to ‘PostgreSQL’, server to ‘db’, Username to ‘postgres’, and Password to ‘example’.
Create a database called ‘Blog’, then inside create a table called ‘posts’, with the following columns:
- cardHeaderTitle — type: character varying — this will be the title of the blog post
- cardHeaderSub — type: date — additionally, add a default value of ‘now()’ so that it always adds a date to our blog post
- cardContent — type: character varying — this will hold the blog post content
- id — type: integer — make sure to make this an index value (AI checkbox)
Setting up AdminJS instance
Head over to the ‘backend’ folder and create a file called ‘index.ts’. The first things we’re going to take care of are: setting up the adapter, connecting to the database, and setting up the posts resource.
In order to do that, we will have to install dependencies. My package manager of choice is yarn.
$ yarn add adminjs
$ yarn add express
$ yarn add express-formidable
$ yarn add express-session
$ yarn add @adminjs/express
$ yarn add @adminjs/sql
With the dependencies installed, open the file called ‘index.ts’ and add the following code:
Let’s see if we can add our first blog post through the AdminJS panel. Open the backend ‘package.json’ file and add a ‘dev’ script to it.
Now that we want to use Typescript to build our code, we will need to add all developer dependencies.
$ yarn add -D typescript
$ yarn add -D tslib
You should also create a tsconfig.json
file:
With the dependencies installed, we’re ready to launch AdminJS.
$ yarn build && yarn start
The panel will be available at http://localhost:3001/admin
, where you will be able to add your first blog post.
There is one small thing that would be nice to address right now, namely a rich text editor. After all, we want all blog posts to be something more than just a bunch of words, we want to be able to import images, add headings, and add links.
const admin = new AdminJS({
resources: [
{
resource: db.table('posts'),
options: {
properties: {
cardContent: {
type: 'richtext',
},
},
},
},
],
});
Much better.
Building a blog with Next.js
Now that the backend part of things is sorted, let’s take care of the pretty parts.
Next.js is a fronted framework that will take care of the navigation components and blog posts. We’re going to mostly rely on readily available React components.
Let’s start by initializing yarn. Navigate to your project directory and create a new folder called ‘frontend’. Once inside the new folder — initialize your project.
$ yarn init
Make sure to point to ‘pages/index.js’ as the entry point of your app. Next, inside the pages folder, create ‘components’, ‘styles’, ‘public’ folders, and a ‘index.js’ file. Inside the ‘components’ folder create files named ‘Cards.component.js’, ‘Menu.components.js’, and ‘AnimatedText.components.js’.
We will need to take care of our dependencies:
$ yarn add react
$ yarn add react-dom
$ yarn add next
$ yarn add axios
$ yarn add @mui/material
$ yarn add @mui/lab
$ yarn add @emotion/react
$ yarn add @emotion/styled
We’re going to use React.js, Next.js, Axios, and MUI. Axios is here to take care of the API requests, and MUI will provide clean-looking and easy-to-use components.
Displaying all our blog posts
Now that most of our files and folders are created, we can start working on the way the blog posts are going to be displayed. We want all the blog posts to be shown as soon as they are added to the database. In order to do that, we will need to fetch data from the backend. Luckily, that’s pretty easy with AdminJS, as it provides a convenient API for that.
Inside the ‘Cards.component.js’ file, we will create a class called ‘PostList’ and add the following code. Keep in mind you will have to import React first.
In order to fetch all our blog posts, we will need to use Axios and point it at Admin’s API address, which is ‘http://localhost:3001/admin/api/resources/posts/actions/list'. Be sure to add ‘?direction=desc&sortBy=id’ at the end of it, as we want our messages sorted from newest to oldest.
Let’s add a ‘componentDidMount’ method inside the class. This method will be called every time our PostList component mounts. With a bit of JSON beautifying, we know that ‘res.data.records’ is an array of objects, and to be more precise an array of posts.
import axios from 'axios';
// ...
componentDidMount() {
axios.get(`http://localhost:3001/admin/api/resources/posts/actions/list?direction=desc&sortBy=id`).then((res) => {
const posts = res.data.records;
this.setState({ posts });
});
}
Next up, we need a way to take all the data from the API response and put it in a readable format. For that, we will create a ‘generatePost’ method.
import Card from '@mui/material/Card';
import CardHeader from '@mui/material/CardHeader';
import CardContent from '@mui/material/CardContent';
// ...
generatePost(record) {
const date = new Date(record.params.cardHeaderSub);
return (
<Card>
<CardHeader title={record.params.cardHeaderTitle} subheader={date.toLocaleDateString()} />
<CardContent>
<div dangerouslySetInnerHTML={{ __html: record.params.cardContent }} />
</CardContent>
</Card>
);
}
Now, let’s add the component we just created to the landing page of our website. Open the file called ‘index.js’ and add the following code.
Let’s see what the page looks like currently and if the component fetching data from the database is working correctly.
Head to the frontend ‘package.json’ file and add a ‘dev’ script. This time, however, we will be using Next.js to run it.
Run the dev command through yarn in your terminal (make sure you’re in the root directory of the frontend app).
$ yarn run dev
The website will be accessible at ‘http://localhost:3000/'.
That’s more like it! We’ve got the first blog post already there. Time to add some more functionality and pizazz added to our blog template.
Head to the file called ‘Menu.component.js’. We’ll create really simple tab-based navigation.
I’ve added an ‘About me’ section, after all the nav component has to be used for something, right?
In the ‘index.js’ file, we will need to add our menu app object and wrap blog posts with it.
Adding pizzas to every blog post
All there’s left to do is to add some pizazz with an animated logo. Head to the ‘pages’ folder, inside of which you will find ‘components’ and finally the ‘AnimatedText.component.js’. You will have to import React here too.
Mind you all the numbers are needed here, due to the fact that we’re importing a .svg file.
Next, in the ‘index.js’ file, we’ll import and then drop the logo component, like so:
I’ve added another post to test things and, as you can clearly see, the blog posts are too close to each other.
We’ll take care of that and a couple of other things with a bit of styling. First, in the folder called ‘styles’ find the ‘styles.mui.js’ file.
Then, we’ll have to append the style sheet we’ve created to our components. Head to ‘index.js’ to do that.
import { ThemeProvider } from '@mui/material'
import { theme } from './styles/styles.mui'
// ...
<ThemeProvider theme={theme}>{MenuApp(<PostList />)}</ThemeProvider>
// ...
The last two things we’re going to add are animation to an otherwise overly static logo and an override that hides the scrollbar. Open the ‘globals.css’ file.
However, Next.js won’t use the ‘globals.css’ file until we explicitly tell it to do so. You will have to create a file called ‘_app.js’ in the ‘pages’ folder. Inside we will define a function ‘MyApp’.
And just like that, we’ve got a simple blog template that can be managed by someone with a basic understanding, as we’ve got AdminJS to help with that.
Further steps
We’ve created a blog template with Next.js, AdminJS, and React. Simple, yet functional. You can easily add new posts with AdminJS’s rich text editor. There are a lot of options to customize your own blog now and most importantly you don’t have to be a full-blown backend developer or a React developer to do so.
If you run into issues while building your own blog, or would like to have a quick chat with me and the team behind AdminJS, be sure to check out our Slack Community. If you are looking for an even easier way of building a CMS for your blog, we’ve got a made-to-order Cloud-based solution for which a trial period is now available!