+
더 멋진 세상을 만들기 위해 노력하는 암냥입니다.
초등학교 시절 운영체제에 흥미를 느껴 컴퓨터를 시작했고, 이후 프로그래밍에 관심을 갖게 되었습니다.
초등학교 4학년 때 Python으로 프로그래밍을 시작했으며, 현재는 TypeScript를 주로 사용합니다.
최근에는 정보보안 분야 중 웹 해킹에 관심이 많습니다.
diff --git a/src/components/Projects.tsx b/src/components/Projects.tsx
index 1a142df..09b991e 100644
--- a/src/components/Projects.tsx
+++ b/src/components/Projects.tsx
@@ -1,31 +1,45 @@
+"use client";
import { SquareArrowOutUpRight } from 'lucide-react';
-import { url } from 'node:inspector';
-
-{/*
Effect Playing Contest 2025 Broadcast Develop
-
today.isangjeong */}
+import React from 'react';
const projects = [
{
name: 'EPC 2025 Broadcast Manager',
- url: 'https://www.youtube.com/@adofaigg',
- desc: '얼불춤 끼얏호우',
+ url: 'https://www.youtube.com/playlist?list=PLZeYZotn5_IOJDek6e35NKzUtJm09yxZD',
+ desc: 'ADOFAI is web-scale',
detail: '달성이 주관하고 ADOFAI.gg가 공동 주최하는 Effect Playing Contest 2025 방송 화면의 대부분의 기능을 개발하였습니다.',
tags: ['React', 'ElysiaJS'],
},
{
- name: 'NYL',
- url: 'https://nyl.ny64.kr',
- desc: '상위 호환',
- detail: '전국의 중고등학교의 시간표와 급식을 쉽게 확인할 수 있는 앱을 유지보수하고 있습니다.',
- tags: ['React Native', 'ElysiaJS']
+ name: 'newsletter',
+ url: 'https://github.com/imnyang/newsletter',
+ desc: 'For Memos',
+ detail: '그저 이메일이 오면 Discord 웹훅으로 포워딩합니다.',
+ tags: ['Rust', 'IMAP']
+ },
+ {
+ name: 'memos-rss',
+ url: 'https://github.com/imnyang/memos-rss',
+ desc: 'For Memos',
+ detail: 'Discord 포럼 채널에 RSS 피드에 올라온 내용을 포워딩합니다.',
+ tags: ['Rust', 'Discord Bot', 'RSS']
+ },
+ {
+ name: 'today.isangjeong',
+ url: 'https://instagram.com/today.isangjeong',
+ desc: 'Instagram Bot',
+ detail: '매일 학교의 급식 메뉴를 자동으로 업로드하는 인스타그램 봇입니다.',
+ tags: ['TypeScript', 'Instagram', '@napi-rs/canvas']
}
];
export default function Projects() {
+ const [visibleCount, setVisibleCount] = React.useState(3);
+
return (
- {projects.map((project, idx) => (
+ {projects.slice(0, visibleCount).map((project, idx) => (
@@ -35,7 +49,7 @@ export default function Projects() {
) : (
- {project.name}
+ {project.name}
)}
{project.desc}
@@ -51,6 +65,14 @@ export default function Projects() {
))}
+ {visibleCount < projects.length && (
+
+ )}
);
}
diff --git a/src/components/dday.tsx b/src/components/dday.tsx
new file mode 100644
index 0000000..54c13de
--- /dev/null
+++ b/src/components/dday.tsx
@@ -0,0 +1,26 @@
+"use client";
+
+interface DDayComponentProps {
+ targetDate: Date;
+ label: string;
+
+}
+
+export default function DDayComponent({ targetDate, label }: DDayComponentProps) {
+ const today = new Date();
+ const diffTime = targetDate.getTime() - today.getTime();
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+
+ const getLabel = () => {
+ if (diffDays > 0) return `D-${diffDays}`;
+ if (diffDays < 0) return `D+${Math.abs(diffDays)}`;
+ return `D-Day`;
+ };
+
+ return (
+
+ {getLabel()}
+ {label} | {targetDate.toDateString()}
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/timeline.tsx b/src/components/timeline.tsx
index 3cfe562..f83936f 100644
--- a/src/components/timeline.tsx
+++ b/src/components/timeline.tsx
@@ -19,8 +19,8 @@ export default function TimelineComponent() {
const filteredEvents = selectedYear
? events.filter(
- (event) => new Date(event.date).getFullYear() === selectedYear
- )
+ (event) => new Date(event.date).getFullYear() === selectedYear
+ )
: [];
return (
@@ -75,6 +75,13 @@ export default function TimelineComponent() {
)}
))}
+ {selectedYear === new Date().getFullYear() && (
+
+
+
✨ | D-{Math.ceil((new Date(new Date().getFullYear() + 1, 0, 1).getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24))}동안 만들어나갈 멋진 것들을 기대해주세요.
+
+
+ )}