From 002b071c72b944ce7936e315470a1a49c2a39f72 Mon Sep 17 00:00:00 2001 From: imnyang Date: Sat, 21 Jun 2025 01:54:34 +0900 Subject: [PATCH] =?UTF-8?q?Seperator=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EC=97=90=EC=84=9C=20=EC=82=AC=EC=9A=A9,=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/page.tsx | 216 +++++++++++++++++++++++------------ src/components/Projects.tsx | 2 +- src/components/Seperator.tsx | 5 + src/index.css | 6 +- src/index.tsx | 92 +++++++++------ 5 files changed, 208 insertions(+), 113 deletions(-) create mode 100644 src/components/Seperator.tsx diff --git a/src/app/page.tsx b/src/app/page.tsx index 84eaf49..5f08d48 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -4,115 +4,179 @@ import Image from "@/profile.avif"; import Timeline from "@/components/TimeLine"; import Contact from "@/components/Contact"; import Projects from "@/components/Projects"; +import Seperator from "@/components/Seperator"; export function Page() { const [age, setAge] = useState(0); const [post, setPost] = useState({}); - useEffect(() => { - const scrollToHash = () => { - const hash = window.location.hash.substring(1); - if (hash) { - const element = document.getElementById(hash); - if (element) { - setTimeout(() => { - element.scrollIntoView({ behavior: "smooth" }); - }, 100); - } - } - }; - scrollToHash(); + useEffect(() => { + const scrollToHash = () => { + const hash = window.location.hash.substring(1); + if (hash) { + const element = document.getElementById(hash); + if (element) { + setTimeout(() => { + element.scrollIntoView({ behavior: "smooth" }); + }, 100); + } + } + }; + scrollToHash(); }, []); useEffect(() => { // 나이 계산 - const referenceDate = new Date(2010, 10, 8); // 2010년 11월 8일 (0-indexed) + const referenceDate = new Date(2010, 10, 8); const currentDate = new Date(); let calculatedAge = currentDate.getFullYear() - referenceDate.getFullYear(); + if (currentDate < new Date(currentDate.getFullYear(), referenceDate.getMonth(), referenceDate.getDate())) { calculatedAge -= 1; } + setAge(calculatedAge); }, []); useEffect(() => { // 블로그 데이터 가져오기 - fetch("https://api.imnya.ng/rss") - .then(response => response.json()) - .then(data => { - if (data) setPost(data[0] || {}); - }) - .catch(error => console.error("Error fetching posts:", error)); + const fetchBlogData = async () => { + try { + const response = await fetch("https://api.imnya.ng/rss"); + const data = await response.json(); + if (data) { + setPost(data[0] || {}); + } + } catch (error) { + console.error("Error fetching posts:", error); + } + }; + + fetchBlogData(); }, []); return (
-

me@imnya.ng

+
+

+ + me@imnya.ng + +

+
-

- 항상 새로운 것을 찾고 삶을 더 간단명료하게 만들고 있는 학생 개발자 남현석입니다. -

+
+

+ 항상 새로운 것을 찾고 삶을 더{" "} + 간단명료하게 만들고 있는 학생 개발자{" "} + 남현석입니다. +

-

- 만든 것들은{" "} - - Two Hearts - ,{" "} - - 오늘 인천상정중학교 - ,{" "} - - Dynamic Kawaii - 이런 것들이 있습니다. -

- - - -

- {age}살의 어린 나이지만, 저는 항상 최적의 코드를 목표로 하며,
- 사용자 경험을 중심적으로 고민합니다.
- 또한 새로운 기술에 대한 관심이 높습니다. -

-

- 초등학교 시절 운영체제에 흥미를 느껴 컴퓨터를 시작했고, - 이후 프로그래밍에 관심을 갖게 되었습니다.
- 초등학교 4학년 때 Python으로 프로그래밍을 시작했으며, - 현재는 TypeScript를 주로 사용합니다.
- 최근에는 정보보안 분야 중 웹 해킹에 관심이 많습니다. -

+

+ 만든 것들은{" "} + + Two Hearts + + ,{" "} + + 오늘 인천상정중학교 + + ,{" "} + + Dynamic Kawaii + {" "} + 이런 것들이 있습니다. +

+
-
- 기술 스택 -
+
+ + 프로필 이미지 + +
-
+
+

+ {age}살의 어린 나이지만, 저는 항상{" "} + 최적의 코드를 목표로 하며, +
+ 사용자 경험을 중심적으로 고민합니다. +
+ 또한 새로운 기술에 대한 관심이 높습니다. +

-

- 최근 블로그 글 :{" "} - - {post.title} - -

+

+ 초등학교 시절 운영체제에 흥미를 느껴 컴퓨터를 시작했고, + 이후 프로그래밍에 관심을 갖게 되었습니다. +
+ 초등학교 4학년 때 Python으로 프로그래밍을 시작했으며, + 현재는 TypeScript를 주로 사용합니다. +
+ 최근에는 정보보안 분야 중 웹 해킹에 관심이 많습니다. +

+
-
+
+
+ 기술 스택 +
+
+ {post.title && ( +
+

+ 최근 블로그 글:{" "} + + {post.title} + +

+
+ )} + + - -
- - + -
- +
diff --git a/src/components/Projects.tsx b/src/components/Projects.tsx index 0c0adb0..a7ba00f 100644 --- a/src/components/Projects.tsx +++ b/src/components/Projects.tsx @@ -29,7 +29,7 @@ const projects = [ export default function Projects() { return ( -
+
{projects.map((project, index) => ( diff --git a/src/components/Seperator.tsx b/src/components/Seperator.tsx new file mode 100644 index 0000000..b5dd564 --- /dev/null +++ b/src/components/Seperator.tsx @@ -0,0 +1,5 @@ +export default function Seperator() { + return ( +
+ ) +} \ No newline at end of file diff --git a/src/index.css b/src/index.css index dffe22c..e3305db 100644 --- a/src/index.css +++ b/src/index.css @@ -1,4 +1,5 @@ -@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+KR&family=Noto+Color+Emoji&display=swap'); +/*@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+KR&family=Noto+Color+Emoji&display=swap');*/ +@import url("https://cdn.jsdelivr.net/gh/wanteddev/wanted-sans@v1.0.3/packages/wanted-sans/fonts/webfonts/variable/split/WantedSansVariable.min.css"); @import "../styles/globals.css"; @layer base { @@ -17,7 +18,8 @@ } * { - font-family: 'IBM Plex Sans KR', sans-serif; + /*font-family: 'IBM Plex Sans KR', sans-serif;*/ + font-family: "Wanted Sans Variable", "Wanted Sans", -apple-system, BlinkMacSystemFont, system-ui, "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif; } .font-ntype { diff --git a/src/index.tsx b/src/index.tsx index 79b7703..49514e7 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,41 +3,65 @@ import index from "./index.html"; // Parse command line arguments for port const args = process.argv.slice(2); -const portArgIndex = args.findIndex(arg => arg === "--port"); -const port = portArgIndex !== -1 && args[portArgIndex + 1] ? - parseInt(args[portArgIndex + 1]) : 3000; +const portArgIndex = args.findIndex((arg) => arg === "--port"); +const defaultPort = + portArgIndex !== -1 && args[portArgIndex + 1] + ? parseInt(args[portArgIndex + 1]) + : 3000; - -const server = serve({ - port: port, - routes: { - // Serve index.html for all unmatched routes. - "/*": index, - "/timeline": Response.redirect("/#timeline"), - "/ads.txt": new Response( - "google.com, pub-4588517451789913, DIRECT, f08c47fec0942fa0", - { - headers: { - "content-type": "text/plain", +// Function to find available port +async function findAvailablePort(startPort: number): Promise { + let port = startPort; + while (port < 65535) { + try { + const testServer = serve({ + port: port, + fetch() { + return new Response("test"); }, - }, - ), - }, - - development: process.env.NODE_ENV !== "production" && { - // Enable browser hot reloading in development - hmr: true, - - // Echo console logs from the browser to the server - console: true, - }, -}); - -console.clear(); -if (process.env.NODE_ENV !== "production") { - console.log(`\x1b[45m Dev \x1b[0m\x1b[35m Bun v${Bun.version}\x1b[0m`); -} else { - console.log(`\x1b[0m\x1b[35m Bun v${Bun.version}\x1b[0m`); + }); + testServer.stop(); + return port; + } catch (error) { + port++; + } + } + throw new Error("No available port found"); } -console.log(`\n\x1b[34m→ \x1b[35m${server.url}\x1b[0m`); +(async () => { + const port = await findAvailablePort(defaultPort); + + const server = serve({ + port: port, + routes: { + // Serve index.html for all unmatched routes. + "/*": index, + "/timeline": Response.redirect("/#timeline"), + "/ads.txt": new Response( + "google.com, pub-4588517451789913, DIRECT, f08c47fec0942fa0", + { + headers: { + "content-type": "text/plain", + }, + } + ), + }, + + development: process.env.NODE_ENV !== "production" && { + // Enable browser hot reloading in development + hmr: true, + + // Echo console logs from the browser to the server + console: true, + }, + }); + + console.clear(); + if (process.env.NODE_ENV !== "production") { + console.log(`\x1b[45m Dev \x1b[0m\x1b[35m Bun v${Bun.version}\x1b[0m`); + } else { + console.log(`\x1b[0m\x1b[35m Bun v${Bun.version}\x1b[0m`); + } + console.log(`\n\x1b[34m→ \x1b[35m${server.url}\x1b[0m`); +})();