shortcodes

shortcodes enhances your markdown content with interactive Angular components. Works with static site generator scully and ngx-markdown.

Getting Started

Installation

First, install the library using npm or yarn

npm i @notiz/shortcodes
# or
yarn add @notiz/shortcodes

Next, import ShortcodeModule in your content module and wrap your markdown content (<scully-content></scully-content> or <markdown></markdown>) with the shortcodes or scullyShortcodes directive. The shortcodes directive is responsible to render the shortcodes correctly.

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { ShortcodeModule } from '@notiz/shortcodes';
import { BlogRoutingModule } from './blog-routing.module';
import { BlogComponent } from './blog.component';

@NgModule({
  declarations: [BlogComponent],
  imports: [
    CommonModule, 
    BlogRoutingModule, 
    ShortcodeModule
  ],
})
export class BlogModule {}

Scully

You need to setup a Angular Scully Project first. If you don't know how, read the blog post Jamstack with Angular and Scully or consolidate the scully docs.

Add ScullyLibModule to your module.

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
+import { ScullyLibModule } from '@scullyio/ng-lib';
import { ShortcodeModule } from '@notiz/shortcodes';
import { BlogRoutingModule } from './blog-routing.module';
import { BlogComponent } from './blog.component';

@NgModule({
  declarations: [BlogComponent],
  imports: [
    CommonModule, 
    BlogRoutingModule, 
    ShortcodeModule,
+   ScullyLibModule
  ],
})
export class BlogModule {}

Wrap scully-content with the scullyShortcodes directive.

import { Component } from '@angular/core';

@Component({
  selector: 'app-blog',
  template: `
    <div scullyShortcodes>
      <scully-content></scully-content>
    </div>
  `,
})
export class BlogComponent {}

Next, add the provided Scully Plugin to your Scully Configuration

import { ScullyConfig } from '@scullyio/scully';
import './node_modules/@notiz/shortcodes/scully';
export const config: ScullyConfig = {
  projectRoot: './src',
  projectName: 'app',
  outDir: './dist/static',
  routes: {
    '/:slug': {
      type: 'contentFolder',
      slug: {
        folder: './docs',
      },
+     postRenderers: ['shortcodes'],
    },
  }
};

ngx-markdown

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
+import { MarkdownModule } from 'ngx-markdown';
+import { HttpClient, HttpClientModule } from '@angular/common/http';
import { ShortcodeModule } from '@notiz/shortcodes';
import { BlogRoutingModule } from './blog-routing.module';
import { BlogComponent } from './blog.component';

@NgModule({
  declarations: [BlogComponent],
  imports: [
    CommonModule, 
    BlogRoutingModule, 
    ShortcodeModule,
+   HttpClientModule,
+   MarkdownModule.forRoot({ loader: HttpClient }),
  ],
})
export class BlogModule {}

Wrap markdown with the shortcodes directive.

import { Component } from '@angular/core';

@Component({
  selector: 'app-blog',
  template: `
    <div shortcodes>
      <markdown [src]="..."></markdown>
    </div>
  `,
})
export class BlogComponent {}

Usage

A shortcode is a normal Angular component containing any templates (from buttons, images to charts), styles, animations and much more.

Shortcode component

Let's create an Angular note component to use as shortcode. In this example, the component is styled with Tailwind CSS utility classes and using material icons.

import { Component, HostBinding, Input } from '@angular/core';

@Component({
  selector: 'app-note',
  template: `
    <i
      class="material-icons-outlined  mt-2"
      [ngClass]="{
        'text-green-700': type === 'success',
        'text-red-700': type === 'danger'
      }"
    >
      {{ type === 'success' ? 'info' : 'dangerous' }}
    </i>

    <div
      [ngClass]="{
        'text-green-700': type === 'success',
        'text-red-700': type === 'danger'
      }"
    >
      <ng-content></ng-content>
    </div>
  `,
})
export class NoteComponent {
  @HostBinding('class')
  get class(): string {
    return `flex space-x-5 border-l-4  rounded-md  p-4 ${
      this.type === 'success'
        ? 'border-green-700 bg-green-50'
        : 'border-red-700 bg-red-50'
    }`;
  }

  @Input() type: 'success' | 'danger' = 'success';
}

Register the shortcode component in the ShortcodeModule in your app.module.ts. This allows to lazy load each shortcode component, similar to the RouterModule.

import { NgModule } from '@angular/core';
import { ShortcodeModule } from '@notiz/shortcodes';

@NgModule({
...
  imports: [
    ShortcodeModule.forRoot([
      {
        shortcode: 'demos',
        loadChildren: () =>
          import('./demos/demos.module').then((m) => m.DemosModule),
      }
    ]),
  ],
  ...
})
export class AppModule {}

Lastly, register the shortcode component with a name in your component.module.ts. The name will be used in your markdown files.

import { NgModule } from '@angular/core';
import { ShortcodeModule, Shortcodes } from '@notiz/shortcodes';
import { NoteComponent } from './note.component';

const shortcodes: Shortcodes = [
  { shortcode: 'note', component: NoteComponent },
];

@NgModule({
  imports: [ShortcodeModule.forChild(shortcodes)],
  declarations: [NoteComponent],
})
export class DemosModule {}

Use your shortcode in your content

Now you are ready to use your shortcode in your markdown content. Add a div with shortcode="path/shortcodeName" to specify your shortcode component. The content will replace the <ng-content></ng-content> inside the note component.

<div shortcode="demos/note">

# This is a note!

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

</div>

Input's are possible too, add them after the shortcode on your div.

<div shortcode="demos/note" type="danger">

# This is a note!

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

</div>

Result

This is a note!

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

note shortcode with input type="danger"

This is a note!

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.