about me is responsive now

This commit is contained in:
parsa aghaei 2024-09-24 13:13:13 +03:30
parent 8875ca6762
commit e749866471
5 changed files with 78 additions and 95 deletions

View File

@ -38,43 +38,27 @@ export default function AboutMe() {
console.error("Failed to fetch about me data"); console.error("Failed to fetch about me data");
} }
}; };
fetchAboutMeData() fetchAboutMeData();
}, []); }, []);
return ( return (
<div <div
className="flex flex-nowrap items-center justify-between my-20" className="my-20 flex w-full flex-wrap items-center justify-center gap-10 px-5"
id="about-me" id="about-me"
> >
{aboutMe?.image ? ( <div className="ms-0 flex w-full min-w-[300px] max-w-[80%] flex-col items-start md:w-[50%]">
<div className="img-container"> <h2 className="w-full text-[65px] font-[600] text-black">
<div className="top-half-circle">
<Image
src={aboutMe.image}
alt="profile picture"
width={538}
height={617}
className="bottom-0"
/>
</div>
<div className="bottom-half-circle"></div>
</div>
) : (
<Skeleton circle={true} width={538} height={538} />
)}
<div className="ms-[105px] flex w-[756px] flex-col items-start">
<h2 className="text-[65px] font-[600] text-black">
{aboutMe?.title || <Skeleton width={300} height={100} />} {aboutMe?.title || <Skeleton width={300} height={100} />}
</h2> </h2>
<p className="text-[21px] font-[400] text-black"> <p className="text-[21px] font-[400] text-black">
{aboutMe?.description || <Skeleton width={350} height={30} />} {aboutMe?.description || <Skeleton width={350} height={30} />}
</p> </p>
<ul className="mt-10 flex flex-col gap-10"> <ul className="mt-10 flex w-full flex-col gap-10">
{aboutMe?.skills ? ( {aboutMe?.skills ? (
aboutMe?.skills.map((skill, key) => ( aboutMe?.skills.map((skill, key) => (
<li key={key}> <li key={key}>
<h3 className="mb-2">{skill.title}</h3> <h3 className="mb-2">{skill.title}</h3>
<div className="h relative h-[12px] w-[753px] rounded-lg bg-[#EDECEC]"> <div className="h relative h-[12px] w-full rounded-lg bg-[#EDECEC]">
<span <span
className="progress absolute h-[12px] rounded-lg bg-[#FD6F00]" className="progress absolute h-[12px] rounded-lg bg-[#FD6F00]"
style={{ width: `${skill.percentage}%` }} style={{ width: `${skill.percentage}%` }}
@ -84,14 +68,21 @@ export default function AboutMe() {
)) ))
) : ( ) : (
<> <>
<Skeleton width={750} height={50} /> <Skeleton width={"100%"} height={50} />
<Skeleton width={750} height={50} /> <Skeleton width={"100%"} height={50} />
<Skeleton width={750} height={50} /> <Skeleton width={"100%"} height={50} />
<Skeleton width={750} height={50} /> <Skeleton width={"100%"} height={50} />
</> </>
)} )}
</ul> </ul>
</div> </div>
{aboutMe?.image ? (
<div className="flex w-full max-w-[80%] items-center justify-center md:w-[40%]">
<img src={aboutMe.image} alt="profile picture" className="" />
</div>
) : (
<Skeleton circle={true} width={360} height={360} />
)}
</div> </div>
); );
} }

View File

