first commit

This commit is contained in:
“dongming”
2025-12-19 13:01:41 +08:00
commit c5e710b94b
114 changed files with 5902 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
import Signin from "@/app/components/Auth/SignIn";
import Breadcrumb from "@/app/components/Common/Breadcrumb";
import { Metadata } from "next";
export const metadata: Metadata = {
title:
"Sign In | Property",
};
const SigninPage = () => {
return (
<>
<Breadcrumb pageName="Sign In Page" />
<Signin />
</>
);
};
export default SigninPage;

View File

@@ -0,0 +1,20 @@
import SignUp from "@/app/components/Auth/SignUp";
import Breadcrumb from "@/app/components/Common/Breadcrumb";
import { Metadata } from "next";
export const metadata: Metadata = {
title:
"Sign Up | Property",
};
const SignupPage = () => {
return (
<>
<Breadcrumb pageName="Sign Up Page" />
<SignUp />
</>
);
};
export default SignupPage;

View File

@@ -0,0 +1,13 @@
import { Documentation } from '@/app/components/Documentation/Documentation'
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Featurs | SiEducational',
}
export default function Page() {
return (
<>
<Documentation />
</>
)
}

View File

@@ -0,0 +1,36 @@
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import GoogleProvider from 'next-auth/providers/google';
import GitHubProvider from 'next-auth/providers/github';
const handler = NextAuth({
site: process.env.NEXTAUTH_URL || 'http://localhost:3000',
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
GitHubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
CredentialsProvider({
name: 'credentials',
credentials: {
username: { label: 'Username', type: 'text' },
password: { label: 'Password', type: 'password' },
},
authorize: async (credentials) => {
// Add your own authentication logic here
if (credentials.username === 'admin' && credentials.password === 'admin123') {
// Return user object if credentials are valid
return Promise.resolve({ id: 1, name: 'Admin', email: 'admin@example.com' });
} else {
// Return null if credentials are invalid
return Promise.resolve(null);
}
},
}),
],
});
export { handler as GET, handler as POST };

View File

@@ -0,0 +1 @@
[]

286
src/app/api/data/route.ts Normal file
View File

@@ -0,0 +1,286 @@
import { NextResponse } from 'next/server'
import { HeaderItem } from '@/app/types/menu'
import { CourseType } from '@/app/types/course'
import { Hourtype } from '@/app/types/hour'
import { CourseDetailType } from '@/app/types/coursedetail'
import { MentorType } from '@/app/types/mentor'
import { TestimonialType } from '@/app/types/testimonial'
import { FooterLinkType } from '@/app/types/footerlinks'
const HeaderData: HeaderItem[] = [
{ label: 'Home', href: '/#Home' },
{ label: 'Courses', href: '/#Courses' },
{ label: 'Mentors', href: '/#mentors-section' },
{ label: 'Testimonial', href: '/#testimonial-section' },
{ label: 'Join', href: '/#join-section' },
{ label: 'Contact Us', href: '/#contact' },
{ label: 'Docs', href: '/documentation' },
]
const CourseData: CourseType[] = [
{ name: 'Mobile Development' },
{ name: 'Web Development' },
{ name: 'Data Science' },
{ name: 'Cloud Computing' },
]
const HourData: Hourtype[] = [
{ name: '20hrs in a Month' },
{ name: '30hrs in a Month' },
{ name: '40hrs in a Month' },
{ name: '50hrs in a Month' },
]
const Companiesdata: { imgSrc: string }[] = [
{
imgSrc: '/images/slickCompany/airbnb.svg',
},
{
imgSrc: '/images/slickCompany/hubspot.svg',
},
{
imgSrc: '/images/slickCompany/microsoft.svg',
},
{
imgSrc: '/images/slickCompany/google.svg',
},
{
imgSrc: '/images/slickCompany/walmart.svg',
},
{
imgSrc: '/images/slickCompany/fedex.svg',
},
]
const CourseDetailData: CourseDetailType[] = [
{
course: 'HTML, CSS, JS',
imageSrc: '/images/courses/coursesOne.svg',
profession: 'HTML, CSS, Javascript Development',
price: '40',
category: 'webdevelopment',
},
{
course: 'Node.js',
imageSrc: '/images/courses/coursesTwo.svg',
profession: 'Backend with Node.js and Express.js',
price: '21',
category: 'webdevelopment',
},
{
course: 'Database',
imageSrc: '/images/courses/coursesThree.svg',
profession: 'Learn Mongodb with Mongoose',
price: '21',
category: 'webdevelopment',
},
{
course: 'React.js',
imageSrc: '/images/courses/coursesFour.svg',
profession: 'Learn React with Redux toolkit',
price: '99',
category: 'webdevelopment',
},
{
course: 'React Native',
imageSrc: '/images/courses/coursesOne.svg',
profession: 'Learn React Native with Node.js',
price: '89',
category: 'mobiledevelopment',
},
{
course: 'Swift',
imageSrc: '/images/courses/coursesThree.svg',
profession: 'Learn Swift from Scratch',
price: '89',
category: 'mobiledevelopment',
},
{
course: 'Flutter',
imageSrc: '/images/courses/coursesFour.svg',
profession: 'Flutter App Development',
price: '69',
category: 'mobiledevelopment',
},
{
course: 'Onsen UI',
imageSrc: '/images/courses/coursesTwo.svg',
profession: 'Learn Onsen Ui with HTML, CSS',
price: '69',
category: 'mobiledevelopment',
},
{
course: 'TensorFlow',
imageSrc: '/images/courses/coursesTwo.svg',
profession: 'Learn TensorFlow with SQL',
price: '99',
category: 'datascience',
},
{
course: 'AWS',
imageSrc: '/images/courses/coursesFour.svg',
profession: 'AWS Deep Learning AMI',
price: '99',
category: 'datascience',
},
{
course: 'Bokeh',
imageSrc: '/images/courses/coursesOne.svg',
profession: 'Learn Bokeh with Python',
price: '99',
category: 'datascience',
},
{
course: 'Scikit',
imageSrc: '/images/courses/coursesThree.svg',
profession: 'Scikit with Python Development',
price: '89',
category: 'datascience',
},
{
course: 'Laas',
imageSrc: '/images/courses/coursesThree.svg',
profession: 'Infra-as-a-Service',
price: '21',
category: 'cloudcomputing',
},
{
course: 'Iaas',
imageSrc: '/images/courses/coursesFour.svg',
profession: 'Info-as-a-Service',
price: '29',
category: 'cloudcomputing',
},
{
course: 'Paas',
imageSrc: '/images/courses/coursesOne.svg',
profession: 'Platform-as-a-Service',
price: '99',
category: 'cloudcomputing',
},
{
course: 'Saas',
imageSrc: '/images/courses/coursesTwo.svg',
profession: 'Software-as-a-Service',
price: '58',
category: 'cloudcomputing',
},
]
const MentorData: MentorType[] = [
{
name: 'Senior UX Designer',
href: '#',
imageSrc: '/images/mentor/boy1.svg',
imageAlt: "Front of men's Basic Tee in black.",
color: 'Shoo Thar Mein',
},
{
name: 'Photoshop Instructor',
href: '#',
imageSrc: '/images/mentor/boy2.svg',
imageAlt: "Front of men's Basic Tee in black.",
color: 'Cristian Doru Barin',
},
{
name: 'SEO Expert',
href: '#',
imageSrc: '/images/mentor/boy3.svg',
imageAlt: "Front of men's Basic Tee in black.",
color: 'Tanzeel Ur Rehman',
},
{
name: 'UI/UX Designer',
href: '#',
imageSrc: '/images/mentor/boy4.svg',
imageAlt: "Front of men's Basic Tee in black.",
color: 'Andrew Williams',
},
{
name: 'Web Development / Web Design',
href: '#',
imageSrc: '/images/mentor/boy5.svg',
imageAlt: "Front of men's Basic Tee in black.",
color: 'Brad Schiff',
},
{
name: 'Adobe Certified Instructor',
href: '#',
imageSrc: '/images/mentor/girl1.svg',
imageAlt: "Front of men's Basic Tee in black.",
color: 'Daniel Walter Scott',
},
]
const TestimonialData: TestimonialType[] = [
{
profession: 'UX/UI Designer',
name: 'Andrew Williams',
imgSrc: '/images/testimonial/user-1.jpg',
starimg: '/images/testimonial/stars.png',
detail:
"I have been a Junior Graphic Designer for more then 10 years. Some things are problem that I had and teach how to solve them. That's why this course is so great!",
},
{
profession: 'UX/UI Designer',
name: 'Cristian Doru Barin',
imgSrc: '/images/testimonial/user-2.jpg',
starimg: '/images/testimonial/stars.png',
detail:
"I have been a Junior Graphic Designer for more then 10 years. Some things are problem that I had and teach how to solve them. That's why this course is so great!",
},
{
profession: 'UX/UI Designer',
name: 'Tanzeel Ur Rehman',
imgSrc: '/images/testimonial/user-3.jpg',
starimg: '/images/testimonial/stars.png',
detail:
"I have been a Junior Graphic Designer for more then 10 years. Some things are problem that I had and teach how to solve them. That's why this course is so great!",
},
{
profession: 'UX/UI Designer',
name: 'Andrew Williams',
imgSrc: '/images/testimonial/user-1.jpg',
starimg: '/images/testimonial/stars.png',
detail:
"I have been a Junior Graphic Designer for more then 10 years. Some things are problem that I had and teach how to solve them. That's why this course is so great!",
},
]
const FooterLinkData: FooterLinkType[] = [
{
section: 'Company',
links: [
{ label: 'Home', href: '/#Home' },
{ label: 'Courses', href: '/#Courses' },
{ label: 'Mentors', href: '/#mentors-section' },
{ label: 'Testimonial', href: '/#testimonial-section' },
{ label: 'Join', href: '/#join-section' },
{ label: 'Contact Us', href: '/#contact' },
],
},
{
section: 'Support',
links: [
{ label: 'Help center', href: '/' },
{ label: 'Terms of service', href: '/' },
{ label: 'Legal', href: '/' },
{ label: 'Privacy Policy', href: '/' },
{ label: 'Status', href: '/' },
],
},
]
export const GET = () => {
return NextResponse.json({
HeaderData,
CourseData,
HourData,
Companiesdata,
CourseDetailData,
MentorData,
TestimonialData,
FooterLinkData,
})
}

View File

@@ -0,0 +1,324 @@
"use client";
import React from "react";
import { useState } from "react";
import toast from "react-hot-toast";
import axios from "axios";
import Loader from "@/app/components/Common/Loader";
import Link from "next/link";
import Image from "next/image";
const ForgotPassword = () => {
const [email, setEmail] = useState("");
const [loader, setLoader] = useState(false);
const handleSubmit = async (e: any) => {
e.preventDefault();
if (!email) {
toast.error("Please enter your email address.");
return;
}
setLoader(true);
try {
const res = await axios.post("/api/forgot-password/reset", {
email: email.toLowerCase(),
});
if (res.status === 404) {
toast.error("User not found.");
return;
}
if (res.status === 200) {
toast.success(res.data);
setEmail("");
}
setEmail("");
setLoader(false);
} catch (error: any) {
toast.error(error?.response.data);
setLoader(false);
}
};
return (
<section className="bg-[#F4F7FF] py-14 dark:bg-dark lg:py-20">
<div className="container">
<div className="-mx-4 flex flex-wrap">
<div className="w-full px-4">
<div
className="wow fadeInUp relative mx-auto max-w-[525px] overflow-hidden rounded-lg bg-white px-8 py-14 text-center dark:bg-dark-2 sm:px-12 md:px-[60px]"
data-wow-delay=".15s"
>
<div className="mb-10 text-center">
<Link href="/" className="mx-auto inline-block max-w-[160px]">
<Image
src="/images/logo/logo.svg"
alt="logo"
width={140}
height={30}
className="dark:hidden"
/>
<Image
src="/images/logo/logo-white.svg"
alt="logo"
width={140}
height={30}
className="hidden dark:block"
/>
</Link>
</div>
<form onSubmit={handleSubmit}>
<div className="mb-[22px]">
<input
type="email"
placeholder="Email"
name="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="w-full rounded-md border border-stroke bg-transparent px-5 py-3 text-base text-dark outline-hidden transition placeholder:text-dark-6 focus:border-primary focus-visible:shadow-none dark:border-dark-3 dark:text-white dark:focus:border-primary"
/>
</div>
<div className="">
<button
type="submit"
className="flex w-full cursor-pointer items-center justify-center rounded-md border border-primary bg-primary px-5 py-3 text-base text-white transition duration-300 ease-in-out hover:bg-blue-dark"
>
Send Email {loader && <Loader />}
</button>
</div>
</form>
<div>
<span className="absolute right-1 top-1">
<svg
width="40"
height="40"
viewBox="0 0 40 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="1.39737"
cy="38.6026"
r="1.39737"
transform="rotate(-90 1.39737 38.6026)"
fill="#3056D3"
/>
<circle
cx="1.39737"
cy="1.99122"
r="1.39737"
transform="rotate(-90 1.39737 1.99122)"
fill="#3056D3"
/>
<circle
cx="13.6943"
cy="38.6026"
r="1.39737"
transform="rotate(-90 13.6943 38.6026)"
fill="#3056D3"
/>
<circle
cx="13.6943"
cy="1.99122"
r="1.39737"
transform="rotate(-90 13.6943 1.99122)"
fill="#3056D3"
/>
<circle
cx="25.9911"
cy="38.6026"
r="1.39737"
transform="rotate(-90 25.9911 38.6026)"
fill="#3056D3"
/>
<circle
cx="25.9911"
cy="1.99122"
r="1.39737"
transform="rotate(-90 25.9911 1.99122)"
fill="#3056D3"
/>
<circle
cx="38.288"
cy="38.6026"
r="1.39737"
transform="rotate(-90 38.288 38.6026)"
fill="#3056D3"
/>
<circle
cx="38.288"
cy="1.99122"
r="1.39737"
transform="rotate(-90 38.288 1.99122)"
fill="#3056D3"
/>
<circle
cx="1.39737"
cy="26.3057"
r="1.39737"
transform="rotate(-90 1.39737 26.3057)"
fill="#3056D3"
/>
<circle
cx="13.6943"
cy="26.3057"
r="1.39737"
transform="rotate(-90 13.6943 26.3057)"
fill="#3056D3"
/>
<circle
cx="25.9911"
cy="26.3057"
r="1.39737"
transform="rotate(-90 25.9911 26.3057)"
fill="#3056D3"
/>
<circle
cx="38.288"
cy="26.3057"
r="1.39737"
transform="rotate(-90 38.288 26.3057)"
fill="#3056D3"
/>
<circle
cx="1.39737"
cy="14.0086"
r="1.39737"
transform="rotate(-90 1.39737 14.0086)"
fill="#3056D3"
/>
<circle
cx="13.6943"
cy="14.0086"
r="1.39737"
transform="rotate(-90 13.6943 14.0086)"
fill="#3056D3"
/>
<circle
cx="25.9911"
cy="14.0086"
r="1.39737"
transform="rotate(-90 25.9911 14.0086)"
fill="#3056D3"
/>
<circle
cx="38.288"
cy="14.0086"
r="1.39737"
transform="rotate(-90 38.288 14.0086)"
fill="#3056D3"
/>
</svg>
</span>
<span className="absolute bottom-1 left-1">
<svg
width="29"
height="40"
viewBox="0 0 29 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="2.288"
cy="25.9912"
r="1.39737"
transform="rotate(-90 2.288 25.9912)"
fill="#3056D3"
/>
<circle
cx="14.5849"
cy="25.9911"
r="1.39737"
transform="rotate(-90 14.5849 25.9911)"
fill="#3056D3"
/>
<circle
cx="26.7216"
cy="25.9911"
r="1.39737"
transform="rotate(-90 26.7216 25.9911)"
fill="#3056D3"
/>
<circle
cx="2.288"
cy="13.6944"
r="1.39737"
transform="rotate(-90 2.288 13.6944)"
fill="#3056D3"
/>
<circle
cx="14.5849"
cy="13.6943"
r="1.39737"
transform="rotate(-90 14.5849 13.6943)"
fill="#3056D3"
/>
<circle
cx="26.7216"
cy="13.6943"
r="1.39737"
transform="rotate(-90 26.7216 13.6943)"
fill="#3056D3"
/>
<circle
cx="2.288"
cy="38.0087"
r="1.39737"
transform="rotate(-90 2.288 38.0087)"
fill="#3056D3"
/>
<circle
cx="2.288"
cy="1.39739"
r="1.39737"
transform="rotate(-90 2.288 1.39739)"
fill="#3056D3"
/>
<circle
cx="14.5849"
cy="38.0089"
r="1.39737"
transform="rotate(-90 14.5849 38.0089)"
fill="#3056D3"
/>
<circle
cx="26.7216"
cy="38.0089"
r="1.39737"
transform="rotate(-90 26.7216 38.0089)"
fill="#3056D3"
/>
<circle
cx="14.5849"
cy="1.39761"
r="1.39737"
transform="rotate(-90 14.5849 1.39761)"
fill="#3056D3"
/>
<circle
cx="26.7216"
cy="1.39761"
r="1.39737"
transform="rotate(-90 26.7216 1.39761)"
fill="#3056D3"
/>
</svg>
</span>
</div>
</div>
</div>
</div>
</div>
</section>
);
};
export default ForgotPassword;

