From 8997ad9f06c78676b493e51afe634849041936f5 Mon Sep 17 00:00:00 2001 From: rakia Date: Sat, 30 Aug 2025 13:43:22 +0300 Subject: [PATCH] Add CMS setup, update frontend pages and layouts, and modify json configs --- next-env.d.ts | 3 +- next.config.mjs | 3 +- package.json | 13 +- src/app/(frontend)/[not-found]/page.jsx | 2 +- src/app/(frontend)/{page.jsx => home.jsx} | 0 src/app/(frontend)/layout.tsx | 48 +++ .../(frontend)/{layout.jsx => mslayout.jsx} | 0 src/app/(frontend)/page.tsx | 64 ++++ src/app/(frontend)/styles.css | 164 ++++++++++ src/app/my-route/route.ts | 12 + src/collections/Media.ts | 16 + src/collections/Users.ts | 13 + src/components/pages/common/breadcrumb.jsx | 73 +++-- src/components/pages/common/skill-bar.jsx | 76 +++-- src/components/pages/error/index.jsx | 6 +- src/payload-types.ts | 299 ++++++++++++++++++ src/payload.config.ts | 37 +++ tsconfig.json | 15 +- 18 files changed, 786 insertions(+), 58 deletions(-) rename src/app/(frontend)/{page.jsx => home.jsx} (100%) create mode 100644 src/app/(frontend)/layout.tsx rename src/app/(frontend)/{layout.jsx => mslayout.jsx} (100%) create mode 100644 src/app/(frontend)/page.tsx create mode 100644 src/app/(frontend)/styles.css create mode 100644 src/app/my-route/route.ts create mode 100644 src/collections/Media.ts create mode 100644 src/collections/Users.ts create mode 100644 src/payload-types.ts create mode 100644 src/payload.config.ts diff --git a/next-env.d.ts b/next-env.d.ts index 4f11a03..830fb59 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/next.config.mjs b/next.config.mjs index 4678774..9b7ea54 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,5 @@ +import { withPayload } from "@payloadcms/next/withPayload"; /** @type {import('next').NextConfig} */ const nextConfig = {}; -export default nextConfig; +export default withPayload(nextConfig); diff --git a/package.json b/package.json index 8742ae0..7c901cb 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,19 @@ "lint": "next lint" }, "dependencies": { + "@payloadcms/db-mongodb": "^3.54.0", + "@payloadcms/next": "^3.54.0", + "@payloadcms/payload-cloud": "^3.54.0", + "@payloadcms/richtext-lexical": "^3.54.0", "bootstrap": "^5.3.3", - "next": "14.1.4", - "react": "^18", + "graphql": "^16.11.0", + "next": "15.5.2", + "payload": "^3.54.0", + "react": "^18.3.1", "react-countup": "^6.5.2", - "react-dom": "^18", + "react-dom": "^18.3.1", "react-icons": "^5.5.0", + "react-intersection-observer": "^9.16.0", "react-modal-video": "^2.0.1", "react-scroll-trigger": "^0.6.14", "react-skillbars": "^2.2.0", diff --git a/src/app/(frontend)/[not-found]/page.jsx b/src/app/(frontend)/[not-found]/page.jsx index 01e49ec..2cf5f48 100644 --- a/src/app/(frontend)/[not-found]/page.jsx +++ b/src/app/(frontend)/[not-found]/page.jsx @@ -1,4 +1,4 @@ -import ErrorPage from '@/src/components/pages/error'; +import ErrorPage from '@/components/pages/error'; import React from 'react'; const NotFound = () => { diff --git a/src/app/(frontend)/page.jsx b/src/app/(frontend)/home.jsx similarity index 100% rename from src/app/(frontend)/page.jsx rename to src/app/(frontend)/home.jsx diff --git a/src/app/(frontend)/layout.tsx b/src/app/(frontend)/layout.tsx new file mode 100644 index 0000000..ed00cb0 --- /dev/null +++ b/src/app/(frontend)/layout.tsx @@ -0,0 +1,48 @@ +// 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 ( +// +// +//
{children}
+// +// +// ) +// } + + +"use client" +import { useEffect } from 'react'; +import "./globals.css"; +import SwitchTab from '@/components/pages/common/dark-light'; +//import SwitchTab from '../../pages/common/dark-light'; +//import SwitchTab from '@/src/components/pages/common/dark-light'; + +//import SwitchTab from '@/src/components/pages/common/dark-light'; + + +export default function RootLayout({ children }) { + useEffect(() => { + require('bootstrap/dist/js/bootstrap.min.js'); + }, []); + + return ( + + + + + + + {children} + + + ); +} diff --git a/src/app/(frontend)/layout.jsx b/src/app/(frontend)/mslayout.jsx similarity index 100% rename from src/app/(frontend)/layout.jsx rename to src/app/(frontend)/mslayout.jsx diff --git a/src/app/(frontend)/page.tsx b/src/app/(frontend)/page.tsx new file mode 100644 index 0000000..47ff87c --- /dev/null +++ b/src/app/(frontend)/page.tsx @@ -0,0 +1,64 @@ +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' + +import HomeOne from "@/components/pages/homes/home"; + +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 ( + //
+ //
+ // + // + // Payload Logo + // + // {!user &&

Welcome to your new project.

} + // {user &&

Welcome back, {user.email}

} + // + //
+ //
+ //