@ -1,5 +1,4 @@
"use client"; "use client";
import Image from "next/image";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Skeleton from "react-loading-skeleton"; import Skeleton from "react-loading-skeleton";
import "react-loading-skeleton/dist/skeleton.css"; import "react-loading-skeleton/dist/skeleton.css";
@ -27,22 +26,17 @@ type Project = {
export default function MyProjects() { export default function MyProjects() {
const [categories, setCategories] = useState<Category[]>([]); const [categories, setCategories] = useState<Category[]>([]);
const [projects, setProjects] = useState<Project[]>([]); const [projects, setProjects] = useState<Project[]>([]);
const [selectedCategory, setSelectedCategory] = useState<string>("All"); const [selectedCategory, setSelectedCategory] = useState<string>("Newest");
useEffect(() => { useEffect(() => {
const fetchProjects = async () => { const fetchProjects = async () => {
const res = await fetch("/api/projects"); const res = await fetch("/api/projects?sort=desc&per_page=20");
const data: { const data = await res.json();
id: number; const resProjects = data.projects.data;
title: string; const resCategories = data.categories;
images: string;
category: string;
created_at: string;
updated_at: string;
}[] = await res.json();
// Convert JSON string to array // Convert JSON string to array
const updatedData = data.map((project) => ({ const updatedData = resProjects.map((project: { images: string }) => ({
...project, ...project,
images: JSON.parse(project.images), images: JSON.parse(project.images),
})); }));
@ -50,16 +44,14 @@ export default function MyProjects() {
setProjects(updatedData); setProjects(updatedData);
// Extract unique categories // Extract unique categories
const uniqueCategories: Category[] = [ const uniqueCategories: Category[] = [{ label: "Newest", active: false }];
{ label: "All", active: false }, const onlyFiveCategoris: Category[] = [
...Array.from( ...resCategories.map((category: string) => ({
new Set(updatedData.map((project) => project.category)),
).map((category) => ({
label: category, label: category,
active: false, active: false,
})), })),
]; ].slice(0, 5);
uniqueCategories.push(...onlyFiveCategoris);
setCategories(uniqueCategories); setCategories(uniqueCategories);
}; };
@ -82,34 +74,9 @@ export default function MyProjects() {
// Filter projects by selected category // Filter projects by selected category
const filteredProjects: Project[] = const filteredProjects: Project[] =
selectedCategory === "All" selectedCategory === "Newest"
? selectProjectsForAll(groupedProjects).slice(0, 6) ? projects.slice(0, 6) // Get first 6 projects for "Newest"
: projects : groupedProjects[selectedCategory]?.slice(0, 6) || []; // Get first 6 projects from selected category
.filter((project) => project.category === selectedCategory)
.slice(0, 6);
// Select 6 projects for the "All" category
function selectProjectsForAll(
groupedProjects: Record<string, Project[]>,
): Project[] {
const selected: Project[] = [];
const remaining: Project[] = [];
// Select at least one project from each category
for (const category in groupedProjects) {
if (groupedProjects[category].length > 0) {
selected.push(groupedProjects[category][0]);
remaining.push(...groupedProjects[category].slice(1));
}
}
// Add remaining projects if less than 6
while (selected.length < 6 && remaining.length > 0) {
selected.push(remaining.shift()!);
}
return selected.slice(0, 6); // Maximum 6 projects
}
return ( return (
<div className="flex flex-col items-center" id="projects"> <div className="flex flex-col items-center" id="projects">
@ -124,7 +91,7 @@ export default function MyProjects() {
<li <li
key={index} key={index}
onClick={() => setSelectedCategory(category.label)} onClick={() => setSelectedCategory(category.label)}
className={`rounded-md border border-[#545454] bg-[#F8F8F8] px-[20px] py-[10px] text-[24px] font-[400] hover:cursor-pointer hover:border-[#FD6F00] ${ className={`select-none rounded-md border border-[#545454] bg-[#F8F8F8] px-[20px] py-[10px] text-[24px] font-[400] hover:cursor-pointer hover:border-[#FD6F00] ${
selectedCategory === category.label selectedCategory === category.label
? "bg-[#FD6F00] text-[#FFFFFF]" ? "bg-[#FD6F00] text-[#FFFFFF]"
: "text-[#000]" : "text-[#000]"
@ -152,7 +119,7 @@ export default function MyProjects() {
key={idx} key={idx}
src={image.src} src={image.src}
alt="UI/UX Vector" alt="UI/UX Vector"
className={`absolute ${image.position} z-${image.zIndex} max-w-[350px] project-image`} className={`absolute ${image.position} z-${image.zIndex} project-image max-w-[350px]`}
/> />
))} ))}
</div> </div>

View File

@ -90,13 +90,13 @@ html {
} }
} */ } */
.img-container { /* .img-container {
position: relative; position: relative;
width: 538px; width: 538px;
height: 617px; height: 617px;
} } */
.top-half-circle { /* .top-half-circle {
position: absolute; position: absolute;
width: 538px; width: 538px;
height: 269px; height: 269px;
@ -107,15 +107,15 @@ html {
border-top-right-radius: 269px; border-top-right-radius: 269px;
z-index: 0; z-index: 0;
animation: top-half 1.5s ease-out; animation: top-half 1.5s ease-out;
} } */
.top-half-circle img { /* .top-half-circle img {
position: absolute; position: absolute;
bottom: -269px; bottom: -269px;
z-index: +5; z-index: +5;
} } */
.bottom-half-circle { /* .bottom-half-circle {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
width: 538px; width: 538px;
@ -127,13 +127,13 @@ html {
overflow: hidden; overflow: hidden;
z-index: 6; z-index: 6;
animation: bottom-half 2s infinite linear; animation: bottom-half 2s infinite linear;
} } */
.bottom-half-circle img { /* .bottom-half-circle img {
position: absolute; position: absolute;
bottom: 0px; bottom: 0px;
z-index: 0; z-index: 0;
} } */
@keyframes top-half { @keyframes top-half {
0% { 0% {
@ -247,5 +247,18 @@ html {
.project-image:hover { .project-image:hover {
scale: 1.05; scale: 1.05;
z-index: 10000; z-index: 10000;
cursor:zoom-in cursor: zoom-in;
} }
.svg-hover{
transition: all ease-in-out 123ms;
-webkit-transition: -webkit-filter 123ms ease-in-out;
scale: 1;
}
.svg-hover:hover {
scale: 1.05;
filter: brightness(0) saturate(100%) invert(46%) sepia(59%) saturate(3359%)
hue-rotate(6deg) brightness(103%) contrast(104%);
transition: all ease-in-out 123ms;
-webkit-transition: -webkit-filter 123ms ease-in-out;
}

View File

@ -10,11 +10,11 @@ export default function Home() {
<div className="my-[100px] flex w-full max-w-[1420px] flex-col items-center gap-[50px]"> <div className="my-[100px] flex w-full max-w-[1420px] flex-col items-center gap-[50px]">
{/* Home */} {/* Home */}
<div <div
className="flex flex-wrap w-full justify-center gap-10 xl:gap-15 2xl:gap-20 lg:flex-nowrap" className="xl:gap-15 flex w-full flex-wrap justify-center gap-10 lg:flex-nowrap 2xl:gap-20"
id="home" id="home"
> >
{/* start */} {/* start */}
<div className="flex flex-wrap justify-center w-full lg:w-[45%] xl:w-[50%] max-w-[500px]"> <div className="flex w-full max-w-[500px] flex-wrap justify-center lg:w-[45%] xl:w-[50%]">
<div className="aboutme-image"> <div className="aboutme-image">
<Image <Image
src={"/images/profile.png"} src={"/images/profile.png"}
@ -32,39 +32,47 @@ export default function Home() {
width={32} width={32}
height={32} height={32}
alt="facebook" alt="facebook"
className="svg-hover hover:cursor-pointer"
/> />
<Image <Image
src={"/images/icons/twitter.svg"} src={"/images/icons/twitter.svg"}
width={32} width={32}
height={32} height={32}
alt="twitter" alt="twitter"
className="svg-hover hover:cursor-pointer"
/> />
<Image <Image
src={"/images/icons/instagram.svg"} src={"/images/icons/instagram.svg"}
width={32} width={32}
height={32} height={32}
alt="instagram" alt="instagram"
className="svg-hover hover:cursor-pointer"
/> />
<Image <Image
src={"/images/icons/linkedin.svg"} src={"/images/icons/linkedin.svg"}
width={32} width={32}
height={32} height={32}
alt="linkedin" alt="linkedin"
className="svg-hover hover:cursor-pointer"
/> />
</div> </div>
</div> </div>
</div> </div>
{/* end */} {/* end */}
<div className="flex flex-col w-full items max-w-[80%] md:max-w-[70%] lg:w-[45%] xl:w-[50%]"> <div className="items flex w-full max-w-[80%] flex-col md:max-w-[70%] lg:w-[45%] xl:w-[50%]">
<p className="text-[20px] 2xl:text-[24px] font-[400] text-black">Hi I am </p> <p className="text-[20px] font-[400] text-black 2xl:text-[24px]">
<p className="text-[30px] 2xl:text-[32px] font-[600] text-[#FD6F00]">Parsa Aghayi</p> Hi I am{" "}
<p className="text-[40px] lg:text-[45px] xl:text-[60px] 2xl:text-[80px] font-[700] text-black text-start whitespace-nowrap"> </p>
<p className="text-[30px] font-[600] text-[#FD6F00] 2xl:text-[32px]">
Parsa Aghayi
</p>
<p className="whitespace-nowrap text-start text-[30px] font-[700] text-black sm:text-[50px] lg:text-[45px] xl:text-[60px] 2xl:text-[80px]">
Frontend & Backend Frontend & Backend
</p> </p>
<p className="text-end mt-[-20px] text-[50px] lg:text-[50px] lg:mt-[-30px] xl:text-[70px] 2xl:text-[100px] font-[700] text-black"> <p className="mt-[-20px] text-end text-[50px] font-[700] text-black lg:mt-[-30px] lg:text-[50px] xl:text-[70px] 2xl:text-[100px]">
Developer Developer
</p> </p>
<p className="my-[40px] pe-[50px] lg:pe-0 text-[21px] font-[400] text-black"> <p className="my-[40px] text-justify text-[21px] font-[400] text-black lg:pe-0">
Lorem ipsum dolor sit amet consectetur. Tristique amet sed massa Lorem ipsum dolor sit amet consectetur. Tristique amet sed massa
nibh lectus netus in. Aliquet donec morbi convallis pretium. Turpis nibh lectus netus in. Aliquet donec morbi convallis pretium. Turpis
tempus pharetra tempus pharetra
@ -87,3 +95,4 @@ export default function Home() {
</div> </div>
); );
} }

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

@ -0,0 +1,3 @@
export type {
}