View File

@@ -0,0 +1,67 @@
"use client";
import { useState } from "react";
import { signIn } from "next-auth/react";
import toast from "react-hot-toast";
import { validateEmail } from "@/utils/validateEmail";
const MagicLink = () => {
const [email, setEmail] = useState("");
const [loader, setLoader] = useState(false);
const handleSubmit = (e: any) => {
e.preventDefault();
if (!email) {
return toast.error("Please enter your email address.");
}
setLoader(true);
if (!validateEmail(email)) {
setLoader(false);
return toast.error("Please enter a valid email address.");
} else {
signIn("email", {
redirect: false,
email: email,
})
.then((callback) => {
if (callback?.ok) {
toast.success("Email sent");
setEmail("");
setLoader(false);
}
})
.catch((error) => {
console.log(error);
toast.error("Unable to send email!");
setLoader(false);
});
}
};
return (
<form onSubmit={handleSubmit}>
<div className="mb-[22px]">
<input
type="email"
placeholder="Email"
name="email"
required
value={email}
onChange={(e) => setEmail(e.target.value.toLowerCase())}
className="w-full rounded-md border border-stroke bg-transparent px-5 py-3 text-base text-dark outline-hidden transition placeholder:text-dark-6 focus:border-primary focus-visible:shadow-none dark:border-dark-3 dark:text-white dark:focus:border-primary"
/>
</div>
<div className="mb-9">
<button
type="submit"
className="flex w-full cursor-pointer items-center justify-center rounded-md border border-primary bg-[#102C46] px-5 py-3 text-base text-white transition duration-300 ease-in-out hover:bg-[#102C46]"
>
Send Magic Link
</button>
</div>
</form>
);
};
export default MagicLink;

View File

@@ -0,0 +1,368 @@
"use client";
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useRouter } from "next/navigation";
import toast from "react-hot-toast";
import Loader from "@/app/components/Common/Loader";
import Link from "next/link";
import Image from "next/image";
const ResetPassword = ({ token }: { token: string }) => {
const [data, setData] = useState({
newPassword: "",
ReNewPassword: "",
});
const [loader, setLoader] = useState(false);
const [user, setUser] = useState({
email: "",
});
const router = useRouter();
useEffect(() => {
const verifyToken = async () => {
try {
const res = await axios.post(`/api/forgot-password/verify-token`, {
token,
});
if (res.status === 200) {
setUser({
email: res.data.email,
});
}
} catch (error: any) {
toast.error(error?.response?.data);
router.push("/forgot-password");
}
};
verifyToken();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setData({
...data,
[e.target.name]: e.target.value,
});
};
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoader(true);
if (data.newPassword === "") {
toast.error("Please enter your password.");
return;
}
try {
const res = await axios.post(`/api/forgot-password/update`, {
email: user?.email,
password: data.newPassword,
});
if (res.status === 200) {
toast.success(res.data);
setData({ newPassword: "", ReNewPassword: "" });
router.push("/signin");
}
setLoader(false);
} catch (error: any) {
toast.error(error.response.data);
setLoader(false);
}
};
return (
<section className="bg-[#F4F7FF] py-14 dark:bg-dark lg:py-20">
<div className="container">
<div className="-mx-4 flex flex-wrap">
<div className="w-full px-4">
<div
className="wow fadeInUp relative mx-auto max-w-[525px] overflow-hidden rounded-lg bg-white px-8 py-14 text-center dark:bg-dark-2 sm:px-12 md:px-[60px]"
data-wow-delay=".15s"
>
<div className="mb-10 text-center">
<Link href="/" className="mx-auto inline-block max-w-[160px]">
<Image
src="/images/logo/logo.svg"
alt="logo"
width={140}
height={30}
className="dark:hidden"
/>
<Image
src="/images/logo/logo-white.svg"
alt="logo"
width={140}
height={30}
className="hidden dark:block"
/>
</Link>
</div>
<form onSubmit={handleSubmit}>
<div className="mb-[22px]">
<input
type="text"
placeholder="New password"
name="newPassword"
value={data?.newPassword}
onChange={handleChange}
required
className="w-full rounded-md border border-stroke bg-transparent px-5 py-3 text-base text-dark outline-hidden transition placeholder:text-dark-6 focus:border-primary focus-visible:shadow-none dark:border-dark-3 dark:text-white dark:focus:border-primary"
/>
</div>
<div className="mb-[22px]">
<input
type="text"
placeholder="New password"
name="newPassword"
value={data?.newPassword}
onChange={handleChange}
required
className="w-full rounded-md border border-stroke bg-transparent px-5 py-3 text-base text-dark outline-hidden transition placeholder:text-dark-6 focus:border-primary focus-visible:shadow-none dark:border-dark-3 dark:text-white dark:focus:border-primary"
/>
</div>
<div className="">
<button
type="submit"
className="flex w-full cursor-pointer items-center justify-center rounded-md border border-primary bg-primary px-5 py-3 text-base text-white transition duration-300 ease-in-out hover:bg-blue-dark"
>
Save Password {loader && <Loader />}
</button>
</div>
</form>
<div>
<span className="absolute right-1 top-1">
<svg
width="40"
height="40"
viewBox="0 0 40 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="1.39737"
cy="38.6026"
r="1.39737"
transform="rotate(-90 1.39737 38.6026)"
fill="#3056D3"
/>
<circle
cx="1.39737"
cy="1.99122"
r="1.39737"
transform="rotate(-90 1.39737 1.99122)"
fill="#3056D3"
/>
<circle
cx="13.6943"
cy="38.6026"
r="1.39737"
transform="rotate(-90 13.6943 38.6026)"
fill="#3056D3"
/>
<circle
cx="13.6943"
cy="1.99122"
r="1.39737"
transform="rotate(-90 13.6943 1.99122)"
fill="#3056D3"
/>
<circle
cx="25.9911"
cy="38.6026"
r="1.39737"
transform="rotate(-90 25.9911 38.6026)"
fill="#3056D3"
/>
<circle
cx="25.9911"
cy="1.99122"
r="1.39737"
transform="rotate(-90 25.9911 1.99122)"
fill="#3056D3"
/>
<circle
cx="38.288"
cy="38.6026"
r="1.39737"
transform="rotate(-90 38.288 38.6026)"
fill="#3056D3"
/>
<circle
cx="38.288"
cy="1.99122"
r="1.39737"
transform="rotate(-90 38.288 1.99122)"
fill="#3056D3"
/>
<circle
cx="1.39737"
cy="26.3057"
r="1.39737"
transform="rotate(-90 1.39737 26.3057)"
fill="#3056D3"
/>
<circle
cx="13.6943"
cy="26.3057"
r="1.39737"
transform="rotate(-90 13.6943 26.3057)"
fill="#3056D3"
/>
<circle
cx="25.9911"
cy="26.3057"
r="1.39737"
transform="rotate(-90 25.9911 26.3057)"
fill="#3056D3"
/>
<circle
cx="38.288"
cy="26.3057"
r="1.39737"
transform="rotate(-90 38.288 26.3057)"
fill="#3056D3"
/>
<circle
cx="1.39737"
cy="14.0086"
r="1.39737"
transform="rotate(-90 1.39737 14.0086)"
fill="#3056D3"
/>
<circle
cx="13.6943"
cy="14.0086"
r="1.39737"
transform="rotate(-90 13.6943 14.0086)"
fill="#3056D3"
/>
<circle
cx="25.9911"
cy="14.0086"
r="1.39737"
transform="rotate(-90 25.9911 14.0086)"
fill="#3056D3"
/>
<circle
cx="38.288"
cy="14.0086"
r="1.39737"
transform="rotate(-90 38.288 14.0086)"
fill="#3056D3"
/>
</svg>
</span>
<span className="absolute bottom-1 left-1">
<svg
width="29"
height="40"
viewBox="0 0 29 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="2.288"
cy="25.9912"
r="1.39737"
transform="rotate(-90 2.288 25.9912)"
fill="#3056D3"
/>
<circle
cx="14.5849"
cy="25.9911"
r="1.39737"
transform="rotate(-90 14.5849 25.9911)"
fill="#3056D3"
/>
<circle
cx="26.7216"
cy="25.9911"
r="1.39737"
transform="rotate(-90 26.7216 25.9911)"
fill="#3056D3"
/>
<circle
cx="2.288"
cy="13.6944"
r="1.39737"
transform="rotate(-90 2.288 13.6944)"
fill="#3056D3"
/>
<circle
cx="14.5849"
cy="13.6943"
r="1.39737"
transform="rotate(-90 14.5849 13.6943)"
fill="#3056D3"
/>
<circle
cx="26.7216"
cy="13.6943"
r="1.39737"
transform="rotate(-90 26.7216 13.6943)"
fill="#3056D3"
/>
<circle
cx="2.288"
cy="38.0087"
r="1.39737"
transform="rotate(-90 2.288 38.0087)"
fill="#3056D3"
/>
<circle
cx="2.288"
cy="1.39739"
r="1.39737"
transform="rotate(-90 2.288 1.39739)"
fill="#3056D3"
/>
<circle
cx="14.5849"
cy="38.0089"
r="1.39737"
transform="rotate(-90 14.5849 38.0089)"
fill="#3056D3"
/>
<circle
cx="26.7216"
cy="38.0089"
r="1.39737"
transform="rotate(-90 26.7216 38.0089)"
fill="#3056D3"
/>
<circle
cx="14.5849"
cy="1.39761"
r="1.39737"
transform="rotate(-90 14.5849 1.39761)"
fill="#3056D3"
/>
<circle
cx="26.7216"
cy="1.39761"
r="1.39737"
transform="rotate(-90 26.7216 1.39761)"
fill="#3056D3"
/>
</svg>
</span>
</div>
</div>
</div>
</div>
</div>
</section>
);
};
export default ResetPassword;

View File

@@ -0,0 +1,107 @@
'use client'
import { signIn } from 'next-auth/react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
import toast from 'react-hot-toast'
import SocialSignIn from '../SocialSignIn'
import Logo from '@/app/components/Layout/Header/Logo'
import Loader from '@/app/components/Common/Loader'
const Signin = () => {
const router = useRouter()
const [loginData, setLoginData] = useState({
email: '',
password: '',
checkboxToggle: false,
})
const [loading, setLoading] = useState(false)
const loginUser = (e: any) => {
e.preventDefault()
setLoading(true)
signIn('credentials', { ...loginData, redirect: false })
.then((callback) => {
if (callback?.error) {
toast.error(callback?.error)
console.log(callback?.error)
setLoading(false)
return
}
if (callback?.ok && !callback?.error) {
toast.success('Login successful')
setLoading(false)
router.push('/')
}
})
.catch((err) => {
setLoading(false)
console.log(err.message)
toast.error(err.message)
})
}
return (
<>
<div className='mb-10 text-center mx-auto inline-block max-w-[160px]'>
<Logo />
</div>
<SocialSignIn />
<span className="z-1 relative my-8 block text-center before:content-[''] before:absolute before:h-px before:w-[40%] before:bg-black/20 before:left-0 before:top-3 after:content-[''] after:absolute after:h-px after:w-[40%] after:bg-black/20 after:top-3 after:right-0">
<span className='text-body-secondary relative z-10 inline-block px-3 text-base text-black'>
OR
</span>
</span>
<form onSubmit={(e) => e.preventDefault()}>
<div className='mb-[22px]'>
<input
type='email'
placeholder='Email'
onChange={(e) =>
setLoginData({ ...loginData, email: e.target.value })
}
className='w-full rounded-md border border-solid bg-transparent px-5 py-3 text-base text-dark outline-hidden transition border-gray-200 placeholder:text-black/30 focus:border-primary focus-visible:shadow-none text-black'
/>
</div>
<div className='mb-[22px]'>
<input
type='password'
placeholder='Password'
onChange={(e) =>
setLoginData({ ...loginData, password: e.target.value })
}
className='w-full rounded-md border border-solid bg-transparent px-5 py-3 text-base text-dark outline-hidden transition border-gray-200 placeholder:text-black/30 focus:border-primary focus-visible:shadow-none text-black'
/>
</div>
<div className='mb-9'>
<button
onClick={loginUser}
type='submit'
className='bg-primary w-full py-3 rounded-lg text-18 font-medium border text-white border-primary hover:text-primary hover:bg-transparent hover:cursor-pointer transition duration-300 ease-in-out'>
Sign In {loading && <Loader />}
</button>
</div>
</form>
<Link
href='/'
className='mb-2 inline-block text-base text-primary hover:underline'>
Forgot Password?
</Link>
<p className='text-body-secondary text-black text-base'>
Not a member yet?{' '}
<Link href='/' className='text-primary hover:underline'>
Sign Up
</Link>
</p>
</>
)
}
export default Signin

