refactor: move ProjectCard component and add prop types validation
This commit is contained in:
parent
f1edb19b5a
commit
3aa7aedeca
3 changed files with 88 additions and 22 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { motion } from "framer-motion";
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
export default function projectCard({project, index, activeCategory}){
|
import { motion } from "framer-motion";
|
||||||
console.log(project.category[0], activeCategory);
|
import PropTypes from "prop-types";
|
||||||
console.log(project.category.includes(activeCategory));
|
|
||||||
|
export default function ProjectCard({ project, index, activeCategory }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{project.category.includes(parseInt(activeCategory)) && (
|
{project.category.includes(parseInt(activeCategory)) && (
|
||||||
|
|
@ -56,3 +56,10 @@ export default function projectCard({project, index, activeCategory}){
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProjectCard.propTypes = {
|
||||||
|
project: PropTypes.object.isRequired,
|
||||||
|
index: PropTypes.number.isRequired,
|
||||||
|
activeCategory: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
||||||
|
.isRequired,
|
||||||
|
};
|
||||||
|
|
|
||||||
65
app/projects/components/ProjectCard.jsx
Normal file
65
app/projects/components/ProjectCard.jsx
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
export default function ProjectCard({ project, index, activeCategory }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{project.category.includes(parseInt(activeCategory)) && (
|
||||||
|
<Link href={"projects/" + project.slug} key={index}>
|
||||||
|
<motion.div
|
||||||
|
className="z-10 relative flex justify-center items-start flex-col mb-5 md:px-10 w-full h-auto bg-gray-400 group/tes py-20 px-5 md:py-2 aspect-video "
|
||||||
|
initial={{
|
||||||
|
opacity: 0,
|
||||||
|
x: -200,
|
||||||
|
}}
|
||||||
|
whileInView={{
|
||||||
|
opacity: 1,
|
||||||
|
x: 0,
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
type: "spring",
|
||||||
|
}}>
|
||||||
|
<Image
|
||||||
|
src={project.thumbnail}
|
||||||
|
alt="Alvalens"
|
||||||
|
layout="fill"
|
||||||
|
objectFit="cover"
|
||||||
|
placeholder="blur"
|
||||||
|
className="bg-slate-950 opacity-10 group-hover/tes:opacity-100 transition-all ease duration-500"
|
||||||
|
blurDataURL={project.thumbnail}
|
||||||
|
/>
|
||||||
|
<div className="absolute top-0 left-0 bg-gray-600 px-4 py-2">
|
||||||
|
<h4 className="text-white">{project.year}</h4>
|
||||||
|
</div>
|
||||||
|
<div className="transition-all ease duration-500 opacity-100 content text-center group-hover/tes:opacity-0 z-10">
|
||||||
|
<h1 className="text-3xl font-bold mb-3">{project.title}</h1>
|
||||||
|
<p>
|
||||||
|
{project.desc[0].length > 125
|
||||||
|
? `${project.desc[0].slice(0, 125)}...`
|
||||||
|
: project.desc[0]}
|
||||||
|
</p>
|
||||||
|
<div className="flex justify-center items-center flex-row mt-5 flex-wrap">
|
||||||
|
{project.tech.map((t, index) => (
|
||||||
|
<span
|
||||||
|
key={index}
|
||||||
|
className="m-1 px-4 py-2 bg-gray-600 text-white ">
|
||||||
|
{t}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectCard.propTypes = {
|
||||||
|
project: PropTypes.object.isRequired,
|
||||||
|
index: PropTypes.number.isRequired,
|
||||||
|
activeCategory: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
||||||
|
.isRequired,
|
||||||
|
};
|
||||||
|
|
@ -12,7 +12,7 @@ import ReactChat3 from "@/public/image/projects/web/trivia/trivia3.png";
|
||||||
import ProjectAll from "@/public/image/projects.png";
|
import ProjectAll from "@/public/image/projects.png";
|
||||||
|
|
||||||
import Hr from "@/components/Hr";
|
import Hr from "@/components/Hr";
|
||||||
import ProjectCard from "./(project-card)";
|
import ProjectCard from "./components/ProjectCard";
|
||||||
import Projects from "@/json/data.json";
|
import Projects from "@/json/data.json";
|
||||||
import FixedButon from "@/components/FixedButton";
|
import FixedButon from "@/components/FixedButton";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
@ -22,12 +22,11 @@ const category = {
|
||||||
1: "Web Development",
|
1: "Web Development",
|
||||||
2: "AI & Machine Learning",
|
2: "AI & Machine Learning",
|
||||||
9: "Other",
|
9: "Other",
|
||||||
}
|
};
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [activeCategory, setActiveCategory] = useState(1);
|
const [activeCategory, setActiveCategory] = useState(1);
|
||||||
const projects = Projects.Projects.filter ((item) => item.show === true
|
const projects = Projects.Projects.filter((item) => item.show === true);
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
|
|
@ -36,10 +35,7 @@ export default function Page() {
|
||||||
<>
|
<>
|
||||||
<main className="overflow-hidden">
|
<main className="overflow-hidden">
|
||||||
<FixedButon href="/#projects">
|
<FixedButon href="/#projects">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon icon={faChevronLeft} className="text-black pr-10" />
|
||||||
icon={faChevronLeft}
|
|
||||||
className="text-black pr-10"
|
|
||||||
/>
|
|
||||||
</FixedButon>
|
</FixedButon>
|
||||||
<div className="relative h-screen w-screen gap-4 p-10 flex justify-center items-center flex-col mb-10 overflow-hidden">
|
<div className="relative h-screen w-screen gap-4 p-10 flex justify-center items-center flex-col mb-10 overflow-hidden">
|
||||||
<div className="z-0 mb-48 md:mb-0 md:absolute top-1/4 md:right-[10%] md:-translate-y-16 ">
|
<div className="z-0 mb-48 md:mb-0 md:absolute top-1/4 md:right-[10%] md:-translate-y-16 ">
|
||||||
|
|
@ -181,15 +177,13 @@ export default function Page() {
|
||||||
Generative Trivia
|
Generative Trivia
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-600 text-justify title text-lg">
|
<p className="text-gray-600 text-justify title text-lg">
|
||||||
A generative trivia website built with Next.js,
|
A generative trivia website built with Next.js, Firebase,
|
||||||
Firebase, NextAuth, Google OAuth, and TypeScript.
|
NextAuth, Google OAuth, and TypeScript. Users can generate trivia
|
||||||
Users can generate trivia questions for predefined
|
questions for predefined school subjects and answer them with a
|
||||||
school subjects and answer them with a unique
|
unique interactive input style. The application supports user
|
||||||
interactive input style. The application supports
|
authentication with Google and stores data in Firestore. You can
|
||||||
user authentication with Google and stores data in
|
see the source code of this project on my github account or
|
||||||
Firestore. You can see the source code of this
|
preview the project by clicking the button below.
|
||||||
project on my github account or preview the project
|
|
||||||
by clicking the button below.
|
|
||||||
</p>{" "}
|
</p>{" "}
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<Button variation="primary">
|
<Button variation="primary">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue