Content Routes
Analog also supports using markdown content as routes, and rendering markdown content in components.
Setup
In the src/app/app.config.ts
, add the provideContent()
function, along with the withMarkdownRenderer()
feature to the providers
array when bootstrapping the application.
import { ApplicationConfig } from '@angular/core';
import { provideContent, withMarkdownRenderer } from '@analogjs/content';
export const appConfig: ApplicationConfig = {
providers: [
// ... other providers
provideContent(withMarkdownRenderer()),
],
};
Defining Content Routes
Content routes include support for frontmatter, metatags, and syntax highlighting with PrismJS.
The example route below in src/app/pages/about.md
defines an /about
route.
---
title: About
meta:
- name: description
content: About Page Description
- property: og:title
content: About
---
## About Analog
Analog is a meta-framework for Angular.
[Back Home](./)
Using the diff Highlight Plugin
Analog supports highlighting diff changes with PrismJS. Add the diff
language and diff-highlight
plugin imports to app.config.ts
:
import 'prismjs/components/prism-diff';
import 'prismjs/plugins/diff-highlight/prism-diff-highlight';
Use the diff
language tag to highlight them or
diff-<language>
to highlight the diff changes in a specific language.
```diff
- This is a sentence.
+ This is a longer sentence.
```
```diff-typescript
- const foo = 'bar';
+ const foo = 'baz';
```
To highlight changed line backgrounds instead of just the text, add this import to your global stylesheet:
@import 'prismjs/plugins/diff-highlight/prism-diff-highlight.css';
Defining Content Files
For more flexibility, markdown content files can be provided in the src/content
folder. Here you can list markdown files such as blog posts.
---
title: My First Post
slug: 2022-12-27-my-first-post
description: My First Post Description
coverImage: https://images.unsplash.com/photo-1493612276216-ee3925520721?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=464&q=80
---
Hello World
Using the Content Files List
To get a list using the list of content files in the src/content
folder, use the injectContentFiles<Attributes>(filterFn?: InjectContentFilesFilterFunction<Attributes>)
function from the @analogjs/content
package in your component. To narrow the files, you can use the filterFn
predicate function as an argument. You can use the InjectContentFilesFilterFunction<T>
type to set up your predicate.
import { Component } from '@angular/core';
import { RouterLink, RouterOutlet } from '@angular/router';
import { injectContentFiles } from '@analogjs/content';
import { NgFor } from '@angular/common';
export interface PostAttributes {
title: string;
slug: string;
description: string;
coverImage: string;
}
@Component({
standalone: true,
imports: [RouterOutlet, RouterLink, NgFor],
template: `
<ul>
<li *ngFor="let post of posts">
<a [routerLink]="['/blog', 'posts', post.slug]">{{
post.attributes.title
}}</a>
</li>
</ul>
`,
})
export default class BlogComponent {
readonly posts = injectContentFiles<PostAttributes>((contentFile) =>
contentFile.filename.includes('/src/content/blog/')
);
}
Using the Analog Markdown Component
Analog provides a MarkdownComponent
and injectContent()
function for rendering markdown content with frontmatter.
The injectContent()
function uses the slug
route parameter by default to get the content file from the src/content
folder.
// /src/app/pages/blog/posts.[slug].page.ts
import { injectContent, MarkdownComponent } from '@analogjs/content';
import { AsyncPipe, NgIf } from '@angular/common';
import { Component } from '@angular/core';
export interface PostAttributes {
title: string;
slug: string;
description: string;
coverImage: string;
}
@Component({
standalone: true,
imports: [MarkdownComponent, AsyncPipe, NgIf],
template: `
<ng-container *ngIf="post$ | async as post">
<h1>{{ post.attributes.title }}</h1>
<analog-markdown [content]="post.content"></analog-markdown>
</ng-container>
`,
})
export default class BlogPostComponent {
readonly post$ = injectContent<PostAttributes>();
}
Enabling support for Mermaid
Analog's markdown component supports Mermaid. To enable support by the MarkdownComponent
define a dynamic import for loadMermaid
in withMarkdownRenderer()
.
withMarkdownRenderer({
loadMermaid: () => import('mermaid'),
});
After it is enabled, Mermaid blocks are transformed by mermaid into SVGs.
Example of mermaid graph:
graph TD
A[Before] -->|Playing with AnalogJS| B(Now Yes !)
Support for Content Subdirectories
Analog also supports subdirectories within your content folder.
The injectContent()
function can also be used with an object that contains the route parameter and subdirectory name.
This can be useful if, for instance, you have blog posts, as well as a portfolio of project markdown files to be used on the site.
src/
└── app/
│ └── pages/
│ └── project.[slug].page.ts
└── content/
├── posts/
│ ├── my-first-post.md
│ └── my-second-post.md
└── projects/
├── my-first-project.md
└── my-second-project.md
// /src/app/pages/project.[slug].page.ts
import { injectContent, MarkdownComponent } from '@analogjs/content';
import { AsyncPipe, NgIf } from '@angular/common';
import { Component } from '@angular/core';
export interface ProjectAttributes {
title: string;
slug: string;
description: string;
coverImage: string;
}
@Component({
standalone: true,
imports: [MarkdownComponent, AsyncPipe, NgIf],
template: `
<ng-container *ngIf="project$ | async as project">
<h1>{{ project.attributes.title }}</h1>
<analog-markdown [content]="project.content"></analog-markdown>
</ng-container>
`,
})
export default class ProjectComponent {
readonly project$ = injectContent<ProjectAttributes>({
param: 'slug',
subdirectory: 'projects',
});
}
Loading Custom Content
By default, Analog uses the route params to build the filename for retrieving a content file from the src/content
folder. Analog also supports using a custom filename for retrieving content from the src/content
folder. This can be useful if, for instance, you have a custom markdown file that you want to load on a page.
The injectContent()
function can be used by passing an object that contains the customFilename
property.
readonly post$ = injectContent<ProjectAttributes>({
customFilename: 'path/to/custom/file',
});