View File

@@ -0,0 +1,112 @@
'use client'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import toast from 'react-hot-toast'
import SocialSignUp from '../SocialSignUp'
import Logo from '@/app/components/Layout/Header/Logo'
import { useState } from 'react'
import Loader from '@/app/components/Common/Loader'
const SignUp = () => {
const router = useRouter()
const [loading, setLoading] = useState(false)
const handleSubmit = (e: any) => {
e.preventDefault()
setLoading(true)
const data = new FormData(e.currentTarget)
const value = Object.fromEntries(data.entries())
const finalData = { ...value }
fetch('/api/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(finalData),
})
.then((res) => res.json())
.then((data) => {
toast.success('Successfully registered')
setLoading(false)
router.push('/signin')
})
.catch((err) => {
toast.error(err.message)
setLoading(false)
})
}
return (
<>
<div className='mb-10 text-center mx-auto inline-block max-w-[160px]'>
<Logo />
</div>
<SocialSignUp />
<span className="z-1 relative my-8 block text-center before:content-[''] before:absolute before:h-px before:w-[40%] before:bg-black/20 before:left-0 before:top-3 after:content-[''] after:absolute after:h-px after:w-[40%] after:bg-black/20 after:top-3 after:right-0">
<span className='text-body-secondary relative z-10 inline-block px-3 text-base text-black'>
OR
</span>
</span>
<form onSubmit={handleSubmit}>
<div className='mb-[22px]'>
<input
type='text'
placeholder='Name'
name='name'
required
className='w-full rounded-md border border-solid bg-transparent px-5 py-3 text-base text-dark outline-hidden transition border-gray-200 placeholder:text-black/30 focus:border-primary focus-visible:shadow-none text-black'
/>
</div>
<div className='mb-[22px]'>
<input
type='email'
placeholder='Email'
name='email'
required
className='w-full rounded-md border border-solid bg-transparent px-5 py-3 text-base text-dark outline-hidden transition border-gray-200 placeholder:text-black/30 focus:border-primary focus-visible:shadow-none text-black'
/>
</div>
<div className='mb-[22px]'>
<input
type='password'
placeholder='Password'
name='password'
required
className='w-full rounded-md border border-solid bg-transparent px-5 py-3 text-base text-dark outline-hidden transition border-gray-200 placeholder:text-black/30 focus:border-primary focus-visible:shadow-none text-black'
/>
</div>
<div className='mb-9'>
<button
type='submit'
className='flex w-full items-center text-18 font-medium justify-center rounded-md text-white bg-primary px-5 py-3 text-darkmode transition duration-300 ease-in-out hover:bg-transparent hover:text-primary border-primary border hover:cursor-pointer'>
Sign Up {loading && <Loader />}
</button>
</div>
</form>
<p className='text-body-secondary mb-4 text-black text-base'>
By creating an account you are agree with our{' '}
<Link href='/#' className='text-primary hover:underline'>
Privacy
</Link>{' '}
and{' '}
<Link href='/#' className='text-primary hover:underline'>
Policy
</Link>
</p>
<p className='text-body-secondary text-black text-base'>
Already have an account?
<Link href='/' className='pl-2 text-primary hover:underline'>
Sign In
</Link>
</p>
</>
)
}
export default SignUp

View File

@@ -0,0 +1,70 @@
import React from 'react'
import { signIn } from 'next-auth/react'
const SocialSignIn = () => {
return (
<>
<div className='flex gap-4'>
<button
onClick={() => signIn('google')}
className='flex w-full items-center justify-center gap-2.5 rounded-lg p-3.5 border border-gray-200 text-black hover:bg-neutral-100 hover:cursor-pointer'>
Sign In
<svg
width='23'
height='22'
viewBox='0 0 23 22'
fill='none'
xmlns='http://www.w3.org/2000/svg'>
<g clipPath='url(#clip0_709_8846)'>
<path
d='M22.5001 11.2438C22.5134 10.4876 22.4338 9.73256 22.2629 8.995H11.7246V13.0771H17.9105C17.7933 13.7929 17.5296 14.478 17.1352 15.0914C16.7409 15.7047 16.224 16.2335 15.6158 16.646L15.5942 16.7827L18.9264 19.3124L19.1571 19.335C21.2772 17.4161 22.4997 14.5926 22.4997 11.2438'
fill='#4285F4'
/>
<path
d='M11.7245 22C14.755 22 17.2992 21.0221 19.1577 19.3355L15.6156 16.6464C14.6679 17.2944 13.3958 17.7467 11.7245 17.7467C10.3051 17.7385 8.92433 17.2926 7.77814 16.472C6.63195 15.6515 5.77851 14.4981 5.33892 13.1755L5.20737 13.1865L1.74255 15.8142L1.69727 15.9376C2.63043 17.7602 4.06252 19.2925 5.83341 20.3631C7.60429 21.4337 9.64416 22.0005 11.7249 22'
fill='#34A853'
/>
<path
d='M5.33889 13.1755C5.09338 12.4753 4.96669 11.7404 4.96388 11C4.9684 10.2608 5.09041 9.52685 5.32552 8.8245L5.31927 8.67868L1.81196 6.00867L1.69724 6.06214C0.910039 7.5938 0.5 9.28491 0.5 10.9999C0.5 12.7148 0.910039 14.406 1.69724 15.9376L5.33889 13.1755Z'
fill='#FBBC05'
/>
<path
d='M11.7249 4.25337C13.3333 4.22889 14.8888 4.8159 16.065 5.89121L19.2329 2.86003C17.2011 0.992106 14.5106 -0.0328008 11.7249 3.27798e-05C9.64418 -0.000452376 7.60433 0.566279 5.83345 1.63686C4.06256 2.70743 2.63046 4.23965 1.69727 6.06218L5.32684 8.82455C5.77077 7.50213 6.62703 6.34962 7.77491 5.5295C8.9228 4.70938 10.3044 4.26302 11.7249 4.25337Z'
fill='#EB4335'
/>
</g>
<defs>
<clipPath id='clip0_709_8846'>
<rect
width='22'
height='22'
fill='white'
transform='translate(0.5)'
/>
</clipPath>
</defs>
</svg>
</button>
<button
onClick={() => signIn('github')}
className='flex w-full items-center justify-center gap-2.5 rounded-lg p-3.5 border border-gray-200 text-black hover:bg-neutral-100 hover:cursor-pointer'>
Sign In
<svg
width='22'
height='22'
viewBox='0 0 22 22'
fill='none'
xmlns='http://www.w3.org/2000/svg'>
<path
d='M10.9997 1.83331C5.93773 1.83331 1.83301 6.04119 1.83301 11.232C1.83301 15.3847 4.45954 18.9077 8.10178 20.1505C8.55988 20.2375 8.72811 19.9466 8.72811 19.6983C8.72811 19.4743 8.71956 18.7338 8.71567 17.9485C6.16541 18.517 5.6273 16.8395 5.6273 16.8395C5.21032 15.7532 4.60951 15.4644 4.60951 15.4644C3.77785 14.8811 4.6722 14.893 4.6722 14.893C5.59272 14.9593 6.07742 15.8615 6.07742 15.8615C6.89499 17.2984 8.22184 16.883 8.74493 16.6429C8.82718 16.0353 9.06478 15.6208 9.32694 15.3861C7.2909 15.1484 5.15051 14.3425 5.15051 10.7412C5.15051 9.71509 5.5086 8.87661 6.09503 8.21844C5.99984 7.98167 5.68611 7.02577 6.18382 5.73115C6.18382 5.73115 6.95358 5.47855 8.70532 6.69458C9.43648 6.48627 10.2207 6.3819 10.9997 6.37836C11.7787 6.3819 12.5635 6.48627 13.2961 6.69458C15.0457 5.47855 15.8145 5.73115 15.8145 5.73115C16.3134 7.02577 15.9995 7.98167 15.9043 8.21844C16.4921 8.87661 16.8477 9.715 16.8477 10.7412C16.8477 14.351 14.7033 15.146 12.662 15.3786C12.9909 15.6702 13.2838 16.2423 13.2838 17.1191C13.2838 18.3766 13.2732 19.3888 13.2732 19.6983C13.2732 19.9485 13.4382 20.2415 13.9028 20.1492C17.5431 18.905 20.1663 15.3833 20.1663 11.232C20.1663 6.04119 16.0621 1.83331 10.9997 1.83331Z'
fill='currentColor'
/>
</svg>
</button>
</div>
</>
)
}
export default SocialSignIn

View File

@@ -0,0 +1,70 @@
import React from 'react'
import { signIn } from 'next-auth/react'
const SocialSignUp = () => {
return (
<>
<div className='flex gap-4'>
<button
onClick={() => signIn('google')}
className='flex w-full items-center justify-center gap-2.5 rounded-lg p-3.5 border border-gray-200 text-black hover:bg-neutral-100 hover:cursor-pointer'>
Sign Up
<svg
width='23'
height='22'
viewBox='0 0 23 22'
fill='none'
xmlns='http://www.w3.org/2000/svg'>
<g clipPath='url(#clip0_709_8846)'>
<path
d='M22.5001 11.2438C22.5134 10.4876 22.4338 9.73256 22.2629 8.995H11.7246V13.0771H17.9105C17.7933 13.7929 17.5296 14.478 17.1352 15.0914C16.7409 15.7047 16.224 16.2335 15.6158 16.646L15.5942 16.7827L18.9264 19.3124L19.1571 19.335C21.2772 17.4161 22.4997 14.5926 22.4997 11.2438'
fill='#4285F4'
/>
<path
d='M11.7245 22C14.755 22 17.2992 21.0221 19.1577 19.3355L15.6156 16.6464C14.6679 17.2944 13.3958 17.7467 11.7245 17.7467C10.3051 17.7385 8.92433 17.2926 7.77814 16.472C6.63195 15.6515 5.77851 14.4981 5.33892 13.1755L5.20737 13.1865L1.74255 15.8142L1.69727 15.9376C2.63043 17.7602 4.06252 19.2925 5.83341 20.3631C7.60429 21.4337 9.64416 22.0005 11.7249 22'
fill='#34A853'
/>
<path
d='M5.33889 13.1755C5.09338 12.4753 4.96669 11.7404 4.96388 11C4.9684 10.2608 5.09041 9.52685 5.32552 8.8245L5.31927 8.67868L1.81196 6.00867L1.69724 6.06214C0.910039 7.5938 0.5 9.28491 0.5 10.9999C0.5 12.7148 0.910039 14.406 1.69724 15.9376L5.33889 13.1755Z'
fill='#FBBC05'
/>
<path
d='M11.7249 4.25337C13.3333 4.22889 14.8888 4.8159 16.065 5.89121L19.2329 2.86003C17.2011 0.992106 14.5106 -0.0328008 11.7249 3.27798e-05C9.64418 -0.000452376 7.60433 0.566279 5.83345 1.63686C4.06256 2.70743 2.63046 4.23965 1.69727 6.06218L5.32684 8.82455C5.77077 7.50213 6.62703 6.34962 7.77491 5.5295C8.9228 4.70938 10.3044 4.26302 11.7249 4.25337Z'
fill='#EB4335'
/>
</g>
<defs>
<clipPath id='clip0_709_8846'>
<rect
width='22'
height='22'
fill='white'
transform='translate(0.5)'
/>
</clipPath>
</defs>
</svg>
</button>
<button
onClick={() => signIn('github')}
className='flex w-full items-center justify-center gap-2.5 rounded-lg p-3.5 border border-gray-200 text-black hover:bg-neutral-100 hover:cursor-pointer'>
Sign Up
<svg
width='22'
height='22'
viewBox='0 0 22 22'
fill='none'
xmlns='http://www.w3.org/2000/svg'>
<path
d='M10.9997 1.83331C5.93773 1.83331 1.83301 6.04119 1.83301 11.232C1.83301 15.3847 4.45954 18.9077 8.10178 20.1505C8.55988 20.2375 8.72811 19.9466 8.72811 19.6983C8.72811 19.4743 8.71956 18.7338 8.71567 17.9485C6.16541 18.517 5.6273 16.8395 5.6273 16.8395C5.21032 15.7532 4.60951 15.4644 4.60951 15.4644C3.77785 14.8811 4.6722 14.893 4.6722 14.893C5.59272 14.9593 6.07742 15.8615 6.07742 15.8615C6.89499 17.2984 8.22184 16.883 8.74493 16.6429C8.82718 16.0353 9.06478 15.6208 9.32694 15.3861C7.2909 15.1484 5.15051 14.3425 5.15051 10.7412C5.15051 9.71509 5.5086 8.87661 6.09503 8.21844C5.99984 7.98167 5.68611 7.02577 6.18382 5.73115C6.18382 5.73115 6.95358 5.47855 8.70532 6.69458C9.43648 6.48627 10.2207 6.3819 10.9997 6.37836C11.7787 6.3819 12.5635 6.48627 13.2961 6.69458C15.0457 5.47855 15.8145 5.73115 15.8145 5.73115C16.3134 7.02577 15.9995 7.98167 15.9043 8.21844C16.4921 8.87661 16.8477 9.715 16.8477 10.7412C16.8477 14.351 14.7033 15.146 12.662 15.3786C12.9909 15.6702 13.2838 16.2423 13.2838 17.1191C13.2838 18.3766 13.2732 19.3888 13.2732 19.6983C13.2732 19.9485 13.4382 20.2415 13.9028 20.1492C17.5431 18.905 20.1663 15.3833 20.1663 11.232C20.1663 6.04119 16.0621 1.83331 10.9997 1.83331Z'
fill='currentColor'
/>
</svg>
</button>
</div>
</>
)
}
export default SocialSignUp

View File

@@ -0,0 +1,27 @@
import React, { FC } from 'react';
import Link from 'next/link';
interface BreadcrumbProps {
links: { href: string; text: string }[];
}
const Breadcrumb: FC<BreadcrumbProps> = ({ links }) => {
const lastIndex = links.length - 1;
return (
<div className="flex items-baseline flex-wrap justify-center my-[0.9375rem] mx-0">
{links.map((link, index) => (
<React.Fragment key={index}>
{index !== lastIndex ? (
<Link href={link.href} className="no-underline flex items-center text-midnight_text dark:text-white dark:text-opacity-70 font-normal md:text-21 text-18 hover:underline after:relative after:content-[''] after:ml-2.5 after:mr-[0.8125rem] after:my-0 after:inline-block after:top-[0.0625rem] after:w-2 after:h-2 after:border-r-2 after:border-solid after:border-b-2 after:border-midnight_text dark:after:border-white after:-rotate-45">
{link.text}
</Link>
) : (
<span className="dark:text-white text-midnight_text md:text-21 text-18 mx-2.5">{link.text}</span>
)}
</React.Fragment>
))}
</div>
);
};
export default Breadcrumb;

