Skip to content

Commit

Permalink
🚏 Blogs to App Router (#2722)
Browse files Browse the repository at this point in the history
* majority of blogs to app rtr

* fix recentPosts

* add notFounds()'s and 404 page

* make not-found into client server

* app router migration tasks – routing

* making usePathname components client

* re-adding lost stuff?

* AI generated fix for build errors

* Revert "AI generated fix for build errors"

This reverts commit 905db7c.

* use client division to stop build errors

* adding in a forgotten generatestatic params

* update next-seo

* rm 404.tsx

* add extra logging and remove excerpt

* updating the blog parameter list

* removing console logs

* blog pagination prerender

* css fix – dropdown width

* global error handling, more cleanly

* making global error client

* global 404?

* testing swc tranform issue

* re-adding the force swc transforms

* re-adding the pages 404

* fix app router notfound page

* increase llama size (betty)

* Update app/blog/[...slug]/page.tsx

Co-authored-by: Caleb Williams [SSW] <[email protected]>

* Update app/blog/page/[page_index]/page.tsx

Co-authored-by: Caleb Williams [SSW] <[email protected]>

* Introduce BlogPageClientProps

* rm log

* removed NotFound()

* rm unused tinaProps

* rm global-error for not-found

* rm unused prop

* rm 404

* added seo

* added optional date

* make last edited optional

* fix typing

* typing v6.0

* make dynamic params true for testing

* add googlebot

* add hotjar, clarity and robots

* fix import directory

* test not client

* change data collection and revert hiding notfoundclient

* add error catching blocks

* rm not found

* try a global error

* improve notFounding'ing

* add extra NotFound()

* push new lock

---------

Co-authored-by: isaaclombardssw <[email protected]>
Co-authored-by: Caleb Williams [SSW] <[email protected]>
  • Loading branch information
3 people authored Jan 22, 2025
1 parent 3c76d74 commit 6f59523
Show file tree
Hide file tree
Showing 31 changed files with 837 additions and 711 deletions.
76 changes: 76 additions & 0 deletions app/blog/[...slug]/BlogPageClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use client';

import React from 'react';
import { formatDate } from 'components/AppRouterMigrationComponents/utils/formatDate';
import { docAndBlogComponents } from 'components/tinaMarkdownComponents/docAndBlogComponents';
import { DocsPagination } from 'components/ui';
import { TinaMarkdown } from 'tinacms/dist/rich-text';
import { BlogPageClientProps } from './BlogType';


const BlogPageClient: React.FC<BlogPageClientProps> = ({ data }) => {
const blogPostData = data.post;

const postedDate = formatDate(blogPostData.date);
const lastEditedDate = blogPostData.last_edited
? formatDate(blogPostData.last_edited)
: null;

const previousPage = blogPostData.prev
? {
slug: blogPostData.prev.id.slice(7, -4),
title: blogPostData.prev.title,
}
: null;

const nextPage = blogPostData.next
? {
slug: blogPostData.next.id.slice(7, -4),
title: blogPostData.next.title,
}
: null;

return (
<div>
<BlogPageTitle title={blogPostData.title} />
<div className="p-6">
<div className="py-12 lg:py-16 last:pb-20 last:lg:pb-32 max-w-prose mx-auto">
<div className="flex flex-col items-center opacity-80 m-0">
<span>{postedDate}</span>
<div className="flex flex-row text-lg gap-1 pb-4">
<span>By </span>
<strong>{blogPostData.author}</strong>
</div>
</div>
<div className="text-[#241748]">
<TinaMarkdown
content={blogPostData.body}
components={docAndBlogComponents}
/>
</div>

{lastEditedDate && (
<div className="mt-2 text-sm opacity-50">
Last Edited: {lastEditedDate}
</div>
)}
<DocsPagination prevPage={previousPage} nextPage={nextPage} />
</div>
</div>
</div>
);
};

function BlogPageTitle({ title }: { title: string }) {
const blogTitleStyling =
'leading-[1.3] max-w-[9em] bg-gradient-to-r from-orange-400 via-orange-500 to-orange-600 ' +
'text-transparent bg-clip-text font-tuner mx-auto text-4xl md:text-5xl lg:text-6xl';

return (
<div className="relative z-10 overflow-visible text-center px-8 py-12 lg:py-16">
<div className={blogTitleStyling}>{title}</div>
</div>
);
}

export default BlogPageClient;
40 changes: 40 additions & 0 deletions app/blog/[...slug]/BlogType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { TinaMarkdownContent } from "tinacms/dist/rich-text";


interface Sys {
filename: string;
basename: string;
breadcrumbs: string[];
path: string;
relativePath: string;
extension: string;
}

interface Seo {
title: string;
description: string;
}

interface PostSummary {
id: string;
title: string;
}

export interface BlogPost {
_sys: Sys;
id: string;
title: string;
date: string;
last_edited: string | null;
author: string;
seo: Seo | null;
prev: PostSummary | null;
next: PostSummary | null;
body: TinaMarkdownContent;
}

export interface BlogPageClientProps {
data: {
post: BlogPost;
};
}
110 changes: 110 additions & 0 deletions app/blog/[...slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { notFound } from 'next/navigation';
import client from 'tina/__generated__/client';
import BlogPageClient from './BlogPageClient';
import { TinaMarkdownContent } from 'tinacms/dist/rich-text';
import { BlogPost } from './BlogType';

export async function generateStaticParams() {
let allPosts = [];
let hasNextPage = true;
let after: string | null = null;

while (hasNextPage) {
try {
const postsResponse = await client.queries.postConnection({ after });

const edges = postsResponse?.data?.postConnection?.edges || [];
const pageInfo = postsResponse?.data?.postConnection?.pageInfo || {
hasNextPage: false,
endCursor: null,
};

allPosts = allPosts.concat(
edges.map((post) => ({
slug: [post?.node?._sys?.filename],
}))
);

hasNextPage = pageInfo.hasNextPage;
after = pageInfo.endCursor;
} catch (error) {
console.error('Error during static params generation:', error);
notFound();
}
}
return allPosts;
}

export const dynamicParams = true;

export async function generateMetadata({
params,
}: {
params: { slug: string[] };
}) {
const slugPath = params.slug.join('/');
const vars = { relativePath: `${slugPath}.mdx` };

try {
const { data } = await client.queries.getExpandedPostDocument(vars);

if (!data?.post) {
console.warn(`No metadata found for slug: ${slugPath}`);
return notFound();
}

return {
title: `${data.post.title} | TinaCMS Blog`,
openGraph: {
title: data.post.title,
},
};
} catch (error) {
console.error('Error generating metadata:', error);
return notFound();
}
}

export default async function BlogPage({
params,
}: {
params: { slug: string[] };
}) {
const slugPath = params.slug.join('/');
const vars = { relativePath: `${slugPath}.mdx` };

try {
const res = await client.queries.getExpandedPostDocument(vars);

if (!res.data?.post) {
console.warn(`No post found for slug: ${slugPath}`);
return notFound();
}

const fetchedPost = res.data.post;

const post: BlogPost = {
_sys: fetchedPost._sys,
id: fetchedPost.id,
title: fetchedPost.title,
date: fetchedPost.date || '',
last_edited: fetchedPost.last_edited ?? null,
author: fetchedPost.author || '',
seo: fetchedPost.seo
? {
title: fetchedPost.seo.title || 'Default SEO Title',
description:
fetchedPost.seo.description || 'Default SEO Description',
}
: null,
prev: fetchedPost.prev ?? null,
next: fetchedPost.next ?? null,
body: fetchedPost.body as TinaMarkdownContent,
};

return <BlogPageClient data={{ post }} />;
} catch (error) {
console.error(`Error fetching post for slug: ${slugPath}`, error);
return notFound();
}
}
21 changes: 21 additions & 0 deletions app/blog/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import BlogPaginationPage from './page/[page_index]/page';

export async function generateMetadata(){

const title = 'TinaCMS Blog';
const description = 'Stay updated with the TinaCMS blog. Get tips, guides and the latest news on content management and development';
return{
title: title,
description: description,
openGraph: {
title: title,
description: description,
url: 'https://tinacms.org/blog',
}
}
}

export default async function BlogPage() {
const params = { page_index: '1' };
return await BlogPaginationPage({ params });
}
78 changes: 78 additions & 0 deletions app/blog/page/[page_index]/BlogIndexPageClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
'use client';

import { DynamicLink } from 'components/ui';
import React from 'react';
import { formatDate } from 'components/AppRouterMigrationComponents/utils/formatDate';
import { MarkdownContent } from 'components/layout';
import NewBlogPagination from 'components/AppRouterMigrationComponents/Blogs/BlogPagination';
import { extractTextFromBody } from 'components/AppRouterMigrationComponents/utils/extractTextFromBody';

interface Post {
id: string;
title: string;
date?: string;
author?: string;
body?: string;
seo?: {
title?: string;
description?: string;
};
_sys: {
filename: string;
basename: string;
breadcrumbs: string[];
path: string;
relativePath: string;
extension: string;
};
}


interface BlogPageClientProps {
currentPageIndexNumber: number;
numberOfPages: number;
postsForPageIndex: Post[];
}
export default function BlogIndexPageClient({
currentPageIndexNumber: pageIndex,
postsForPageIndex: posts,
numberOfPages: numPages,
}: BlogPageClientProps) {

return (
<div className="p-6">
<div className="py-12 lg:py-16 last:pb-20 last:lg:pb-32 max-w-prose mx-auto">
{posts.map((post) => (
<DynamicLink
key={post.id}
href={`/blog/${post._sys.filename}`}
passHref
>
<div className="w-full group flex flex-col gap-6 lg:gap-8 items-start mb-6 lg:mb-8">
<h3 className="font-tuner text-3xl lg:text-4xl lg:leading-tight bg-gradient-to-br from-blue-700/70 via-blue-900/90 to-blue-1000 group-hover:from-orange-300 group-hover:via-orange-500 group-hover:to-orange-700 bg-clip-text text-transparent">
{post.title}
</h3>
<div className="w-full text-[#241748] ">
<div className="flex justify-between items-center w-full mb-6 -mt-2">
<p className="opacity-70">
<span className="mr-1">By</span>
<strong>{post.author}</strong>
</p>
<p className="opacity-70">{formatDate(post.date || '')}</p>
</div>
<div className=' font-light mb-6'>
<MarkdownContent skipHtml={true} content={extractTextFromBody(post.body)} />
</div>

<hr className="block border-none bg-[url('/svg/hr.svg')] bg-no-repeat bg-[length:auto_100%] h-[7px] w-full my-8" />
</div>
</div>
</DynamicLink>
))}
<div className="mt-12">
<NewBlogPagination currentPage={pageIndex} numPages={numPages} />
</div>
</div>
</div>
);
}
Loading

0 comments on commit 6f59523

Please sign in to comment.