Skip to content

Commit

Permalink
Base routes to app router (tinacms#2787)
Browse files Browse the repository at this point in the history
* moved search over to app router

* move /examples to app router

* add metaData

* update metadata

* remove early access and add redirect

* remove index

* move community to app router

* add community seo

* fix hydration of useSearchParams

* fix spelling

* suspense :0

* comment out generateMetaData

* migration home page and [slug}.tsx with confused error

* fix the BlockPage error

* 🐛 Fix the error that can not edit the component

* add missing information

* registry for styled component

* migrate pages/api

* rm comment

* rm logs

---------

Co-authored-by: ZenoWang1999 <[email protected]>
  • Loading branch information
joshbermanssw and ZenoWang1999 authored Jan 29, 2025
1 parent 724aa7c commit 9ea95ca
Show file tree
Hide file tree
Showing 36 changed files with 948 additions and 966 deletions.
22 changes: 22 additions & 0 deletions app/[slug]/client-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use client'

import { BlocksPage } from 'components/blocks/BlocksPage'
import { useTina } from 'tinacms/dist/react'

interface ClientPageProps {
query: string
data: any
variables: {
relativePath: string
}
}

export default function ClientPage({ query, data, variables }: ClientPageProps) {
const tinaData = useTina({
query,
data,
variables,
})

return <BlocksPage data={tinaData.data.page} recentPosts={tinaData.data.recentPosts} />
}
73 changes: 73 additions & 0 deletions app/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { client } from '../../tina/__generated__/client';
import ClientPage from './client-page';
import { fileToUrl } from 'utils/urls';
import { notFound } from 'next/navigation';
import { Metadata } from 'next';
import path from 'path';

const fg = require('fast-glob');

interface PageProps {
params: {
slug?: string;
};
}

export async function generateMetadata({
params,
}: PageProps): Promise<Metadata> {
const slug = params?.slug || 'home';

try {
const res = await client.queries.pageWithRecentPosts({
relativePath: slug + '.json',
});

const data = res.data.page;

if (!data.seo) {
return {};
}

return {
title: {
default: data.seo.title,
template: data.seo.hasCustomSuffix ? '%s' : '%s | Tina',
},
description: data.seo.description,
openGraph: {
title: data.seo.title,
description: data.seo.description,
},
};
} catch (error) {
return {};
}
}

export async function generateStaticParams() {
const pages = await fg(`./content/blocksPages/*.json`);
return pages
.filter((file) => {
const filename = path.basename(file);
return !filename.includes('_400x400') && !filename.endsWith('.jpg.json');
})
.map((file) => ({
slug: fileToUrl(file, 'blocksPages'),
}));
}

export default async function Page({ params }: PageProps) {
const slug = params?.slug || 'home';
const vars = { relativePath: slug + '.json' };

try {
const res = await client.queries.pageWithRecentPosts({
relativePath: slug + '.json',
});

return <ClientPage query={res.query} data={res.data} variables={vars} />;
} catch (error) {
notFound();
}
}
35 changes: 35 additions & 0 deletions app/api/analytics/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { sql, VercelPoolClient } from '@vercel/postgres';
import { NextRequest, NextResponse } from 'next/server';

// create table analytics_search (timestamp bigint, vercel_env varchar(255), session_id varchar(255), search_query text);
export async function POST(request: NextRequest) {
const { VERCEL_ENV = 'local' } = process.env;

try {
const body = await request.json();
const { timestamp, id, query } = body;

let client: VercelPoolClient | undefined;

try {
client = await sql.connect();
await client.sql`INSERT INTO analytics_search
VALUES (${timestamp}, ${VERCEL_ENV}, ${id}, ${query});`;

return NextResponse.json({ message: 'ok' }, { status: 200 });
} catch (e) {
console.error(e);
return NextResponse.json(
{ message: 'internal server error' },
{ status: 500 }
);
} finally {
client?.release();
}
} catch (e) {
return NextResponse.json(
{ message: 'invalid request body' },
{ status: 400 }
);
}
}
39 changes: 39 additions & 0 deletions app/api/mailchimp/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import mailchimp from '@mailchimp/mailchimp_marketing';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { email_address, status, merge_fields } = body;

mailchimp.setConfig({
apiKey: process.env.MAILCHIMP_API_KEY,
server: process.env.MAILCHIMP_SERVER_PREFIX,
});

try {
const response = await mailchimp.lists.addListMember(
process.env.MAILCHIMP_AUDIENCE_ID!,
{ email_address, status, merge_fields }
);

return NextResponse.json(
{ success: true, response },
{ status: 200 }
);
} catch (err: any) {
const errorStatus = err.response ? err.response.status : 500;
const errorMessage = err.response ? err.response.text : err.message;

return NextResponse.json(
{ error: true, message: errorMessage },
{ status: errorStatus }
);
}
} catch (err) {
return NextResponse.json(
{ error: true, message: 'Invalid request body' },
{ status: 400 }
);
}
}
9 changes: 9 additions & 0 deletions app/api/reset-preview/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';