View File

@@ -0,0 +1,46 @@
import Link from "next/link";
import { BreadcrumbProps } from "../../types/breadcrumb"; // Adjust the import path based on your project structure
const Breadcrumb: React.FC<BreadcrumbProps> = ({
pageName,
pageDescription,
}) => {
return (
<div className="dark:bg-darkmode relative z-10 overflow-hidden pb-[60px] pt-[120px] md:pt-[130px] lg:pt-[160px]">
<div className="from-stroke/0 via-stroke to-stroke/0 dark:via-dark-3 absolute bottom-0 left-0 h-px w-full bg-linear-to-r"></div>
<div className="container mx-auto">
<div className="-mx-4 flex flex-wrap items-center">
<div className="w-full px-4">
<div className="text-center">
<h1 className="text-black mb-4 text-3xl font-bold sm:text-4xl md:text-[40px] md:leading-[1.2] dark:text-white">
{pageName}
</h1>
<p className="text-black dark:text-black-6 mb-5 text-base">
{pageDescription}
</p>
<ul className="flex items-center justify-center gap-[10px]">
<li>
<Link
href="/"
className="text-black flex items-center gap-[10px] text-base font-medium dark:text-white dark:text-opacity-50"
>
Home
</Link>
</li>
<li>
<p className="text-body-color flex items-center gap-[10px] text-base font-medium">
<span className="text-body-color dark:text-white dark:text-opacity-50"> / </span>
{pageName}
</p>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
);
};
export default Breadcrumb;

View File

@@ -0,0 +1,11 @@
import React from "react";
const Loader = () => {
return (
<span
className={`ml-1.5 h-4 w-4 animate-spin rounded-full border-2 border-solid border-white border-t-transparent dark:border-t-transparent`}
></span>
);
};
export default Loader;

View File

@@ -0,0 +1,11 @@
import React from "react";
const PreLoader = () => {
return (
<div className="fixed left-0 top-0 z-999999 flex h-screen w-screen items-center justify-center bg-white">
<div className="h-16 w-16 animate-spin rounded-full border-4 border-solid border-primary border-t-transparent"></div>
</div>
);
};
export default PreLoader;

View File

@@ -0,0 +1,9 @@
"use client";
import { useEffect } from "react";
export default function ScrollUp() {
useEffect(() => window.document.scrollingElement?.scrollTo(0, 0), []);
return null;
}

View File

@@ -0,0 +1,181 @@
'use client'
import React from 'react'
import { useState, useEffect } from 'react'
const ContactForm = () => {
const [formData, setFormData] = useState({
firstname: '',
lastname: '',
email: '',
phnumber: '',
Message: '',
})
const [submitted, setSubmitted] = useState(false)
const [showThanks, setShowThanks] = useState(false)
const [loader, setLoader] = useState(false)
const [isFormValid, setIsFormValid] = useState(false)
useEffect(() => {
const isValid = Object.values(formData).every(
(value) => value.trim() !== ''
)
setIsFormValid(isValid)
}, [formData])
const handleChange = (e: any) => {
const { name, value } = e.target
setFormData((prevData) => ({
...prevData,
[name]: value,
}))
}
const reset = () => {
formData.firstname = ''
formData.lastname = ''
formData.email = ''
formData.phnumber = ''
formData.Message = ''
}
const handleSubmit = async (e: any) => {
e.preventDefault()
setLoader(true)
// TODO: 替换为你自己的邮箱地址
fetch('https://formsubmit.co/ajax/your-email@example.com', {
method: 'POST',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({
Name: formData.firstname,
LastName: formData.lastname,
Email: formData.email,
PhoneNo: formData.phnumber,
Message: formData.Message,
}),
})
.then((response) => response.json())
.then((data) => {
if (data.success) {
setSubmitted(true)
setShowThanks(true)
reset()
setTimeout(() => {
setShowThanks(false)
}, 5000)
}
reset()
})
.catch((error) => {
setLoader(false)
console.log(error.message)
})
}
return (
<section id='contact'>
<div className='container'>
<div className='relative'>
<h2 className='mb-9 font-bold tracking-tight'>Get in Touch</h2>
<form
onSubmit={handleSubmit}
className='flex flex-wrap w-full m-auto justify-between'>
<div className='sm:flex gap-3 w-full'>
<div className='mx-0 my-2.5 flex-1'>
<label htmlFor='fname' className='pb-3 inline-block text-base'>
First Name
</label>
<input
id='fname'
type='text'
name='firstname'
value={formData.firstname}
onChange={handleChange}
placeholder='John'
className='w-full text-base px-4 rounded-2xl py-2.5 border-solid border transition-all duration-500 focus:border-primary focus:outline-0'
/>
</div>
<div className='mx-0 my-2.5 flex-1'>
<label htmlFor='lname' className='pb-3 inline-block text-base'>
Last Name
</label>
<input
id='lname'
type='text'
name='lastname'
value={formData.lastname}
onChange={handleChange}
placeholder='Doe'
className='w-full text-base px-4 rounded-2xl py-2.5 border-solid border transition-all duration-500 focus:border-primary focus:outline-0'
/>
</div>
</div>
<div className='sm:flex gap-3 w-full'>
<div className='mx-0 my-2.5 flex-1'>
<label htmlFor='email' className='pb-3 inline-block text-base'>
Email address
</label>
<input
id='email'
type='email'
name='email'
value={formData.email}
onChange={handleChange}
placeholder='john.doe@example.com'
className='w-full text-base px-4 rounded-2xl py-2.5 border-solid border transition-all duration-500 focus:border-primary focus:outline-0'
/>
</div>
<div className='mx-0 my-2.5 flex-1'>
<label
htmlFor='Phnumber'
className='pb-3 inline-block text-base'>
Phone Number
</label>
<input
id='Phnumber'
type='tel'
name='phnumber'
placeholder='+1234567890'
value={formData.phnumber}
onChange={handleChange}
className='w-full text-base px-4 rounded-2xl py-2.5 border-solid border transition-all duration-500 focus:border-primary focus:outline-0'
/>
</div>
</div>
<div className='w-full mx-0 my-2.5 flex-1'>
<label htmlFor='message' className='text-base inline-block'>
Message
</label>
<textarea
id='message'
name='Message'
value={formData.Message}
onChange={handleChange}
className='w-full mt-2 rounded-2xl px-5 py-3 border-solid border transition-all duration-500 focus:border-primary focus:outline-0'
placeholder='Anything else you wanna communicate'></textarea>
</div>
<div className='mx-0 my-2.5 w-full'>
<button
type='submit'
disabled={!isFormValid || loader}
className={`border leading-none px-6 text-lg font-medium py-4 rounded-full
${
!isFormValid || loader
? 'bg-gray-300 text-gray-500 cursor-not-allowed'
: 'bg-primary border-primary text-white hover:bg-transparent hover:text-primary cursor-pointer'
}`}>
Submit
</button>
</div>
</form>
{showThanks && (
<div className='text-white bg-primary rounded-full px-4 text-lg mb-4.5 mt-1 absolute flex items-center gap-2'>
Thank you for contacting us! We will get back to you soon.
<div className='w-3 h-3 rounded-full animate-spin border-2 border-solid border-white border-t-transparent'></div>
</div>
)}
</div>
</div>
</section>
)
}
export default ContactForm

View File

