Analog
On this page

Rutas de Contenido

Analog también soporta el uso de contenido en markdown como rutas y la renderización de contenido en componentes.

Configuración

En el archivo src/app/app.config.ts, añade la función provideContent() junto con la característica withMarkdownRenderer() al arreglo de providers al iniciar la aplicación.

export const appConfig: ApplicationConfig = {
  providers: [
    // ... otros proveedores
    provideContent(withMarkdownRenderer()),
  ],
};

Luego, habilitar el paquete contenido en el archivo vite.config.ts

/// <reference types="vitest" />
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
  plugins: [
    analog({
      // enable content/highlighter
      content: {
        highlighter: 'prism',
      },
    }),
  ],
}));

Definiendo Rutas de Contenido

Las rutas de contenido incluyen soporte para frontmatter, metatags y resaltado de sintaxis con PrismJS.

El ejemplo de ruta a continuación en src/app/pages/about.md define una ruta /about.

---
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](./)

Resaltado de Sintaxis con PrismJS

Analog soporta el resaltado de sintaxis con PrismJS. Para habilitar el resaltado de sintaxis con PrismJS, añade withPrismHighlighter() a la función provideContent() en app.config.ts.

+ import { withPrismHighlighter } from '@analogjs/content/prism-highlighter';

export const appConfig: ApplicationConfig = {
  providers: [
    // ... otros proveedores
-   provideContent(withMarkdownRenderer()),
+   provideContent(withMarkdownRenderer(), withPrismHighlighter()),
  ],
};

Importa un tema de Prism en tu hoja de estilos global:

@import 'prismjs/themes/prism.css';

Usando el Plugin de Resaltado diff

Analog soporta el resaltado de cambios en diffs con PrismJS.

Añade el lenguaje prism-diff a additionalLangs en el plugin analog:

export default defineConfig({
  // ...
  plugins: [
    analog({
      content: {
        highlighter: 'prism',
        prismOptions: {
          additionalLangs: ['prism-diff'],
        },
      },
    }),
  ],
});

Añade la importación del plugin diff-highlight al app.config.ts:

+ import { withShikiHighlighter } from '@analogjs/content/shiki-highlighter';

export const appConfig: ApplicationConfig = {
  providers: [
    // ... otros proveedores
-   provideContent(withMarkdownRenderer()),
+   provideContent(withMarkdownRenderer(), withShikiHighlighter()),
  ],
};

Para habilitar el resaltado de sintaxis en tiempo de compilación con shiki, configura el plugin analog en el vite.config.ts.

export default defineConfig({
  // ...
  plugins: [
    analog({
      content: {
        highlighter: 'shiki',
      },
    }),
  ],
});

Configurar el Resaltador Shiki

Por favor, consulta la Documentación de Shiki para más información sobre la configuración de Shiki.

Para configurar Shiki, puedes pasar opciones al objeto shikiOptions.

export default defineConfig({
  // ...
  plugins: [
    analog({
      content: {
        highlighter: 'shiki',
        shikiOptions: {
          highlight: {
            // tema alternativo
            theme: 'ayu-dark'
          }
          highlighter: {
             // añadir más lenguajes
            additionalLangs: ['mermaid'],
          },
        },
      },
    }),
  ],
});

Por defecto, shikiOptions tiene las siguientes opciones.

{
  "container": "%s",
  "highlight": {
    "theme": "github-dark"
  }
  "highlighter": {
    "langs": [
      "json",
      "ts",
      "tsx",
      "js",
      "jsx",
      "html",
      "css",
      "angular-html",
      "angular-ts",
    ],
    "themes": ["github-dark", "github-light"]
  }
}

Definiendo Archivos de Contenido

Para mayor flexibilidad, los archivos de contenido en markdown pueden proporcionarse en la carpeta src/content. Aquí puedes listar archivos markdown como entradas de blog.

---
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

Usando la Lista de Archivos de Contenido

Para obtener una lista usando los archivos de contenido en la carpeta src/content, usa la función injectContentFiles(filterFn?: InjectContentFilesFilterFunction) del paquete @analogjs/content en tu componente. Para filtrar los archivos, puedes usar la función predicado filterFn como argumento. Puedes usar el tipo InjectContentFilesFilterFunction para configurar tu predicado.

export interface PostAttributes {
  title: string;
  slug: string;
  description: string;
  coverImage: string;
}

