AdminBro feature allowing you to add an amazing blog to your project.
Features
- Beautiful UI
- Uploading inline files and splash screen
- Auto-saving
- Draft and Publish states
- Assign Tags
- Managing of post's Meta-Data like ogTags, Facebook meta or Twitter meta
Demo
To see the demo visit: http://premium.adminbro.com
Where to buy this addon?
The price of the addon is 100 USD. It covers:
- addon itself with the license to host it on 1 site
- access addon updates for 1 year
- our support
To buy it - contact us on slack on #premium addons channel or the email: [email protected]
Installation
To install the addon run:
yarn add @softwarebrothers/admin-bro-blog
and install it's peer dependency @admin-bro/upload
yarn add @admin-bro/upload
Usage
As with other features - this one also has to be passed to the resource in AdminBroOptions#resources option:
import AdminBro from 'admin-bro'
import AdminBroExpress from '@admin-bro/express'
import blogFeature from '@softwarebrothers/admin-bro-blog'
// part where you load adapter and models
import BlogPost from './blog-post'
const options = {
resources: [{
resource: BlogPost,
options: {},
features: [blogFeature({
// your options goes here
})]
}]
}
const adminBro = new AdminBro(options)
// and the rest of your app
The simplest case
@softwarebrothers/admin-bro-blog has lot's of configuration options but let's start with something super simple, an article with the following properties:
- title, for storing post title
- postUrl, for post URLs
- body, here we will put content
- excerpt, here we will put article excerpt
- ogTags, here we will put metadata of open graph tags
- status, and finally - blog post status: either published or a draft
Let's imagine that we already have a simple-blog
model defined and this is our schema (typeorm
example, written in typescript):
import { BlogPostMeta } from '@softwarebrothers/admin-bro-blog'
@Entity({ name: 'simple-blogs' })
export class SimpleBlog extends BaseEntity {
@PrimaryGeneratedColumn()
public id: number;
@Column({ nullable: false })
public caption: string; // this is title
@Column({ type: 'text' })
public document: string; // this is body
@Column()
public status: string; // this is status
@Column({ nullable: false })
public slug: string; // this is postUrl
@Column({ nullable: true })
public shortDescription?: string; // this is excerpt
@Column({ type: 'jsonb', nullable: true })
public metaTags?: BlogPostMeta; // ogTags
@CreateDateColumn()
public createdAt: Date;
@UpdateDateColumn()
public updatedAt: Date;
}
type BlogPostMeta = {
title?: string;
description?: string;
}
Now go back to the settings section and lets map all these fields to the blogFeature()
{
features: [blogFeature({
properties: {
title: 'caption',
body: 'document',
status: 'status',
postUrl: 'slug',
excerpt: 'shortDescription',
ogTags: 'metaTags',
},
})]
}
And this is it. You have a running blog engine.
Adding photo upload
The basic case uses the native Quill Editor feature to add images to the content of a blog post as Base64 strings. This is ok for some cases but in general, you would like to change that to a regular upload.
So let's add:
- option to upload post "splash" image (aka.
postImage
) - option to upload multiple images to the blog post content.
To do this we have to add to our schema 2 new 'mixed' properties. This will be of type jsob
in
our typeorm example.
import { BlogPostImage, BlogPostImages } from '@admin-bro/upload'
@Entity({ name: 'simple-blogs' })
export class SimpleBlog extends BaseEntity {
// ... new properties
@Column({type: 'jsonb', nullable: true })
public image?: BlogPostImage; // this will be an image
@Column({ type: 'jsonb', nullable: true })
public inlineImages?: BlogPostImages; // this will hold all inline images
}
and alter the ResourceOptions by defining your upload provider.
For reference check out the @admin-bro/upload plugin documentation
In the example, I will use Google Storage so I had to add to environmental variables 2 properties:
- GOOGLE_APPLICATION_CREDENTIALS='path-to-your-json-file'
- GOOGLE_STORAGE_MEDIA_BUCKET=name-of-your-bucket
Next, I have to install Google Cloud SDK for storage
yarn add @google-cloud/storage
and now I can go back to setup @softwarebrothers/admin-bro-blog
{
features: [blogFeature({
properties: {
title: 'caption',
body: 'document',
status: 'status',
postUrl: 'slug',
excerpt: 'shortDescription',
ogTags: 'metaTags',
postImage: 'image', // we mapped postImage to the image `mixed` property in db
inlineImages: 'image', // we mapped postImage to the image `mixed` property in db
},
// this will be passed to @admin-bro/upload feature
uploadProvider: {
gcp: {
bucket: process.env.GOOGLE_STORAGE_MEDIA_BUCKET as string,
},
},
})]
}
And this is it as well - now we can upload both splash image and "inline" images inside the editor.
Tags
The last things are tags. To add them you will have to have Tags
model in the database and
set tags
property in the BlogOptions
.
Let's start with tags model (typeorm example):
@Entity({ name: 'tags' })
export class Tag extends BaseEntity {
@PrimaryGeneratedColumn()
public id: number;
@Column({ nullable: true })
public name: string;
}
Having it, you can now add tags to BlogOptions:
{
features: [blogFeature({
properties: {
title: 'caption',
body: 'document',
status: 'status',
postUrl: 'slug',
excerpt: 'shortDescription',
ogTags: 'metaTags',
postImage: 'image', // we mapped postImage to the image `mixed` property in db
inlineImages: 'image', // we mapped postImage to the image `mixed` property in db
},
// this will be passed to @admin-bro/upload fature
uploadProvider: {
gcp: {
bucket: process.env.GOOGLE_STORAGE_MEDIA_BUCKET as string,
},
},
tags: {
// under this property AdminBro will store all tags in BlogPost
property: 'tags',
// we created `Tag` model in typeorm. Basically this is what
// you see when you click tags in the path: `admin/resources/__HERE__/records`
resourceId: 'Tag',
// column responsible for holding tag name
nameColumn: 'name',
},
})]
}
Lastly, we have to update the SimpleBlog
entity by adding tags array:
@Entity({ name: 'simple-blogs' })
export class SimpleBlog extends BaseEntity {
// this will be array of numbers because we hold references in this format.
@Column({type: 'jsonb', nullable: true })
public tags?: Array<number>;
}
All options
For the list of all available options, you can take a look at BlogOptions below.
Example
in the repository there is an example-app
folder - check it out if you need more information.
Type Definitions
# BlogOptions
Configuration options for @softwarebrothers/admin-bro-blog feature
Properties:
Name | Type | Attributes | Description |
---|---|---|---|
properties |
object | ||
title |
string | Database property holding post title: should be a string type |
|
body |
string | Database property holding html body: should allow to save long texts |
|
status |
string | Property holding post status |
|
postUrl |
string |
<optional> |
URL of the post - so called slug. It is optional but highly recommended. |
excerpt |
string |
<optional> |
A brief information regarding the Blog post. Blog excerpts give your readers a taste or, teaser of a full blog post. When visitors see an excerpt that grabs their attention,, they can click the title, image, or Read More link to open the full post. |
ogTags |
string |
<optional> |
OpenGraph Tags which should be placed in the head of the page. |
facebookMeta |
string |
<optional> |
Similar to ogTags - facebook meta also has to be of type |
twitterMeta |
string |
<optional> |
Similar to ogTags - twitter meta also has to be of type |
postImage |
string |
<optional> |
Post image holds the main image which will be assigned to the post. You should use here,
a |
inlineImages |
string |
<optional> |
Inline images holds the images uploaded by the editor. Property selected here should be,
a |
updatedAt |
string |
<optional> |
updatedAt column which is used to hold the information about the update date. |
tags |
object |
<optional> |
Set in case blog should have tags. Tags are implemented as one to many |
property |
string | ||
resourceId |
string | ||
nameColumn |
string |
<optional> |
|
uploadProvider |
UploadOptionsProvider |
<optional> |
Upload provider options passed to @admin-bro/upload peerDependency., If you use either postImage or inlineImages you have to make sure that this is set. |
# BlogPostImage
Type for an mixed property stored in the database responsible for photoImage
You can use it in your TypeScript schema like this:
import { BlogPostImage } from '@softwarebrothers/admin-bro-blog'
Properties:
Name | Type | Description |
---|---|---|
key |
string | property holding object key (uploaded path) |
mime |
string | mime type of uploaded file |
bucket |
string | bucket (folder) where file has been stored |
size |
number | size of the uploaded file |
# BlogPostMeta
Type for an mixed property stored in the database responsible for meta tags like ogTags, facebookMeta and twitterMeta
Properties:
Name | Type | Description |
---|---|---|
title |
string | Meta title |
description |
string | Meta description |
# BlogPostImages
Similar to BlogPostImage but for mixed property stored in the database responsible
for inlineImages
.
Properties:
Name | Type | Description |
---|---|---|
key |
Array.<string> | Array holding object keys (uploaded path) |
mimeType |
Array.<string> | Array holding mime types |
bucket |
Array.<string> | Array holding buckets (folders) |
size |
Array.<number> | Array holding sizes |