completely rewrite blog page

Co-authored-by: Pukimaa <me@pukima.site>
This commit is contained in:
2024-10-30 12:50:58 +01:00
parent 9a651b55f1
commit 70f2955cc5

View File

@@ -1,14 +1,16 @@
import { defineQuery, PortableText } from "next-sanity"; import { PortableText, defineQuery } from "next-sanity";
import imageUrlBuilder from "@sanity/image-url"; 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 {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 POST_QUERY = defineQuery(`*[_type == "post" && slug.current == $slug][0]`);
const POSTS_QUERY = defineQuery(`*[_type == "post"]{slug}`)
type PageParams = Promise<{ type PageParams = Promise<{
slug: string; slug: string;
@@ -22,30 +24,53 @@ const urlFor = (source: SanityImageSource) =>
export async function generateStaticParams() { export async function generateStaticParams() {
const posts: Post[] = (await sanityFetch({ query: POSTS_QUERY, stega: false, perspective: "published" })).data; 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); return posts.map((post) => ({
slug: post.slug?.current ?? ""
}))
} }
export default async function PostPage(props: { params: PageParams }) { export async function generateMetadata(props: { params: Promise<PageParams> }): Promise<Metadata> {
const { slug } = await props.params; const params = await props.params;
const post: Post = (await sanityFetch({ query: POST_QUERY, params, stega: false })).data;
const post: Post = (await sanityFetch({ query: POST_QUERY, params: { slug } })).data; const ogImage = post.mainImage
? urlFor(post.mainImage)?.width(550).height(310).url()
if (!post) { : null;
return ( const firstBlock = post.body ? post.body[0] : undefined;
<main> let description: string | undefined = undefined;
<p>Post not found</p> if (firstBlock && firstBlock._type === 'block' && firstBlock.children) {
</main> 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; const targetWidth = isInline ? 100 : 768;
return (targetWidth * originalHeight) / originalWidth; return (targetWidth * originalHeight) / originalWidth;
} }
function PortableImage({ value, isInline }: { value: SanityImageAsset, isInline: boolean } ) { function PortableImage({ value, isInline }: { value: SanityImageAsset, isInline: boolean } ) {
const {width, height} = getImageDimensions(value) const {width, height} = getImageDimensions(value)
console.log(isInline, width, height); console.log(isInline, width, height);
return ( return (
@@ -58,7 +83,7 @@ export default async function PostPage(props: { params: PageParams }) {
.fit('max') .fit('max')
.auto('format') .auto('format')
.url()} .url()}
width={isInline ? (width >= 100 ? 100 : width) : (width >= 768 ? 768 : width)} width={isInline ? (width >= 100 ? 768 : width) : (width >= 768 ? 768 : width)}
height={dynamicHeight(height, width, isInline)} height={dynamicHeight(height, width, isInline)}
alt={value.altText || ' '} alt={value.altText || ' '}
loading="lazy" loading="lazy"
@@ -69,31 +94,40 @@ export default async function PostPage(props: { params: PageParams }) {
}} }}
/> />
) )
} }
const components = { const components = {
types: { types: {
image: PortableImage image: PortableImage
} }
} }
export default async function PostPage(props: { params: Promise<PageParams> }) {
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 ( return (
<main className="container mx-auto min-h-screen max-w-3xl p-8 flex flex-col gap-4"> <main className="container mx-auto min-h-screen max-w-3xl p-8 flex flex-col gap-4">
<Link href="/blog" className="hover:underline"> <Link href="/blog" className="hover:underline">
Blog Back to posts
</Link> </Link>
{postImageUrl && ( {postImageUrl && (
<Image <Image
src={postImageUrl} src={postImageUrl}
alt={`Banner for ${post.title}` } alt={post.title ?? `Blog Post Banner Image for ${post.title}`}
className="aspect-video rounded-xl" className="aspect-video rounded-xl w-full"
width="550" width="912"
height="310" height="576"
/> />
)} )}
<h1 className="text-4xl font-bold mb-8">{post.title}</h1> <h1 className="text-4xl font-bold mb-8">{post.title}</h1>
<div className="prose"> <p className="text-sm text-neutral-600 dark:text-neutral-400 max-w-full w-fit">
<p>Published: {new Date(post.publishedAt ?? "").toISOString().substring(0, 10)}</p> {post.publishedAt}
</p>
<div className="items-start mt-2 mb-8 text-sm prose dark:prose-invert max-w-full w-full text-left">
{Array.isArray(post.body) && <PortableText value={post.body} components={ components } />} {Array.isArray(post.body) && <PortableText value={post.body} components={ components } />}
</div> </div>
</main> </main>