diff --git a/src/app/blog/[slug]/page.tsx b/src/app/blog/[slug]/page.tsx index 0ce4d38..4c9fdf3 100644 --- a/src/app/blog/[slug]/page.tsx +++ b/src/app/blog/[slug]/page.tsx @@ -1,17 +1,19 @@ -import { defineQuery, PortableText } from "next-sanity"; +import { PortableText, defineQuery } from "next-sanity"; import imageUrlBuilder from "@sanity/image-url"; -import type { SanityImageSource } from "@sanity/image-url/lib/types/types"; -import { client, sanityFetch } from "../../../sanity/client"; -import Link from "next/link"; -import Image from "next/image"; -import { Post, SanityImageAsset } from "@/sanity/sanity.types"; import {getImageDimensions} from '@sanity/asset-utils' +import type { SanityImageSource } from "@sanity/image-url/lib/types/types"; +import { client } from "@/sanity/client"; +import { sanityFetch } from '@/sanity/client'; +import Link from "next/link"; +import { Post, SanityImageAsset } from "@/sanity/sanity.types"; +import type { Metadata } from "next"; +import Image from 'next/image' +const POSTS_QUERY = defineQuery(`*[_type == "post"]{ slug }`); const POST_QUERY = defineQuery(`*[_type == "post" && slug.current == $slug][0]`); -const POSTS_QUERY = defineQuery(`*[_type == "post"]{slug}`) type PageParams = Promise<{ - slug: string; + slug: string; }> const { projectId, dataset } = client.config(); @@ -21,81 +23,113 @@ const urlFor = (source: SanityImageSource) => : null; export async function generateStaticParams() { - const posts: Post[] = (await sanityFetch({ query: POSTS_QUERY, stega: false, perspective: "published" })).data; - return posts.map((post) => ({ slug: post.slug?.current ?? null })).filter((post) => post.slug); + const posts: Post[] = (await sanityFetch({ query: POSTS_QUERY, stega: false, perspective: "published" })).data; + return posts.map((post) => ({ + slug: post.slug?.current ?? "" + })) } -export default async function PostPage(props: { params: PageParams }) { - const { slug } = await props.params; - - const post: Post = (await sanityFetch({ query: POST_QUERY, params: { slug } })).data; - - if (!post) { - return ( -
-

Post not found

-
- ); +export async function generateMetadata(props: { params: Promise }): Promise { + const params = await props.params; + const post: Post = (await sanityFetch({ query: POST_QUERY, params, stega: false })).data; + const ogImage = post.mainImage + ? urlFor(post.mainImage)?.width(550).height(310).url() + : null; + const firstBlock = post.body ? post.body[0] : undefined; + let description: string | undefined = undefined; + if (firstBlock && firstBlock._type === 'block' && firstBlock.children) { + description = firstBlock.children.map(child => child.text).join(" "); } - const postImageUrl = post.mainImage ? urlFor(post.mainImage)?.width(550).height(310).url() : null; + return { + title: post.title, + description, + openGraph: { + title: post.title, + description, + type: "article", + publishedTime: post.publishedAt, + url: `/blog/${post.slug}`, + images: [ + { + url: ogImage ?? "", + }, + ], + }, + twitter: { + card: "summary_large_image", + title: post.title, + description, + images: ogImage ? [ogImage] : [], + }, + }; +} - function dynamicHeight(originalHeight: number, originalWidth: number, isInline: boolean) { +function dynamicHeight(originalHeight: number, originalWidth: number, isInline: boolean) { const targetWidth = isInline ? 100 : 768; return (targetWidth * originalHeight) / originalWidth; } - function PortableImage({ value, isInline }: { value: SanityImageAsset, isInline: boolean } ) { - const {width, height} = getImageDimensions(value) - console.log(isInline, width, height); - return ( - = 100 ? 100 : width) : (width >= 768 ? 768 : width)} - height={dynamicHeight(height, width, isInline)} - alt={value.altText || ' '} - loading="lazy" - className="border rounded-lg shadow-md" - style={{ - display: isInline ? 'inline-block' : 'block', - aspectRatio: width / height, - }} - /> - ) - } +function PortableImage({ value, isInline }: { value: SanityImageAsset, isInline: boolean } ) { + const {width, height} = getImageDimensions(value) + console.log(isInline, width, height); + return ( + = 100 ? 768 : width) : (width >= 768 ? 768 : width)} + height={dynamicHeight(height, width, isInline)} + alt={value.altText || ' '} + loading="lazy" + className="border rounded-lg shadow-md" + style={{ + display: isInline ? 'inline-block' : 'block', + aspectRatio: width / height, + }} + /> + ) +} - const components = { +const components = { types: { image: PortableImage } - } +} + +export default async function PostPage(props: { params: Promise }) { + const params = await props.params; + const post: Post = (await sanityFetch({ query: POST_QUERY, params })).data; + const postImageUrl = post.mainImage + ? urlFor(post.mainImage)?.width(912).height(576).url() + : null; return (
- - ← Blog - - {postImageUrl && ( - {`Banner - )} -

{post.title}

-
-

Published: {new Date(post.publishedAt ?? "").toISOString().substring(0, 10)}

- {Array.isArray(post.body) && } -
+ + ← Back to posts + + {postImageUrl && ( + {post.title + )} +

{post.title}

+

+ {post.publishedAt} +

+
+ {Array.isArray(post.body) && } +
); -} +} \ No newline at end of file