@@ -0,0 +1,38 @@
export const ColorConfiguration = () => {
return (
<>
<h3 className=" text-xl font-semibold mt-8 text-black">Colors</h3>
<div className="p-6 rounded-md border mt-4 border-dark_border border-opacity-60">
<p className="text-base font-medium text-muted text-opacity-60">
<span className="font-semibold text-lg text-black">
1. Override Colors
</span>{" "}
<br />
For any change in colors : tailwind.config.ts
</p>
<div className="py-4 px-5 rounded-md bg-black mt-8">
<p className="text-sm text-white/60 flex flex-col gap-2">
<span>--color-primary: #611f69;</span>
<span>--color-cream: #fcf5ef;</span>
<span>--color-success: #6b9f36;</span>
<span>--color-orange: #f9cd92;</span>
</p>
</div>
</div>
<div className="p-6 rounded-md border mt-4 border-dark_border border-opacity-60">
<p className="text-base font-medium text-muted text-opacity-60">
<span className="font-semibold text-lg text-black">
2. Override Theme Colors
</span>{" "}
<br />
For change , go to : tailwind.config.ts
</p>
<div className="py-4 px-5 rounded-md bg-black mt-8">
<p className="text-sm text-white/60 flex flex-col gap-2">
<span>--color-primary: #611f69;</span>
</p>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,16 @@
import { ColorConfiguration } from "./ColorConfiguraion"
import { LogoConfiguration } from "./LogoConfiguration"
import { TypographyConfiguration } from "./TypographyConfiguration"
export const Configuration = () => {
return (
<>
<div className="pb-10 md:scroll-m-[180px] scroll-m-28" id="configuration">
<h3 className="text-2xl font-semibold mt-4 text-black" >Project Configuration</h3>
<ColorConfiguration />
<TypographyConfiguration />
<LogoConfiguration />
</div>
</>
)
}

View File

@@ -0,0 +1,58 @@
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
export const DocNavigation = () => {
const [navItem, setNavItem] = useState("version");
function getNavItem(item: string) {
setNavItem(item);
}
useEffect(() => {
console.log(navItem);
}, [navItem]);
const DocsNav = [
{
id: 1,
navItem: "Package Versions",
hash: "version",
},
{
id: 2,
navItem: "Pacakge Structure",
hash: "structure",
},
{
id: 3,
navItem: "Quick Start",
hash: "start",
},
{
id: 4,
navItem: "Project Configuration",
hash: "configuration",
},
];
return (
<div className="flex flex-col gap-0.5 mt-4 items-start fixed pe-4">
{DocsNav.map((item) => {
return (
<Link
key={item.id}
href={`#${item.hash}`}
onClick={() => getNavItem(item.hash)}
className={`py-2.5 hover:bg-primary/20 hover:text-primary dark:hover:text-primary xl:min-w-60 lg:min-w-52 min-w-full px-4 rounded-md text-base font-medium ${item.hash === navItem
? "bg-primary text-white"
: "text-black/60"
}`}
>
{item.navItem}
</Link>
);
})}
</div>
);
};

View File

@@ -0,0 +1,25 @@
import { Configuration } from './Configuration'
import { DocNavigation } from './DocNavigation'
import { Introduction } from './Introduction'
import { PackageStructure } from './PackageStructure'
import { QuickStart } from './QuickStart'
export const Documentation = () => {
return (
<div className=''>
<div className='container mx-auto max-w-7xl p-6 lg:pt-44 pt-16'>
<div className='grid grid-cols-12 gap-6'>
<div className='lg:col-span-3 col-span-12 lg:block hidden'>
<DocNavigation />
</div>
<div className='lg:col-span-9 col-span-12'>
<Introduction />
<PackageStructure />
<QuickStart />
<Configuration />
</div>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,139 @@
'use client'
import Image from 'next/image'
// import nextImg from '/public/images/documentation/Categories=Nextjs.svg'
// import reactImg from '/public/images/documentation/Categories=React.svg'
// import tailwindImg from '/public/images/documentation/Categories=Tailwind.svg'
// import nextauthImg from '/public/images/documentation/nextauth.png'
// import typescriptImg from '/public/images/documentation/Categories=Typescript.svg'
// import axiosImg from '/public/images/documentation/axios.svg'
import { Icon } from '@iconify/react/dist/iconify.js'
import { useState } from 'react'
import { DocNavigation } from './DocNavigation'
export const Introduction = () => {
const [docNavbarOpen, setDocNavbarOpen] = useState(false)
const PackageVersions = [
{
id: '1',
packageName: 'NextJs',
img: '/images/documentation/Categories=Nextjs.svg',
version: '15.5.9',
},
{
id: '2',
packageName: 'React',
img: '/images/documentation/Categories=React.svg',
version: '19.2.3',
},
{
id: '3',
packageName: 'Tailwindcss',
img: '/images/documentation/Categories=Tailwind.svg',
version: '4',
},
{
id: '4',
packageName: 'NextAuth',
img: '/images/documentation/nextauth.png',
version: '4.24.11',
},
{
id: '5',
packageName: 'Typescript',
img: '/images/documentation/Categories=Typescript.svg',
version: '5',
},
]
return (
<>
<div id='version' className='md:scroll-m-[180px] scroll-m-28'>
{docNavbarOpen && (
<div
className='fixed top-0 left-0 w-full h-full bg-black bg-opacity-50 z-40'
onClick={() => setDocNavbarOpen(false)}
/>
)}
<div className='flex item-center justify-between'>
<h3 className=' text-2xl mt-4 font-semibold mb-6 text-black'>
Package Versions
</h3>
<button onClick={() => setDocNavbarOpen(true)} className='p-0'>
{' '}
<Icon icon='gg:menu-right' className='text-3xl lg:hidden block' />
</button>
</div>
<div className='w-full flex justify-between lg:gap-0 gap-6 lg:flex-nowrap flex-wrap p-6 rounded-md border border-dark_border border-opacity-60'>
{PackageVersions &&
PackageVersions.map((item) => {
return (
<div
key={item.id}
className='lg:w-1/5 md:w-full text-center lg:border-b-0 border-b lg:border-e lg:last:border-e-0 last:border-b-0 border-dark_border border-opacity-60'>
<Image
src={item.img}
width={64}
height={64}
alt='npm-package'
className=' mx-auto w-10 h-10 '
/>
<h5 className='text-2xl font-bold mt-3.5 text-black'>{`v${item.version}`}</h5>
<p className='text-base font-medium text-muted'>
{item.packageName}
</p>
</div>
)
})}
</div>
<div className='mt-5'>
<p className='text-base font-medium text-muted text-opacity-60'>
SiEducational Tailwind NextJs Template is built with Tailwindcss and
Nextjs.
</p>
<p className='text-base font-medium text-muted text-opacity-60'>
These theme is ready to use and you can totally customize as per
your requirement.
</p>
<p className='text-base font-medium text-muted text-opacity-60'>
For Customize, You should have knowledge of NextJs, ReactJs,
Tailwind and JSX to be able to modify these template.
</p>
</div>
</div>
<div
className={`lg:hidden block fixed top-0 right-0 h-full w-full bg-white dark:bg-dark shadow-lg transform transition-transform duration-300 max-w-xs ${
docNavbarOpen ? 'translate-x-0' : 'translate-x-full'
} z-50`}>
<div className='flex items-center justify-between p-4'>
<h2 className='text-lg font-bold text-midnight_text dark:text-black'>
Docs Menu
</h2>
<button
onClick={() => setDocNavbarOpen(false)}
aria-label='Close mobile menu'>
<svg
xmlns='http://www.w3.org/2000/svg'
width='24'
height='24'
viewBox='0 0 24 24'
className='dark:text-black'>
<path
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='2'
d='M6 18L18 6M6 6l12 12'
/>
</svg>
</button>
</div>
<nav className='px-4'>
<DocNavigation />
</nav>
</div>
</>
)
}

View File

@@ -0,0 +1,32 @@
export const LogoConfiguration = () => {
return (
<>
<h3 className=" text-xl font-semibold mt-8 text-black">Logo</h3>
<div className="p-6 rounded-md border mt-4 border-dark_border border-opacity-60">
<p className="text-base font-medium text-muted text-opacity-60 flex lg:flex-row flex-col">
1. Change Logo over here :{" "}
<span className="font-semibold text-base overflow-x-auto">
{" "}
src/components/Layout/Header/Logo/index.tsx
</span>{" "}
</p>
<div className="py-4 px-3 rounded-md bg-black mt-8">
<div className="text-sm text-white/60">
<p>&#x3C;Link href=&#x22;/&#x22;&#x3E;</p>
<p>&#x3C;Image</p>
<p>src=&#x22;/images/logo/logo.svg&#x22;</p>
<p>alt=&#x22;logo&#x22;</p>
<p>width={160}</p>
<p>height={50}</p>
<p>quality={100}</p>
<p>
style=&#x7B;width: &#x22;auto&#x22;, height:
&#x22;auto&#x22;&#x7D;
</p>
<p>/&#x3E;</p>
</div>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,469 @@
import { Icon } from "@iconify/react/dist/iconify.js";
import Image from "next/image";
import tline from "/public/images/svgs/T-Line.svg";
import t_half_line from "/public/images/svgs/T-half_line.svg";
import straight_line from "/public/images/svgs/straight_group.svg";
import small_straight_line from "/public/images/svgs/smal_straight_line.svg";
export const PackageStructure = () => {
const Counts = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
];
return (
<div id="structure" className="md:scroll-m-[130px] scroll-m-28">
<h3 className="text-2xl font-semibold mt-8 text-black">
Pacakge Structure
</h3>
<div className="rounded-md p-6 pt-3 border border-dark_border border-opacity-60 mt-6">
<div className="flex items-center gap-4">
<h5 className="text-base font-medium text-muted mt-3 mb-1">
SiEducational Tailwind NextJs Template
</h5>
</div>
<ul className="ps-0 md:ps-5 list-unstyled">
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
packages
</span>
</div>
<div className="flex">
<div className="flex flex-col justify-between gap-2 mt-2">
{Counts.slice(0, 22).map((item) => {
return <p className="text-xl text-black">|</p>;
})}
</div>
<ul className="ps-5 md:ps-5 list-unstyled">
<li className="py-0">
<ul className="ps-2 ps-md-3 list-unstyled">
<li className="py-2">
<ul className="ps-0 md:ps-5 list-unstyled">
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
markdown
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
public
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
src
</span>
</div>
<div className="flex">
<div className="flex flex-col justify-between gap-2 mt-2">
{Counts.slice(0, 22).map((item) => {
return <p className="text-xl text-black">|</p>;
})}
</div>
<ul className="ps-5 md:ps-12 list-unstyled">
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
app
</span>
</div>
<div className="flex">
<div className="flex flex-col justify-between gap-2 mt-2">
{Counts.slice(0, 16).map((item) => {
return (
<p className="text-xl text-black">|</p>
);
})}
</div>
<ul className="ps-5 md:ps-12 list-unstyled red">
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
(site)
</span>{" "}
<span className="fs-9 text-muted ms-4">
(Contains all the pages)
</span>
</div>
<div className="flex">
<div className="flex flex-col justify-between gap-2 mt-2">
{Counts.slice(0, 5).map(
(item, index) => {
return (
<p
key={index}
className="text-xl text-black"
>
|
</p>
);
}
)}
</div>
<ul className="ps-5 md:ps-12 list-unstyled">
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">
|
</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
(auth)
</span>
</div>
<div className="flex">
<div className="flex flex-col justify-between gap-1 mt-2">
{Counts.slice(0, 2).map(
(item) => {
return (
<p className="text-xl text-black">
|
</p>
);
}
)}
</div>
<ul className="ps-5 md:ps-12 list-unstyled">
<li className="py-2">
<div className="flex items-center gap-8">
<p className="text-xl text-black">
|
</p>
<div className="flex items-center gap-3">
<p className="text-xl text-black">
|
</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
signin
</span>
</div>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-8">
<p className="text-xl text-black">
|
</p>
<div className="flex items-center gap-3">
<p className="text-xl text-black">
|
</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
signup
</span>
</div>
</div>
</li>
</ul>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">
|
</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
documentation
</span>
</div>
</li>
</ul>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
api
</span>
</div>
<div className="flex">
<div className="flex flex-col justify-between gap-2 mt-2">
{Counts.slice(0, 2).map((item) => {
return (
<p className="text-xl text-black">
|
</p>
);
})}
</div>
<ul className="ps-5 md:ps-12 list-unstyled">
<li className="py-2">
<div className="flex items-center gap-8">
<p className="text-xl text-black">
|
</p>
<div className="flex items-center gap-3">
<p className="text-xl text-black">
|
</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
auth
</span>
</div>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-8">
<p className="text-xl text-black">
|
</p>
<div className="flex items-center gap-3">
<p className="text-xl text-black">
|
</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
contex
</span>
</div>
</div>
</li>
</ul>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
Context
</span>
</div>
<div className="flex">
<div className="flex flex-col justify-between gap-2 mt-2">
{Counts.slice(0, 1).map((item) => {
return (
<p className="text-xl text-black">
|
</p>
);
})}
</div>
<ul className="ps-5 md:ps-12 list-unstyled">
<li className="py-2">
<div className="flex items-center gap-8">
<p className="text-xl text-black">
|
</p>
<div className="flex items-center gap-3">
<p className="text-xl text-black">
|
</p>
<span className="font-medium text-muted flex items-center flex-wrap">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
<p className="max-w-12 lg:max-w-full truncate">
authDialogContext.tsx
</p>
</span>
</div>
</div>
</li>
</ul>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
global.css
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
layout.tsx
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
not-found.tsx
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
page.tsx
</span>
</div>
</li>
</ul>
</div>
</li>
<li className="py-2">
<div className="flex items-center flex-wrap gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
components
</span>{" "}
<span className="fs-9 text-muted ms-4">
(All the Components of this template.)
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
styles
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
types
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<Icon
icon="tabler:folder"
className="text-primary text-base inline-block me-2"
/>
utils
</span>
</div>
</li>
</ul>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<i className="ti ti-file me-2 text-primary font-bold" />
next.config.mjs
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<i className="ti ti-file me-2 text-primary font-bold" />
postcss.config.mjs
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<i className="ti ti-file me-2 text-primary font-bold" />
package.json
</span>
</div>
</li>
<li className="py-2">
<div className="flex items-center gap-3">
<p className="text-xl text-black">|</p>
<span className="font-medium text-muted">
<i className="ti ti-file me-2 text-primary font-bold" />
tsconfig.json
</span>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
);
};

View File

@@ -0,0 +1,87 @@
export const QuickStart = () => {
return (
<div className="pb-10 md:scroll-m-[180px] scroll-m-28" id="start">
<h3 className=" text-black text-2xl font-semibold mt-8">Quick Start</h3>
<div className="p-6 rounded-md border mt-6 border-dark_border border-opacity-60">
<h6 className="text-black text-lg font-medium">1. Requirements</h6>
<p className="text-base font-medium text-muted text-opacity-60">
Before proceeding, you need to have the latest stable{" "}
<a href="https://nodejs.org/" className="text-primary">
node.js
</a>{" "}
</p>
<h6 className="mt-4 mb-2 text-black font-medium text-base">
Recommended environment:
</h6>
<ul className="list-disc text-muted text-opacity-60 ps-6">
<li>node js 20+</li>
<li>npm js 10+</li>
</ul>
</div>
<div className="p-6 rounded-md border mt-6 border-dark_border border-opacity-60">
<h6 className="text-black text-lg font-medium">2. Install</h6>
<p className="text-base font-medium text-muted text-opacity-60">
Open package folder and install its dependencies. We recommanded yarn
or npm.{" "}
</p>
<h6 className="mt-4 mb-2 text-black text-dark font-medium text-base">
1) Install with npm:
</h6>
<div className="py-4 px-3 rounded-md bg-black">
<p className="text-sm text-white/60">
<span className="text-yellow-500">cd</span> project-folder
</p>
<p className="text-sm text-white/60 mt-2">npm install</p>
</div>
<h6 className="mt-4 mb-2 text-black text-dark font-medium text-base">
1) Install with yarn:
</h6>
<div className="py-4 px-3 rounded-md bg-black">
<p className="text-sm text-white/60">
<span className="text-yellow-500">cd</span> project-folder
</p>
<p className="text-sm text-white/60 mt-2">yarn install</p>
</div>
</div>
<div className="p-6 rounded-md border mt-6 border-dark_border border-opacity-60">
<h6 className="text-black text-lg font-medium">3. Start</h6>
<p className="text-base font-medium text-muted text-opacity-60 mb-4">
Once npm install is done now you an run the app.
</p>
<div className="py-4 px-3 rounded-md bg-black">
<p className="text-sm text-white/60">npm run dev or yarn run dev</p>
</div>
<p className="text-base font-medium text-muted text-opacity-60 my-4">
This command will start a local webserver{" "}
<span className="dark:text-black">http://localhost:3000:</span>
</p>
<div className="py-4 px-3 rounded-md bg-black">
<p className="text-sm text-white/60">
{"> sieducational_project@2.0.0 dev"}
</p>
<p className="text-sm text-white/60 mt-1">{"> next dev"}</p>
<p className="text-sm text-white/60 mt-6">{"-Next.js 14.2.4"}</p>
<p className="text-sm text-white/60 mt-1">
{"-Local: http://localhost:3000"}
</p>
</div>
</div>
<div className="p-6 rounded-md border mt-6 border-dark_border border-opacity-60">
<h6 className="text-black text-lg font-medium">
4. Build / Deployment
</h6>
<p className="text-base font-medium text-muted text-opacity-60 mb-4">
After adding url run below command for build a app.
</p>
<div className="py-4 px-3 rounded-md bg-black">
<p className="text-sm text-white/60">npm run build or yarn build</p>
</div>
<p className="text-base font-medium text-muted text-opacity-60 mt-6">
Finally, Your webiste is ready to be deployed.🥳
</p>
</div>
</div>
);
};

View File

@@ -0,0 +1,21 @@
export const TypographyConfiguration = () => {
return (
<>
<h3 className="text-xl font-semibold mt-8 text-black">Typography</h3>
<div className="p-6 rounded-md border mt-4 border-dark_border border-opacity-60">
<p className="text-base font-medium text-muted text-opacity-60">
1. Change Font family over here :{" "}
<span className="font-semibold text-base">src/app/layout.tsx</span>{" "}
</p>
<div className="py-4 px-3 rounded-md bg-black mt-8">
<p className="text-sm text-white/60 flex flex-col gap-2 mb-3">
{`import { Inter } from "next/font/google";`}
</p>
<p className="text-sm text-white/60 flex flex-col gap-2">
{`const font = Inter({ subsets: ["latin"] });`}
</p>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,92 @@
'use client'
import React, { useEffect, useState } from 'react'
import Slider from 'react-slick'
import 'slick-carousel/slick/slick.css'
import 'slick-carousel/slick/slick-theme.css'
import Image from 'next/image'
const Companies = () => {
const settings = {
dots: false,
infinite: true,
slidesToShow: 4,
slidesToScroll: 1,
arrows: false,
autoplay: true,
speed: 2000,
autoplaySpeed: 2000,
cssEase: 'linear',
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 4,
slidesToScroll: 1,
infinite: true,
dots: false,
},
},
{
breakpoint: 700,
settings: {
slidesToShow: 2,
slidesToScroll: 1,
infinite: true,
dots: false,
},
},
{
breakpoint: 500,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
infinite: true,
dots: false,
},
},
],
}
const [companies, setCompianes] = useState<{ imgSrc: string }[]>([])
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/data')
if (!res.ok) throw new Error('Failed to fetch')
const data = await res.json()
setCompianes(data.Companiesdata)
} catch (error) {
console.error('Error fetching services:', error)
}
}
fetchData()
}, [])
return (
<section>
<div className='container mx-auto max-w-7xl px-4'>
<h2 className='text-lg mb-10 text-black/40 text-center'>
Trusted by companies of all sizes
</h2>
<div>
<Slider {...settings}>
{companies.map((item, i) => (
<div key={i}>
<Image
src={item.imgSrc}
alt={item.imgSrc}
width={100}
height={50}
className='w-auto'
/>
</div>
))}
</Slider>
</div>
</div>
</section>
)
}
export default Companies

View File

