diff --git a/bun.lock b/bun.lock
index 964b043..a123208 100644
--- a/bun.lock
+++ b/bun.lock
@@ -11,6 +11,7 @@
"@payloadcms/plugin-seo": "^3.59.1",
"@payloadcms/richtext-lexical": "3.59.1",
"@payloadcms/ui": "3.59.1",
+ "@portabletext/react": "^4.0.3",
"@radix-ui/react-slot": "^1.2.3",
"@tailwindcss/postcss": "^4.1.14",
"class-variance-authority": "^0.7.1",
@@ -497,6 +498,12 @@
"@playwright/test": ["@playwright/test@1.54.1", "", { "dependencies": { "playwright": "1.54.1" }, "bin": { "playwright": "cli.js" } }, "sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw=="],
+ "@portabletext/react": ["@portabletext/react@4.0.3", "", { "dependencies": { "@portabletext/toolkit": "^3.0.1", "@portabletext/types": "^2.0.15" }, "peerDependencies": { "react": "^18.2 || ^19" } }, "sha512-sdVSXbi0L5MBVb1Ch5KwbBPZjW/Oqe6s5ZkPi4LcItzHl8rqY2jB0VxsFaGywZyn8Jc47cGLaOtyBM9HkW/9Hg=="],
+
+ "@portabletext/toolkit": ["@portabletext/toolkit@3.0.1", "", { "dependencies": { "@portabletext/types": "^2.0.15" } }, "sha512-z8NGqxKxfP0zuC58hPe8+xFC17qSbQ3nC9DgZmhrr7NUFaENJ6vAHJBsH5QzT7nKUjj++dTn+i4O2Uz9cqiGjA=="],
+
+ "@portabletext/types": ["@portabletext/types@2.0.15", "", {}, "sha512-2e6i2gSQsrA/5OL5Gm4/9bxB9MNO73Fa47zj+0mT93xkoQUCGCWX5fZh1YBJ86hszaRYlqvqG08oULxvvPPp/Q=="],
+
"@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
diff --git a/package.json b/package.json
index 9953110..aaad988 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"@payloadcms/plugin-seo": "^3.59.1",
"@payloadcms/richtext-lexical": "3.59.1",
"@payloadcms/ui": "3.59.1",
+ "@portabletext/react": "^4.0.3",
"@radix-ui/react-slot": "^1.2.3",
"@tailwindcss/postcss": "^4.1.14",
"class-variance-authority": "^0.7.1",
diff --git a/src/app/(frontend)/[slug]/page.tsx b/src/app/(frontend)/[slug]/page.tsx
new file mode 100644
index 0000000..5bbee00
--- /dev/null
+++ b/src/app/(frontend)/[slug]/page.tsx
@@ -0,0 +1,7 @@
+import React from 'react'
+
+export default function SinglePage() {
+ return (
+
SinglePage
+ )
+}
diff --git a/src/app/(frontend)/globals.css b/src/app/(frontend)/globals.css
index 238e915..385ed45 100644
--- a/src/app/(frontend)/globals.css
+++ b/src/app/(frontend)/globals.css
@@ -164,3 +164,7 @@ svg {
}
}
}
+
+h2 {
+ @apply text-3xl font-bold
+}
\ No newline at end of file
diff --git a/src/app/(frontend)/page.tsx b/src/app/(frontend)/page.tsx
index 81db63c..e709f85 100644
--- a/src/app/(frontend)/page.tsx
+++ b/src/app/(frontend)/page.tsx
@@ -90,7 +90,7 @@ export default async function HomePage() {
.filter((item) => !item.featuredProject)
.map((item) => (
-
+
{item.title}
{item.description}
diff --git a/src/app/(frontend)/projects/[slug]/page.tsx b/src/app/(frontend)/projects/[slug]/page.tsx
new file mode 100644
index 0000000..de883dc
--- /dev/null
+++ b/src/app/(frontend)/projects/[slug]/page.tsx
@@ -0,0 +1,31 @@
+import { SINGLE_PROJECT_QUERY } from '@/utilities/queries'
+import React from 'react'
+import { PortableText } from "@portabletext/react"
+import { RichTextComponent } from '@/src/components/RichTextComponents'
+import Image from 'next/image'
+import { RichText } from '@payloadcms/richtext-lexical/react'
+
+export default async function SingleProjectPage({ params }: { params: { slug: string } }) {
+ const fetchData = await SINGLE_PROJECT_QUERY(params.slug)
+ const pageData = fetchData.docs[0];
+ // console.log(pageData)
+
+ return (
+
+ {pageData.title}
+ {pageData.featuredImage && (
+
+ )}
+
+ {pageData.richText && (
+
+ )}
+
+
+ )
+}
diff --git a/src/components/RichTextComponents.tsx b/src/components/RichTextComponents.tsx
new file mode 100644
index 0000000..1bbd810
--- /dev/null
+++ b/src/components/RichTextComponents.tsx
@@ -0,0 +1,57 @@
+import Image from 'next/image';
+import Link from 'next/link';
+
+export const RichTextComponent: any = {
+ types: {
+ image: ({ value }: any) => {
+ return (
+
+ {/* */}
+
+ );
+ },
+ },
+ list: {
+ bullet: ({ children }: any) => {
+
+ },
+ number: ({ children }: any) => {
+ {children}
+ },
+ },
+ block: {
+ // Ex. 1: customizing common block types
+ h1: ({children}: any) => {children}
,
+ h2: ({ children }: any) => {children}
,
+ h3: ({ children }: any) => {children}
,
+ h4: ({ children }: any) => {children}
,
+ blockquote: ({ children }: any) => (
+
+ {children}
+
+ ),
+ normal: ({children}: any) => {children}
+ },
+ marks: {
+ link: ({ children, value }: any) => {
+ const rel = !value.href.startsWith("")
+ ? "noreferrer noopener"
+ : undefined;
+
+ return (
+
+ {children}
+
+ )
+ }
+ }
+}
diff --git a/utilities/queries.ts b/utilities/queries.ts
index 9b71213..d478aa6 100644
--- a/utilities/queries.ts
+++ b/utilities/queries.ts
@@ -24,6 +24,18 @@ export const PROJECT_QUERY = await payload.find({
order: true,
categories: true,
featuredProject: true,
- },
+ },
sort: '-order'
-})
\ No newline at end of file
+})
+
+export const SINGLE_PROJECT_QUERY = async (slug: string) => {
+ return await payload.find({
+ collection: 'projects',
+ where: {
+ slug: {
+ equals: slug
+ }
+ },
+ limit: 1
+ }
+)}
\ No newline at end of file