From cf96fbf6bdb1880ad5872bced8f35a64a7f708b7 Mon Sep 17 00:00:00 2001 From: Kay Hennig Date: Sun, 20 Jul 2025 12:10:22 +0200 Subject: [PATCH] slides, first slide --- package-lock.json | 46 +++++++++++++++++ package.json | 13 ++--- src/app/globals.css | 7 +++ src/app/page.tsx | 67 +++++++++++++++++++++--- src/components/Slide.tsx | 25 +++++++++ src/components/Slide1.tsx | 106 ++++++++++++++++++++++++++++++++++++++ src/components/Slide2.tsx | 8 +++ src/components/Slide3.tsx | 8 +++ src/components/Slide4.tsx | 8 +++ src/components/Slide5.tsx | 8 +++ 10 files changed, 283 insertions(+), 13 deletions(-) create mode 100644 src/components/Slide.tsx create mode 100644 src/components/Slide1.tsx create mode 100644 src/components/Slide2.tsx create mode 100644 src/components/Slide3.tsx create mode 100644 src/components/Slide4.tsx create mode 100644 src/components/Slide5.tsx diff --git a/package-lock.json b/package-lock.json index cb4b626..d29cea8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "homepage", "version": "0.1.0", "dependencies": { + "framer-motion": "^12.23.6", "next": "15.4.2", "react": "19.1.0", "react-dom": "19.1.0" @@ -22,6 +23,9 @@ "eslint-config-next": "15.4.2", "tailwindcss": "^4", "typescript": "^5" + }, + "engines": { + "node": ">=20.0.0" } }, "node_modules/@alloc/quick-lru": { @@ -3326,6 +3330,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/framer-motion": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.6.tgz", + "integrity": "sha512-dsJ389QImVE3lQvM8Mnk99/j8tiZDM/7706PCqvkQ8sSCnpmWxsgX+g0lj7r5OBVL0U36pIecCTBoIWcM2RuKw==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.23.6", + "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/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4598,6 +4629,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/motion-dom": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.6.tgz", + "integrity": "sha512-G2w6Nw7ZOVSzcQmsdLc0doMe64O/Sbuc2bVAbgMz6oP/6/pRStKRiVRV4bQfHp5AHYAKEGhEdVHTM+R3FDgi5w==", + "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 fe9f781..4024812 100644 --- a/package.json +++ b/package.json @@ -12,19 +12,20 @@ "lint": "next lint" }, "dependencies": { + "framer-motion": "^12.23.6", + "next": "15.4.2", "react": "19.1.0", - "react-dom": "19.1.0", - "next": "15.4.2" + "react-dom": "19.1.0" }, "devDependencies": { - "typescript": "^5", + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "@tailwindcss/postcss": "^4", - "tailwindcss": "^4", "eslint": "^9", "eslint-config-next": "15.4.2", - "@eslint/eslintrc": "^3" + "tailwindcss": "^4", + "typescript": "^5" } } diff --git a/src/app/globals.css b/src/app/globals.css index e366830..b87dedf 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,7 +1,14 @@ @import "tailwindcss"; +@tailwind base; +@tailwind components; +@tailwind utilities; + @layer base { body { @apply bg-gray-900 text-gray-200 antialiased; } + html, body { + @apply h-full overflow-hidden; + } } \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index e488b3c..186b18d 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,9 +1,62 @@ +'use client' + +import { useState, useEffect, useCallback } from 'react' +import Slide from '@/components/Slide'; +import Slide1 from '@/components/Slide1'; +import Slide2 from '@/components/Slide2'; +import Slide3 from '@/components/Slide3'; +import Slide4 from '@/components/Slide4'; +import Slide5 from '@/components/Slide5'; + + +const slides = [ + , + //, + //, + //, + //, +] + export default function Home() { + const [current, setCurrent] = useState(0) + + + const nextSlide = useCallback(() => { + if (current < slides.length - 1) setCurrent(current + 1) + }, [current]) + + const prevSlide = useCallback(() => { + if (current > 0) setCurrent(current - 1) + }, [current]) + + useEffect(() => { + const handleScroll = (e: WheelEvent) => { + if (e.deltaY > 0) nextSlide() + else prevSlide() + } + + const handleKey = (e: KeyboardEvent) => { + if (e.key === 'ArrowDown') nextSlide() + if (e.key === 'ArrowUp') prevSlide() + } + + window.addEventListener('wheel', handleScroll) + window.addEventListener('keydown', handleKey) + + return () => { + window.removeEventListener('wheel', handleScroll) + window.removeEventListener('keydown', handleKey) + } + }, [current, nextSlide, prevSlide]) + + return ( -
-
-

Work in Progress

-
-
- ); -} +
+ {slides.map((slide, idx) => ( + + {slide} + + ))} +
+ ) +} \ No newline at end of file diff --git a/src/components/Slide.tsx b/src/components/Slide.tsx new file mode 100644 index 0000000..8175606 --- /dev/null +++ b/src/components/Slide.tsx @@ -0,0 +1,25 @@ + +import { motion } from 'framer-motion'; +import { ReactNode } from 'react'; + +type SlideProps = { + children: ReactNode + index: number + currentSlide: number +} + +export default function Slide({ children, index, currentSlide }: SlideProps) { + const isActive = index === currentSlide + + return ( + + {children} + + ) +} diff --git a/src/components/Slide1.tsx b/src/components/Slide1.tsx new file mode 100644 index 0000000..a6fad4f --- /dev/null +++ b/src/components/Slide1.tsx @@ -0,0 +1,106 @@ +'use client' + +import { motion, MotionValue, useTime, useTransform } from 'framer-motion'; +import { useMemo } from 'react'; + +const titles = [ + 'Full Stack Developer', + 'DevOps Engineer', + 'Game Developer', + 'Open Source Contributor', + 'Tech Enthusiast', + 'Gamer', +]; + +function Title({ title, progress, range, ys, os }: { title: string, progress: MotionValue, range: number[], ys: string[], os: number[] }) { + const y = useTransform(progress, range, ys); + const opacity = useTransform(progress, range, os); + + return ( + + {title} + + ); +} + +export default function Slide1() { + const time = useTime(); + + + + const genRanges = useMemo(() => { + const ranges = []; + for (let i = 0; i < titles.length+1; i++) { + const start = i * 1500 + 250 * i; + const end = start + 1500; + ranges.push(start, end); + } + return ranges; + }, []); + + const genYs = useMemo(() => { + const ys = []; + for (let i = 0; i < titles.length; i++) { + ys.push([]); + for (let j = 0; j < titles.length+1; j++) { + if ((j % titles.length) === i) { + ys[i].push('0%', '0%'); // Current title + } else if (j < i) { + ys[i].push('100%', '100%'); // Previous titles + } else if (j == i + 1) { + ys[i].push('-100%', '100%'); // Next title + } else { + ys[i].push('100%', '100%'); // Titles after next + } + } + } + return ys; + }, []); + + const genOs = useMemo(() => { + const os = []; + for (let i = 0; i < titles.length; i++) { + os.push([]); + for (let j = 0; j < titles.length+1; j++) { + if ((j % titles.length) === i) { + os[i].push(1, 1); // Current title + } else if (j < i) { + os[i].push(0, 0); // Previous titles + } else if (j == i + 1) { + os[i].push(0, 0); // Next title + } else { + os[i].push(0, 0); // Titles after next + } + } + } + return os; + }, []); + + const progress = useTransform(time, (t) => ((t * 2) % genRanges[genRanges.length - 2])); + + // + + return ( + <> +

I'm Kay

+
+ {titles.map((title, i) => ( + + ))} + </div> + </> + ) +} \ No newline at end of file diff --git a/src/components/Slide2.tsx b/src/components/Slide2.tsx new file mode 100644 index 0000000..f2a9244 --- /dev/null +++ b/src/components/Slide2.tsx @@ -0,0 +1,8 @@ + +export default function Slide2() { + return ( + <div> + + </div> + ) +} \ No newline at end of file diff --git a/src/components/Slide3.tsx b/src/components/Slide3.tsx new file mode 100644 index 0000000..a932854 --- /dev/null +++ b/src/components/Slide3.tsx @@ -0,0 +1,8 @@ + +export default function Slide3() { + return ( + <div> + + </div> + ) +} \ No newline at end of file diff --git a/src/components/Slide4.tsx b/src/components/Slide4.tsx new file mode 100644 index 0000000..8de6590 --- /dev/null +++ b/src/components/Slide4.tsx @@ -0,0 +1,8 @@ + +export default function Slide4() { + return ( + <div> + + </div> + ) +} \ No newline at end of file diff --git a/src/components/Slide5.tsx b/src/components/Slide5.tsx new file mode 100644 index 0000000..fb1d863 --- /dev/null +++ b/src/components/Slide5.tsx @@ -0,0 +1,8 @@ + +export default function Slide5() { + return ( + <div> + + </div> + ) +} \ No newline at end of file