@@ -0,0 +1,252 @@
'use client'
import { useEffect, useState } from 'react'
import { Icon } from '@iconify/react/dist/iconify.js'
import Image from 'next/image'
import { CourseDetailType } from '@/app/types/coursedetail'
import CourseDetailSkeleton from '../../Skeleton/CourseDetail'
import Link from 'next/link'
interface Name {
imageSrc: string
course: string
price: string
profession: string
category:
| 'webdevelopment'
| 'mobiledevelopment'
| 'datascience'
| 'cloudcomputing'
}
const NamesList = () => {
// -------------------------------------------------------------
const [courseDetail, setCourseDetail] = useState<CourseDetailType[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/data')
if (!res.ok) throw new Error('Failed to fetch.')
const data = await res.json()
setCourseDetail(data.CourseDetailData)
} catch (error) {
console.error('Error fetching services:', error)
} finally {
setLoading(false)
}
}
fetchData()
}, [])
// -------------------------------------------------------------
const [selectedButton, setSelectedButton] = useState<
| 'mobiledevelopment'
| 'webdevelopment'
| 'datascience'
| 'cloudcomputing'
| 'all'
| null
>('webdevelopment')
const mobileDevelopment = courseDetail.filter(
(name) => name.category === 'mobiledevelopment'
)
const webDevelopment = courseDetail.filter(
(name) => name.category === 'webdevelopment'
)
const dataScience = courseDetail.filter(
(name) => name.category === 'datascience'
)
const cloudComputing = courseDetail.filter(
(name) => name.category === 'cloudcomputing'
)
let selectedNames: Name[] = []
if (selectedButton === 'mobiledevelopment') {
selectedNames = mobileDevelopment
} else if (selectedButton === 'webdevelopment') {
selectedNames = webDevelopment
} else if (selectedButton === 'datascience') {
selectedNames = dataScience
} else if (selectedButton === 'cloudcomputing') {
selectedNames = cloudComputing
}
const nameElements = selectedNames.map((name, index) => (
<div id='Courses' key={index} className='shadow-lg rounded-xl group flex'>
<div className='py-5 lg:py-0 flex flex-col'>
<div className='overflow-hidden rounded-lg bg-gray-100'>
<Image
src={name.imageSrc}
alt={name.course}
width={700}
height={700}
className='h-full w-full object-cover object-center group-hover:scale-125 transition duration-300 ease-in-out'
/>
</div>
<div className='p-4 flex flex-col justify-between gap-5 flex-1'>
<div className="flex flex-col gap-5">
<div className='flex items-center justify-between'>
<p className='block font-normal text-gray-900'>{name.course}</p>
<div className='block text-lg font-semibold text-success border-solid border-2 border-success rounded-md px-1'>
<p>${name.price}</p>
</div>
</div>
<Link href={'/'}>
<p
aria-hidden='true'
className='text-xl font-semibold group-hover:text-primary group-hover:cursor-pointer'>
{name.profession}
</p>
</Link>
</div>
<div className='flex justify-between border-solid border-2 rounded-md p-2'>
<p>12 Classes</p>
<div className='flex flex-row space-x-4'>
<div className='flex'>
<Image
src={'/images/courses/account.svg'}
width={18}
height={20}
alt='circle'
/>
<p className='text-lightgrey ml-1'>120</p>
</div>
<div className='flex'>
<Image
src={'/images/courses/Star.svg'}
width={18}
height={20}
alt='star'
/>
<p className='ml-1'>4.5</p>
</div>
</div>
</div>
</div>
</div>
</div>
))
return (
<section id='courses-section'>
<div className='container mx-auto max-w-7xl px-4'>
<div className='flex flex-col sm:flex-row justify-between sm:items-center gap-5 mb-4'>
<h2 className='font-bold tracking-tight'>Popular Courses</h2>
<div>
<button className='bg-transparent cursor-pointer hover:bg-primary text-primary font-medium hover:text-white py-3 px-4 border border-primary hover:border-transparent rounded-sm duration-300'>
Explore Classes
</button>
</div>
</div>
<div className='flex nowhitespace space-x-5 rounded-xl bg-white p-1 overflow-x-auto mb-4'>
{/* FOR DESKTOP VIEW */}
<button
onClick={() => setSelectedButton('webdevelopment')}
className={
'bg-white' +
(selectedButton === 'webdevelopment'
? 'text-black border-b-2 border-yellow-200'
: 'text-black/40') +
' pb-2 text-lg hidden sm:block hover:cursor-pointer'
}>
Web Development
</button>
<button
onClick={() => setSelectedButton('mobiledevelopment')}
className={
'bg-white ' +
(selectedButton === 'mobiledevelopment'
? 'text-black border-b-2 border-yellow-200'
: 'text-black/40') +
' pb-2 text-lg hidden sm:block hover:cursor-pointer'
}>
Mobile Development
</button>
<button
onClick={() => setSelectedButton('datascience')}
className={
'bg-white ' +
(selectedButton === 'datascience'
? 'text-black border-b-2 border-yellow-200'
: 'text-black/40') +
' pb-2 text-lg hidden sm:block hover:cursor-pointer'
}>
Data Science
</button>
<button
onClick={() => setSelectedButton('cloudcomputing')}
className={
'bg-white ' +
(selectedButton === 'cloudcomputing'
? 'text-black border-b-2 border-yellow-200'
: 'text-black/40') +
' pb-2 text-lg hidden sm:block hover:cursor-pointer'
}>
Cloud Computing
</button>
{/* FOR MOBILE VIEW */}
<Icon
icon='solar:global-line-duotone'
onClick={() => setSelectedButton('webdevelopment')}
className={
'text-5xl sm:hidden block ' +
(selectedButton === 'webdevelopment'
? 'border-b-2 border-yellow-200'
: 'text-gray-400')
}
/>
<Icon
icon='solar:smartphone-line-duotone'
onClick={() => setSelectedButton('mobiledevelopment')}
className={
'text-5xl sm:hidden block ' +
(selectedButton === 'mobiledevelopment'
? 'border-b-2 border-yellow-200'
: 'text-gray-400')
}
/>
<Icon
icon='solar:database-line-duotone'
onClick={() => setSelectedButton('datascience')}
className={
'text-5xl sm:hidden block ' +
(selectedButton === 'datascience'
? 'border-b-2 border-yellow-200'
: 'text-gray-400')
}
/>
<Icon
icon='solar:cloud-line-duotone'
onClick={() => setSelectedButton('cloudcomputing')}
className={
'text-5xl sm:hidden block ' +
(selectedButton === 'cloudcomputing'
? 'border-b-2 border-yellow-200'
: 'text-gray-400')
}
/>
</div>
<div>
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8'>
{loading ? (
Array.from({ length: 4 }).map((_, i) => (
<CourseDetailSkeleton key={i} />
))
) : nameElements.length > 0 ? (
nameElements
) : (
<p>No data to show</p>
)}
</div>
</div>
</div>
</section>
)
}
export default NamesList

View File

@@ -0,0 +1,91 @@
'use client'
import { Fragment, useEffect, useState } from 'react'
import {
Listbox,
ListboxButton,
ListboxOptions,
ListboxOption,
Transition,
} from '@headlessui/react'
import { Icon } from '@iconify/react/dist/iconify.js'
import { CourseType } from '@/app/types/course'
const Dropdown = () => {
const [course, setCourse] = useState<CourseType[]>([])
const [selected, setSelected] = useState<CourseType | null>(null)
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/data')
if (!res.ok) throw new Error('Failed to fetch')
const data = await res.json()
setCourse(data.CourseData)
setSelected(data.CourseData[0])
} catch (error) {
console.error('Error fetching services:', error)
}
}
fetchData()
}, [])
return (
<div className='w-full'>
<p className='text-lg text-gray-500'>What do you want to learn?</p>
<Listbox value={selected} onChange={setSelected}>
<div className='relative mt-1'>
<ListboxButton className='relative w-full cursor-default rounded-lg bg-white text-xl py-2 pr-10 text-left focus:outline-hidden focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm hover:cursor-pointer'>
<span className='block truncate text-xl font-semibold '>
{selected?.name}
</span>
<span className='pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2'>
<Icon
icon='tabler:chevron-down'
className='text-gray-400 text-xl inline-block me-2'
/>
</span>
</ListboxButton>
<Transition
as={Fragment}
leave='transition ease-in duration-100'
leaveFrom='opacity-100'
leaveTo='opacity-0'>
<ListboxOptions className='absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-hidden sm:text-sm'>
{course.map((person, personIdx) => (
<ListboxOption
key={personIdx}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-10 pr-4 ${
active ? 'bg-amber-100 text-amber-900' : 'text-gray-900'
}`
}
value={person}>
{({ selected }) => (
<>
<span
className={`block truncate ${
selected ? 'font-medium' : 'font-normal'
}`}>
{person.name}
</span>
{selected ? (
<span className='absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600'>
<Icon
icon='tabler:check'
className='text-xl inline-block me-2'
/>
</span>
) : null}
</>
)}
</ListboxOption>
))}
</ListboxOptions>
</Transition>
</div>
</Listbox>
</div>
)
}
export default Dropdown

View File

@@ -0,0 +1,91 @@
'use client'
import { Fragment, useEffect, useState } from 'react'
import {
Listbox,
ListboxButton,
ListboxOptions,
ListboxOption,
Transition,
} from '@headlessui/react'
import { Icon } from '@iconify/react/dist/iconify.js'
import { Hourtype } from '@/app/types/hour'
const Dropdown = () => {
const [hour, setHour] = useState<Hourtype[]>([])
const [selected, setSelected] = useState<Hourtype | null>(null)
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/data')
if (!res.ok) throw new Error('Failed to fetch')
const data = await res.json()
setHour(data.HourData)
setSelected(data.HourData[0])
} catch (error) {
console.error('Error fetching services:', error)
}
}
fetchData()
}, [])
return (
<div className='w-full'>
<p className='text-lg text-gray-500'>Hours you going to invest?</p>
<Listbox value={selected} onChange={setSelected}>
<div className='relative mt-1'>
<ListboxButton className='relative w-full cursor-default rounded-lg bg-white text-xl py-2 pr-10 text-left focus:outline-hidden focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm hover:cursor-pointer'>
<span className='block truncate text-xl font-semibold '>
{selected?.name}
</span>
<span className='pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2'>
<Icon
icon='tabler:chevron-down'
className='text-gray-400 text-xl inline-block me-2'
/>
</span>
</ListboxButton>
<Transition
as={Fragment}
leave='transition ease-in duration-100'
leaveFrom='opacity-100'
leaveTo='opacity-0'>
<ListboxOptions className='absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-hidden sm:text-sm'>
{hour.map((person, personIdx) => (
<ListboxOption
key={personIdx}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-10 pr-4 ${
active ? 'bg-amber-100 text-amber-900' : 'text-gray-900'
}`
}
value={person}>
{({ selected }) => (
<>
<span
className={`block truncate ${
selected ? 'font-medium' : 'font-normal'
}`}>
{person.name}
</span>
{selected ? (
<span className='absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600'>
<Icon
icon='tabler:check'
className='text-xl inline-block me-2'
/>
</span>
) : null}
</>
)}
</ListboxOption>
))}
</ListboxOptions>
</Transition>
</div>
</Listbox>
</div>
)
}
export default Dropdown

View File

@@ -0,0 +1,103 @@
import Link from 'next/link'
import Dropdownone from './Dropdownone'
import Dropdowntwo from './Dropdowntwo'
import Image from 'next/image'
const Banner = () => {
return (
<section id='Home' className='bg-banner-image pt-28 pb-20'>
<div className='relative px-6 lg:px-8'>
<div className='container'>
<div className='flex flex-col gap-4 text-center'>
<h1 className='leading-tight font-bold tracking-tight max-w-4xl mx-auto'>
Advance your engineering skills with our courses
</h1>
<p className='text-lg leading-8 text-black'>
Build skills with our courses and mentor from world-class
companies.
</p>
<div className='backdrop-blur-md bg-white/30 border border-white/30 rounded-lg shadow-lg p-6 w-fit mx-auto'>
<div className='flex items-center justify-center gap-8'>
<div className='hidden sm:block -space-x-2 overflow-hidden'>
<Image
className='inline-block h-12 w-12 rounded-full ring-2 ring-white'
src='https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'
alt='img1'
width={12}
height={12}
/>
<Image
className='inline-block h-12 w-12 rounded-full ring-2 ring-white'
src='https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'
alt='img2'
width={12}
height={12}
/>
<Image
className='inline-block h-12 w-12 rounded-full ring-2 ring-white'
src='https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80'
alt='img3'
width={12}
height={12}
/>
<Image
className='inline-block h-12 w-12 rounded-full ring-2 ring-white'
src='https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'
alt='img4'
width={12}
height={12}
/>
<Image
className='inline-block h-12 w-12 rounded-full ring-2 ring-white'
src='https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'
alt='img5'
width={12}
height={12}
/>
</div>
<div>
<div className='flex justify-center sm:justify-start'>
<h3 className='text-2xl font-semibold mr-2'>4.6</h3>
<Image
src={'/images/banner/Stars.svg'}
alt='stars-icon'
width={32}
height={32}
className='w-[60%]'
/>
</div>
<div>
<h3 className='text-sm'>Rated by 25k on google.</h3>
</div>
</div>
</div>
</div>
</div>
{/* DROPDOWN BUTTONS */}
<div className='mx-auto max-w-4xl mt-12 p-6 lg:max-w-4xl lg:px-8 bg-white rounded-lg boxshadow'>
<div className='grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 lg:grid-cols-8 xl:gap-x-8'>
<div className='col-span-3'>
<Dropdownone />
</div>
<div className='col-span-3'>
<Dropdowntwo />
</div>
<div className='col-span-3 sm:col-span-2 mt-2'>
<Link href={'/#courses-section'}>
<button className='bg-primary w-full hover:bg-transparent hover:text-primary duration-300 border border-primary text-white font-bold py-4 px-3 rounded-sm hover:cursor-pointer'>
Start
</button>
</Link>
</div>
</div>
</div>
</div>
</div>
</section>
)
}
export default Banner

View File

@@ -0,0 +1,79 @@
'use client'
import Image from 'next/image'
import Link from 'next/link'
import { useEffect, useState } from 'react'
import { MentorType } from '@/app/types/mentor'
import MentorSkeleton from '../../Skeleton/Mentor'
const Mentor = () => {
const [mentor, setMentor] = useState<MentorType[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/data')
if (!res.ok) throw new Error('Failed to fetch')
const data = await res.json()
setMentor(data.MentorData)
} catch (error) {
console.error('Error fetching services:', error)
} finally {
setLoading(false)
}
}
fetchData()
}, [])
return (
<section id='mentors-section'>
<div className='container'>
<div className='flex flex-col sm:flex-row gap-5 justify-between sm:items-center mb-12'>
<h2 className='font-bold tracking-tight'>Meet with our Mentors</h2>
<div>
<button className='bg-transparent cursor-pointer hover:bg-primary text-primary font-medium hover:text-white py-3 px-4 border border-primary hover:border-transparent rounded-sm duration-300'>
Explore 10+ our Mentor
</button>
</div>
</div>
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 xl:gap-8'>
{loading
? Array.from({ length: 6 }).map((_, i) => (
<MentorSkeleton key={i} />
))
: mentor.map((item, index) => (
<div key={index} className='group relative shadow-lg'>
<div className='min-h-80 w-full overflow-hidden rounded-lg bg-gray-200 lg:h-80'>
<Image
src={item.imageSrc}
alt={item.imageAlt}
width={700}
height={700}
className='h-full w-full object-cover object-center lg:h-full lg:w-full '
/>
</div>
<div className='my-4 flex justify-center '>
<div>
<div className='border border-white rounded-lg -mt-8 bg-white p-2 shadow-mentorShadow flex items-center justify-center'>
<Link
href='/'
className='text-sm text-gray-700 text-center'>
{item.name}
</Link>
</div>
<p className='mt-3 text-2xl font-semibold text-black/80 text-center'>
{item.color}
</p>
</div>
</div>
</div>
))}
</div>
</div>
</section>
)
}
export default Mentor

View File

