mirror of
https://github.com/UiO-Gaming/uiogaming.no.git
synced 2026-11-05 13:56:47 +01:00
Rerendering translations apparently caused issues with safari because apple fucking sucks. Thus we had to rewrite the logic to use prefix-based translations. This is the attempt at this. It might be a mega commit but it's how it ought to be...
156 lines
3.8 KiB
TypeScript
156 lines
3.8 KiB
TypeScript
import Layout from "@/app/[locale]/layout"
|
|
|
|
import Footer from "@/components/page-sections/footer"
|
|
import { generateSeoMetadata, generateSeoViewport } from "@/components/seo"
|
|
import Back from "@/components/ui/back"
|
|
|
|
import { urlFor } from "@/lib/imageUrlBuilder"
|
|
import { getBlogPost } from "@/lib/sanity"
|
|
|
|
import { PortableText, PortableTextComponents } from "@portabletext/react"
|
|
import { Metadata, Viewport } from "next"
|
|
import { notFound } from "next/navigation"
|
|
import { getLocale } from "next-intl/server"
|
|
import Image from "next/image"
|
|
|
|
import * as styles from "./page.module.css"
|
|
|
|
interface BlogPageParams {
|
|
params: Promise<{
|
|
slug: string
|
|
locale: string
|
|
}>
|
|
}
|
|
|
|
interface ImageValue {
|
|
asset?: {
|
|
_id: string
|
|
url: string
|
|
}
|
|
alt?: string
|
|
caption?: string
|
|
}
|
|
|
|
interface LinkValue {
|
|
href: string
|
|
}
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: BlogPageParams): Promise<Metadata> {
|
|
const { slug } = await params
|
|
const data = await getBlogPost(slug)
|
|
|
|
return generateSeoMetadata({
|
|
title: data.title,
|
|
description: data.excerpt,
|
|
imageURL: data.mainImage?.asset?.url,
|
|
author: data.author?.name,
|
|
})
|
|
}
|
|
|
|
export function generateViewport(): Viewport {
|
|
return generateSeoViewport()
|
|
}
|
|
|
|
const components: PortableTextComponents = {
|
|
types: {
|
|
image: ({ value }: { value: ImageValue }) => {
|
|
if (!value?.asset) return null
|
|
return (
|
|
<div className={styles.imageContainer}>
|
|
<Image
|
|
src={urlFor(value).url()}
|
|
alt={value.alt || "Blog image"}
|
|
width={800}
|
|
height={400}
|
|
style={{ width: "100%", height: "auto" }}
|
|
/>
|
|
{value.caption && (
|
|
<p className={styles.imageCaption}>{value.caption}</p>
|
|
)}
|
|
</div>
|
|
)
|
|
},
|
|
},
|
|
marks: {
|
|
link: ({
|
|
children,
|
|
value,
|
|
}: {
|
|
children?: React.ReactNode
|
|
value?: LinkValue
|
|
}) => (
|
|
<a
|
|
href={value?.href ?? "#"}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className={styles.link}
|
|
>
|
|
{children}
|
|
</a>
|
|
),
|
|
},
|
|
}
|
|
|
|
const BlogPost = async ({ params }: BlogPageParams) => {
|
|
const { slug }: { slug: string } = await params
|
|
const locale = await getLocale()
|
|
|
|
const data = await getBlogPost(slug)
|
|
|
|
if (!data) return notFound()
|
|
|
|
const createdAt = new Date(data._createdAt).toLocaleDateString(locale, {
|
|
day: "numeric",
|
|
month: "long",
|
|
year: "numeric",
|
|
})
|
|
|
|
return (
|
|
<Layout>
|
|
<div className={styles.container}>
|
|
<div className={styles.backButton}>
|
|
<Back />
|
|
</div>
|
|
<article className={styles.article}>
|
|
<header className={styles.header}>
|
|
{data.mainImage && (
|
|
<Image
|
|
src={urlFor(data.mainImage).url()}
|
|
alt={data.title}
|
|
width={800}
|
|
height={400}
|
|
className={styles.headerImage}
|
|
/>
|
|
)}
|
|
<h1 className={styles.title}>{data.title}</h1>
|
|
<p className={styles.excerpt}>{data.excerpt}</p>
|
|
<div className={styles.author}>
|
|
{data.author?.image && (
|
|
<Image
|
|
className="circular"
|
|
alt={data.author.name}
|
|
src={urlFor(data.author.image).width(50).height(50).url()}
|
|
width={50}
|
|
height={50}
|
|
/>
|
|
)}
|
|
<div className={styles.authorNameSection}>
|
|
<p>{data.author?.name}</p>
|
|
<p>{createdAt}</p>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
<div className={styles.content}>
|
|
<PortableText value={data.body} components={components} />
|
|
</div>
|
|
</article>
|
|
</div>
|
|
<Footer />
|
|
</Layout>
|
|
)
|
|
}
|
|
|
|
export default BlogPost
|