diff --git a/public/1500x500.jpg b/public/1500x500.jpg deleted file mode 100644 index b5ef0d3..0000000 Binary files a/public/1500x500.jpg and /dev/null differ diff --git a/public/background/1.avif b/public/background/1.avif deleted file mode 100644 index c40b70d..0000000 Binary files a/public/background/1.avif and /dev/null differ diff --git a/public/background/10.avif b/public/background/10.avif deleted file mode 100644 index 07bba24..0000000 Binary files a/public/background/10.avif and /dev/null differ diff --git a/public/background/11.avif b/public/background/11.avif deleted file mode 100644 index c04cb49..0000000 Binary files a/public/background/11.avif and /dev/null differ diff --git a/public/background/12.avif b/public/background/12.avif deleted file mode 100644 index 3c0008e..0000000 Binary files a/public/background/12.avif and /dev/null differ diff --git a/public/background/13.avif b/public/background/13.avif deleted file mode 100644 index 5349006..0000000 Binary files a/public/background/13.avif and /dev/null differ diff --git a/public/background/14.avif b/public/background/14.avif deleted file mode 100644 index e533667..0000000 Binary files a/public/background/14.avif and /dev/null differ diff --git a/public/background/2.avif b/public/background/2.avif deleted file mode 100644 index c2e74c7..0000000 Binary files a/public/background/2.avif and /dev/null differ diff --git a/public/background/3.avif b/public/background/3.avif deleted file mode 100644 index 9b9b8bb..0000000 Binary files a/public/background/3.avif and /dev/null differ diff --git a/public/background/4.avif b/public/background/4.avif deleted file mode 100644 index 846c9b5..0000000 Binary files a/public/background/4.avif and /dev/null differ diff --git a/public/background/5.avif b/public/background/5.avif deleted file mode 100644 index 261193e..0000000 Binary files a/public/background/5.avif and /dev/null differ diff --git a/public/background/6.avif b/public/background/6.avif deleted file mode 100644 index fbbb8cf..0000000 Binary files a/public/background/6.avif and /dev/null differ diff --git a/public/background/7.avif b/public/background/7.avif deleted file mode 100644 index b386682..0000000 Binary files a/public/background/7.avif and /dev/null differ diff --git a/public/background/8.avif b/public/background/8.avif deleted file mode 100644 index 2e9792f..0000000 Binary files a/public/background/8.avif and /dev/null differ diff --git a/public/background/9.avif b/public/background/9.avif deleted file mode 100644 index a5f4cf2..0000000 Binary files a/public/background/9.avif and /dev/null differ diff --git a/public/char.avif b/public/char.avif deleted file mode 100644 index ea2d596..0000000 Binary files a/public/char.avif and /dev/null differ diff --git a/public/full.webp b/public/full.webp new file mode 100644 index 0000000..d9a2387 Binary files /dev/null and b/public/full.webp differ diff --git a/public/test.avif b/public/test.avif deleted file mode 100644 index 8f17b54..0000000 Binary files a/public/test.avif and /dev/null differ diff --git a/public/window.png b/public/window.png new file mode 100644 index 0000000..b21a683 Binary files /dev/null and b/public/window.png differ diff --git a/src/app/globals.css b/src/app/globals.css index 0fe5445..b8898e1 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -182,4 +182,18 @@ .image-scale:hover { z-index:10; box-shadow:0 15px 45px #0006 +} + +/* Fullscreen Scroll Snap */ +html { + scroll-behavior: smooth; +} + +body { + scroll-snap-type: y mandatory; +} + +.snap-section { + scroll-snap-align: start; + scroll-snap-stop: always; } \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index 210341e..fcf6a70 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -3,45 +3,46 @@ import Projects from "@/components/Projects"; import TimelineComponent from "@/components/timeline"; import Top from "@/components/Top"; import Image from "next/image"; +import DraggableWindow from "@/components/DraggableWindow"; +import ReadmeWindow from "@/components/ReadmeWindow"; export default async function BlogIndex() { return ( -
- {/*
-
- logo -

- me@imnya.ng -

-
-
- - test image - -
-
*/} - -
-
-

πŸ’• About

-

였직 ν˜ΈκΈ°μ‹¬κ³Ό μ‹€ν–‰λ ₯으둜만 μ„±μž₯ν•΄ 온 개발자, μ •λ³΄λ³΄μ•ˆμ „λ¬Έκ°€ λ‚¨ν˜„μ„μž…λ‹ˆλ‹€.

+
+
+ logo +

+ me@imnya.ng +

+
+
+ +
+

λ‚˜μ˜ 어두움이 λ‹€λ₯Έ μ‚¬λžŒλ“€μ—κ² 빛이 되길 λ°”λΌλŠ” 개발자, μ •λ³΄λ³΄μ•ˆμ „λ¬Έκ°€ λ‚¨ν˜„μ„μž…λ‹ˆλ‹€.

μ΄ˆλ“±ν•™κ΅ μ‹œμ ˆ μš΄μ˜μ²΄μ œμ— ν₯λ―Έλ₯Ό 느껴 컴퓨터λ₯Ό μ‹œμž‘ν–ˆκ³ , 이후 ν”„λ‘œκ·Έλž˜λ°μ— 관심을 κ°–κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

μ΄ˆλ“±ν•™κ΅ 4ν•™λ…„ λ•Œ Python으둜 ν”„λ‘œκ·Έλž˜λ°μ„ μ‹œμž‘ν–ˆμœΌλ©°, ν˜„μž¬λŠ” TypeScriptλ₯Ό 주둜 μ‚¬μš©ν•©λ‹ˆλ‹€.

μ΅œκ·Όμ—λŠ” μ •λ³΄λ³΄μ•ˆ λΆ„μ•Ό 쀑 μ›Ή 해킹에 관심이 λ§ŽμŠ΅λ‹ˆλ‹€.


-

λŒ€ν‘œμ μΈ ν”„λ‘œμ νŠΈλ“€μ€ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

+
+

λŒ€ν‘œμ μΈ ν”„λ‘œμ νŠΈλ“€μ€ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

+
+ + +
+
+

Β© 2025 HyunSuk Nam. All rights reserved.

+

이 μ›Ήμ‚¬μ΄νŠΈμ˜ 일뢀 μ΄λ―Έμ§€λŠ” μƒμ„±ν˜• 인곡지λŠ₯을 톡해 μ œμž‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

+
+
- - -
); diff --git a/src/components/DraggableWindow.tsx b/src/components/DraggableWindow.tsx new file mode 100644 index 0000000..13618b6 --- /dev/null +++ b/src/components/DraggableWindow.tsx @@ -0,0 +1,95 @@ +'use client'; + +import { useState, useRef, useEffect } from 'react'; +import Image from 'next/image'; +import { useIsMobile } from '@/hooks/use-mobile'; + +export default function DraggableWindow() { + const isMobile = useIsMobile(); + const [isVisible, setIsVisible] = useState(true); + const [position, setPosition] = useState({ x: 100, y: 100 }); + const [isDragging, setIsDragging] = useState(false); + const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 }); + const windowRef = useRef(null); + + const handleMouseDown = (e: React.MouseEvent) => { + setIsDragging(true); + if (windowRef.current) { + const rect = windowRef.current.getBoundingClientRect(); + setDragOffset({ + x: e.clientX - rect.left, + y: e.clientY - rect.top, + }); + } + }; + + useEffect(() => { + const handleMouseMove = (e: MouseEvent) => { + if (!isDragging) return; + + setPosition({ + x: e.clientX - dragOffset.x, + y: e.clientY - dragOffset.y, + }); + }; + + const handleMouseUp = () => { + setIsDragging(false); + }; + + if (isDragging) { + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + } + + return () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + }, [isDragging, dragOffset]); + + return ( + isMobile ? ( +
+ + Banner + +
+ ) : ( + isVisible && ( +
+
+ Draggable Window +
+
+ ) + ) + ); +} diff --git a/src/components/Projects.tsx b/src/components/Projects.tsx index 50f37f7..5e70a13 100644 --- a/src/components/Projects.tsx +++ b/src/components/Projects.tsx @@ -1,4 +1,5 @@ import { SquareArrowOutUpRight } from 'lucide-react'; +import { url } from 'node:inspector'; {/* Effect Playing Contest 2025 Broadcast Develop
today.isangjeong */} @@ -18,6 +19,13 @@ const projects = [ detail: '였늘의 급식을 μ‚¬μ§„μœΌλ‘œ κ³΅μœ ν•˜λŠ” μΈμŠ€νƒ€κ·Έλž¨ κ³„μ •μž…λ‹ˆλ‹€. 맀일 학ꡐ 급식을 μžλ™μœΌλ‘œ μ •λ¦¬ν•˜μ—¬ μ œκ³΅ν•©λ‹ˆλ‹€.', tags: ['TypeScript', 'igramapi', '@napi-rs/canvas'], }, + { + name: 'NYL', + url: 'https://nyl.ny64.kr', + desc: 'μƒμœ„ ν˜Έν™˜', + detail: 'μ „κ΅­μ˜ μ€‘κ³ λ“±ν•™κ΅μ˜ μ‹œκ°„ν‘œμ™€ 급식을 μ‰½κ²Œ 확인할 수 μžˆλŠ” 앱을 μœ μ§€λ³΄μˆ˜ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.', + tags: ['React Native', 'ElysiaJS'] + } ]; export default function Projects() { diff --git a/src/components/ReadmeWindow.tsx b/src/components/ReadmeWindow.tsx new file mode 100644 index 0000000..74398a3 --- /dev/null +++ b/src/components/ReadmeWindow.tsx @@ -0,0 +1,21 @@ +'use client'; + +import { useState, useRef, useEffect } from 'react'; +import { useReadmeWaka } from '@/hooks/use-readme-waka'; + +export default function ReadmeWindow() { + const { wakaContent, isLoading, error } = useReadmeWaka(); + + if (!wakaContent) return null; + + return ( +
+
+

WakaTime Stats

+
+                    {wakaContent.replace(/```(txt)?/g, '')}
+                
+
+
+ ); +} diff --git a/src/hooks/use-readme-waka.ts b/src/hooks/use-readme-waka.ts new file mode 100644 index 0000000..d91b3f0 --- /dev/null +++ b/src/hooks/use-readme-waka.ts @@ -0,0 +1,40 @@ +import { useState, useEffect } from 'react'; + +export function useReadmeWaka() { + const [wakaContent, setWakaContent] = useState(''); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchWakaContent = async () => { + try { + const response = await fetch( + 'https://raw.githubusercontent.com/imnyang/imnyang/refs/heads/main/README.md' + ); + if (!response.ok) throw new Error('Failed to fetch README'); + + const text = await response.text(); + const startMarker = ''; + const endMarker = ''; + + const startIdx = text.indexOf(startMarker); + const endIdx = text.indexOf(endMarker); + + if (startIdx !== -1 && endIdx !== -1) { + const content = text.slice(startIdx + startMarker.length, endIdx).trim(); + setWakaContent(content); + } else { + setError('Could not find waka section'); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'Unknown error'); + } finally { + setIsLoading(false); + } + }; + + fetchWakaContent(); + }, []); + + return { wakaContent, isLoading, error }; +}