Update this page by editing

+ // + // app/(frontend)/page.tsx + // + //
+ //
+ <> + + + ) +} diff --git a/src/app/(frontend)/styles.css b/src/app/(frontend)/styles.css new file mode 100644 index 0000000..d1fb941 --- /dev/null +++ b/src/app/(frontend)/styles.css @@ -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; + } + } +} diff --git a/src/app/my-route/route.ts b/src/app/my-route/route.ts new file mode 100644 index 0000000..0755886 --- /dev/null +++ b/src/app/my-route/route.ts @@ -0,0 +1,12 @@ +import configPromise from '@payload-config' +import { getPayload } from 'payload' + +export const GET = async (request: Request) => { + const payload = await getPayload({ + config: configPromise, + }) + + return Response.json({ + message: 'This is an example of a custom route.', + }) +} diff --git a/src/collections/Media.ts b/src/collections/Media.ts new file mode 100644 index 0000000..568cf42 --- /dev/null +++ b/src/collections/Media.ts @@ -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, +} diff --git a/src/collections/Users.ts b/src/collections/Users.ts new file mode 100644 index 0000000..c683d0e --- /dev/null +++ b/src/collections/Users.ts @@ -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 + ], +} diff --git a/src/components/pages/common/breadcrumb.jsx b/src/components/pages/common/breadcrumb.jsx index 9983345..99e83ce 100644 --- a/src/components/pages/common/breadcrumb.jsx +++ b/src/components/pages/common/breadcrumb.jsx @@ -1,26 +1,57 @@ -import Link from 'next/link'; -import breadCrumbBg from "../../../public/assets/img/pages/page-banner.jpg"; +// import Link from 'next/link'; +// import breadCrumbBg from "../../../public/assets/img/pages/page-banner.jpg"; -const BreadCrumb = ({title, innerTitle}) => { - const firstThreeWords = title?.split(' ').slice(0, 1); - return ( -
-
-
-
-
- {firstThreeWords} -
    -
  • Home|
  • -
  • {innerTitle}
  • -
-

{title}

-
-
-
+// const BreadCrumb = ({title, innerTitle}) => { +// const firstThreeWords = title?.split(' ').slice(0, 1); +// return ( +//
+//
+//
+//
+//
+// {firstThreeWords} +//
    +//
  • Home|
  • +//
  • {innerTitle}
  • +//
+//

{title}

+//
+//
+//
+//
+//
+// ); +// }; + +// export default BreadCrumb; + + +const BreadCrumb = ({ title, innerTitle }) => { + const firstThreeWords = title?.split(' ').slice(0, 1); + return ( +
+
+
+
+
+ {firstThreeWords} +
    +
  • + Home + | +
  • +
  • {innerTitle}
  • +
