feat: metadata for blog posts

Signed-off-by: Filipe Medeiros <hello@filipesm.eu>
This commit is contained in:
Filipe Medeiros 2023-04-11 20:32:13 +01:00
parent 743424d84c
commit 9112897833
Signed by: filipe
GPG key ID: 9533BD5467CC1E78
14 changed files with 102 additions and 16 deletions

Binary file not shown.

View file

@ -0,0 +1,30 @@
import getMostRecentRevisions from '../../lib/cms/getMostRecentRevisions';
import groq from 'groq';
export const forBlogPostPage = groq`
${getMostRecentRevisions(groq`_type == "blogPost"`)}
{
"slug": slug.current,
title,
content[]{
_type == 'image' => {
...,
"lqip": @.asset->metadata.lqip,
"alt": @.asset->altText,
"aspectRatio": @.asset->metadata.dimensions.aspectRatio
},
_type != 'image' => @
},
headerImage,
publishDate
}`;
export const forBlogPage = groq`
${getMostRecentRevisions(groq`_type == "blogPost"`)}
{
title,
summary,
publishDate,
"slug": slug.current
}
`;

View file

@ -0,0 +1,18 @@
---
import type { ImageObject } from '../lib/cms/types';
import urlFor from '../lib/cms/urlFor';
export interface Props {
description: string;
image: ImageObject;
twitterCardType: 'summary' | 'summary_large_image' | 'player' | 'app';
title?: string;
}
const { description, image, twitterCardType, title } = Astro.props;
---
<meta name="description" content={description} />
<meta name="og:image" content={urlFor(image).width(1200).height(630).url()} />
<meta name="twitter:card" content={twitterCardType} />
{title && <meta name="og:title" content={title} />}

View file

@ -1,6 +1,6 @@
---
import type { PortableTextBlock } from '@portabletext/types';
import urlFor from '../../../../lib/cms/urlFor';
import urlFor from '../../../lib/cms/urlFor';
export interface Props {
node: BlogPostContentImage;

View file

@ -13,9 +13,10 @@ const hasFooter = !!footer;
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/favicon" href="/favicon.ico" />
<title>{title}</title>
<slot name="metadata" />
</head>
<body class="bg-orange-50 font-serif">
<main class:list={['px-6 pt-4 md:px-20 md:pt-6', hasFooter && 'mb-32']}>

View file

@ -16,7 +16,9 @@ export const forBlogPostPage = groq`
_type != 'image' => @
},
headerImage,
publishDate
publishDate,
summary,
metadata
}`;
export const forBlogPage = groq`

View file

@ -0,0 +1,5 @@
export interface ImageObject {
_type: 'image';
_key: string;
asset: { _type: 'reference'; ref: string };
}

View file

@ -1,6 +1,6 @@
---
import client from '../../../lib/cms/client';
import { forLibraryPage } from '../../../lib/cms/queries/libraryItems';
import client from '../../lib/cms/client';
import { forLibraryPage } from '../../lib/cms/queries/libraryItems';
import ButtonLink from '../../components/ButtonLink.astro';
import CardLink from '../../components/CardLink.astro';
import PageTitle from '../../components/PageTitle.astro';

View file

@ -1,11 +1,27 @@
---
import type { PortableTextBlock } from '@portabletext/types';
import client from '../../../../lib/cms/client';
import { forBlogPostPage } from '../../../../lib/cms/queries/blogPosts';
import client from '../../../lib/cms/client';
import { forBlogPostPage } from '../../../lib/cms/queries/blogPosts';
import BlogPostContent from '../../../components/portableText/BlogPostContent.astro';
import ButtonLink from '../../../components/ButtonLink.astro';
import PageTitle from '../../../components/PageTitle.astro';
import Layout from '../../../layouts/Layout.astro';
import BlogPostMetadata from '../../../components/BlogPostMetadata.astro';
import type { ImageObject } from '../../../lib/cms/types';
export interface Props {
title: string;
content: PortableTextBlock[];
publishDate: string;
headerImage: ImageObject;
summary: string;
metadata: {
twitterCardType: 'summary' | 'summary_large_image' | 'player' | 'app';
description: string;
title: string;
image: ImageObject;
};
}
export async function getStaticPaths() {
const posts: {
@ -13,20 +29,33 @@ export async function getStaticPaths() {
title: string;
content: PortableTextBlock[];
publishDate: string;
headerImage: ImageObject;
summary: string;
metadata: Props['metadata'];
}[] = await client.fetch(forBlogPostPage, { live: !import.meta.env.DEV });
return posts.map(({ slug, title, content, publishDate }) => {
return {
params: { slug },
props: { title, content, publishDate },
};
});
return posts.map(
({ slug, title, content, publishDate, headerImage, summary, metadata }) => {
return {
params: { slug },
props: { title, content, publishDate, headerImage, summary, metadata },
};
},
);
}
const { title, content, publishDate } = Astro.props;
const { title, content, publishDate, headerImage, summary, metadata } =
Astro.props;
---
<Layout title={`${title} - Filipe Medeiros`}>
<BlogPostMetadata
slot="metadata"
title={metadata.title ?? title}
description={metadata.description ?? summary}
image={metadata.image ?? headerImage}
twitterCardType={metadata.twitterCardType}
/>
<article class="max-w-prose m-auto">
<header class="mb-5">
<PageTitle class="mb-2 break-words">{title}</PageTitle>

View file

@ -1,10 +1,11 @@
---
import client from '../../../lib/cms/client';
import { forBlogPage } from '../../../lib/cms/queries/blogPosts';
import client from '../../lib/cms/client';
import { forBlogPage } from '../../lib/cms/queries/blogPosts';
import ButtonLink from '../../components/ButtonLink.astro';
import CardLink from '../../components/CardLink.astro';
import PageTitle from '../../components/PageTitle.astro';
import Layout from '../../layouts/Layout.astro';
import type { ImageObject } from '../../lib/cms/types';
const posts: {
title: string;