@Component({
  imports: [RouterOutlet, RouterLink],
  template: `
    <ul>
      @for (post of posts; track post.slug) {
        <li>
          <a [routerLink]="['/blog', 'posts', post.slug]">
            {{ post.attributes.title }}
          </a>
        </li>
      } @empty {
        <li>No posts yet.</li>
      }
    </ul>
  `,
})
export default class BlogComponent {
  readonly posts = injectContentFiles<PostAttributes>((contentFile) =>
    contentFile.filename.includes('/src/content/blog/'),
  );
}

Usando el Componente Markdown de Analog

Analog provee un MarkdownComponent y la función injectContent() para renderizar contenido en markdown con frontmatter.

La función injectContent() usa el parámetro de ruta slug por defecto para obtener el archivo de contenido de la carpeta src/content.

// /src/app/pages/blog/posts.[slug].page.ts
export interface PostAttributes {
  title: string;
  slug: string;
  description: string;
  coverImage: string;
}

@Component({
  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>();
}

Usando un Resolver para Metatags

En tu configuración de rutas, puedes usar el objeto RouteMeta para resolver metatags para una ruta. Esto se hace asignando la función postMetaResolver a la propiedad meta.

A continuación se muestra un ejemplo de uso de una función postMetaResolver que obtiene los metatags para una entrada. Esta función retorna un arreglo de metatags.

export const postMetaResolver: ResolveFn<MetaTag[]> = (route) => {
  const postAttributes = injectActivePostAttributes(route);

  return [
    {
      name: 'description',
      content: postAttributes.description,
    },
    {
      name: 'author',
      content: 'Analog Team',
    },
    {
      property: 'og:title',
      content: postAttributes.title,
    },
    {
      property: 'og:description',
      content: postAttributes.description,
    },
    {
      property: 'og:image',
      content: postAttributes.coverImage,
    },
  ];
};

Los metatags también pueden ser resueltos de forma asíncrona. Asigna la función postMetaResolver a la propiedad meta.

export const routeMeta: RouteMeta = {
  title: postTitleResolver,
  meta: postMetaResolver,
};

Los metatags resueltos también pueden ser accedidos en el componente usando el servicio ActivatedRoute.

export default class BlogPostComponent {
  readonly route = inject(ActivatedRoute);
  readonly metaTags$ = this.route.data.pipe(map(data => data['meta']));

  // En la plantilla
  <my-component [metaTags]="metaTags$ | async"></my-component>
}

Habilitando el Soporte para Mermaid

El componente markdown de Analog soporta Mermaid. Para habilitar el soporte por el MarkdownComponent, define una importación dinámica para loadMermaid en withMarkdownRenderer().

withMarkdownRenderer({
  loadMermaid: () => import('mermaid'),
});

Después de habilitarlo, los bloques de Mermaid son transformados por mermaid en SVGs.

Ejemplo de gráfico Mermaid:

graph TD
    A[Before] -->|Playing with AnalogJS| B(Now Yes !)

Soporte para Subdirectorios de Contenido

Analog también soporta subdirectorios dentro de tu carpeta de contenido.

La función injectContent() también puede ser usada con un objeto que contiene el parámetro de ruta y el nombre del subdirectorio.

Esto puede ser útil si, por ejemplo, tienes entradas de blog, así como un portafolio de archivos markdown de proyectos para ser usados en el sitio.

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
export interface ProjectAttributes {
  title: string;
  slug: string;
  description: string;
  coverImage: string;
}

@Component({
  imports: [MarkdownComponent, AsyncPipe],
  template: `
    @if (project$ | async; as project) {
      <h1>{{ project.attributes.title }}</h1>
      <analog-markdown [content]="project.content"></analog-markdown>
    }
  `,
})
export default class ProjectComponent {
  readonly project$ = injectContent<ProjectAttributes>({
    param: 'slug',
    subdirectory: 'projects',
  });
}

Cargando Contenido Personalizado

Por defecto, Analog usa los parámetros de ruta para construir el nombre de archivo para recuperar un archivo de contenido de la carpeta src/content. Analog también soporta el uso de un nombre de archivo personalizado para recuperar contenido de la carpeta src/content. Esto puede ser útil si, por ejemplo, tienes un archivo markdown personalizado que deseas cargar en una página.

La función injectContent() puede ser usada pasando un objeto que contiene la propiedad customFilename.

readonly post$ = injectContent<ProjectAttributes>({
  customFilename: 'path/to/custom/file',
});