@@ -0,0 +1,45 @@
import Image from 'next/image'
const Newsletter = () => {
return (
<section id='join-section' className='-mb-64'>
<div className='relative z-10'>
<div className='mx-auto max-w-2xl py-16 md:py-24 px-4 sm:px-6 md:max-w-7xl lg:px-24 bg-orange rounded-lg bg-newsletter bg-contain bg-no-repeat bg-right-bottom'>
<div className='grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 xl:gap-x-8'>
<div>
<h3 className='text-5xl font-bold mb-3'> Join Our Newsletter </h3>
<h4 className='text-lg font-medium mb-7'>
Subscribe our newsletter for discounts, promo and many more.
</h4>
<div className='flex gap-2'>
<input
type='Email address'
name='q'
className='py-4 w-full text-base px-4 bg-white transition-all duration-500 focus:border-primary focus:outline-1 rounded-lg pl-4'
placeholder='Enter your email'
autoComplete='off'
/>
<button className='bg-primary cursor-pointer hover:bg-transparent border border-primary hover:text-primary text-white font-medium py-2 px-4 rounded-sm'>
Subscribe
</button>
</div>
</div>
<div className='hidden sm:block'>
<div className='float-right -mt-32'>
<Image
src={'/images/newsletter/Free.svg'}
alt='bgimg'
width={64}
height={64}
className='w-auto'
/>
</div>
</div>
</div>
</div>
</div>
</section>
)
}
export default Newsletter

View File

@@ -0,0 +1,110 @@
'use client'
import { useEffect, useState } from 'react'
import Image from 'next/image'
import Slider from 'react-slick'
import 'slick-carousel/slick/slick.css'
import 'slick-carousel/slick/slick-theme.css'
import { TestimonialType } from '@/app/types/testimonial'
import TestimonialSkeleton from '../../Skeleton/Testimonial'
// CAROUSEL SETTINGS
const Testimonial = () => {
const [testimonial, setTestimonial] = useState<TestimonialType[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/data')
if (!res.ok) throw new Error('Failed to fetch')
const data = await res.json()
setTestimonial(data.TestimonialData)
} catch (error) {
console.error('Error fetching services:', error)
} finally {
setLoading(false)
}
}
fetchData()
}, [])
const settings = {
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
arrows: false,
autoplay: false,
cssEase: 'linear',
responsive: [
{
breakpoint: 1200,
settings: {
slidesToShow: 2,
},
},
{
breakpoint: 800,
settings: {
slidesToShow: 1,
},
},
],
}
return (
<section id='testimonial-section' className='bg-cream'>
<div className='container'>
<div className='flex flex-col sm:flex-row gap-5 justify-between sm:items-center mb-6'>
<h2 className='font-bold tracking-tight'>
What Our Happy <br /> Students Says
</h2>
<div>
<button className='bg-transparent cursor-pointer hover:bg-primary text-primary font-semibold hover:text-white py-3 px-4 border border-primary hover:border-transparent rounded-sm duration-300'>
Give Your Review
</button>
</div>
</div>
<p className='text-lg font-medium mb-6'>
Build skills with our courses and mentor <br /> from world-class
companies.
</p>
<Slider {...settings}>
{loading
? Array.from({ length: 3 }).map((_, i) => (
<TestimonialSkeleton key={i} />
))
: testimonial.map((items, i) => (
<div key={i}>
<div className='bg-white m-4 pt-8 px-12 pb-10 text-center rounded-lg'>
<div className="relative z-0 flex justify-center items-center before:absolute before:bg-[url('/images/testimonial/greenpic.svg')] before:h-6 before:w-6 before:bottom-0 before:z-10 before:left-54%">
<Image
src={items.imgSrc}
alt='gaby'
width={64}
height={64}
className='inline-block rounded-full ring-2 ring-white relative'
/>
</div>
<p className='text-sm pt-4 pb-2'>{items.profession}</p>
<p className='text-2xl font-semibold pb-3'>{items.name}</p>
<Image
src={items.starimg}
alt='stars-img'
className='m-auto pb-6 w-[30%]'
width={32}
height={32}
/>
<p className='text-lg font-medium leading-7'>
{items.detail}
</p>
</div>
</div>
))}
</Slider>
</div>
</section>
)
}
export default Testimonial

View File

@@ -0,0 +1,139 @@
'use client'
import Link from 'next/link'
import Image from 'next/image'
import { Icon } from '@iconify/react/dist/iconify.js'
import { useEffect, useState } from 'react'
import { FooterLinkType } from '@/app/types/footerlinks'
const Footer = () => {
const [footerlink, SetFooterlink] = useState<FooterLinkType[]>([])
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/data')
if (!res.ok) throw new Error('Failed to fetch')
const data = await res.json()
SetFooterlink(data.FooterLinkData)
} catch (error) {
console.error('Error fetching services:', error)
}
}
fetchData()
}, [])
return (
<div className='bg-primary' id='first-section'>
<div className='container pt-60 pb-10'>
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-12 gap-16 xl:gap-8'>
<div className='col-span-4 flex flex-col gap-5'>
<div>
<Image
src='/images/logo/logo2.svg'
alt='Logo'
width={48}
height={64}
/>
</div>
<p className='text-white text-lg font-medium leading-7'>
{' '}
Level up your skills, and get dream <br /> job with passion.{' '}
</p>
<div className='flex gap-4'>
<Link
href='/'
className='bg-white/20 rounded-full p-2 text-white hover:bg-cream hover:text-primary duration-300'>
<Icon
icon='tabler:brand-instagram'
className='text-2xl inline-block'
/>
</Link>
<Link
href='/'
className='bg-white/20 rounded-full p-2 text-white hover:bg-cream hover:text-primary duration-300'>
<Icon
icon='tabler:brand-dribbble'
className='text-2xl inline-block'
/>
</Link>
<Link
href='/'
className='bg-white/20 rounded-full p-2 text-white hover:bg-cream hover:text-primary duration-300'>
<Icon
icon='tabler:brand-twitter-filled'
className='text-2xl inline-block'
/>
</Link>
<Link
href='/'
className='bg-white/20 rounded-full p-2 text-white hover:bg-cream hover:text-primary duration-300'>
<Icon
icon='tabler:brand-youtube-filled'
className='text-2xl inline-block'
/>
</Link>
</div>
</div>
{/* CLOUMN-2/3 */}
<div className='col-span-4'>
<div className='flex gap-20'>
{footerlink.map((product, i) => (
<div key={i} className='group relative col-span-2'>
<p className='text-white text-xl font-semibold mb-9'>
{product.section}
</p>
<ul>
{product.links.map((item, i) => (
<li key={i} className='mb-3'>
<Link
href={item.href}
className='text-white/60 hover:text-white text-sm font-normal mb-6'>
{item.label}
</Link>
</li>
))}
</ul>
</div>
))}
</div>
</div>
{/* CLOUMN-4 */}
<div className='col-span-4'>
<h3 className='text-white text-xl font-semibold mb-6'>
Stay up to date
</h3>
<div className='relative text-white focus-within:text-white flex flex-row-reverse w-[50%] lg:w-full'>
<input
type='Email address'
name='q'
className='py-4 text-sm w-full text-white bg-white/15 rounded-md pl-4 focus:outline-hidden bg-emailbg focus:text-white'
placeholder='Your email address'
autoComplete='off'
/>
<div className='absolute inset-y-0 right-0 flex items-center pr-2'>
<button
type='submit'
className='p-1 focus:outline-hidden focus:shadow-outline'>
<Icon
icon='tabler:send'
className='text-white text-2xl inline-block me-2'
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div className='py-3'>
<h3 className='text-center text-white/60'>
@2025 - All Rights Reserved
</h3>
</div>
</div>
)
}
export default Footer

View File

@@ -0,0 +1,19 @@
import Image from "next/image";
import Link from "next/link";
const Logo: React.FC = () => {
return (
<Link href="/">
<Image
src="/images/logo/logo.svg"
alt="logo"
width={160}
height={50}
style={{ width: "auto", height: "auto" }}
quality={100}
/>
</Link>
);
};
export default Logo;

View File

@@ -0,0 +1,70 @@
'use client'
import { useState } from 'react'
import Link from 'next/link'
import { HeaderItem } from '../../../../types/menu'
import { usePathname } from 'next/navigation'
const HeaderLink: React.FC<{ item: HeaderItem }> = ({ item }) => {
const [submenuOpen, setSubmenuOpen] = useState(false)
const path = usePathname()
const handleMouseEnter = () => {
if (item.submenu) {
setSubmenuOpen(true)
}
}
const handleMouseLeave = () => {
setSubmenuOpen(false)
}
return (
<div
className='relative'
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}>
<Link
href={item.href}
className={`text-base flex font-medium hover:text-primary capitalized ${
path === item.href ? 'text-primary ' : 'text-black'
}`}>
{item.label}
{item.submenu && (
<svg
xmlns='http://www.w3.org/2000/svg'
width='1.5em'
height='1.5em'
viewBox='0 0 24 24'>
<path
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='1.5'
d='m7 10l5 5l5-5'
/>
</svg>
)}
</Link>
{submenuOpen && (
<div
className={`absolute py-2 left-0 mt-0.5 w-60 bg-white dark:bg-darklight dark:text-white shadow-lg rounded-lg `}
data-aos='fade-up'
data-aos-duration='500'>
{item.submenu?.map((subItem, index) => (
<Link
key={index}
href={subItem.href}
className={`block px-4 py-2 ${
path === subItem.href
? 'bg-primary text-white'
: 'text-black dark:text-white hover:bg-primary'
}`}>
{subItem.label}
</Link>
))}
</div>
)}
</div>
)
}
export default HeaderLink

View File

@@ -0,0 +1,52 @@
import { useState } from 'react'
import Link from 'next/link'
import { HeaderItem } from '../../../../types/menu'
const MobileHeaderLink: React.FC<{ item: HeaderItem }> = ({ item }) => {
const [submenuOpen, setSubmenuOpen] = useState(false)
const handleToggle = () => {
setSubmenuOpen(!submenuOpen)
}
return (
<div className='relative w-full'>
<Link
href={item.href}
onClick={item.submenu ? handleToggle : undefined}
className='flex items-center justify-between w-full py-2 text-black focus:outline-hidden'>
{item.label}
{item.submenu && (
<svg
xmlns='http://www.w3.org/2000/svg'
width='1.5em'
height='1.5em'
viewBox='0 0 24 24'>
<path
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='1.5'
d='m7 10l5 5l5-5'
/>
</svg>
)}
</Link>
{submenuOpen && item.submenu && (
<div className='bg-white p-2 w-full'>
{item.submenu.map((subItem, index) => (
<Link
key={index}
href={subItem.href}
className='block py-2 text-gray-500 hover:bg-gray-200'>
{subItem.label}
</Link>
))}
</div>
)}
</div>
)
}
export default MobileHeaderLink

View File

@@ -0,0 +1,33 @@
'use client'
import { useTheme } from "next-themes";
const ThemeToggler = () => {
const { theme, setTheme } = useTheme();
return (
<button
aria-label="theme toggler"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
className="text-body-color flex h-8 w-8 items-center justify-center duration-300 dark:text-white"
>
<span>
<svg
viewBox="0 0 16 16"
className="hidden h-[22px] w-[22px] fill-current dark:block"
>
<path d="M4.50663 3.2267L3.30663 2.03337L2.36663 2.97337L3.55996 4.1667L4.50663 3.2267ZM2.66663 7.00003H0.666626V8.33337H2.66663V7.00003ZM8.66663 0.366699H7.33329V2.33337H8.66663V0.366699V0.366699ZM13.6333 2.97337L12.6933 2.03337L11.5 3.2267L12.44 4.1667L13.6333 2.97337ZM11.4933 12.1067L12.6866 13.3067L13.6266 12.3667L12.4266 11.1734L11.4933 12.1067ZM13.3333 7.00003V8.33337H15.3333V7.00003H13.3333ZM7.99996 3.6667C5.79329 3.6667 3.99996 5.46003 3.99996 7.6667C3.99996 9.87337 5.79329 11.6667 7.99996 11.6667C10.2066 11.6667 12 9.87337 12 7.6667C12 5.46003 10.2066 3.6667 7.99996 3.6667ZM7.33329 14.9667H8.66663V13H7.33329V14.9667ZM2.36663 12.36L3.30663 13.3L4.49996 12.1L3.55996 11.16L2.36663 12.36Z" />
</svg>
<svg
viewBox="0 0 23 23"
className="h-[30px] w-[30px] fill-current dark:hidden"
>
<g clipPath="url(#clip0_40_125)">
<path d="M16.6111 15.855C17.591 15.1394 18.3151 14.1979 18.7723 13.1623C16.4824 13.4065 14.1342 12.4631 12.6795 10.4711C11.2248 8.47905 11.0409 5.95516 11.9705 3.84818C10.8449 3.9685 9.72768 4.37162 8.74781 5.08719C5.7759 7.25747 5.12529 11.4308 7.29558 14.4028C9.46586 17.3747 13.6392 18.0253 16.6111 15.855Z" />
</g>
</svg>
</span>
</button>
);
};
export default ThemeToggler;

View File

