Feature: Allow for custom component to be passed to render .md routes

This issue has been tracked since 2023-01-18.

Which scope/s are relevant/related to the feature request?

router

Information

This relates to #214

I would like to propose allowing developers to pass in their own custom components to render
their markdown routes. We still default to the built in MarkdownComponent provided by
Analog.

To achieve that I am proposing to allow to pass a customComponent to the getRoutes function

/**
 * Function used to parse list of files and return
 * configuration of routes.
 *
 * @param files
 * @param customComponent
 * @returns Array of routes
 */
export function getRoutes(files: Files, customComponent?: Type<unknown>) {
  const ROUTES = Object.keys(files).sort((a, b) => a.length - b.length);

  const routeConfigs = ROUTES.reduce<Route[]>(
    (routes: Route[], key: string) => {
      const module = key.endsWith('.md')
        ? buildModule({ _analogContent: files[key] }, customComponent)
        : (files[key] as () => Promise<RouteExport>);
...

Then, it is determined if the custom component should be used or the default component from Analog.

function buildModule(
  routeMeta: RouteMeta,
  customComponent?: Type<unknown>
): () => Promise<RouteExport> {
  console.log('customComponent', customComponent);
  return customComponent
    ? () =>
        Promise.resolve({
          default: customComponent,
          routeMeta,
        })
    : () =>
        import('@analogjs/content').then((m) => ({
          default: m.MarkdownComponent,
          routeMeta,
        }));
}

I am not sure what the best way to register this component would be.
Ideally, it could just be passed as the features array here:

export const provideFileRouter = (
  ...features: (RouterFeatures | Type<unknown>)[]
) => {
  const component = features.shift();
  return provideRouter(
    getAnalogRoutesWithComponent(component as Type<unknown>),
    ...(features as RouterFeatures[])
  );
};

The custom component is to be passed through here:

export function getAnalogRoutesWithComponent(customComponent?: Type<unknown>): Route[] {
  return [...getRoutes({ ...FILES, ...CONTENT_FILES }, customComponent)];
}

I think there is probably a bunch of ways to improve this.
Obviously a better way to pass in the component in the config.
Also, making the custom component extend a base class that injects the content, etc.
I just wanted to open this issue to get a conversation going, because I think this could allow for some great customization.

Describe any alternatives/workarounds you're currently using

No response

I would be willing to submit a PR to fix this issue

  • Yes
  • No
markostanimirovic wrote this answer on 2023-01-25

Hi @goetzrobin 👋

Can you give an example where a custom markdown component would be a better fit?

If we need to define a custom shell for the markdown route, we can use the file router "shell" feature:

// routes/about/index.md

# About

About Page

// routes/about.ts

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

@Component({
  standalone: true,
  imports: [RouterOutlet],
  template: `
    <p>Before</p>
    <router-outlet></router-outlet> <!-- about/index.md content will be rendered here -->
    <p>After</p>
  `,
})
export default class AboutComponent {}
goetzrobin wrote this answer on 2023-01-25

Hi @markostanimirovic,
I think that actually makes sense.
The use case I was thinking about is:
I want to wrap all my markdown components in the same styling, e.g. add a header/footer, etc.

But I think it might be overcomplicating things as global layouts can be placed in the AppComponent
and if I really wanted specific styling I can add that as you described above.

I am ready to close this issue unless you want to leave it open for someone else to make an argument 👍

More Details About Repo
Owner Name analogjs
Repo Name analog
Full Name analogjs/analog
Language TypeScript
Created Date 2022-07-06
Updated Date 2023-03-28
Star Count 885
Watcher Count 18
Fork Count 67
Issue Count 33

YOU MAY BE INTERESTED

Issue Title Created Date Updated Date