Animated look (way better)
This commit is contained in:
Generated
+43
@@ -17,6 +17,7 @@
|
|||||||
"@notionhq/client": "^2.2.15",
|
"@notionhq/client": "^2.2.15",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
|
"framer-motion": "^12.23.25",
|
||||||
"katex": "^0.16.19",
|
"katex": "^0.16.19",
|
||||||
"lucide-react": "^0.554.0",
|
"lucide-react": "^0.554.0",
|
||||||
"next": "^16.0.7",
|
"next": "^16.0.7",
|
||||||
@@ -1600,6 +1601,33 @@
|
|||||||
"node": ">=0.4.x"
|
"node": ">=0.4.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/framer-motion": {
|
||||||
|
"version": "12.23.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.25.tgz",
|
||||||
|
"integrity": "sha512-gUHGl2e4VG66jOcH0JHhuJQr6ZNwrET9g31ZG0xdXzT0CznP7fHX4P8Bcvuc4MiUB90ysNnWX2ukHRIggkl6hQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"motion-dom": "^12.23.23",
|
||||||
|
"motion-utils": "^12.23.6",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/is-prop-valid": "*",
|
||||||
|
"react": "^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/is-prop-valid": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
@@ -3273,6 +3301,21 @@
|
|||||||
"node": ">=16 || 14 >=14.17"
|
"node": ">=16 || 14 >=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/motion-dom": {
|
||||||
|
"version": "12.23.23",
|
||||||
|
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
|
||||||
|
"integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"motion-utils": "^12.23.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/motion-utils": {
|
||||||
|
"version": "12.23.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
|
||||||
|
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"@notionhq/client": "^2.2.15",
|
"@notionhq/client": "^2.2.15",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
|
"framer-motion": "^12.23.25",
|
||||||
"katex": "^0.16.19",
|
"katex": "^0.16.19",
|
||||||
"lucide-react": "^0.554.0",
|
"lucide-react": "^0.554.0",
|
||||||
"next": "^16.0.7",
|
"next": "^16.0.7",
|
||||||
|
|||||||
+151
-56
@@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { motion, spring } from "framer-motion";
|
||||||
import PinnedRepos from "@/components/PinnedRepos";
|
import PinnedRepos from "@/components/PinnedRepos";
|
||||||
import Skill from "@/components/Skill";
|
import Skill from "@/components/Skill";
|
||||||
import {
|
import {
|
||||||
@@ -17,6 +18,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
import { CoffeeIcon, HeartIcon } from "lucide-react";
|
import { CoffeeIcon, HeartIcon } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import GitHubCalendar from "react-github-calendar";
|
import GitHubCalendar from "react-github-calendar";
|
||||||
|
import { fadeInUp, popIn, staggerContainer } from "@/components/effects";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [contribs, setContribs] = useState<number>();
|
const [contribs, setContribs] = useState<number>();
|
||||||
@@ -25,81 +27,154 @@ export default function App() {
|
|||||||
const fetchContributions = async () => {
|
const fetchContributions = async () => {
|
||||||
const res = await fetch("/api/contribs");
|
const res = await fetch("/api/contribs");
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
console.log("Total contributions:", data.total);
|
|
||||||
setContribs(data.total || undefined);
|
setContribs(data.total || undefined);
|
||||||
};
|
};
|
||||||
fetchContributions();
|
fetchContributions();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full max-w-screen-lg mx-auto animate-fadeIn ">
|
<motion.div
|
||||||
|
className="w-full max-w-screen-lg mx-auto"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 0.6 }}
|
||||||
|
>
|
||||||
<div className="px-8 md:px-10 lg:px-15 xl:px-24">
|
<div className="px-8 md:px-10 lg:px-15 xl:px-24">
|
||||||
<h1 className="py-2 text-gray-300">Hey, I'm Klesti! 👋🏻</h1>
|
{/* HEADER */}
|
||||||
<p className="font-semibold text-gray-300">
|
<motion.h1
|
||||||
|
className="py-2 text-gray-300"
|
||||||
|
variants={fadeInUp}
|
||||||
|
initial="hidden"
|
||||||
|
animate="show"
|
||||||
|
>
|
||||||
|
Hey, I'm Klesti! 👋🏻
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
<motion.p
|
||||||
|
className="font-semibold text-gray-300"
|
||||||
|
variants={fadeInUp}
|
||||||
|
initial="hidden"
|
||||||
|
animate="show"
|
||||||
|
transition={{ delay: 0.15 }}
|
||||||
|
>
|
||||||
A 15 year old Software Engineer from Tirane, Albania, with 6 years of
|
A 15 year old Software Engineer from Tirane, Albania, with 6 years of
|
||||||
experience, specializing in full-stack web development, desktop
|
experience, specializing in full-stack web development, desktop
|
||||||
applications, TUI apps, and hacking. I also have a deep interest in
|
applications, TUI apps, and hacking. I also have a deep interest in
|
||||||
low-level programming.
|
low-level programming.
|
||||||
</p>
|
</motion.p>
|
||||||
|
|
||||||
<div className="pt-6">
|
{/* KO-FI BUTTON */}
|
||||||
|
<motion.div
|
||||||
|
className="pt-6"
|
||||||
|
animate={{ y: [0, -3, 0] }}
|
||||||
|
transition={{ repeat: Infinity, duration: 3 }}
|
||||||
|
>
|
||||||
<a href="https://ko-fi.com/X8X01OX1WR" target="_blank">
|
<a href="https://ko-fi.com/X8X01OX1WR" target="_blank">
|
||||||
<span className="bg-transparent-ish rounded-md border border-slate-400 p-2 flex w-max gap-2 items-center">
|
<motion.span
|
||||||
|
whileHover={{ scale: 1.05 }}
|
||||||
|
whileTap={{ scale: 0.95 }}
|
||||||
|
className="bg-transparent-ish rounded-md border border-slate-400 p-2 flex w-max gap-2 items-center cursor-pointer"
|
||||||
|
>
|
||||||
<CoffeeIcon /> Support me on Ko-fi
|
<CoffeeIcon /> Support me on Ko-fi
|
||||||
</span>
|
</motion.span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Socials and skill */}
|
{/* SOCIALS + SKILLS */}
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 bg-transparent">
|
<motion.div
|
||||||
|
className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 bg-transparent"
|
||||||
|
variants={staggerContainer}
|
||||||
|
initial="hidden"
|
||||||
|
animate="show"
|
||||||
|
>
|
||||||
{/* socials */}
|
{/* socials */}
|
||||||
<div className="pt-5 flex flex-row gap-5 w-max">
|
<motion.div className="pt-5 flex flex-row gap-5 w-max">
|
||||||
<a href="https://github.com/selimaj-dev/" target="blank_">
|
{[faGithub, faLinkedin, faInstagram].map((icon, i) => (
|
||||||
<FontAwesomeIcon
|
<motion.a
|
||||||
icon={faGithub}
|
key={i}
|
||||||
className="text-slate-400 size-[2.3rem]"
|
href={
|
||||||
/>
|
icon === faGithub
|
||||||
</a>
|
? "https://github.com/selimaj-dev/"
|
||||||
<a
|
: icon === faLinkedin
|
||||||
href="https://www.linkedin.com/in/klesti-selimaj-7a0162343/"
|
? "https://www.linkedin.com/in/klesti-selimaj-7a0162343/"
|
||||||
|
: "https://www.instagram.com/selimaj.dev/"
|
||||||
|
}
|
||||||
target="blank_"
|
target="blank_"
|
||||||
|
variants={popIn}
|
||||||
|
whileHover={{ scale: 1.2, rotate: 3 }}
|
||||||
|
whileTap={{ scale: 0.9 }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faLinkedin}
|
icon={icon}
|
||||||
className="text-slate-400 size-[2.3rem]"
|
className="text-slate-400 size-[2.3rem]"
|
||||||
/>
|
/>
|
||||||
</a>
|
</motion.a>
|
||||||
<a href="https://www.instagram.com/selimaj.dev/" target="blank_">
|
))}
|
||||||
<FontAwesomeIcon
|
</motion.div>
|
||||||
icon={faInstagram}
|
|
||||||
className="text-slate-400 size-[2.3rem]"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="p-3 rounded-xl">
|
|
||||||
<div className="mx-auto w-max flex flex-row gap-5">
|
|
||||||
<Skill skill="Rust" icon={faRust} />
|
|
||||||
<Skill skill="Go" icon={faGolang} />
|
|
||||||
<Skill skill="JavaScript" icon={faJs} />
|
|
||||||
<Skill skill="Java" icon={faJava} classInsert="p-1" />
|
|
||||||
<Skill skill="Python" icon={faPython} />
|
|
||||||
<Skill skill="React" icon={faReact} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 className="text-slate-300">Pinned Projects</h1>
|
{/* skills */}
|
||||||
<section className="">
|
<motion.div variants={popIn}>
|
||||||
|
<div className="p-3 rounded-xl">
|
||||||
|
<motion.div
|
||||||
|
className="mx-auto w-max flex flex-row gap-5"
|
||||||
|
variants={staggerContainer}
|
||||||
|
initial="hidden"
|
||||||
|
animate="show"
|
||||||
|
>
|
||||||
|
<motion.div variants={popIn}>
|
||||||
|
<Skill skill="Rust" icon={faRust} />
|
||||||
|
</motion.div>
|
||||||
|
<motion.div variants={popIn}>
|
||||||
|
<Skill skill="Go" icon={faGolang} />
|
||||||
|
</motion.div>
|
||||||
|
<motion.div variants={popIn}>
|
||||||
|
<Skill skill="JavaScript" icon={faJs} />
|
||||||
|
</motion.div>
|
||||||
|
<motion.div variants={popIn}>
|
||||||
|
<Skill skill="Java" icon={faJava} classInsert="p-1" />
|
||||||
|
</motion.div>
|
||||||
|
<motion.div variants={popIn}>
|
||||||
|
<Skill skill="Python" icon={faPython} />
|
||||||
|
</motion.div>
|
||||||
|
<motion.div variants={popIn}>
|
||||||
|
<Skill skill="React" icon={faReact} />
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* PINNED PROJECTS */}
|
||||||
|
<motion.h1
|
||||||
|
className="text-slate-300 mt-4"
|
||||||
|
variants={fadeInUp}
|
||||||
|
initial="hidden"
|
||||||
|
animate="show"
|
||||||
|
>
|
||||||
|
Pinned Projects
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
<motion.section>
|
||||||
<PinnedRepos />
|
<PinnedRepos />
|
||||||
</section>
|
</motion.section>
|
||||||
<h2 className="text-slate-300 mt-7">
|
|
||||||
|
{/* CONTRIBUTIONS */}
|
||||||
|
<motion.h2
|
||||||
|
className="text-slate-300 mt-7"
|
||||||
|
variants={fadeInUp}
|
||||||
|
initial="hidden"
|
||||||
|
animate="show"
|
||||||
|
>
|
||||||
{contribs || "Loading.."} contributions in the last year
|
{contribs || "Loading.."} contributions in the last year
|
||||||
</h2>
|
</motion.h2>
|
||||||
<section className="mt-4">
|
|
||||||
|
<motion.section
|
||||||
|
className="mt-4"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
whileInView={{ opacity: 1 }}
|
||||||
|
>
|
||||||
<GitHubCalendar
|
<GitHubCalendar
|
||||||
hideTotalCount
|
// hideTotalCount
|
||||||
username="selimaj-dev"
|
username="selimaj-dev"
|
||||||
theme={{
|
theme={{
|
||||||
light: [
|
light: [
|
||||||
@@ -118,16 +193,36 @@ export default function App() {
|
|||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</section>
|
</motion.section>
|
||||||
|
|
||||||
|
{/* FOOTER */}
|
||||||
<footer className="mt-8 border-t pt-3 pb-8">
|
<footer className="mt-8 border-t pt-3 pb-8">
|
||||||
<p className="flex gap-1 items-center">
|
<motion.p
|
||||||
If you see this i <HeartIcon className="size-4" /> you
|
className="flex gap-1 items-center"
|
||||||
</p>
|
initial={{ opacity: 0 }}
|
||||||
<p className="text-slate-300 mx-auto w-max mt-2">
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ delay: 0.4 }}
|
||||||
|
>
|
||||||
|
If you see this i{" "}
|
||||||
|
<motion.span
|
||||||
|
animate={{ scale: [1, 1.2, 1] }}
|
||||||
|
transition={{ repeat: Infinity, duration: 1.3 }}
|
||||||
|
>
|
||||||
|
<HeartIcon className="size-4" />
|
||||||
|
</motion.span>{" "}
|
||||||
|
you
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
<motion.p
|
||||||
|
className="text-slate-300 mx-auto w-max mt-2"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ delay: 0.6 }}
|
||||||
|
>
|
||||||
© 2025 Klesti. All rights reserved.
|
© 2025 Klesti. All rights reserved.
|
||||||
</p>
|
</motion.p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import { fadeInUp, fadeInUp2, staggerContainer } from "./effects";
|
||||||
|
|
||||||
type PinnedRepo = {
|
type PinnedRepo = {
|
||||||
author: string;
|
author: string;
|
||||||
@@ -21,22 +23,12 @@ export function Repo({
|
|||||||
href,
|
href,
|
||||||
}: PinnedRepo) {
|
}: PinnedRepo) {
|
||||||
return (
|
return (
|
||||||
<div
|
<motion.div
|
||||||
className={`
|
variants={fadeInUp2}
|
||||||
group
|
initial="hidden"
|
||||||
relative
|
whileInView="visible"
|
||||||
flex
|
viewport={{ once: true, amount: 0.2 }}
|
||||||
size-full
|
className="group relative flex size-full overflow-hidden rounded-xl h-full border border-slate-400 hover:shadow-md transition-shadow duration-300 backdrop-blur-[2px]"
|
||||||
overflow-hidden
|
|
||||||
rounded-xl
|
|
||||||
h-full
|
|
||||||
border
|
|
||||||
border-slate-400
|
|
||||||
hover:shadow-md
|
|
||||||
transition-shadow
|
|
||||||
duration-300
|
|
||||||
backdrop-blur-[2px]
|
|
||||||
`}
|
|
||||||
>
|
>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="rounded-xl border text-card-foreground shadow h-full bg-transparent border-none flex flex-col">
|
<div className="rounded-xl border text-card-foreground shadow h-full bg-transparent border-none flex flex-col">
|
||||||
@@ -133,7 +125,7 @@ export function Repo({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +150,13 @@ export default function PinnedRepos() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 bg-transparent">
|
<motion.div
|
||||||
|
variants={staggerContainer}
|
||||||
|
initial="hidden"
|
||||||
|
whileInView="visible"
|
||||||
|
viewport={{ once: true, amount: 0.2 }}
|
||||||
|
className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 bg-transparent"
|
||||||
|
>
|
||||||
{pinned &&
|
{pinned &&
|
||||||
pinned.map((repo, i) => (
|
pinned.map((repo, i) => (
|
||||||
<Repo
|
<Repo
|
||||||
@@ -172,7 +170,7 @@ export default function PinnedRepos() {
|
|||||||
href={`https://github.com/${repo.author}/${repo.name}`}
|
href={`https://github.com/${repo.author}/${repo.name}`}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return <p>{e.toString()}</p>;
|
return <p>{e.toString()}</p>;
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { easeOut, spring } from "framer-motion";
|
||||||
|
|
||||||
|
export const fadeInUp = {
|
||||||
|
hidden: { opacity: 0, y: 20 },
|
||||||
|
show: { opacity: 1, y: 0, transition: { duration: 0.5 } },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fadeInUp2 = {
|
||||||
|
hidden: { opacity: 0, y: 20 },
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: { duration: 0.4, ease: easeOut },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const staggerContainer = {
|
||||||
|
show: {
|
||||||
|
transition: {
|
||||||
|
staggerChildren: 0.12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const popIn = {
|
||||||
|
hidden: { opacity: 0, scale: 0.8 },
|
||||||
|
show: {
|
||||||
|
opacity: 1,
|
||||||
|
scale: 1,
|
||||||
|
transition: { type: spring, stiffness: 120 },
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user