This commit is contained in:
imnyang 2024-12-12 22:52:35 +09:00
commit 55a9f0481d
4 changed files with 101 additions and 32 deletions

View file

@ -10,6 +10,7 @@
}, },
"dependencies": { "dependencies": {
"@tippyjs/react": "^4.2.6", "@tippyjs/react": "^4.2.6",
"lucide-react": "^0.468.0",
"next": "15.0.3", "next": "15.0.3",
"react": "19.0.0-rc-66855b96-20241106", "react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106", "react-dom": "19.0.0-rc-66855b96-20241106",

12
pnpm-lock.yaml generated
View file

@ -11,6 +11,9 @@ importers:
'@tippyjs/react': '@tippyjs/react':
specifier: ^4.2.6 specifier: ^4.2.6
version: 4.2.6(react-dom@19.0.0-rc-66855b96-20241106(react@19.0.0-rc-66855b96-20241106))(react@19.0.0-rc-66855b96-20241106) version: 4.2.6(react-dom@19.0.0-rc-66855b96-20241106(react@19.0.0-rc-66855b96-20241106))(react@19.0.0-rc-66855b96-20241106)
lucide-react:
specifier: ^0.468.0
version: 0.468.0(react@19.0.0-rc-66855b96-20241106)
next: next:
specifier: 15.0.3 specifier: 15.0.3
version: 15.0.3(react-dom@19.0.0-rc-66855b96-20241106(react@19.0.0-rc-66855b96-20241106))(react@19.0.0-rc-66855b96-20241106) version: 15.0.3(react-dom@19.0.0-rc-66855b96-20241106(react@19.0.0-rc-66855b96-20241106))(react@19.0.0-rc-66855b96-20241106)
@ -1140,6 +1143,11 @@ packages:
lru-cache@10.4.3: lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lucide-react@0.468.0:
resolution: {integrity: sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
merge2@1.4.1: merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -2905,6 +2913,10 @@ snapshots:
lru-cache@10.4.3: {} lru-cache@10.4.3: {}
lucide-react@0.468.0(react@19.0.0-rc-66855b96-20241106):
dependencies:
react: 19.0.0-rc-66855b96-20241106
merge2@1.4.1: {} merge2@1.4.1: {}
micromatch@4.0.8: micromatch@4.0.8:

View file

@ -38,7 +38,7 @@ export default function Timeline() {
return ( return (
<div> <div>
{events.map((event, index) => ( {events.map((event, index) => (
<div key={index} className="flex flex-row gap-4"> <div key={index} className="flex flex-col gap-4">
<p className="tabular-nums">{event.date}</p> <p className="tabular-nums">{event.date}</p>
{event.link ? <a href={event.link}>{event.description}</a> : event.description} {event.link ? <a href={event.link}>{event.description}</a> : event.description}
</div> </div>

View file

@ -2,13 +2,51 @@
import { useEffect, useState, forwardRef, Ref } from "react"; import { useEffect, useState, forwardRef, Ref } from "react";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import Repos from "./components/repos"; import Link from "next/link";
import Tippy from "@tippyjs/react"; import Tippy from "@tippyjs/react";
import "tippy.js/dist/tippy.css"; import "tippy.js/dist/tippy.css";
import "./index.css"; import "./index.css";
import { Link as LinkIcon } from 'lucide-react';
const events = [
{ date: '2024-12-07', description: '글로벌 스타트업 학교 팀 1위', link: 'https://blog.imnyang.xyz/blog/gss' },
{ date: '2024-12-07', description: '글로벌 스타트업 학교 개인 최우수상', link: 'https://blog.imnyang.xyz/blog/gss' },
{ date: '2024-08-18', description: '29회 해킹캠프 CTF 1위 (고민중독)', link: 'https://ctf.hackingcamp.org/' },
{ date: '2024-08-05', description: '29회 해킹캠프 선발', link: 'https://hackingcamp.org/' },
{ date: '2024-08-01', description: '글로벌 스타트업 학교 2기 베트남 해외 연수 데모데이 대상 (1위)', link: 'http://ncf.or.kr' },
{ date: '2024-05-16', description: '글로벌 스타트업 학교 2기 합격', link: 'http://ncf.or.kr' },
{ date: '2024-05-11', description: 'LG AI 청소년 캠프 1기 LG 탐색상 수상', link: 'https://lgaiyouthcamp.or.kr/' },
{ date: '2024-05-11', description: 'LG AI 청소년 캠프 1기 수료', link: 'https://lgaiyouthcamp.or.kr/' },
{ date: '2024-04-22', description: '@isangjeong.today (인천상정중학교의 오늘 급식)', link: 'https://www.instagram.com/isangjeong.today/' },
{ date: '2024-04-06', description: 'TimeTable (Sekai 개조판 배포) [API 유실]', link: 'https://timeline.imnyang.xyz' },
{ date: '2024-03-24', description: 'Dreamhack #133', link: 'https://dreamhack.io/users/40116/wargame' },
{ date: '2024-03-24', description: 'Ubuntu Mirror', link: 'https://launchpad.net/ubuntu/+mirror/mirror.imnyang.xyz-release' },
{ date: '2024-03-24', description: '내 목소리로 AI Cover 만들기', link: 'https://colab.research.google.com/drive/1a4G4hD9huBeGRZhEL2HNDMpqSuf4y61k?usp=sharing' },
{ date: '2024-01-26', description: 'Fastapi를 통해 API 제작', link: 'https://github.com/imnyang/api' },
{ date: '2023-12-20', description: 'LG AI 청소년 캠프 1기 합격' },
{ date: '2023-11-14', description: '인천상정중학교 2023학년도 SW 문제 해결 활동 우수상(2위) 수여' },
{ date: '2023-11-01', description: '블로그 시작', link: 'https://blog.imnyang.xyz' },
{ date: '2023-10-12', description: '나는 로컬 시간을 알고 싶다', link: 'https://time.imnyang.xyz/' },
{ date: '2023-09-24', description: 'sqlr.kr 기획 및 초기 개발', link: 'https://github.com/sqlare/sqlr.kr/tree/main' },
{ date: '2023-09-02', description: '선린인터넷고등학교 제6회 소프트웨어나늠축제 Layer7 부서 과정 이수' },
{ date: '2023-08-26', description: '컴시간 시간표를 더 나아보이게 Sekai', link: 'https://github.com/imnyang/Sekai' },
{ date: '2023-08-23', description: '디스코드 통화방 녹음', link: 'https://github.com/imnyang/discord-voice-rec'},
{ date: '2023-07-24', description: '한국정보기술연구원이 주도하는 사이버 가디언즈 보안캠프 수료' },
{ date: '2023-03-20', description: '디스코드에서 대화형 인공지능 Siru 제작', link: 'https://github.com/imnyang/siru' },
{ date: '2023-05-15', description: '한국 코드페어 예선 진출' },
{ date: '2023-03-14', description: '타이머', link: 'https://github.com/imnyang/imnyang-timer' },
{ date: '2022-12-20', description: '2022 SW영재 창작대회 은상 수상'},
{ date: '2022-09-27', description: '2022 삼성 주니어 SW 창작대회 본선 진출' },
{ date: '2022-05-23', description: '2022학년도 석정초SW영재학급 첫 수업' },
{ date: '2022-07-26', description: '제 14회 맑은하늘 맑은웃음 공모전에서 맑은웃음상 수여' },
{ date: '2021-11-14', description: 'Become a ZEPETO Creator 이수' },
{ date: '2021-05-19', description: '소프트웨어와 전자신문이 주관한 소프트웨어재단 꿈찾기 캠프 이수' },
{ date: '2018-01-27', description: '제4회 맑은하늘 맑은웃음 어린이 문예공모전에서 위닉스상(2위) 수여' },
];
interface TippyWrapperProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> { interface TippyWrapperProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
children: React.ReactNode; children: React.ReactNode;
ref?: Ref<HTMLAnchorElement>; ref?: Ref<HTMLAnchorElement>;
@ -37,45 +75,47 @@ export default function Home() {
}, []); }, []);
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const [imageSrc, setImageSrc] = useState( const [imageSrc, setImageSrc] = useState("https://f.imnyang.xyz/profile/imnyang.webp");
"https://f.imnyang.xyz/profile/imnyang.webp",
);
const [gotoHref, setGotoHref] = useState("/"); const [gotoHref, setGotoHref] = useState("/");
const [isMobile, setIsMobile] = useState(false); const [isMobile, setIsMobile] = useState(false);
useEffect(() => { useEffect(() => {
setIsMobile(window.innerWidth <= 768);
const handleResize = () => { const handleResize = () => {
setIsMobile(window.innerWidth <= 768); setIsMobile(window.innerWidth <= 768);
}; };
handleResize(); // 초기화 시점에 호출
window.addEventListener('resize', handleResize); window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize);
}, []); }, []);
useEffect(() => { useEffect(() => {
if (searchParams.has("kawaii")) { const updateImageSrc = () => {
setImageSrc("https://f.imnyang.xyz/profile/hatchu_imnyang.webp"); if (searchParams.has("kawaii")) {
setGotoHref("/"); setImageSrc("https://f.imnyang.xyz/profile/hatchu_imnyang.webp");
} else { setGotoHref("/");
setImageSrc("https://f.imnyang.xyz/profile/imnyang.webp"); } else {
setGotoHref("/?kawaii"); setImageSrc("https://f.imnyang.xyz/profile/imnyang.webp");
} setGotoHref("/?kawaii");
if (searchParams.has("no_hair") && searchParams.has("no_ear")) { }
setImageSrc("https://f.imnyang.xyz/profile/no_ear_no_long_hair.png"); if (searchParams.has("no_hair") && searchParams.has("no_ear")) {
} else if (searchParams.has("no_ear")) { setImageSrc("https://f.imnyang.xyz/profile/no_ear_no_long_hair.png");
setImageSrc("https://f.imnyang.xyz/profile/no_ear.png"); } else if (searchParams.has("no_ear")) {
} else if (searchParams.has("no_hair")) { setImageSrc("https://f.imnyang.xyz/profile/no_ear.png");
setImageSrc("https://f.imnyang.xyz/profile/no_hair.avif"); } else if (searchParams.has("no_hair")) {
} setImageSrc("https://f.imnyang.xyz/profile/no_hair.avif");
if (searchParams.has("fast")) { }
const style = document.createElement("style"); if (searchParams.has("fast")) {
style.innerHTML = ` const style = document.createElement("style");
.profile:hover { style.innerHTML = `
animation: rotate 1ms linear infinite; .profile:hover {
} animation: rotate 1ms linear infinite;
`; }
document.head.appendChild(style); `;
} document.head.appendChild(style);
}
};
updateImageSrc();
}, [searchParams]); }, [searchParams]);
interface SocialLinkProps { interface SocialLinkProps {
@ -103,19 +143,35 @@ export default function Home() {
return ( return (
<div className="main"> <div className="main">
<div className="profile flex flex-col items-center gap-4"> <div className="profile flex flex-col items-center gap-4 mt-10 mb-10">
<Image src={imageSrc} width={128} height={128} className="rounded-full avatar" alt="Profile" priority /> <Image src={imageSrc} width={128} height={128} className="rounded-full avatar" alt="Profile" priority />
<h1 className="text-white text-2xl font-bold">hyun._.suk</h1> <h1 className="text-white text-2xl font-bold">hyun._.suk</h1>
<div className="flex flex-row gap-6"> <div className="flex flex-row gap-6">
{isMobile && ( {isMobile && (
<SocialLink href="supertoss://send?bank=토스뱅크&accountNo=100079352039&origin=qr" icon="fa-solid fa-circle-dollar-to-slot" tooltip="Toss" /> <SocialLink href="supertoss://send?bank=토스뱅크&accountNo=100079352039&origin=qr" icon="fa-solid fa-circle-dollar-to-slot" tooltip="Toss" />
)} )}
<SocialLink href="https://github.com/imnyang" icon="fa-brands fa-github" tooltip={`Github | ${userInfo.public_repos} Repos`} /> <SocialLink href={gotoHref} icon="fa-brands fa-github" tooltip={`Github | ${userInfo.public_repos} Repos`} />
<SocialLink href="mailto:me@imnyang.xyz" icon="fa-solid fa-at" tooltip="Mail" /> <SocialLink href="mailto:me@imnyang.xyz" icon="fa-solid fa-at" tooltip="Mail" />
<SocialLink href="https://instagram.com/fur_local" icon="fa-brands fa-instagram" tooltip="Instagram" /> <SocialLink href="https://instagram.com/fur_local" icon="fa-brands fa-instagram" tooltip="Instagram" />
<SocialLink href="https://x.com/fur_local" icon="fa-brands fa-x-twitter" tooltip="X" /> <SocialLink href="https://x.com/fur_local" icon="fa-brands fa-x-twitter" tooltip="X" />
</div> </div>
</div> </div>
<div className="timeline text-white">
{events.map((event, index) => (
<div key={index} className="flex flex-col mb-3">
<p className="tabular-nums">{event.date}</p>
<div className="flex items-center">
{event.link && (
<Link href={event.link} className="flex gap-2">
<LinkIcon width={18} />
<span>{event.description}</span>
</Link>
)}
{!event.link && <span className="ml-7">{event.description}</span>}
</div>
</div>
))}
</div>
</div> </div>
); );
} }