images updated

This commit is contained in:
parsa aghaei 2026-06-29 09:21:46 +03:30
parent 470036d6b9
commit dfedd18f66
19 changed files with 165 additions and 0 deletions

BIN
public/images/parsa2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

BIN
public/images/profile1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -0,0 +1,115 @@
"use client";
import React from "react";
import Image from "next/image";
import { motion } from "framer-motion";
import { AboutMeDataType } from "@/app/types/types";
interface AboutMeContentProps {
data: AboutMeDataType;
}
const CATEGORIES = {
"Core Tech": ["React", "Next.js", "TypeScript", "JavaScript"],
"Backend & Tools": ["Laravel", "PHP", "MySQL", "Node.js", "Docker", "Git"],
"Architecture & Others": ["REST API", "TDD", "UI/UX Design", "Clean Architecture"],
};
type CategoryKey = keyof typeof CATEGORIES | "Other";
export default function AboutMeContent({ data }: AboutMeContentProps) {
const categorizedSkills: Record<CategoryKey, string[]> = {
"Core Tech": [],
"Backend & Tools": [],
"Architecture & Others": [],
"Other": [],
};
data.skills.forEach((skill) => {
let matched = false;
for (const [cat, skills] of Object.entries(CATEGORIES)) {
if (skills.some((s) => skill.title.toLowerCase().includes(s.toLowerCase()))) {
categorizedSkills[cat as CategoryKey].push(skill.title);
matched = true;
break;
}
}
if (!matched) categorizedSkills["Other"].push(skill.title);
});
const isRTL = typeof document !== "undefined" && document.dir === "rtl";
return (
<section
className="relative flex w-full max-w-[1200px] flex-col items-center justify-center gap-12 py-20 lg:flex-row"
id="about-me"
>
{/* Text Section */}
<motion.div
initial={{ opacity: 0, x: isRTL ? 50 : -50 }}
whileInView={{ opacity: 1, x: 0 }}
transition={{ duration: 0.8 }}
viewport={{ once: true }}
className="flex w-full flex-col items-start gap-6 lg:w-[55%]"
>
<h2 className="text-4xl md:text-5xl font-bold text-foreground tracking-tight">
{data.title}
</h2>
<p className="text-lg text-muted-foreground leading-relaxed text-balance">
{data.description}
</p>
<div className="mt-8 grid grid-cols-1 md:grid-cols-2 gap-8 w-full">
{Object.entries(categorizedSkills).map(([category, skills]) => (
skills.length > 0 && (
<motion.div
key={category}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
viewport={{ once: true }}
className="flex flex-col gap-3"
>
<h3 className="text-sm font-mono font-bold text-primary uppercase tracking-widest">
{category}
</h3>
<div className="flex flex-wrap gap-2">
{skills.map((skill, idx) => (
<span
key={idx}
className="tech-tag"
>
{skill}
</span>
))}
</div>
</motion.div>
)
))}
</div>
</motion.div>
{/* Image Section */}
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
whileInView={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.8 }}
viewport={{ once: true }}
className="relative w-full max-w-[450px] flex justify-center lg:w-[40%]"
>
<div className="relative group">
<div className="absolute -inset-4 bg-gradient-to-tr from-primary to-purple-600 rounded-3xl blur opacity-20 group-hover:opacity-40 transition duration-500"></div>
<div className="relative overflow-hidden rounded-3xl border-4 border-background shadow-2xl">
<Image
src={process.env.NEXT_PUBLIC_BACK_URL + data.image}
alt="profile picture"
width={450}
height={450}
className="w-full h-auto transition-transform duration-500 group-hover:scale-105"
/>
</div>
</div>
</motion.div>
</section>
);
}

View File

@ -0,0 +1,50 @@
import localFont from 'next/font/local';
import './globals.css';
import { getDefaultLocale } from './lib/functions/utils';
import { ThemeProvider } from './lib/providers/theme-provider';
const mikhak = localFont({
src: 'lib/fonts/mikhak-v32/variable/Mikhak[DSTY,KSHD,wght].woff2',
variable: '--font-mikhak',
weight: '100 900',
});
const inter = localFont({
src: 'lib/fonts/inter/variable/Inter-Variable.woff2',
variable: '--font-inter',
weight: '100 900',
});
const jetbrainsMono = localFont({
src: 'lib/fonts/jetbrains-mono/variable/JetBrainsMono-Variable.woff2',
variable: '--font-jetbrains-mono',
weight: '100 800',
});
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const defaultLocale = await getDefaultLocale();
return (
<html lang={defaultLocale} dir={defaultLocale === 'fa' ? 'rtl' : 'ltr'} suppressHydrationWarning>
<body
suppressHydrationWarning={true}
className={`${mikhak.variable} ${inter.variable} ${jetbrainsMono.variable} relative flex h-full w-full flex-col items-center justify-between antialiased`}
>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange
>
<div className="main flex h-full w-full flex-wrap justify-center">
{children}
</div>
</ThemeProvider>
</body>
</html>
);
}

Binary file not shown.