@@ -0,0 +1,213 @@
'use client'
import { useEffect, useRef, useState } from 'react'
import Logo from './Logo'
import HeaderLink from '../Header/Navigation/HeaderLink'
import MobileHeaderLink from '../Header/Navigation/MobileHeaderLink'
import Signin from '@/app/components/Auth/SignIn'
import SignUp from '@/app/components/Auth/SignUp'
import { Icon } from '@iconify/react/dist/iconify.js'
import { HeaderItem } from '@/app/types/menu'
const Header: React.FC = () => {
const [headerData, setHeaderData] = useState<HeaderItem[]>([])
const [navbarOpen, setNavbarOpen] = useState(false)
const [sticky, setSticky] = useState(false)
const [isSignInOpen, setIsSignInOpen] = useState(false)
const [isSignUpOpen, setIsSignUpOpen] = useState(false)
const navbarRef = useRef<HTMLDivElement>(null)
const signInRef = useRef<HTMLDivElement>(null)
const signUpRef = useRef<HTMLDivElement>(null)
const mobileMenuRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/data')
if (!res.ok) throw new Error('Failed to fetch')
const data = await res.json()
setHeaderData(data.HeaderData)
} catch (error) {
console.error('Error fetching services:', error)
}
}
fetchData()
}, [])
const handleScroll = () => {
setSticky(window.scrollY >= 10)
}
const handleClickOutside = (event: MouseEvent) => {
if (
signInRef.current &&
!signInRef.current.contains(event.target as Node)
) {
setIsSignInOpen(false)
}
if (
signUpRef.current &&
!signUpRef.current.contains(event.target as Node)
) {
setIsSignUpOpen(false)
}
if (
mobileMenuRef.current &&
!mobileMenuRef.current.contains(event.target as Node) &&
navbarOpen
) {
setNavbarOpen(false)
}
}
useEffect(() => {
window.addEventListener('scroll', handleScroll)
document.addEventListener('mousedown', handleClickOutside)
return () => {
window.removeEventListener('scroll', handleScroll)
document.removeEventListener('mousedown', handleClickOutside)
}
}, [navbarOpen, isSignInOpen, isSignUpOpen])
useEffect(() => {
if (isSignInOpen || isSignUpOpen || navbarOpen) {
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = ''
}
}, [isSignInOpen, isSignUpOpen, navbarOpen])
return (
<header
className={`fixed top-0 z-40 w-full transition-all duration-300 ${
sticky ? ' shadow-lg bg-white py-4' : 'shadow-none py-4'
}`}>
<div>
<div className='container mx-auto max-w-7xl px-4 flex items-center justify-between'>
<Logo />
<nav className='hidden lg:flex grow items-center gap-8 justify-start ml-14'>
{headerData.map((item, index) => (
<HeaderLink key={index} item={item} />
))}
</nav>
<div className='flex items-center gap-4'>
<button
className='hidden lg:block bg-transparent text-primary border hover:bg-primary border-primary hover:text-white duration-300 px-6 py-2 rounded-lg hover:cursor-pointer'
onClick={() => {
setIsSignInOpen(true)
}}>
Sign In
</button>
{isSignInOpen && (
<div className='fixed top-0 left-0 w-full h-full bg-black/50 flex items-center justify-center z-50'>
<div
ref={signInRef}
className='relative mx-auto w-full max-w-md overflow-hidden rounded-lg px-8 pt-14 pb-8 text-center bg-dark_grey/90 backdrop-blur-md bg-white'>
<button
onClick={() => setIsSignInOpen(false)}
className='absolute top-0 right-0 mr-8 mt-8 dark:invert'
aria-label='Close Sign In Modal'>
<Icon
icon='material-symbols:close-rounded'
width={24}
height={24}
className='text-black hover:text-primary inline-block hover:cursor-pointer'
/>
</button>
<Signin />
</div>
</div>
)}
<button
className='hidden lg:block bg-primary text-white text-base font-medium hover:bg-transparent duration-300 hover:text-primary border border-primary px-6 py-2 rounded-lg hover:cursor-pointer'
onClick={() => {
setIsSignUpOpen(true)
}}>
Sign Up
</button>
{isSignUpOpen && (
<div className='fixed top-0 left-0 w-full h-full bg-black/50 flex items-center justify-center z-50'>
<div
ref={signUpRef}
className='relative mx-auto bg-white w-full max-w-md overflow-hidden rounded-lg bg-dark_grey/90 backdrop-blur-md px-8 pt-14 pb-8 text-center'>
<button
onClick={() => setIsSignUpOpen(false)}
className='absolute top-0 right-0 mr-8 mt-8 dark:invert'
aria-label='Close Sign Up Modal'>
<Icon
icon='material-symbols:close-rounded'
width={24}
height={24}
className='text-black hover:text-primary inline-block hover:cursor-pointer'
/>
</button>
<SignUp />
</div>
</div>
)}
<button
onClick={() => setNavbarOpen(!navbarOpen)}
className='block lg:hidden p-2 rounded-lg'
aria-label='Toggle mobile menu'>
<span className='block w-6 h-0.5 bg-black'></span>
<span className='block w-6 h-0.5 bg-black mt-1.5'></span>
<span className='block w-6 h-0.5 bg-black mt-1.5'></span>
</button>
</div>
</div>
{navbarOpen && (
<div className='fixed top-0 left-0 w-full h-full bg-black/50 z-40' />
)}
<div
ref={mobileMenuRef}
className={`lg:hidden fixed top-0 right-0 h-full w-full bg-white shadow-lg transform transition-transform duration-300 max-w-xs ${
navbarOpen ? 'translate-x-0' : 'translate-x-full'
} z-50`}>
<div className='flex items-center justify-between p-4'>
<h2 className='text-lg font-bold text-midnight_text'>
<Logo />
</h2>
{/* */}
<button
onClick={() => setNavbarOpen(false)}
className='bg-black/30 rounded-full p-1 text-white'
aria-label='Close menu Modal'>
<Icon
icon={'material-symbols:close-rounded'}
width={24}
height={24}
/>
</button>
</div>
<nav className='flex flex-col items-start p-4'>
{headerData.map((item, index) => (
<MobileHeaderLink key={index} item={item} />
))}
<div className='mt-4 flex flex-col gap-4 w-full'>
<button
className='bg-primary text-white px-4 py-2 rounded-lg border border-primary hover:text-primary hover:bg-transparent hover:cursor-pointer transition duration-300 ease-in-out'
onClick={() => {
setIsSignInOpen(true)
setNavbarOpen(false)
}}>
Sign In
</button>
<button
className='bg-primary text-white px-4 py-2 rounded-lg border border-primary hover:text-primary hover:bg-transparent hover:cursor-pointer transition duration-300 ease-in-out'
onClick={() => {
setIsSignUpOpen(true)
setNavbarOpen(false)
}}>
Sign Up
</button>
</div>
</nav>
</div>
</div>
</header>
)
}
export default Header

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,40 @@
'use client'
import { useEffect, useState } from 'react'
export default function ScrollToTop() {
const [isVisible, setIsVisible] = useState(false)
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth',
})
}
useEffect(() => {
const toggleVisibility = () => {
if (window.pageYOffset > 300) {
setIsVisible(true)
} else {
setIsVisible(false)
}
}
window.addEventListener('scroll', toggleVisibility)
return () => window.removeEventListener('scroll', toggleVisibility)
}, [])
return (
<>
{isVisible && (
<div
onClick={scrollToTop}
aria-label='scroll to top'
className='fixed bottom-8 right-8 z-999 back-to-top flex h-10 w-10 cursor-pointer items-center justify-center rounded-md bg-[#102C46] text-white shadow-md transition duration-300 ease-in-out hover:bg-dark'>
<span className='mt-[6px] h-3 w-3 rotate-45 border-l border-t border-white'></span>
</div>
)}
</>
)
}

View File

@@ -0,0 +1,20 @@
import React, { FC } from "react";
interface HeroSubProps {
title: string;
}
const HeroSub: FC<HeroSubProps> = ({ title }) => {
return (
<>
<section className="py-40 bg-herosub-bg bg-no-repeat bg-cover lg:mt-40 sm:mt-44 mt-20">
<div className="container mx-auto lg:max-w-(--breakpoint-xl) px-4">
<h2 className="text-white md:text-56 text-36 font-medium">{title}</h2>
</div>
</section>
</>
);
};
export default HeroSub;

View File

@@ -0,0 +1,25 @@
import Link from "next/link";
const Volunteer = () => {
return (
<section className="py-28 bg-volunteer-bg bg-no-repeat bg-cover">
<div className="container mx-auto lg:max-w-(--breakpoint-xl) px-4">
<div className="text-center">
<h2 className="text-30 font-medium text-white mb-6">
Become a Volunteer
</h2>
<p className="text-16 text-white lg:max-w-60% mx-auto mb-6">
Lorem ipsum dolor sit amet, consectetur adipiscelit. Nam malesu dolor sit amet, consectetur adipiscelit. consectetur adipiscelit. Nam malesu dolor.
</p>
<div className="flex justify-center ">
<Link href="#" className="text-white bg-linear-to-r from-error to-warning px-7 py-5 hover:from-transparent hover:to-transparent border border-transparent hover:border-error hover:text-error rounded-sm">
Donate now
</Link>
</div>
</div>
</div>
</section>
)
}
export default Volunteer;

View File

@@ -0,0 +1,29 @@
const CourseDetailSkeleton = () => {
return (
<>
<div>
<div
role='status'
className='max-w-md animate-pulse overflow-hidden rounded-lg bg-gray-100 p-8 mb-28'>
<svg
className='w-full h-30 text-gray-200 my-10'
aria-hidden='true'
xmlns='http://www.w3.org/2000/svg'
fill='currentColor'
viewBox='0 0 20 18'>
<path d='M18 0H2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2Zm-5.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm4.376 10.481A1 1 0 0 1 16 15H4a1 1 0 0 1-.895-1.447l3.5-7A1 1 0 0 1 7.468 6a.965.965 0 0 1 .9.5l2.775 4.757 1.546-1.887a1 1 0 0 1 1.618.1l2.541 4a1 1 0 0 1 .028 1.011Z' />
</svg>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[300px] mb-2.5'></div>
<span className='sr-only'>Loading...</span>
</div>
</div>
</>
)
}
export default CourseDetailSkeleton

View File

@@ -0,0 +1,25 @@
const MentorSkeleton = () => {
return (
<>
<div>
<div
role='status'
className='max-w-md animate-pulse overflow-hidden rounded-lg bg-gray-100 p-8'>
<svg
className='w-full h-30 text-gray-200 my-10'
aria-hidden='true'
xmlns='http://www.w3.org/2000/svg'
fill='currentColor'
viewBox='0 0 20 18'>
<path d='M18 0H2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2Zm-5.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm4.376 10.481A1 1 0 0 1 16 15H4a1 1 0 0 1-.895-1.447l3.5-7A1 1 0 0 1 7.468 6a.965.965 0 0 1 .9.5l2.775 4.757 1.546-1.887a1 1 0 0 1 1.618.1l2.541 4a1 1 0 0 1 .028 1.011Z' />
</svg>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5'></div>
<span className='sr-only'>Loading...</span>
</div>
</div>
</>
)
}
export default MentorSkeleton

View File

@@ -0,0 +1,33 @@
const TestimonialSkeleton = () => {
return (
<>
<div className="m-4">
<div
role='status'
className='max-w-md animate-pulse overflow-hidden rounded-lg bg-white p-8'>
<svg
className='w-20 h-20 mx-auto text-gray-200 my-5'
aria-hidden='true'
xmlns='http://www.w3.org/2000/svg'
fill='currentColor'
viewBox='0 0 20 18'>
<path d='M18 0H2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2Zm-5.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm4.376 10.481A1 1 0 0 1 16 15H4a1 1 0 0 1-.895-1.447l3.5-7A1 1 0 0 1 7.468 6a.965.965 0 0 1 .9.5l2.775 4.757 1.546-1.887a1 1 0 0 1 1.618.1l2.541 4a1 1 0 0 1 .028 1.011Z' />
</svg>
<div className='h-2 w-28 mx-auto bg-gray-200 rounded-full dark:bg-gray-700'></div>
<div className='h-2 w-48 mx-auto bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] my-5'></div>
<div className='h-2 w-24 mx-auto bg-gray-200 rounded-full dark:bg-gray-700 mb-10'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5'></div>
<div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5'></div>
<span className='sr-only'>Loading...</span>
</div>
</div>
</>
)
}
export default TestimonialSkeleton

BIN
src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

57
src/app/globals.css Normal file
View File

@@ -0,0 +1,57 @@
@import 'tailwindcss';
@custom-variant dark (&:is(.dark *));
@theme {
--shadow-mentor-shadow: 0px 4px 20px rgba(110, 127, 185, 0.1);
--inset-54\%: 54%;
--color-primary: #611f69;
--color-cream: #fcf5ef;
--color-success: #6b9f36;
--color-orange: #f9cd92;
--background-image-banner-image: url('/images/banner/background.png');
--background-image-newsletter: url('/images/newsletter/hands.svg');
}
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
section {
@apply py-14
}
h1 {
@apply text-black md:text-7xl sm:text-6xl text-5xl
}
h2 {
@apply text-black sm:text-5xl text-4xl
}
}
@layer utilities {
.container {
@apply max-w-7xl mx-auto w-full px-4;
}
}
html {
scroll-behavior: smooth;
}

26
src/app/layout.tsx Normal file
View File

@@ -0,0 +1,26 @@
import { Inter } from "next/font/google";
import "./globals.css";
import Header from "@/app/components/Layout/Header";
import Footer from "@/app/components/Layout/Footer";
import ScrollToTop from "@/app/components/ScrollToTop";
import Aoscompo from "@/utils/aos";
const font = Inter({ subsets: ["latin"] });
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning>
<body className={`${font.className}`}>
<Aoscompo>
<Header />
{children}
<Footer />
</Aoscompo>
<ScrollToTop />
</body>
</html>
);
}

20
src/app/not-found.tsx Normal file
View File

@@ -0,0 +1,20 @@
import HeroSub from "@/app/components/SharedComponent/HeroSub";
import NotFound from "@/app/components/NotFound";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "404 Page | Venus ",
};
const ErrorPage = () => {
return (
<>
<HeroSub
title="404"
/>
<NotFound />
</>
);
};
export default ErrorPage;

26
src/app/page.tsx Normal file
View File

@@ -0,0 +1,26 @@
import React from 'react'
import Hero from '@/app/components/Home/Hero'
import Companies from '@/app/components/Home/Companies'
import NamesList from '@/app/components/Home/Courses'
import Mentor from '@/app/components/Home/Mentor'
import Testimonial from '@/app/components/Home/Testimonial'
import Newsletter from '@/app/components/Home/Newsletter'
import { Metadata } from 'next'
import ContactForm from './components/Contact/Form'
export const metadata: Metadata = {
title: 'Si Educational',
}
export default function Home() {
return (
<main>
<Hero />
<Companies />
<NamesList />
<Mentor />
<Testimonial />
<ContactForm />
<Newsletter />
</main>
)
}

8
src/app/types/blog.ts Normal file
View File

@@ -0,0 +1,8 @@
export type Blog = {
id?: number;
title?: string;
slug?: string;
excerpt?: string;
coverImage: string;
date: string;
};

View File

@@ -0,0 +1,9 @@
export interface BreadcrumbProps {
pageName: string;
pageDescription?: string;
}
export interface BreadcrumbLink {
href: string;
text: string;
}

3
src/app/types/course.ts Normal file
View File

@@ -0,0 +1,3 @@
export type CourseType = {
name: string
}

View File

@@ -0,0 +1,11 @@
export type CourseDetailType = {
course: string
imageSrc: string
profession: string
price: string
category:
| 'mobiledevelopment'
| 'webdevelopment'
| 'datascience'
| 'cloudcomputing'
}

View File

@@ -0,0 +1,9 @@
export type Link = {
label: string
href: string
}
export type FooterLinkType = {
section: string
links: Link[]
}

3
src/app/types/hour.ts Normal file
View File

@@ -0,0 +1,3 @@
export type Hourtype = {
name: string
}

7
src/app/types/mentor.ts Normal file
View File

@@ -0,0 +1,7 @@
export type MentorType = {
name: string
href: string
imageSrc: string
imageAlt: string
color: string
}

10
src/app/types/menu.ts Normal file
View File

@@ -0,0 +1,10 @@
export type SubmenuItem = {
label: string
href: string
}
export type HeaderItem = {
label: string
href: string
submenu?: SubmenuItem[]
}

View File

@@ -0,0 +1,7 @@
export type TestimonialType = {
profession: string
name: string
imgSrc: string
starimg: string
detail: string
}

20
src/utils/aos.tsx Normal file
View File

@@ -0,0 +1,20 @@
'use client'
import { useEffect } from "react";
import AOS from "aos"
import 'aos/dist/aos.css';
const Aoscompo = ({children}:any) => {
useEffect(() => {
AOS.init({
duration: 800,
once: false,
})
}, [])
return (
<div>
{children}
</div>
)
}
export default Aoscompo

View File

@@ -0,0 +1,7 @@
export const validateEmail = (email: string) => {
return String(email)
.toLowerCase()
.match(
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
);
};