+

{title}

+
- ); +
+
+ ); }; -export default BreadCrumb; \ No newline at end of file +export default BreadCrumb; diff --git a/src/components/pages/common/skill-bar.jsx b/src/components/pages/common/skill-bar.jsx index da5ddf6..140136b 100644 --- a/src/components/pages/common/skill-bar.jsx +++ b/src/components/pages/common/skill-bar.jsx @@ -1,25 +1,57 @@ -import { useState } from "react"; -import CountUp from 'react-countup'; -import ScrollTrigger from "react-scroll-trigger"; -import ReactSkillBar from 'react-skillbars'; +// import { useState } from "react"; +// import CountUp from 'react-countup'; +// import ScrollTrigger from "react-scroll-trigger"; +// import ReactSkillBar from 'react-skillbars'; -const SkillBarItem = ({countUp}) => { - const [skillBar, setSkillBar] = useState(false); - const skillLevel = [ - { type: 'one', level: countUp } - ]; - return ( - <> - setSkillBar(true)} onExit={()=> setSkillBar(false)}> -
- {skillBar && } - - {skillBar && }% - -
-
- - ); +// const SkillBarItem = ({countUp}) => { +// const [skillBar, setSkillBar] = useState(false); +// const skillLevel = [ +// { type: 'one', level: countUp } +// ]; +// return ( +// <> +// setSkillBar(true)} onExit={()=> setSkillBar(false)}> +//
+// {skillBar && } +// +// {skillBar && }% +// +//
+//
+// +// ); +// }; + +// export default SkillBarItem; + + +import { useState, useEffect } from "react"; +import CountUp from "react-countup"; +import { useInView } from "react-intersection-observer"; +import ReactSkillBar from "react-skillbars"; + +const SkillBarItem = ({ countUp }) => { + const [skillBar, setSkillBar] = useState(false); + const { ref, inView } = useInView({ triggerOnce: true }); + const skillLevel = [{ type: "one", level: countUp }]; + + useEffect(() => { + if (inView) setSkillBar(true); + }, [inView]); + + return ( +
+ {skillBar && ( + + )} + + + {skillBar && } + + % + +
+ ); }; -export default SkillBarItem; \ No newline at end of file +export default SkillBarItem; diff --git a/src/components/pages/error/index.jsx b/src/components/pages/error/index.jsx index e25f458..1aa5de6 100644 --- a/src/components/pages/error/index.jsx +++ b/src/components/pages/error/index.jsx @@ -1,9 +1,9 @@ "use client"; -import SEO from '@/src/components/data/seo'; -import HeaderThree from '@/src/components/layout/header/header-three'; +import SEO from '@/components/data/seo'; +import HeaderThree from '@/components/layout/header/header-three'; import BreadCrumb from '../common/breadcrumb'; import Error from './error'; -import FooterThree from '@/src/components/layout/footer/footer-three'; +import FooterThree from '@/components/layout/footer/footer-three'; import ScrollToTop from '../common/scroll/scroll-to-top'; const ErrorPage = () => { diff --git a/src/payload-types.ts b/src/payload-types.ts new file mode 100644 index 0000000..a9606af --- /dev/null +++ b/src/payload-types.ts @@ -0,0 +1,299 @@ +/* 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. + */ + +/** + * Supported timezones in IANA format. + * + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "supportedTimezones". + */ +export type SupportedTimezones = + | 'Pacific/Midway' + | 'Pacific/Niue' + | 'Pacific/Honolulu' + | 'Pacific/Rarotonga' + | 'America/Anchorage' + | 'Pacific/Gambier' + | 'America/Los_Angeles' + | 'America/Tijuana' + | 'America/Denver' + | 'America/Phoenix' + | 'America/Chicago' + | 'America/Guatemala' + | 'America/New_York' + | 'America/Bogota' + | 'America/Caracas' + | 'America/Santiago' + | 'America/Buenos_Aires' + | 'America/Sao_Paulo' + | 'Atlantic/South_Georgia' + | 'Atlantic/Azores' + | 'Atlantic/Cape_Verde' + | 'Europe/London' + | 'Europe/Berlin' + | 'Africa/Lagos' + | 'Europe/Athens' + | 'Africa/Cairo' + | 'Europe/Moscow' + | 'Asia/Riyadh' + | 'Asia/Dubai' + | 'Asia/Baku' + | 'Asia/Karachi' + | 'Asia/Tashkent' + | 'Asia/Calcutta' + | 'Asia/Dhaka' + | 'Asia/Almaty' + | 'Asia/Jakarta' + | 'Asia/Bangkok' + | 'Asia/Shanghai' + | 'Asia/Singapore' + | 'Asia/Tokyo' + | 'Asia/Seoul' + | 'Australia/Brisbane' + | 'Australia/Sydney' + | 'Pacific/Guam' + | 'Pacific/Noumea' + | 'Pacific/Auckland' + | 'Pacific/Fiji'; + +export interface Config { + auth: { + users: UserAuthOperations; + }; + blocks: {}; + collections: { + users: User; + media: Media; + 'payload-locked-documents': PayloadLockedDocument; + 'payload-preferences': PayloadPreference; + 'payload-migrations': PayloadMigration; + }; + collectionsJoins: {}; + collectionsSelect: { + users: UsersSelect | UsersSelect; + media: MediaSelect | MediaSelect; + 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; + 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; + 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; + }; + db: { + defaultIDType: string; + }; + 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: string; + updatedAt: string; + createdAt: string; + email: string; + resetPasswordToken?: string | null; + resetPasswordExpiration?: string | null; + salt?: string | null; + hash?: string | null; + loginAttempts?: number | null; + lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; + password?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media". + */ +export interface Media { + id: string; + alt: string; + 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` "payload-locked-documents". + */ +export interface PayloadLockedDocument { + id: string; + document?: + | ({ + relationTo: 'users'; + value: string | User; + } | null) + | ({ + relationTo: 'media'; + value: string | Media; + } | null); + globalSlug?: string | null; + user: { + relationTo: 'users'; + value: string | User; + }; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences". + */ +export interface PayloadPreference { + id: string; + user: { + relationTo: 'users'; + value: string | 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: string; + 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 { + updatedAt?: T; + createdAt?: T; + email?: T; + resetPasswordToken?: T; + resetPasswordExpiration?: T; + salt?: T; + hash?: T; + loginAttempts?: T; + lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media_select". + */ +export interface MediaSelect { + alt?: 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` "payload-locked-documents_select". + */ +export interface PayloadLockedDocumentsSelect { + 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 { + 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 { + 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 {} +} \ No newline at end of file diff --git a/src/payload.config.ts b/src/payload.config.ts new file mode 100644 index 0000000..0bc1ea5 --- /dev/null +++ b/src/payload.config.ts @@ -0,0 +1,37 @@ +// storage-adapter-import-placeholder +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { payloadCloudPlugin } from '@payloadcms/payload-cloud' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +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' + +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], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET || '', + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI || '', + }), + sharp, + plugins: [ + payloadCloudPlugin(), + // storage-adapter-placeholder + ], +}) diff --git a/tsconfig.json b/tsconfig.json index c04b195..ea2ccec 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,13 +32,16 @@ // "node_modules" // ] // } - - { "compilerOptions": { "baseUrl": ".", "paths": { - "@/*": ["src/*"] + "@/*": [ + "src/*" + ], + "@payload-config": [ + "./src/payload.config.ts" + ] }, "lib": [ "dom", @@ -60,7 +63,8 @@ { "name": "next" } - ] + ], + "target": "ES2017" }, "include": [ "next-env.d.ts", @@ -71,5 +75,4 @@ "exclude": [ "node_modules" ] -} - +} \ No newline at end of file