commit
ae27849a45
1
.gitignore
vendored
1
.gitignore
vendored
@ -32,6 +32,7 @@ yarn-error.log*
|
|||||||
|
|
||||||
# env files (can opt-in for committing if needed)
|
# env files (can opt-in for committing if needed)
|
||||||
.env*
|
.env*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
47
README.md
47
README.md
@ -2,35 +2,38 @@ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-
|
|||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
First, run the development server:
|
### 1. Create .env file
|
||||||
|
|
||||||
|
You can create `.env` file based on `env` file, put some env variable that is required by payload cms.
|
||||||
|
|
||||||
|
### 2. Run
|
||||||
|
|
||||||
|
You can run the development server with old bundler:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev-old
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
or run the development server with new bundler (turbopack):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm run dev
|
||||||
# or
|
|
||||||
yarn dev
|
|
||||||
# or
|
|
||||||
pnpm dev
|
|
||||||
# or
|
|
||||||
bun dev
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
### 3. Open
|
||||||
|
|
||||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
You can access it by visiting:
|
||||||
|
|
||||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
```
|
||||||
|
http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
## Learn More
|
## Admin Panel
|
||||||
|
|
||||||
To learn more about Next.js, take a look at the following resources:
|
The admin panel has been provided by `Payload CMS`, you can access it by visiting:
|
||||||
|
|
||||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
```
|
||||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
http://localhost:3000/admin
|
||||||
|
```
|
||||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
|
||||||
|
|
||||||
## Deploy on Vercel
|
|
||||||
|
|
||||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
|
||||||
|
|
||||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
|
||||||
|
12
env
12
env
@ -2,4 +2,14 @@ SERVICE_SUPABASESERVICE_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXB
|
|||||||
|
|
||||||
SERVICE_SUPABASEANON_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsImlhdCI6MTczODQ3MzA2MCwiZXhwIjo0ODk0MTQ2NjYwLCJyb2xlIjoiYW5vbiJ9.WXJvhzD1gD6Kxlq8PLFAcpaVFmh9h3xbJHh9oow2IFQ
|
SERVICE_SUPABASEANON_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsImlhdCI6MTczODQ3MzA2MCwiZXhwIjo0ODk0MTQ2NjYwLCJyb2xlIjoiYW5vbiJ9.WXJvhzD1gD6Kxlq8PLFAcpaVFmh9h3xbJHh9oow2IFQ
|
||||||
|
|
||||||
SUPABASE_URL=https://supabasekong-n00g8kwoos4skc0gw44k8sks.dev3vds1.link
|
SUPABASE_URL=https://supabasekong-n00g8kwoos4skc0gw44k8sks.dev3vds1.link
|
||||||
|
|
||||||
|
<!-- Payload -->
|
||||||
|
|
||||||
|
DATABASE_URI=your-connection-string-here
|
||||||
|
PAYLOAD_SECRET=YOUR_SECRET_HERE
|
||||||
|
S3_BUCKET=YOUR_BUCKET
|
||||||
|
S3_ACCESS_KEY_ID=YOUR_ACCESS_KEY
|
||||||
|
S3_SECRET_ACCESS_KEY=YOUR_SECRET
|
||||||
|
S3_REGION=YOUR_REGION
|
||||||
|
S3_ENDPOINT=YOUR_ENDPOINT
|
||||||
|
@ -1,21 +1,7 @@
|
|||||||
|
import { withPayload } from "@payloadcms/next/withPayload";
|
||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
|
||||||
// webpack: (config, options) => {
|
|
||||||
// config.module.rules.push({
|
|
||||||
// test: require.resolve("wowjs/dist/wow.js"),
|
|
||||||
// use: [
|
|
||||||
// {
|
|
||||||
// loader: "exports-loader",
|
|
||||||
// options: {
|
|
||||||
// exports: "this.WOW",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// });
|
|
||||||
// return config;
|
|
||||||
// },
|
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
@ -26,4 +12,4 @@ const nextConfig: NextConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default withPayload(nextConfig);
|
||||||
|
7041
package-lock.json
generated
7041
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@ -2,28 +2,42 @@
|
|||||||
"name": "my-app",
|
"name": "my-app",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack",
|
"dev": "next dev --turbopack",
|
||||||
|
"dev-old": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint",
|
||||||
|
"payload:generate:types": "payload generate:types",
|
||||||
|
"tsc": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@payloadcms/db-postgres": "^3.20.0",
|
||||||
|
"@payloadcms/next": "^3.20.0",
|
||||||
|
"@payloadcms/payload-cloud": "^3.20.0",
|
||||||
|
"@payloadcms/richtext-lexical": "^3.20.0",
|
||||||
|
"@payloadcms/storage-s3": "^3.20.0",
|
||||||
"@popperjs/core": "2.11.8",
|
"@popperjs/core": "2.11.8",
|
||||||
"bootstrap": "^5.1.3",
|
"bootstrap": "^5.1.3",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
|
"graphql": "^16.10.0",
|
||||||
"imagesloaded": "^5.0.0",
|
"imagesloaded": "^5.0.0",
|
||||||
"isotope-layout": "^3.0.6",
|
"isotope-layout": "^3.0.6",
|
||||||
"jarallax": "^2.2.1",
|
"jarallax": "^2.2.1",
|
||||||
"next": "15.1.6",
|
"next": "15.1.6",
|
||||||
|
"payload": "^3.20.0",
|
||||||
"photoswipe": "^5.4.4",
|
"photoswipe": "^5.4.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-modal-video": "^2.0.2",
|
"react-modal-video": "^2.0.2",
|
||||||
"react-photoswipe-gallery": "^3.0.1",
|
"react-photoswipe-gallery": "^3.0.1",
|
||||||
"rellax": "^1.12.1",
|
"rellax": "^1.12.1",
|
||||||
|
"sharp": "^0.33.5",
|
||||||
"swiper": "^11.1.4",
|
"swiper": "^11.1.4",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"typewriter-effect": "^2.21.0",
|
"typewriter-effect": "^2.21.0",
|
||||||
|
"wow.js": "^1.2.2",
|
||||||
"wowjs": "^1.1.3"
|
"wowjs": "^1.1.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -39,9 +53,10 @@
|
|||||||
"eslint-config-next": "15.1.6",
|
"eslint-config-next": "15.1.6",
|
||||||
"eslint-config-prettier": "^10.0.1",
|
"eslint-config-prettier": "^10.0.1",
|
||||||
"eslint-plugin-prettier": "^5.2.3",
|
"eslint-plugin-prettier": "^5.2.3",
|
||||||
|
"exports-loader": "^5.0.0",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
145
src/app/(main)/blog/[slug]/page.tsx
Normal file
145
src/app/(main)/blog/[slug]/page.tsx
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import BlogComments from "@/components/Blogs/BlogComments";
|
||||||
|
import BlogWidget from "@/components/Blogs/BlogWidget";
|
||||||
|
import CommentForm from "@/components/CommentForm";
|
||||||
|
import { fetchBlogDetail } from "@/services/payload/blog";
|
||||||
|
import { RichText } from "@payloadcms/richtext-lexical/react";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: { slug: string };
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const blog = await fetchBlogDetail(params.slug);
|
||||||
|
|
||||||
|
if (!blog) {
|
||||||
|
return {
|
||||||
|
title: "Cochise Oncology",
|
||||||
|
description: "Cochise Oncology",
|
||||||
|
openGraph: {
|
||||||
|
title: "Cochise Oncology",
|
||||||
|
description: "Cochise Oncology",
|
||||||
|
images: [""],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = `${blog.data.title} - Cochise Oncology`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
description: title,
|
||||||
|
openGraph: {
|
||||||
|
title: title,
|
||||||
|
description: title,
|
||||||
|
images: [blog.imgUrl || ""],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function SingleBlogPage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ slug: string }>;
|
||||||
|
}) {
|
||||||
|
const slug = (await params).slug;
|
||||||
|
const data = await fetchBlogDetail(slug);
|
||||||
|
|
||||||
|
if (!data) return <></>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section
|
||||||
|
className="page-section bg-gradient-gray-light-1 bg-scroll overflow-hidden"
|
||||||
|
id="home"
|
||||||
|
>
|
||||||
|
{/* <!-- Background Shape --> */}
|
||||||
|
<div className="bg-shape-1 wow fadeIn">
|
||||||
|
<Image
|
||||||
|
src="/assets/images/demo-fancy/bg-shape-1.svg"
|
||||||
|
width={1443}
|
||||||
|
height={844}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* <!-- End Background Shape --> */}
|
||||||
|
|
||||||
|
<div className="container position-relative pt-sm-40 text-center">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
|
||||||
|
<h1 className="hs-title-10 mb-10 wow fadeInUp">
|
||||||
|
{data.data.title}
|
||||||
|
</h1>
|
||||||
|
{/* Author, Categories, Comments */}
|
||||||
|
<div
|
||||||
|
className="blog-item-data mb-0 wow fadeIn"
|
||||||
|
data-wow-delay="0.2s"
|
||||||
|
>
|
||||||
|
<div className="d-inline-block me-3">
|
||||||
|
<a href="#">
|
||||||
|
<i className="mi-clock size-16" />
|
||||||
|
<span className="visually-hidden">Date:</span>{" "}
|
||||||
|
{data.createdAt}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="d-inline-block me-3">
|
||||||
|
<i className="mi-folder size-16" />
|
||||||
|
<span className="visually-hidden">Categories:</span>{" "}
|
||||||
|
<a href="#">Design</a>, <a href="#">Branding</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* End Author, Categories, Comments */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<>
|
||||||
|
{/* Section */}
|
||||||
|
<section className="page-section">
|
||||||
|
<div className="container relative">
|
||||||
|
<div className="row">
|
||||||
|
{/* Content */}
|
||||||
|
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
|
||||||
|
{/* Post */}
|
||||||
|
<div className="blog-item mb-80 mb-xs-40">
|
||||||
|
<div className="blog-item-body">
|
||||||
|
<div className="mb-40 mb-xs-30">
|
||||||
|
<Image
|
||||||
|
src={data.imgUrl}
|
||||||
|
alt="Image Description"
|
||||||
|
width={1350}
|
||||||
|
height={759}
|
||||||
|
className="round"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<RichText data={data.data.content} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* End Post */}
|
||||||
|
</div>
|
||||||
|
{/* End Content */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{/* End Section */}
|
||||||
|
{/* Divider */}
|
||||||
|
<hr className="mt-0 mb-0" />
|
||||||
|
{/* End Divider */}
|
||||||
|
{/* Section */}
|
||||||
|
<section className="page-section">
|
||||||
|
<div className="container relative">
|
||||||
|
<div className="row mt-n60">
|
||||||
|
<BlogWidget
|
||||||
|
inputClass="newsletter-field form-control input-md circle mb-10"
|
||||||
|
btnClass="btn btn-mod btn-color btn-medium btn-circle btn-hover-anim form-control"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -1,19 +1,22 @@
|
|||||||
import Blogs from "@/components/Blogs";
|
import Blogs from "@/components/Blogs/Blogs";
|
||||||
import NewsletterForm from "@/components/NewsletterForm";
|
|
||||||
import { archiveLinks } from "@/data/archieve";
|
import { archiveLinks } from "@/data/archieve";
|
||||||
import { categories } from "@/data/categories";
|
import { categories } from "@/data/categories";
|
||||||
import { tags } from "@/data/tags";
|
import { tags } from "@/data/tags";
|
||||||
|
import { sanitizePageNumber } from "@/utils/sanitize";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title:
|
title: "Blogs | Cochise Oncology",
|
||||||
"Slick Blogs || Resonance — One & Multi Page React Nextjs Creative Template",
|
description: "Blogs | Cochise Oncology",
|
||||||
description:
|
|
||||||
"Resonance — One & Multi Page React Nextjs Creative Template",
|
|
||||||
};
|
};
|
||||||
const onePage = false;
|
|
||||||
const dark = false;
|
export default async function BlogPage({
|
||||||
export default function SlickBlogPage() {
|
searchParams,
|
||||||
|
}: {
|
||||||
|
searchParams?: { page?: string };
|
||||||
|
}) {
|
||||||
|
const page = sanitizePageNumber(searchParams?.page);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section
|
<section
|
||||||
@ -47,7 +50,7 @@ export default function SlickBlogPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="page-section" id="blog">
|
<section className="page-section" id="blog">
|
||||||
<Blogs />
|
<Blogs page={page} />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<>
|
<>
|
||||||
@ -58,7 +61,7 @@ export default function SlickBlogPage() {
|
|||||||
<section className="page-section">
|
<section className="page-section">
|
||||||
<div className="container relative">
|
<div className="container relative">
|
||||||
<div className="row mt-n60">
|
<div className="row mt-n60">
|
||||||
<div className="col-sm-6 col-lg-3 mt-60">
|
<div className="col-sm-6 col-lg-4 mt-60">
|
||||||
{/* Widget */}
|
{/* Widget */}
|
||||||
<div className="widget mb-0">
|
<div className="widget mb-0">
|
||||||
<h3 className="widget-title">Categories</h3>
|
<h3 className="widget-title">Categories</h3>
|
||||||
@ -77,7 +80,7 @@ export default function SlickBlogPage() {
|
|||||||
</div>
|
</div>
|
||||||
{/* End Widget */}
|
{/* End Widget */}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-6 col-lg-3 mt-60">
|
<div className="col-sm-6 col-lg-4 mt-60">
|
||||||
{/* Widget */}
|
{/* Widget */}
|
||||||
<div className="widget mb-0">
|
<div className="widget mb-0">
|
||||||
<h3 className="widget-title">Tags</h3>
|
<h3 className="widget-title">Tags</h3>
|
||||||
@ -93,7 +96,7 @@ export default function SlickBlogPage() {
|
|||||||
</div>
|
</div>
|
||||||
{/* End Widget */}
|
{/* End Widget */}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-6 col-lg-3 mt-60">
|
<div className="col-sm-6 col-lg-4 mt-60">
|
||||||
{/* Widget */}
|
{/* Widget */}
|
||||||
<div className="widget mb-0">
|
<div className="widget mb-0">
|
||||||
<h3 className="widget-title">Archive</h3>
|
<h3 className="widget-title">Archive</h3>
|
||||||
@ -111,18 +114,6 @@ export default function SlickBlogPage() {
|
|||||||
</div>
|
</div>
|
||||||
{/* End Widget */}
|
{/* End Widget */}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-6 col-lg-3 mt-60">
|
|
||||||
{/* Widget */}
|
|
||||||
<div className="widget mb-0">
|
|
||||||
<h3 className="widget-title">Newsletter</h3>
|
|
||||||
<div className="widget-body">
|
|
||||||
<div className="widget-text clearfix">
|
|
||||||
<NewsletterForm />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* End Widget */}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
@ -1,202 +0,0 @@
|
|||||||
import BlogComments from "@/components/BlogComments";
|
|
||||||
import BlogWidget from "@/components/BlogWidget";
|
|
||||||
import CommentForm from "@/components/CommentForm";
|
|
||||||
import { allBlogs } from "@/data/blogs";
|
|
||||||
import Image from "next/image";
|
|
||||||
export const metadata = {
|
|
||||||
title:
|
|
||||||
"Slick Blogs Single || Resonance — One & Multi Page React Nextjs Creative Template",
|
|
||||||
description:
|
|
||||||
"Resonance — One & Multi Page React Nextjs Creative Template",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function asyncSlickBlogSinglePage(
|
|
||||||
params: Promise<{ id: number }>
|
|
||||||
) {
|
|
||||||
const id = (await params).id;
|
|
||||||
const blog = allBlogs.filter((elm) => elm.id == id)[0] || allBlogs[0];
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<section
|
|
||||||
className="page-section bg-gradient-gray-light-1 bg-scroll overflow-hidden"
|
|
||||||
id="home"
|
|
||||||
>
|
|
||||||
{/* <!-- Background Shape --> */}
|
|
||||||
<div className="bg-shape-1 wow fadeIn">
|
|
||||||
<Image
|
|
||||||
src="/assets/images/demo-fancy/bg-shape-1.svg"
|
|
||||||
width={1443}
|
|
||||||
height={844}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/* <!-- End Background Shape --> */}
|
|
||||||
|
|
||||||
<div className="container position-relative pt-sm-40 text-center">
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
|
|
||||||
<h1 className="hs-title-10 mb-10 wow fadeInUp">
|
|
||||||
{/* @ts-ignore */}
|
|
||||||
{blog?.title || blog?.postTitle}
|
|
||||||
</h1>
|
|
||||||
{/* Author, Categories, Comments */}
|
|
||||||
<div
|
|
||||||
className="blog-item-data mb-0 wow fadeIn"
|
|
||||||
data-wow-delay="0.2s"
|
|
||||||
>
|
|
||||||
<div className="d-inline-block me-3">
|
|
||||||
<a href="#">
|
|
||||||
<i className="mi-clock size-16" />
|
|
||||||
<span className="visually-hidden">Date:</span> December 25
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="d-inline-block me-3">
|
|
||||||
<a href="#">
|
|
||||||
<i className="mi-user size-16" />
|
|
||||||
<span className="visually-hidden">Author:</span> John Doe
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="d-inline-block me-3">
|
|
||||||
<i className="mi-folder size-16" />
|
|
||||||
<span className="visually-hidden">Categories:</span>
|
|
||||||
<a href="#">Design</a>, <a href="#">Branding</a>
|
|
||||||
</div>
|
|
||||||
<div className="d-inline-block me-3">
|
|
||||||
<a href="#">
|
|
||||||
<i className="mi-message size-16" /> 5 Comments
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* End Author, Categories, Comments */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<>
|
|
||||||
{/* Section */}
|
|
||||||
<section className="page-section">
|
|
||||||
<div className="container relative">
|
|
||||||
<div className="row">
|
|
||||||
{/* Content */}
|
|
||||||
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
|
|
||||||
{/* Post */}
|
|
||||||
<div className="blog-item mb-80 mb-xs-40">
|
|
||||||
<div className="blog-item-body">
|
|
||||||
<div className="mb-40 mb-xs-30">
|
|
||||||
<Image
|
|
||||||
src="/assets/images/demo-fancy/blog/post-prev-3-large.jpg"
|
|
||||||
alt="Image Description"
|
|
||||||
width={1350}
|
|
||||||
height={759}
|
|
||||||
className="round"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
Morbi lacus massa, euismod ut turpis molestie, tristique
|
|
||||||
sodales est. Integer sit amet mi id sapien tempor molestie
|
|
||||||
in nec massa. Fusce non ante sed lorem rutrum feugiat.
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
||||||
Mauris non laoreet dui. Morbi lacus massa, euismod ut
|
|
||||||
turpis molestie, tristique sodales est. Integer sit amet
|
|
||||||
mi id sapien tempor molestie in nec massa.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Fusce non ante sed lorem rutrum feugiat. Vestibulum
|
|
||||||
pellentesque, purus ut dignissim consectetur, nulla
|
|
||||||
erat ultrices purus, ut consequat sem elit non sem.
|
|
||||||
Morbi lacus massa, euismod ut turpis molestie, tristique
|
|
||||||
sodales est. Integer sit amet mi id sapien tempor molestie
|
|
||||||
in nec massa. Fusce non ante sed lorem rutrum feugiat.
|
|
||||||
</p>
|
|
||||||
<blockquote>
|
|
||||||
<p>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
||||||
Integer posuere erat a ante. Vestibulum
|
|
||||||
pellentesque, purus ut dignissim consectetur, nulla erat
|
|
||||||
ultrices purus.
|
|
||||||
</p>
|
|
||||||
<footer>
|
|
||||||
Someone famous in
|
|
||||||
<cite title="Source Title"> Source Title </cite>
|
|
||||||
</footer>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Praesent ultricies ut ipsum non laoreet. Nunc ac
|
|
||||||
<a href="#">ultricies</a> leo. Nulla ac ultrices arcu.
|
|
||||||
Nullam adipiscing lacus in consectetur posuere. Nunc
|
|
||||||
malesuada tellus turpis, ac pretium orci molestie vel.
|
|
||||||
Morbi lacus massa, euismod ut turpis molestie, tristique
|
|
||||||
sodales est. Integer sit amet mi id sapien tempor molestie
|
|
||||||
in nec massa. Fusce non ante sed lorem rutrum feugiat.
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>First item of the list</li>
|
|
||||||
<li>Second item of the list</li>
|
|
||||||
<li>Third item of the list</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
||||||
Mauris non laoreet dui. Morbi lacus massa, euismod ut
|
|
||||||
turpis molestie, tristique sodales est. Integer sit amet
|
|
||||||
mi id sapien tempor molestie in nec massa. Fusce non ante
|
|
||||||
sed lorem rutrum feugiat. Vestibulum pellentesque, purus
|
|
||||||
ut dignissim consectetur, nulla erat ultrices purus,
|
|
||||||
ut consequat sem elit non sem.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* End Post */}
|
|
||||||
{/* Comments */}
|
|
||||||
<div className="mb-80 mb-xs-40">
|
|
||||||
<h4 className="blog-page-title">
|
|
||||||
Comments <small className="number">(3)</small>
|
|
||||||
</h4>
|
|
||||||
<ul className="media-list comment-list clearlist">
|
|
||||||
<BlogComments />
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{/* End Comments */}
|
|
||||||
{/* Add Comment */}
|
|
||||||
<div className="mb-80 mb-xs-40">
|
|
||||||
<h4 className="blog-page-title">Leave a comment</h4>
|
|
||||||
{/* Form */}
|
|
||||||
<CommentForm />
|
|
||||||
{/* End Form */}
|
|
||||||
</div>
|
|
||||||
{/* End Add Comment */}
|
|
||||||
{/* Prev/Next Post */}
|
|
||||||
<div className="clearfix mt-40">
|
|
||||||
<a href="#" className="blog-item-more circle left">
|
|
||||||
<i className="mi-chevron-left" />
|
|
||||||
Prev post
|
|
||||||
</a>
|
|
||||||
<a href="#" className="blog-item-more circle right">
|
|
||||||
Next post
|
|
||||||
<i className="mi-chevron-right" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{/* End Prev/Next Post */}
|
|
||||||
</div>
|
|
||||||
{/* End Content */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
{/* End Section */}
|
|
||||||
{/* Divider */}
|
|
||||||
<hr className="mt-0 mb-0" />
|
|
||||||
{/* End Divider */}
|
|
||||||
{/* Section */}
|
|
||||||
<section className="page-section">
|
|
||||||
<div className="container relative">
|
|
||||||
<div className="row mt-n60">
|
|
||||||
<BlogWidget
|
|
||||||
inputClass="newsletter-field form-control input-md circle mb-10"
|
|
||||||
btnClass="btn btn-mod btn-color btn-medium btn-circle btn-hover-anim form-control"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
24
src/app/(payload)/admin/[[...segments]]/not-found.tsx
Normal file
24
src/app/(payload)/admin/[[...segments]]/not-found.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
|
import type { Metadata } from 'next'
|
||||||
|
|
||||||
|
import config from '@payload-config'
|
||||||
|
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
|
||||||
|
import { importMap } from '../importMap'
|
||||||
|
|
||||||
|
type Args = {
|
||||||
|
params: Promise<{
|
||||||
|
segments: string[]
|
||||||
|
}>
|
||||||
|
searchParams: Promise<{
|
||||||
|
[key: string]: string | string[]
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||||
|
generatePageMetadata({ config, params, searchParams })
|
||||||
|
|
||||||
|
const NotFound = ({ params, searchParams }: Args) =>
|
||||||
|
NotFoundPage({ config, params, searchParams, importMap })
|
||||||
|
|
||||||
|
export default NotFound
|
24
src/app/(payload)/admin/[[...segments]]/page.tsx
Normal file
24
src/app/(payload)/admin/[[...segments]]/page.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
|
import type { Metadata } from 'next'
|
||||||
|
|
||||||
|
import config from '@payload-config'
|
||||||
|
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
|
||||||
|
import { importMap } from '../importMap'
|
||||||
|
|
||||||
|
type Args = {
|
||||||
|
params: Promise<{
|
||||||
|
segments: string[]
|
||||||
|
}>
|
||||||
|
searchParams: Promise<{
|
||||||
|
[key: string]: string | string[]
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||||
|
generatePageMetadata({ config, params, searchParams })
|
||||||
|
|
||||||
|
const Page = ({ params, searchParams }: Args) =>
|
||||||
|
RootPage({ config, params, searchParams, importMap })
|
||||||
|
|
||||||
|
export default Page
|
47
src/app/(payload)/admin/importMap.js
Normal file
47
src/app/(payload)/admin/importMap.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { RscEntryLexicalCell as RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc'
|
||||||
|
import { RscEntryLexicalField as RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc'
|
||||||
|
import { InlineToolbarFeatureClient as InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { UploadFeatureClient as UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { BlockquoteFeatureClient as BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { RelationshipFeatureClient as RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { LinkFeatureClient as LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { ChecklistFeatureClient as ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { OrderedListFeatureClient as OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { UnorderedListFeatureClient as UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { IndentFeatureClient as IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { AlignFeatureClient as AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { HeadingFeatureClient as HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { ParagraphFeatureClient as ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { InlineCodeFeatureClient as InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { SuperscriptFeatureClient as SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { SubscriptFeatureClient as SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { StrikethroughFeatureClient as StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
|
||||||
|
export const importMap = {
|
||||||
|
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||||
|
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalField": RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||||
|
"@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#UploadFeatureClient": UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#BlockquoteFeatureClient": BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#RelationshipFeatureClient": RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#LinkFeatureClient": LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#ChecklistFeatureClient": ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#OrderedListFeatureClient": OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#UnorderedListFeatureClient": UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#IndentFeatureClient": IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#AlignFeatureClient": AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#HeadingFeatureClient": HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#ParagraphFeatureClient": ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#InlineCodeFeatureClient": InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#SuperscriptFeatureClient": SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#SubscriptFeatureClient": SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#StrikethroughFeatureClient": StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864
|
||||||
|
}
|
19
src/app/(payload)/api/[...slug]/route.ts
Normal file
19
src/app/(payload)/api/[...slug]/route.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
|
import config from '@payload-config'
|
||||||
|
import '@payloadcms/next/css'
|
||||||
|
import {
|
||||||
|
REST_DELETE,
|
||||||
|
REST_GET,
|
||||||
|
REST_OPTIONS,
|
||||||
|
REST_PATCH,
|
||||||
|
REST_POST,
|
||||||
|
REST_PUT,
|
||||||
|
} from '@payloadcms/next/routes'
|
||||||
|
|
||||||
|
export const GET = REST_GET(config)
|
||||||
|
export const POST = REST_POST(config)
|
||||||
|
export const DELETE = REST_DELETE(config)
|
||||||
|
export const PATCH = REST_PATCH(config)
|
||||||
|
export const PUT = REST_PUT(config)
|
||||||
|
export const OPTIONS = REST_OPTIONS(config)
|
7
src/app/(payload)/api/graphql-playground/route.ts
Normal file
7
src/app/(payload)/api/graphql-playground/route.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
|
import config from '@payload-config'
|
||||||
|
import '@payloadcms/next/css'
|
||||||
|
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
|
||||||
|
|
||||||
|
export const GET = GRAPHQL_PLAYGROUND_GET(config)
|
8
src/app/(payload)/api/graphql/route.ts
Normal file
8
src/app/(payload)/api/graphql/route.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
|
import config from '@payload-config'
|
||||||
|
import { GRAPHQL_POST, REST_OPTIONS } from '@payloadcms/next/routes'
|
||||||
|
|
||||||
|
export const POST = GRAPHQL_POST(config)
|
||||||
|
|
||||||
|
export const OPTIONS = REST_OPTIONS(config)
|
0
src/app/(payload)/custom.scss
Normal file
0
src/app/(payload)/custom.scss
Normal file
31
src/app/(payload)/layout.tsx
Normal file
31
src/app/(payload)/layout.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
|
import config from '@payload-config'
|
||||||
|
import '@payloadcms/next/css'
|
||||||
|
import type { ServerFunctionClient } from 'payload'
|
||||||
|
import { handleServerFunctions, RootLayout } from '@payloadcms/next/layouts'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { importMap } from './admin/importMap.js'
|
||||||
|
import './custom.scss'
|
||||||
|
|
||||||
|
type Args = {
|
||||||
|
children: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverFunction: ServerFunctionClient = async function (args) {
|
||||||
|
'use server'
|
||||||
|
return handleServerFunctions({
|
||||||
|
...args,
|
||||||
|
config,
|
||||||
|
importMap,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const Layout = ({ children }: Args) => (
|
||||||
|
<RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
|
||||||
|
{children}
|
||||||
|
</RootLayout>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Layout
|
19
src/app/frontend-sample-payload/layout.tsx
Normal file
19
src/app/frontend-sample-payload/layout.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import './styles.css'
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
description: 'A blank template using Payload in a Next.js app.',
|
||||||
|
title: 'Payload Blank Template',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function RootLayout(props: { children: React.ReactNode }) {
|
||||||
|
const { children } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body>
|
||||||
|
<main>{children}</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
59
src/app/frontend-sample-payload/page.tsx
Normal file
59
src/app/frontend-sample-payload/page.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { headers as getHeaders } from 'next/headers.js'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import { getPayload } from 'payload'
|
||||||
|
import React from 'react'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
|
import config from '@/payload.config'
|
||||||
|
import './styles.css'
|
||||||
|
|
||||||
|
export default async function HomePage() {
|
||||||
|
const headers = await getHeaders()
|
||||||
|
const payloadConfig = await config
|
||||||
|
const payload = await getPayload({ config: payloadConfig })
|
||||||
|
const { user } = await payload.auth({ headers })
|
||||||
|
|
||||||
|
const fileURL = `vscode://file/${fileURLToPath(import.meta.url)}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="home">
|
||||||
|
<div className="content">
|
||||||
|
<picture>
|
||||||
|
<source srcSet="https://raw.githubusercontent.com/payloadcms/payload/main/packages/ui/src/assets/payload-favicon.svg" />
|
||||||
|
<Image
|
||||||
|
alt="Payload Logo"
|
||||||
|
height={65}
|
||||||
|
src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/ui/src/assets/payload-favicon.svg"
|
||||||
|
width={65}
|
||||||
|
/>
|
||||||
|
</picture>
|
||||||
|
{!user && <h1>Welcome to your new project.</h1>}
|
||||||
|
{user && <h1>Welcome back, {user.email}</h1>}
|
||||||
|
<div className="links">
|
||||||
|
<a
|
||||||
|
className="admin"
|
||||||
|
href={payloadConfig.routes.admin}
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Go to admin panel
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="docs"
|
||||||
|
href="https://payloadcms.com/docs"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Documentation
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="footer">
|
||||||
|
<p>Update this page by editing</p>
|
||||||
|
<a className="codeLink" href={fileURL}>
|
||||||
|
<code>app/(frontend)/page.tsx</code>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
164
src/app/frontend-sample-payload/styles.css
Normal file
164
src/app/frontend-sample-payload/styles.css
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
:root {
|
||||||
|
--font-mono: 'Roboto Mono', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 32px;
|
||||||
|
|
||||||
|
background: rgb(0, 0, 0);
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#app {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: system-ui;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 32px;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
color: rgb(1000, 1000, 1000);
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 40px 0;
|
||||||
|
font-size: 64px;
|
||||||
|
line-height: 70px;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
margin: 24px 0;
|
||||||
|
font-size: 42px;
|
||||||
|
line-height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
font-size: 38px;
|
||||||
|
line-height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
font-size: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 24px 0;
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
margin: calc(var(--base) * 0.75) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: currentColor;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
opacity: 0.8;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
padding: 45px;
|
||||||
|
max-width: 1024px;
|
||||||
|
margin: 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin {
|
||||||
|
color: rgb(0, 0, 0);
|
||||||
|
background: rgb(1000, 1000, 1000);
|
||||||
|
border: 1px solid rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs {
|
||||||
|
color: rgb(1000, 1000, 1000);
|
||||||
|
background: rgb(0, 0, 0);
|
||||||
|
border: 1px solid rgb(1000, 1000, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeLink {
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
background: rgb(60, 60, 60);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
export default function RootLayout({
|
|
||||||
children,
|
|
||||||
}: Readonly<{
|
|
||||||
children: React.ReactNode;
|
|
||||||
}>) {
|
|
||||||
return <>{children}</>;
|
|
||||||
}
|
|
14
src/app/my-route/route.ts
Normal file
14
src/app/my-route/route.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import configPromise from '@payload-config'
|
||||||
|
import { getPayload } from 'payload'
|
||||||
|
|
||||||
|
export const GET = async () => {
|
||||||
|
const payload = await getPayload({
|
||||||
|
config: configPromise,
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await payload.find({
|
||||||
|
collection: 'users',
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json(data)
|
||||||
|
}
|
31
src/collections/Blogs.ts
Normal file
31
src/collections/Blogs.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import type { CollectionConfig } from "payload";
|
||||||
|
import { lexicalEditor } from "@payloadcms/richtext-lexical";
|
||||||
|
|
||||||
|
export const Blogs: CollectionConfig = {
|
||||||
|
slug: "blogs",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "title",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "slug",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "img",
|
||||||
|
label: "Image",
|
||||||
|
type: "upload",
|
||||||
|
relationTo: "media",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "content",
|
||||||
|
type: "richText",
|
||||||
|
required: true,
|
||||||
|
editor: lexicalEditor({}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
16
src/collections/Media.ts
Normal file
16
src/collections/Media.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type { CollectionConfig } from "payload";
|
||||||
|
|
||||||
|
export const Media: CollectionConfig = {
|
||||||
|
slug: "media",
|
||||||
|
access: {
|
||||||
|
read: () => true,
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "alt",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
upload: true,
|
||||||
|
};
|
13
src/collections/Users.ts
Normal file
13
src/collections/Users.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import type { CollectionConfig } from "payload";
|
||||||
|
|
||||||
|
export const Users: CollectionConfig = {
|
||||||
|
slug: "users",
|
||||||
|
admin: {
|
||||||
|
useAsTitle: "email",
|
||||||
|
},
|
||||||
|
auth: true,
|
||||||
|
fields: [
|
||||||
|
// Email added by default
|
||||||
|
// Add more fields as needed
|
||||||
|
],
|
||||||
|
};
|
@ -1,63 +0,0 @@
|
|||||||
import Pagination from "@/components/Pagination";
|
|
||||||
import { blogs11 } from "@/data/blogs";
|
|
||||||
import Image from "next/image";
|
|
||||||
import Link from "next/link";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export default function Blogs() {
|
|
||||||
return (
|
|
||||||
<div className="container position-relative">
|
|
||||||
{/* Blog Posts Grid */}
|
|
||||||
<div className="row mt-n50 mb-50">
|
|
||||||
{/* Post Item */}
|
|
||||||
{blogs11.map((elm, i) => (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
className="post-prev-3 col-12 col-lg-10 offset-lg-1 col-xl-6 offset-xl-0 mt-50"
|
|
||||||
>
|
|
||||||
<div className="post-prev-3-container d-block d-sm-flex">
|
|
||||||
<div className="post-prev-3-img">
|
|
||||||
<Link href={`/slick-blog-single/${elm.id}`}>
|
|
||||||
<Image
|
|
||||||
width={400}
|
|
||||||
height={488}
|
|
||||||
src={elm.imgSrc}
|
|
||||||
alt="Add Image Description"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div className="post-prev-3-intro">
|
|
||||||
<h4 className="post-prev-3-title">
|
|
||||||
<Link href={`/slick-blog-single/${elm.id}`}>{elm.title}</Link>
|
|
||||||
</h4>
|
|
||||||
<div className="post-prev-3-text">{elm.text}</div>
|
|
||||||
<div className="post-prev-3-info clearfix">
|
|
||||||
<div className="float-start">
|
|
||||||
<a href="#">
|
|
||||||
<Image
|
|
||||||
className="post-prev-3-author-img"
|
|
||||||
width={30}
|
|
||||||
height={30}
|
|
||||||
src={elm.authorImg}
|
|
||||||
alt="Image Description"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<a href="#">{elm.author}</a>
|
|
||||||
</div>
|
|
||||||
<div className="float-end">
|
|
||||||
<a href="#">{elm.date}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{/* End Post Item */}
|
|
||||||
</div>
|
|
||||||
{/* End Blog Posts Grid */}
|
|
||||||
{/* Pagination */}
|
|
||||||
<Pagination />
|
|
||||||
{/* End Pagination */}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
63
src/components/Blogs/BlogCardItem.tsx
Normal file
63
src/components/Blogs/BlogCardItem.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export interface BlogCardItemProps {
|
||||||
|
data: {
|
||||||
|
slug: string;
|
||||||
|
title: string;
|
||||||
|
img?: {
|
||||||
|
url: string;
|
||||||
|
alt: string;
|
||||||
|
};
|
||||||
|
contentPreview: string;
|
||||||
|
author?: {
|
||||||
|
name: string;
|
||||||
|
img: string;
|
||||||
|
};
|
||||||
|
date: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BlogCardItem({ data }: BlogCardItemProps) {
|
||||||
|
return (
|
||||||
|
<div className="post-prev-3 col-12 col-lg-10 offset-lg-1 col-xl-6 offset-xl-0 mt-50">
|
||||||
|
<div className="post-prev-3-container d-block d-sm-flex">
|
||||||
|
<div className="post-prev-3-img">
|
||||||
|
<Link href={`/blog/${data.slug}`}>
|
||||||
|
<Image
|
||||||
|
width={400}
|
||||||
|
height={488}
|
||||||
|
src={data?.img?.url ?? ""}
|
||||||
|
alt={data?.img?.alt ?? ""}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="post-prev-3-intro">
|
||||||
|
<h4 className="post-prev-3-title">
|
||||||
|
<Link href={`/blog/${data.slug}`}>{data.title}</Link>
|
||||||
|
</h4>
|
||||||
|
<div className="post-prev-3-text">{data.contentPreview}</div>
|
||||||
|
<div className="post-prev-3-info clearfix">
|
||||||
|
{!!data?.author?.name && (
|
||||||
|
<div className="float-start">
|
||||||
|
<a href="#">
|
||||||
|
<Image
|
||||||
|
className="post-prev-3-author-img"
|
||||||
|
width={30}
|
||||||
|
height={30}
|
||||||
|
src={data.author?.img ?? "#"}
|
||||||
|
alt="Image Description"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<a href="#">{data.author.name}</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={!!data?.author?.name ? "float-end" : "float-start"}>
|
||||||
|
<a href="#">{data.date}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -10,7 +10,7 @@ export default function BlogWidget({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="col-sm-6 col-lg-3 mt-60">
|
<div className="col-sm-6 col-lg-4 mt-60">
|
||||||
{/* Widget */}
|
{/* Widget */}
|
||||||
<div className="widget mb-0">
|
<div className="widget mb-0">
|
||||||
<h3 className="widget-title">Categories</h3>
|
<h3 className="widget-title">Categories</h3>
|
||||||
@ -29,7 +29,7 @@ export default function BlogWidget({
|
|||||||
</div>
|
</div>
|
||||||
{/* End Widget */}
|
{/* End Widget */}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-6 col-lg-3 mt-60">
|
<div className="col-sm-6 col-lg-4 mt-60">
|
||||||
{/* Widget */}
|
{/* Widget */}
|
||||||
<div className="widget mb-0">
|
<div className="widget mb-0">
|
||||||
<h3 className="widget-title">Tags</h3>
|
<h3 className="widget-title">Tags</h3>
|
||||||
@ -45,7 +45,7 @@ export default function BlogWidget({
|
|||||||
</div>
|
</div>
|
||||||
{/* End Widget */}
|
{/* End Widget */}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-6 col-lg-3 mt-60">
|
<div className="col-sm-6 col-lg-4 mt-60">
|
||||||
{/* Widget */}
|
{/* Widget */}
|
||||||
<div className="widget mb-0">
|
<div className="widget mb-0">
|
||||||
<h3 className="widget-title">Archive</h3>
|
<h3 className="widget-title">Archive</h3>
|
||||||
@ -63,52 +63,6 @@ export default function BlogWidget({
|
|||||||
</div>
|
</div>
|
||||||
{/* End Widget */}
|
{/* End Widget */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-sm-6 col-lg-3 mt-60">
|
|
||||||
<div className="widget mb-0">
|
|
||||||
<h3 className="widget-title">Newsletter</h3>
|
|
||||||
|
|
||||||
<div className="widget-body">
|
|
||||||
<div className="widget-text clearfix">
|
|
||||||
<form
|
|
||||||
onSubmit={(e) => e.preventDefault()}
|
|
||||||
className="form"
|
|
||||||
id="mailchimp"
|
|
||||||
>
|
|
||||||
<div className="mb-20">Stay informed with our newsletter.</div>
|
|
||||||
|
|
||||||
<div className="mb-20">
|
|
||||||
<input
|
|
||||||
placeholder="Enter your email"
|
|
||||||
className={inputClass}
|
|
||||||
type="email"
|
|
||||||
pattern=".{5,100}"
|
|
||||||
required
|
|
||||||
aria-required="true"
|
|
||||||
/>
|
|
||||||
<button type="submit" className={btnClass}>
|
|
||||||
<span>Subscribe</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-tip">
|
|
||||||
<i className="icon-info size-16" aria-hidden="true"></i>
|
|
||||||
By sending the form you agree to the
|
|
||||||
<a href="#">Terms & Conditions</a> and
|
|
||||||
<a href="#">Privacy Policy</a>.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
id="subscribe-result"
|
|
||||||
role="region"
|
|
||||||
aria-live="polite"
|
|
||||||
aria-atomic="true"
|
|
||||||
></div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
56
src/components/Blogs/Blogs.tsx
Normal file
56
src/components/Blogs/Blogs.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import Pagination from "@/components/Pagination";
|
||||||
|
import { fetchBlog } from "@/services/payload/blog";
|
||||||
|
import { BlogCardItem } from "./BlogCardItem";
|
||||||
|
import { sanitizeBlogContentIntoStringPreview } from "@/utils/sanitize";
|
||||||
|
|
||||||
|
export interface BlogsProps {
|
||||||
|
page: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Blogs({ page }: BlogsProps) {
|
||||||
|
const data = await fetchBlog(page);
|
||||||
|
|
||||||
|
if (!data?.totalDocs) return <></>;
|
||||||
|
|
||||||
|
const handleClickPage = (clickedPage: number) => {
|
||||||
|
if (typeof window === "undefined") return;
|
||||||
|
|
||||||
|
window.location.href = `/blog/?page=${clickedPage}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container position-relative">
|
||||||
|
{/* Blog Posts Grid */}
|
||||||
|
<div className="row mt-n50 mb-50">
|
||||||
|
{/* Post Item */}
|
||||||
|
{data.formattedData.map((blog, i) => (
|
||||||
|
<BlogCardItem
|
||||||
|
key={i}
|
||||||
|
data={{
|
||||||
|
slug: blog.slug,
|
||||||
|
title: blog.title,
|
||||||
|
contentPreview: sanitizeBlogContentIntoStringPreview(
|
||||||
|
blog.content
|
||||||
|
),
|
||||||
|
date: blog.createdAtFormatted,
|
||||||
|
img: blog.imgFormatted,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{/* End Post Item */}
|
||||||
|
</div>
|
||||||
|
{/* End Blog Posts Grid */}
|
||||||
|
{/* Pagination */}
|
||||||
|
{data.totalPages > 1 && (
|
||||||
|
<Pagination
|
||||||
|
page={data.page ?? 1}
|
||||||
|
hasNextPage={data.hasNextPage}
|
||||||
|
hasPreviousPage={data.hasPrevPage}
|
||||||
|
totalPages={data.totalPages}
|
||||||
|
onClickPage={handleClickPage}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* End Pagination */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -4,7 +4,7 @@ import Facts from "./Facts";
|
|||||||
import Service from "./Service";
|
import Service from "./Service";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Testimonials from "./Testimonials";
|
import Testimonials from "./Testimonials";
|
||||||
import Blog from "./Blog";
|
import Blog from "./Blogs/Blog";
|
||||||
import Newsletter from "./Newsletter";
|
import Newsletter from "./Newsletter";
|
||||||
import Contact from "./Contact";
|
import Contact from "./Contact";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
@ -1,78 +1,104 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, { useState } from "react";
|
|
||||||
|
|
||||||
export default function Pagination({ className }: { className?: string }) {
|
import React from "react";
|
||||||
const [activePage, setActivePage] = useState(1); // Initialize active page
|
|
||||||
|
interface PaginationProps {
|
||||||
|
page: number;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
totalPages: number;
|
||||||
|
onClickPage?: (page: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Pagination({
|
||||||
|
page,
|
||||||
|
hasPreviousPage,
|
||||||
|
hasNextPage,
|
||||||
|
totalPages,
|
||||||
|
onClickPage,
|
||||||
|
}: PaginationProps) {
|
||||||
|
const activePage = page;
|
||||||
|
|
||||||
// Function to handle page change
|
// Function to handle page change
|
||||||
const handlePageChange = (page: number) => {
|
const handlePageChange = (page: string | number) => {
|
||||||
setActivePage(page);
|
if (typeof page === "string") return;
|
||||||
|
onClickPage?.(page);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPageNumbers = () => {
|
||||||
|
const pages = [];
|
||||||
|
const showEllipsisStart = activePage > 4;
|
||||||
|
const showEllipsisEnd = activePage < totalPages - 3;
|
||||||
|
|
||||||
|
if (totalPages <= 7) {
|
||||||
|
// Show all pages if total is 7 or less
|
||||||
|
for (let i = 1; i <= totalPages; i++) {
|
||||||
|
pages.push(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Always show first page
|
||||||
|
pages.push(1);
|
||||||
|
|
||||||
|
if (showEllipsisStart) {
|
||||||
|
pages.push("...");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show pages around current page
|
||||||
|
const start = showEllipsisStart ? Math.max(2, activePage - 1) : 2;
|
||||||
|
const end = showEllipsisEnd
|
||||||
|
? Math.min(totalPages - 1, activePage + 1)
|
||||||
|
: totalPages - 1;
|
||||||
|
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
pages.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showEllipsisEnd) {
|
||||||
|
pages.push("...");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always show last page
|
||||||
|
pages.push(totalPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={"pagination justify-content-center"}>
|
||||||
className={className ? className : "pagination justify-content-center"}
|
|
||||||
>
|
|
||||||
{/* Previous Page Button */}
|
{/* Previous Page Button */}
|
||||||
<a
|
{hasPreviousPage && (
|
||||||
onClick={() => activePage > 1 && handlePageChange(activePage - 1)}
|
<a
|
||||||
className={activePage === 1 ? "disabled" : ""}
|
onClick={() => activePage > 1 && handlePageChange(activePage - 1)}
|
||||||
>
|
className={activePage === 1 ? "disabled" : ""}
|
||||||
<i className="mi-chevron-left" />
|
>
|
||||||
<span className="visually-hidden">Previous page</span>
|
<i className="mi-chevron-left" />
|
||||||
</a>
|
<span className="visually-hidden">Previous page</span>
|
||||||
|
</a>
|
||||||
{/* Page Number 1 */}
|
|
||||||
<a
|
|
||||||
onClick={() => handlePageChange(1)}
|
|
||||||
className={activePage === 1 ? "active" : ""}
|
|
||||||
>
|
|
||||||
1
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{/* Page Number 2 */}
|
|
||||||
<a
|
|
||||||
onClick={() => handlePageChange(2)}
|
|
||||||
className={activePage === 2 ? "active" : ""}
|
|
||||||
>
|
|
||||||
2
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{/* Page Number 3 */}
|
|
||||||
<a
|
|
||||||
onClick={() => handlePageChange(3)}
|
|
||||||
className={activePage === 3 ? "active" : ""}
|
|
||||||
>
|
|
||||||
3
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{activePage > 4 && activePage < 8 && (
|
|
||||||
<span className="no-active">...</span>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{activePage > 3 && activePage < 8 && (
|
{getPageNumbers().map((page, key) => (
|
||||||
<a className={"active"}>{activePage}</a>
|
<a
|
||||||
)}
|
key={key}
|
||||||
|
onClick={() => handlePageChange(page)}
|
||||||
{/* Ellipsis */}
|
className={activePage === page ? "active" : ""}
|
||||||
<span className="no-active">...</span>
|
>
|
||||||
{activePage == 8 && <a className={"active"}>{8}</a>}
|
{page}
|
||||||
{/* Page Number 9 */}
|
</a>
|
||||||
<a
|
))}
|
||||||
onClick={() => handlePageChange(9)}
|
|
||||||
className={activePage === 9 ? "active" : ""}
|
|
||||||
>
|
|
||||||
9
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{/* Next Page Button */}
|
{/* Next Page Button */}
|
||||||
<a
|
{hasNextPage && (
|
||||||
onClick={() => activePage < 9 && handlePageChange(activePage + 1)}
|
<a
|
||||||
className={activePage === 9 ? "disabled" : ""}
|
onClick={() =>
|
||||||
>
|
activePage < totalPages && handlePageChange(activePage + 1)
|
||||||
<i className="mi-chevron-right" />
|
}
|
||||||
<span className="visually-hidden">Next page</span>
|
className={activePage === totalPages ? "disabled" : ""}
|
||||||
</a>
|
>
|
||||||
|
<i className="mi-chevron-right" />
|
||||||
|
<span className="visually-hidden">Next page</span>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ export const slickMultipages = [
|
|||||||
{ href: "/slick-about", text: "About", class: "active" },
|
{ href: "/slick-about", text: "About", class: "active" },
|
||||||
{ href: "/slick-services", text: "Services" },
|
{ href: "/slick-services", text: "Services" },
|
||||||
{ href: "/slick-portfolio", text: "Portfolio" },
|
{ href: "/slick-portfolio", text: "Portfolio" },
|
||||||
{ href: "/slick-blog", text: "Blog" },
|
{ href: "/blog", text: "Blog" },
|
||||||
{ href: "/slick-contact", text: "Contact" },
|
{ href: "/slick-contact", text: "Contact" },
|
||||||
];
|
];
|
||||||
export const slickMultipagesDark = [
|
export const slickMultipagesDark = [
|
||||||
@ -36,7 +36,7 @@ export const slickMultipagesDark = [
|
|||||||
{ href: "/slick-about-dark", text: "About", class: "active" },
|
{ href: "/slick-about-dark", text: "About", class: "active" },
|
||||||
{ href: "/slick-services-dark", text: "Services" },
|
{ href: "/slick-services-dark", text: "Services" },
|
||||||
{ href: "/slick-portfolio-dark", text: "Portfolio" },
|
{ href: "/slick-portfolio-dark", text: "Portfolio" },
|
||||||
{ href: "/slick-blog-dark", text: "Blog" },
|
{ href: "/blog", text: "Blog" },
|
||||||
{ href: "/slick-contact-dark", text: "Contact" },
|
{ href: "/slick-contact-dark", text: "Contact" },
|
||||||
];
|
];
|
||||||
export const slickOnepage = [
|
export const slickOnepage = [
|
||||||
|
276
src/payload-types.ts
Normal file
276
src/payload-types.ts
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* This file was automatically generated by Payload.
|
||||||
|
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||||
|
* and re-run `payload generate:types` to regenerate this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
auth: {
|
||||||
|
users: UserAuthOperations;
|
||||||
|
};
|
||||||
|
collections: {
|
||||||
|
users: User;
|
||||||
|
media: Media;
|
||||||
|
blogs: Blog;
|
||||||
|
'payload-locked-documents': PayloadLockedDocument;
|
||||||
|
'payload-preferences': PayloadPreference;
|
||||||
|
'payload-migrations': PayloadMigration;
|
||||||
|
};
|
||||||
|
collectionsJoins: {};
|
||||||
|
collectionsSelect: {
|
||||||
|
users: UsersSelect<false> | UsersSelect<true>;
|
||||||
|
media: MediaSelect<false> | MediaSelect<true>;
|
||||||
|
blogs: BlogsSelect<false> | BlogsSelect<true>;
|
||||||
|
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
||||||
|
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
||||||
|
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
||||||
|
};
|
||||||
|
db: {
|
||||||
|
defaultIDType: number;
|
||||||
|
};
|
||||||
|
globals: {};
|
||||||
|
globalsSelect: {};
|
||||||
|
locale: null;
|
||||||
|
user: User & {
|
||||||
|
collection: 'users';
|
||||||
|
};
|
||||||
|
jobs: {
|
||||||
|
tasks: unknown;
|
||||||
|
workflows: unknown;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export interface UserAuthOperations {
|
||||||
|
forgotPassword: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
login: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
registerFirstUser: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
unlock: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "users".
|
||||||
|
*/
|
||||||
|
export interface User {
|
||||||
|
id: number;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
email: string;
|
||||||
|
resetPasswordToken?: string | null;
|
||||||
|
resetPasswordExpiration?: string | null;
|
||||||
|
salt?: string | null;
|
||||||
|
hash?: string | null;
|
||||||
|
loginAttempts?: number | null;
|
||||||
|
lockUntil?: string | null;
|
||||||
|
password?: string | null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "media".
|
||||||
|
*/
|
||||||
|
export interface Media {
|
||||||
|
id: number;
|
||||||
|
alt: string;
|
||||||
|
prefix?: string | null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
url?: string | null;
|
||||||
|
thumbnailURL?: string | null;
|
||||||
|
filename?: string | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
focalX?: number | null;
|
||||||
|
focalY?: number | null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "blogs".
|
||||||
|
*/
|
||||||
|
export interface Blog {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
slug: string;
|
||||||
|
img: number | Media;
|
||||||
|
content: {
|
||||||
|
root: {
|
||||||
|
type: string;
|
||||||
|
children: {
|
||||||
|
type: string;
|
||||||
|
version: number;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
direction: ('ltr' | 'rtl') | null;
|
||||||
|
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||||
|
indent: number;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-locked-documents".
|
||||||
|
*/
|
||||||
|
export interface PayloadLockedDocument {
|
||||||
|
id: number;
|
||||||
|
document?:
|
||||||
|
| ({
|
||||||
|
relationTo: 'users';
|
||||||
|
value: number | User;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'media';
|
||||||
|
value: number | Media;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'blogs';
|
||||||
|
value: number | Blog;
|
||||||
|
} | null);
|
||||||
|
globalSlug?: string | null;
|
||||||
|
user: {
|
||||||
|
relationTo: 'users';
|
||||||
|
value: number | User;
|
||||||
|
};
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-preferences".
|
||||||
|
*/
|
||||||
|
export interface PayloadPreference {
|
||||||
|
id: number;
|
||||||
|
user: {
|
||||||
|
relationTo: 'users';
|
||||||
|
value: number | User;
|
||||||
|
};
|
||||||
|
key?: string | null;
|
||||||
|
value?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-migrations".
|
||||||
|
*/
|
||||||
|
export interface PayloadMigration {
|
||||||
|
id: number;
|
||||||
|
name?: string | null;
|
||||||
|
batch?: number | null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "users_select".
|
||||||
|
*/
|
||||||
|
export interface UsersSelect<T extends boolean = true> {
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
email?: T;
|
||||||
|
resetPasswordToken?: T;
|
||||||
|
resetPasswordExpiration?: T;
|
||||||
|
salt?: T;
|
||||||
|
hash?: T;
|
||||||
|
loginAttempts?: T;
|
||||||
|
lockUntil?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "media_select".
|
||||||
|
*/
|
||||||
|
export interface MediaSelect<T extends boolean = true> {
|
||||||
|
alt?: T;
|
||||||
|
prefix?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
url?: T;
|
||||||
|
thumbnailURL?: T;
|
||||||
|
filename?: T;
|
||||||
|
mimeType?: T;
|
||||||
|
filesize?: T;
|
||||||
|
width?: T;
|
||||||
|
height?: T;
|
||||||
|
focalX?: T;
|
||||||
|
focalY?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "blogs_select".
|
||||||
|
*/
|
||||||
|
export interface BlogsSelect<T extends boolean = true> {
|
||||||
|
title?: T;
|
||||||
|
slug?: T;
|
||||||
|
img?: T;
|
||||||
|
content?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-locked-documents_select".
|
||||||
|
*/
|
||||||
|
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
|
||||||
|
document?: T;
|
||||||
|
globalSlug?: T;
|
||||||
|
user?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-preferences_select".
|
||||||
|
*/
|
||||||
|
export interface PayloadPreferencesSelect<T extends boolean = true> {
|
||||||
|
user?: T;
|
||||||
|
key?: T;
|
||||||
|
value?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-migrations_select".
|
||||||
|
*/
|
||||||
|
export interface PayloadMigrationsSelect<T extends boolean = true> {
|
||||||
|
name?: T;
|
||||||
|
batch?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "auth".
|
||||||
|
*/
|
||||||
|
export interface Auth {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
declare module 'payload' {
|
||||||
|
export interface GeneratedTypes extends Config {}
|
||||||
|
}
|
56
src/payload.config.ts
Normal file
56
src/payload.config.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// storage-adapter-import-placeholder
|
||||||
|
import { postgresAdapter } from "@payloadcms/db-postgres";
|
||||||
|
import { payloadCloudPlugin } from "@payloadcms/payload-cloud";
|
||||||
|
import { s3Storage } from "@payloadcms/storage-s3";
|
||||||
|
import path from "path";
|
||||||
|
import { buildConfig } from "payload";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import sharp from "sharp";
|
||||||
|
|
||||||
|
import { Users } from "./collections/Users";
|
||||||
|
import { Media } from "./collections/Media";
|
||||||
|
import { Blogs } from "./collections/Blogs";
|
||||||
|
|
||||||
|
const filename = fileURLToPath(import.meta.url);
|
||||||
|
const dirname = path.dirname(filename);
|
||||||
|
|
||||||
|
export default buildConfig({
|
||||||
|
admin: {
|
||||||
|
user: Users.slug,
|
||||||
|
importMap: {
|
||||||
|
baseDir: path.resolve(dirname),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
collections: [Users, Media, Blogs],
|
||||||
|
secret: process.env.PAYLOAD_SECRET || "",
|
||||||
|
typescript: {
|
||||||
|
outputFile: path.resolve(dirname, "payload-types.ts"),
|
||||||
|
},
|
||||||
|
db: postgresAdapter({
|
||||||
|
pool: {
|
||||||
|
connectionString: process.env.DATABASE_URI || "",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
sharp,
|
||||||
|
plugins: [
|
||||||
|
payloadCloudPlugin(),
|
||||||
|
// storage-adapter-placeholder
|
||||||
|
s3Storage({
|
||||||
|
collections: {
|
||||||
|
media: {
|
||||||
|
prefix: "media",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bucket: process.env.S3_BUCKET || "",
|
||||||
|
config: {
|
||||||
|
forcePathStyle: true, // Important for using Supabase
|
||||||
|
credentials: {
|
||||||
|
accessKeyId: process.env.S3_ACCESS_KEY_ID || "",
|
||||||
|
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY || "",
|
||||||
|
},
|
||||||
|
region: process.env.S3_REGION,
|
||||||
|
endpoint: process.env.S3_ENDPOINT,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
52
src/services/payload/blog.ts
Normal file
52
src/services/payload/blog.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import payloadConfig from "@/payload.config";
|
||||||
|
import { formatDate } from "@/utils/datetime";
|
||||||
|
import { getPayload } from "payload";
|
||||||
|
|
||||||
|
export async function fetchBlog(page: number = 1) {
|
||||||
|
const payload = await getPayload({ config: payloadConfig });
|
||||||
|
const blogDataQuery = await payload.find({
|
||||||
|
collection: "blogs",
|
||||||
|
page,
|
||||||
|
pagination: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const formattedData = blogDataQuery.docs.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
imgFormatted:
|
||||||
|
typeof item.img !== "number"
|
||||||
|
? { url: item?.img?.url ?? "", alt: item.img.alt }
|
||||||
|
: undefined,
|
||||||
|
createdAtFormatted: formatDate(item.createdAt),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...blogDataQuery,
|
||||||
|
formattedData,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchBlogDetail(slug: string) {
|
||||||
|
const payload = await getPayload({ config: payloadConfig });
|
||||||
|
const blogDataQuery = await payload.find({
|
||||||
|
collection: "blogs",
|
||||||
|
where: {
|
||||||
|
slug: { equals: slug },
|
||||||
|
},
|
||||||
|
limit: 1,
|
||||||
|
pagination: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!blogDataQuery?.docs?.[0]) return null;
|
||||||
|
|
||||||
|
const data = blogDataQuery?.docs?.[0];
|
||||||
|
const createdAt = formatDate(data.createdAt);
|
||||||
|
const imgUrl = typeof data.img !== "number" ? (data?.img?.url ?? "") : "";
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
createdAt,
|
||||||
|
imgUrl,
|
||||||
|
};
|
||||||
|
}
|
5
src/utils/datetime.ts
Normal file
5
src/utils/datetime.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
export function formatDate(iso: string, format: string = "MMM, D YYYY") {
|
||||||
|
return dayjs(iso).format(format);
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
|
// @ts-nocheck
|
||||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||||
|
|
||||||
// @ts-nocheck
|
|
||||||
export function init_wow() {
|
export function init_wow() {
|
||||||
const { WOW } = require("wowjs");
|
const WOW = require("wow.js");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
/* Wow init */
|
/* Wow init */
|
||||||
if (document.body.classList.contains("appear-animate")) {
|
if (document.body.classList.contains("appear-animate")) {
|
||||||
@ -14,13 +15,11 @@ export function init_wow() {
|
|||||||
boxClass: "wow",
|
boxClass: "wow",
|
||||||
animateClass: "animatedfgfg",
|
animateClass: "animatedfgfg",
|
||||||
offset: 100,
|
offset: 100,
|
||||||
|
|
||||||
live: false,
|
live: false,
|
||||||
callback: function (box) {
|
callback: function (box) {
|
||||||
box.classList.add("animated");
|
box.classList.add("animated");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (document.body.classList.contains("appear-animate")) {
|
if (document.body.classList.contains("appear-animate")) {
|
||||||
wow.init();
|
wow.init();
|
||||||
} else {
|
} else {
|
||||||
@ -28,7 +27,6 @@ export function init_wow() {
|
|||||||
.querySelectorAll(".wow")
|
.querySelectorAll(".wow")
|
||||||
.forEach((el) => (el.style.opacity = "1"));
|
.forEach((el) => (el.style.opacity = "1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wow for portfolio init */
|
/* Wow for portfolio init */
|
||||||
if (document.body.classList.contains("appear-animate")) {
|
if (document.body.classList.contains("appear-animate")) {
|
||||||
document
|
document
|
||||||
@ -39,13 +37,11 @@ export function init_wow() {
|
|||||||
boxClass: "wow-p",
|
boxClass: "wow-p",
|
||||||
animateClass: "animatedfgfg",
|
animateClass: "animatedfgfg",
|
||||||
offset: 100,
|
offset: 100,
|
||||||
|
|
||||||
live: false,
|
live: false,
|
||||||
callback: function (box) {
|
callback: function (box) {
|
||||||
box.classList.add("animated");
|
box.classList.add("animated");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (document.body.classList.contains("appear-animate")) {
|
if (document.body.classList.contains("appear-animate")) {
|
||||||
wow_p.init();
|
wow_p.init();
|
||||||
} else {
|
} else {
|
||||||
@ -53,7 +49,6 @@ export function init_wow() {
|
|||||||
.querySelectorAll(".wow-p")
|
.querySelectorAll(".wow-p")
|
||||||
.forEach((el) => (el.style.opacity = "1"));
|
.forEach((el) => (el.style.opacity = "1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wow for menu bar init */
|
/* Wow for menu bar init */
|
||||||
if (
|
if (
|
||||||
document.body.classList.contains("appear-animate") &&
|
document.body.classList.contains("appear-animate") &&
|
||||||
|
32
src/utils/sanitize.ts
Normal file
32
src/utils/sanitize.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Blog } from "@/payload-types";
|
||||||
|
|
||||||
|
export function sanitizePageNumber(page: any, defaultPage = 1): number {
|
||||||
|
const parsedPage = Number(page);
|
||||||
|
|
||||||
|
if (isNaN(parsedPage) || parsedPage < 1 || !Number.isInteger(parsedPage)) {
|
||||||
|
return defaultPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sanitizeBlogContentIntoStringPreview(data: Blog["content"]) {
|
||||||
|
// Find the first paragraph that has children with text
|
||||||
|
const firstParagraph = data.root.children.find(
|
||||||
|
(node) =>
|
||||||
|
node.type === "paragraph" &&
|
||||||
|
Array.isArray(node.children) &&
|
||||||
|
node.children.length > 0 &&
|
||||||
|
!!node.children?.[0]?.text
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!firstParagraph) {
|
||||||
|
return "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const text = firstParagraph.children?.[0]?.text ?? "";
|
||||||
|
|
||||||
|
// Limit to 100 characters
|
||||||
|
return `${text.length > 100 ? text.slice(0, 100) : text}...`;
|
||||||
|
}
|
@ -1,7 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2017",
|
"target": "ES2017",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@ -19,10 +23,25 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"],
|
"@/*": [
|
||||||
"@public/*": ["./public/*"]
|
"./src/*"
|
||||||
|
],
|
||||||
|
"@public/*": [
|
||||||
|
"./public/*"
|
||||||
|
],
|
||||||
|
"@payload-config": [
|
||||||
|
"./src/payload.config.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/utils/initWow.js"],
|
"include": [
|
||||||
"exclude": ["node_modules"]
|
"next-env.d.ts",
|
||||||
}
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
"src/utils/initWow.js"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user