export async function GET() {
cookies().delete('__prerender_bypass');
cookies().delete('__next_preview_data');

return new NextResponse(null, { status: 200 });
}
120 changes: 120 additions & 0 deletions app/community/community-client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
'use client';

import { Hero, MarkdownContent, RichTextWrapper } from 'components/layout';
import { FaDiscord, FaTwitter, FaGithub } from 'react-icons/fa';
import TinaIconSvg from 'public/svg/tina-icon.svg';
import Image from 'next/image';
import { EmailForm } from 'components/modals/AppRouterEmailForm';
import { ButtonGroup, LinkButton } from 'components/ui';

export default function CommunityPageClient(data) {

return (
<div className="flex flex-col">
<div className="text-center my-10">
<h1 className="text-5xl font-tuner bg-gradient-to-br from-orange-400 via-orange-500 to-orange-600 text-transparent bg-clip-text">
{data.headline}
</h1>
</div>

{/* Info Section */}
<div className="grid gap-16 lg:grid-cols-2 lg:items-center lg:gap-8 my-16 px-6 lg:px-20">
{/* Info Content */}
<div className="space-y-6">
<h2 className="text-4xl font-tuner bg-gradient-to-br from-orange-400 via-orange-500 to-orange-600 text-transparent bg-clip-text">
{data.supporting_headline}
</h2>
<hr className="block border-none bg-[url('/svg/hr.svg')] bg-no-repeat bg-[length:auto_100%] h-[10px] w-full my-8" />
<RichTextWrapper>
<div className="text-gray-700 tracking-wide leading-relaxed">
<MarkdownContent content={data.supporting_body} />
</div>
</RichTextWrapper>

<ButtonGroup>
<LinkButton
color="white"
link={'https://github.com/tinacms/tinacms/discussions'}
>
<TinaIconSvg
// @ts-ignore
style={{
fill: '#EC4815',
height: '1.675rem',
width: 'auto',
margin: '0 0.675rem 0 0.125rem',
}}
/>{' '}
Discussion
</LinkButton>
<LinkButton
link={'https://discord.com/invite/zumN63Ybpf'}
color="white"
>
<FaDiscord
style={{
color: '#5865f2',
height: '1.5rem',
width: 'auto',
margin: '0 0.675rem 0 0.125rem',
}}
/>{' '}
Discord
</LinkButton>
<LinkButton
link={'https://github.com/tinacms/tinacms'}
color="white"
>
<FaGithub
style={{
color: '#24292e',
height: '1.5rem',
width: 'auto',
margin: '0 0.675rem 0 0.125rem',
}}
/>{' '}
GitHub
</LinkButton>
<LinkButton link={'https://twitter.com/tinacms'} color="white">
<FaTwitter
style={{
color: '#1DA1F2',
height: '1.5rem',
width: 'auto',
margin: '0 0.675rem 0 0.125rem',
}}
/>{' '}
Twitter
</LinkButton>
</ButtonGroup>
</div>

{/* Info Image */}
<div className="flex justify-center">
<Image
src={data.img.src}
alt={data.img.alt}
height={600}
width={600}
className="rounded-2xl shadow-lg"
/>
</div>
</div>

{/* Newsletter Section */}
<div className="bg-green-100 py-12">
<div className="text-center px-6 lg:px-20">
<h2 className="text-4xl font-tuner bg-gradient-to-br from-orange-400 via-orange-500 to-orange-600 text-transparent bg-clip-text">
{data.newsletter_header}
</h2>
<p className="text-gray-600 mt-2">{data.newsletter_cta}</p>
<div className="flex justify-center mt-6">
<div className="w-full">
<EmailForm />
</div>
</div>
</div>
</div>
</div>
);
}
36 changes: 36 additions & 0 deletions app/community/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { getJsonPreviewProps } from 'utils/getJsonPreviewProps';
import CommunityPageClient from './community-client';

export async function generateMetadata(){
const data = await getCommunityPageData();
const cleanData = data.props.file.data;
return{
title: cleanData.title,
description: cleanData.description,
openGraph: {
title: cleanData.title,
description: cleanData.description,
}
}
}

async function getCommunityPageData() {
const previewProps = await getJsonPreviewProps(
'content/pages/community.json'
);
return previewProps;
}

export default async function CommunityPage() {
const data = await getCommunityPageData();
const cleanData = data.props.file.data;


return (
<>
<div>
<CommunityPageClient {...cleanData} />
</div>
</>
);
}
Loading

0 comments on commit 9ea95ca

Please sign in to comment.