diff --git a/package-lock.json b/package-lock.json index 4ed2d48..89c87aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@notionhq/client": "^2.2.15", "@types/react-syntax-highlighter": "^15.5.13", "dotenv": "^16.4.7", + "framer-motion": "^12.23.25", "katex": "^0.16.19", "lucide-react": "^0.554.0", "next": "^16.0.7", @@ -1600,6 +1601,33 @@ "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": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3273,6 +3301,21 @@ "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": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index d3d4428..747c66b 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@notionhq/client": "^2.2.15", "@types/react-syntax-highlighter": "^15.5.13", "dotenv": "^16.4.7", + "framer-motion": "^12.23.25", "katex": "^0.16.19", "lucide-react": "^0.554.0", "next": "^16.0.7", diff --git a/src/app/page.tsx b/src/app/page.tsx index 89aff49..1dd5ac3 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,6 @@ "use client"; +import { motion, spring } from "framer-motion"; import PinnedRepos from "@/components/PinnedRepos"; import Skill from "@/components/Skill"; import { @@ -17,6 +18,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { CoffeeIcon, HeartIcon } from "lucide-react"; import { useEffect, useState } from "react"; import GitHubCalendar from "react-github-calendar"; +import { fadeInUp, popIn, staggerContainer } from "@/components/effects"; export default function App() { const [contribs, setContribs] = useState(); @@ -25,81 +27,154 @@ export default function App() { const fetchContributions = async () => { const res = await fetch("/api/contribs"); const data = await res.json(); - console.log("Total contributions:", data.total); setContribs(data.total || undefined); }; fetchContributions(); }, []); return ( -
+
-

Hey, I'm Klesti! 👋🏻

-

+ {/* HEADER */} + + Hey, I'm Klesti! 👋🏻 + + + A 15 year old Software Engineer from Tirane, Albania, with 6 years of experience, specializing in full-stack web development, desktop applications, TUI apps, and hacking. I also have a deep interest in low-level programming. -

+ -
+ {/* KO-FI BUTTON */} + - - Support me on Ko-fi - - -
- - {/* Socials and skill */} -
- {/* socials */} - -
-
-
- - - - - - -
-
-
-
+ Support me on Ko-fi + + + -

Pinned Projects

-
+ {/* SOCIALS + SKILLS */} + + {/* socials */} + + {[faGithub, faLinkedin, faInstagram].map((icon, i) => ( + + + + ))} + + + {/* skills */} + +
+ + + + + + + + + + + + + + + + + + + + +
+
+
+ + {/* PINNED PROJECTS */} + + Pinned Projects + + + -
-

+ + + {/* CONTRIBUTIONS */} + {contribs || "Loading.."} contributions in the last year -

-
+ + + -
+ + + {/* FOOTER */}
-

- If you see this i you -

-

+ + If you see this i{" "} + + + {" "} + you + + + © 2025 Klesti. All rights reserved. -

+
-
+ ); } diff --git a/src/components/PinnedRepos.tsx b/src/components/PinnedRepos.tsx index 5b7cc4a..cd150a2 100644 --- a/src/components/PinnedRepos.tsx +++ b/src/components/PinnedRepos.tsx @@ -1,6 +1,8 @@ "use client"; import { useEffect, useState } from "react"; +import { motion } from "framer-motion"; +import { fadeInUp, fadeInUp2, staggerContainer } from "./effects"; type PinnedRepo = { author: string; @@ -21,22 +23,12 @@ export function Repo({ href, }: PinnedRepo) { return ( -
@@ -133,7 +125,7 @@ export function Repo({
- + ); } @@ -158,7 +150,13 @@ export default function PinnedRepos() { }); return ( -
+ {pinned && pinned.map((repo, i) => ( ))} -
+ ); } catch (e: any) { return

{e.toString()}

; diff --git a/src/components/effects.ts b/src/components/effects.ts new file mode 100644 index 0000000..7335a1c --- /dev/null +++ b/src/components/effects.ts @@ -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 }, + }, +};