Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: update injectContent function to return content object instead of string #228

Closed
2 tasks
brandonroberts opened this issue Jan 20, 2023 · 4 comments · Fixed by #229
Closed
2 tasks
Labels
enhancement New feature or request

Comments

@brandonroberts
Copy link
Member

brandonroberts commented Jan 20, 2023

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

content

Information

Currently if you want to display a single post, you can use the injectContent() function to get the rendered markdown as a string. If you want to display the metadata from the content within the component, you basically have to reimplement injectContent() to return the content with metadata.

import { AsyncPipe, DatePipe, NgIf } from '@angular/common';
import { Component } from '@angular/core';
import { MarkdownComponent } from '@analogjs/content';
import { ContentFile, injectContentFiles } from '@analogjs/content';
import { injectActivatedRoute } from '@analogjs/router';

export function injectPost(slug: string) {
  const route = injectActivatedRoute();
  return injectContentFiles<Post>().find(
    (posts) =>
      posts.filename === `/src/content/${route.snapshot.paramMap.get(slug)}.md`
  );
}

@Component({
  selector: 'post',
  standalone: true,
  imports: [MarkdownComponent, AsyncPipe, NgIf, DatePipe, ReadingTimePipe],
  template: `
    <div class="flex flex-grow justify-center min-h-screen" *ngIf="post">
      <article class="w-screen max-w-4xl p-8">
        <h2 class="text-gray-600 text-2xl">{{ post.attributes.title }}</h2>

        <span class="font-light text-sm">
          {{ post.attributes.publishedDate | date : 'MMMM dd, yyyy' }} -
          {{ post.content | readingtime }} min read
        </span>

        <analog-markdown [content]="post.content"></analog-markdown>
      </article>
    </div>
  `,
})
export default class BlogPostComponent {
  post = injectPost('slug');
}

The proposed change would return the content with metadata instead of the string itself

import { AsyncPipe, DatePipe, NgIf } from '@angular/common';
import { Component } from '@angular/core';
import { MarkdownComponent, injectContent } from '@analogjs/content';

export interface Post {
  title: string;
  slug: string;
  published: boolean;
  publishedDate: string;
}

@Component({
  selector: 'post',
  standalone: true,
  imports: [MarkdownComponent, AsyncPipe, NgIf, DatePipe, ReadingTimePipe],
  template: `
    <div class="flex flex-grow justify-center min-h-screen" *ngIf="post">
      <article class="w-screen max-w-4xl p-8">
        <h2 class="text-gray-600 text-2xl">{{ post.attributes.title }}</h2>

        <span class="font-light text-sm">
          {{ post.attributes.publishedDate | date : 'MMMM dd, yyyy' }} -
          {{ post.content | readingtime }} min read
        </span>

        <analog-markdown [content]="post.content"></analog-markdown>
      </article>
    </div>
  `,
})
export default class BlogPostComponent {
  post = injectContent<Post>();
}

Describe any alternatives/workarounds you're currently using

No response

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

  • Yes
  • No
@brandonroberts brandonroberts added the enhancement New feature or request label Jan 20, 2023
@goetzrobin
Copy link
Member

@brandonroberts just ran into the same issue working on my personal website! I can work on this if you want

@brandonroberts
Copy link
Member Author

That would be great 👍

@goetzrobin
Copy link
Member

Awesome! What do you think we should do when no file is found for the current route?
Currently the customFallback param is returned.
When returning an object we have other options:

  1. Returning an optional ContentFile inside the Observable & deprecating the fallback param
export function injectContent<
  Attributes extends Record<string, any> = Record<string, any>
>(
  param = 'slug',
  fallback = 'No Content Found'
): Observable<ContentFile<Attributes> | undefined> {
  const route = inject(ActivatedRoute);
  const contentFiles = injectContentFiles<Attributes>();
  return route.paramMap.pipe(
    map((params) => params.get(param)),
    map((slug) => {
      return contentFiles.find(
        (file) => file.filename === `/src/content/${slug}.md`
      );
    })
  );
}
  1. Building a 'not found' ContentFile that returns the customFallback as its content
export function injectContent<
  Attributes extends Record<string, any> = Record<string, any>
>(
  param = 'slug',
  fallback = 'No Content Found'
): Observable<ContentFile<Attributes | Record<string, never>>> {
  const route = inject(ActivatedRoute);
  const contentFiles = injectContentFiles<Attributes | Record<string, never>>();
  return route.paramMap.pipe(
    map((params) => params.get(param)),
    map((slug) => {
      return (
        contentFiles.find(
          (file) => file.filename === `/src/content/${slug}.md`
        ) || {
          attributes: {},
          filename: '',
          content: fallback,
        }
      );
    })
  );
}

Let me know what you think 👍

@brandonroberts
Copy link
Member Author

Option 2 is good to me

goetzrobin added a commit to goetzrobin/analog that referenced this issue Jan 22, 2023
… instead of string

instead of only extracting the content string from
the front-matter results the full object is returned.

closes analogjs#228
brandonroberts pushed a commit that referenced this issue Jan 22, 2023
#229)

Closes #228

BREAKING CHANGES:

The signature of the `injectContent` function has changed.

BEFORE:

injectContent now returns an observable of a string from the rendered markdown.

AFTER:

injectContent now ContentFile<Attributes | Record<string, never>> which is an object that includes the rendered markdown as the `content` property.
Villanuevand pushed a commit to Villanuevand/analog that referenced this issue Sep 12, 2023
analogjs#229)

Closes analogjs#228

BREAKING CHANGES:

The signature of the `injectContent` function has changed.

BEFORE:

injectContent now returns an observable of a string from the rendered markdown.

AFTER:

injectContent now ContentFile<Attributes | Record<string, never>> which is an object that includes the rendered markdown as the `content` property.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants