diff --git a/bun.lock b/bun.lock index 1c680c4..bb3ab7c 100644 --- a/bun.lock +++ b/bun.lock @@ -4,10 +4,11 @@ "": { "name": "imnyang", "dependencies": { + "@radix-ui/react-accordion": "^1.2.3", "@radix-ui/react-dropdown-menu": "^2.1.6", "@radix-ui/react-scroll-area": "^1.2.3", "@radix-ui/react-tooltip": "^1.1.8", - "@tailwindcss/vite": "^4.0.5", + "@tailwindcss/vite": "^4.0.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.475.0", @@ -177,8 +178,12 @@ "@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="], + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collapsible": "1.1.3", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A=="], + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg=="], + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw=="], + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw=="], "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="], @@ -269,33 +274,33 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.6", "", { "os": "win32", "cpu": "x64" }, "sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w=="], - "@tailwindcss/node": ["@tailwindcss/node@4.0.5", "", { "dependencies": { "enhanced-resolve": "^5.18.0", "jiti": "^2.4.2", "tailwindcss": "4.0.5" } }, "sha512-ffTz4DX1cgr4XPuqjhm32YV6Lyx58R1CxAAnSFTamg6wXwfk3oWdb6exgAbGesPzvUgicTO0gwUdQGSsg4nNog=="], + "@tailwindcss/node": ["@tailwindcss/node@4.0.6", "", { "dependencies": { "enhanced-resolve": "^5.18.0", "jiti": "^2.4.2", "tailwindcss": "4.0.6" } }, "sha512-jb6E0WeSq7OQbVYcIJ6LxnZTeC4HjMvbzFBMCrQff4R50HBlo/obmYNk6V2GCUXDeqiXtvtrQgcIbT+/boB03Q=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.0.5", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.0.5", "@tailwindcss/oxide-darwin-arm64": "4.0.5", "@tailwindcss/oxide-darwin-x64": "4.0.5", "@tailwindcss/oxide-freebsd-x64": "4.0.5", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.5", "@tailwindcss/oxide-linux-arm64-gnu": "4.0.5", "@tailwindcss/oxide-linux-arm64-musl": "4.0.5", "@tailwindcss/oxide-linux-x64-gnu": "4.0.5", "@tailwindcss/oxide-linux-x64-musl": "4.0.5", "@tailwindcss/oxide-win32-arm64-msvc": "4.0.5", "@tailwindcss/oxide-win32-x64-msvc": "4.0.5" } }, "sha512-iWGyOCu0TuzvCBisWbGv2K9+7QCfE0ztgtrZOvb9iF7V7ChVkD15Obe3HevZrhjngAc34jDA+OMSuSvkrpTy4A=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.0.6", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.0.6", "@tailwindcss/oxide-darwin-arm64": "4.0.6", "@tailwindcss/oxide-darwin-x64": "4.0.6", "@tailwindcss/oxide-freebsd-x64": "4.0.6", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.6", "@tailwindcss/oxide-linux-arm64-gnu": "4.0.6", "@tailwindcss/oxide-linux-arm64-musl": "4.0.6", "@tailwindcss/oxide-linux-x64-gnu": "4.0.6", "@tailwindcss/oxide-linux-x64-musl": "4.0.6", "@tailwindcss/oxide-win32-arm64-msvc": "4.0.6", "@tailwindcss/oxide-win32-x64-msvc": "4.0.6" } }, "sha512-lVyKV2y58UE9CeKVcYykULe9QaE1dtKdxDEdrTPIdbzRgBk6bdxHNAoDqvcqXbIGXubn3VOl1O/CFF77v/EqSA=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.0.5", "", { "os": "android", "cpu": "arm64" }, "sha512-kK/ik8aIAKWDIEYDZGUCJcnU1qU5sPoMBlVzPvtsUqiV6cSHcnVRUdkcLwKqTeUowzZtjjRiamELLd9Gb0x5BQ=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.0.6", "", { "os": "android", "cpu": "arm64" }, "sha512-xDbym6bDPW3D2XqQqX3PjqW3CKGe1KXH7Fdkc60sX5ZLVUbzPkFeunQaoP+BuYlLc2cC1FoClrIRYnRzof9Sow=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.0.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vkbXFv0FfAEbrSa5NBjFEE+xi06ha7mxuxjY8LRn7d7/tBGrAZOEJnnsEbB6M1+x2pGRTjjei0XyTIXdVCglJA=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.0.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-1f71/ju/tvyGl5c2bDkchZHy8p8EK/tDHCxlpYJ1hGNvsYihZNurxVpZ0DefpN7cNc9RTT8DjrRoV8xXZKKRjg=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.0.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-PedA64rHBXEa4e6abBWE4Yj4gHulfPb5T+rBNnX+WGkjjge5Txa2oS99TLmJ5BPDkXXqz/Ba7oweWIDDG7i5NQ=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.0.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-s/hg/ZPgxFIrGMb0kqyeaqZt505P891buUkSezmrDY6lxv2ixIELAlOcUVTkVh245SeaeEiUVUPiUN37cwoL2g=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.0.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-silz3nuZdEYDfic3v/ooVUQChj9hbxDSee43GCQNwr/iD9L4K/JsZtoNqr0w69pUkvWcKINOGOG0r7WqUqkAeg=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.0.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Z3Wo8FWZnmio8+xlcbb7JUo/hqRMSmhQw8IGIRoRJ7GmLR0C+25Wq+bEX/135xe/yEle2lFkhu9JBHd4wZYiig=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-ElneG75XS64B9I2G83A/Hc7EtNVOD5xahs7avq0aeW7mEX6CtMc8m8RCXMn3jGhz8enFE52l6QU0wO7iVkEtXQ=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.0.6", "", { "os": "linux", "cpu": "arm" }, "sha512-SNSwkkim1myAgmnbHs4EjXsPL7rQbVGtjcok5EaIzkHkCAVK9QBQsWeP2Jm2/JJhq4wdx8tZB9Y7psMzHYWCkA=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.0.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-8yoXpWTeIFaByUaKy2qRAppznLVaDHP9xYCAbS3FG7+uUwHi8CHE4TcomM7eyamo0U7dbUIDgKMGoAX5s2iVrA=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.0.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-tJ+mevtSDMQhKlwCCuhsFEFg058kBiSy4TkoeBG921EfrHKmexOaCyFKYhVXy4JtkaeeOcjJnCLasEeqml4i+Q=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.0.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-BDlVSiiJ08GRz9KKnXgaPFs2fkukPF3pym6uK3oWEKW45jKlVGgybLqulcV5nLEqREOuyq4Rn4vnZss4/bbQ/g=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.0.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-IoArz1vfuTR4rALXMUXI/GWWfx2EaO4gFNtBNkDNOYhlTD4NVEwE45nbBoojYiTulajI4c2XH8UmVEVJTOJKxA=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.0.5", "", { "os": "linux", "cpu": "x64" }, "sha512-DYgieNDRkTy69bWPgdsc47nAXa74P63P/RetUwYM9vYj5USyOfHCEcqIthkCuYw3dXKBhjgwe697TmL2g2jpAw=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.0.6", "", { "os": "linux", "cpu": "x64" }, "sha512-QtsUfLkEAeWAC3Owx9Kg+7JdzE+k9drPhwTAXbXugYB9RZUnEWWx5x3q/au6TvUYcL+n0RBqDEO2gucZRvRFgQ=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.0.5", "", { "os": "linux", "cpu": "x64" }, "sha512-z2RzUvOQl0ZqrZqmCFP53tJbBXQ3UmLD/E6J7+q0e+4VaFnXCcIYTfQbHgI8f3fash+q6gK80Ko/ywEQ+bvv6Q=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.0.6", "", { "os": "linux", "cpu": "x64" }, "sha512-QthvJqIji2KlGNwLcK/PPYo7w1Wsi/8NK0wAtRGbv4eOPdZHkQ9KUk+oCoP20oPO7i2a6X1aBAFQEL7i08nNMA=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.0.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-ho1dJ4o5Q8nAOxdMkbfBu5aSqI+/bzQ0jEeHcXaEdEJzf2fSWs3HY7bIKtE6vQS8c4SmSBvls7IhGPuJxNg+2Q=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.0.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-+oka+dYX8jy9iP00DJ9Y100XsqvbqR5s0yfMZJuPR1H/lDVtDfsZiSix1UFBQ3X1HWxoEEl6iXNJHWd56TocVw=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.0.5", "", { "os": "win32", "cpu": "x64" }, "sha512-yjw6JhtyDXr+G0aZrj3L3NlEV7CobSqOdPyfo6G3d91WEZ5b8PyGm86IAreX08Jp9DChGXEd53gWysVpWCTs+w=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.0.6", "", { "os": "win32", "cpu": "x64" }, "sha512-+o+juAkik4p8Ue/0LiflQXPmVatl6Av3LEZXpBTfg4qkMIbZdhCGWFzHdt2NjoMiLOJCFDddoV6GYaimvK1Olw=="], - "@tailwindcss/vite": ["@tailwindcss/vite@4.0.5", "", { "dependencies": { "@tailwindcss/node": "^4.0.5", "@tailwindcss/oxide": "^4.0.5", "lightningcss": "^1.29.1", "tailwindcss": "4.0.5" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-/i4hjLTUYVjUG0MTUviQP3HR/hzwyzv8Sq4sz2pnsNuf+FIjjhJB0vcnIMH1KIX0k8ozD6CBv2Dl76tlm/JFFA=="], + "@tailwindcss/vite": ["@tailwindcss/vite@4.0.6", "", { "dependencies": { "@tailwindcss/node": "^4.0.6", "@tailwindcss/oxide": "^4.0.6", "lightningcss": "^1.29.1", "tailwindcss": "4.0.6" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-O25vZ/URWbZ2JHdk2o8wH7jOKqEGCsYmX3GwGmYS5DjE4X3mpf93a72Rn7VRnefldNauBzr5z2hfZptmBNtTUQ=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], @@ -659,6 +664,10 @@ "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], + "@tailwindcss/node/tailwindcss": ["tailwindcss@4.0.6", "", {}, "sha512-mysewHYJKaXgNOW6pp5xon/emCsfAMnO8WMaGKZZ35fomnR/T5gYnRg2/yRTTrtXiEl1tiVkeRt0eMO6HxEZqw=="], + + "@tailwindcss/vite/tailwindcss": ["tailwindcss@4.0.6", "", {}, "sha512-mysewHYJKaXgNOW6pp5xon/emCsfAMnO8WMaGKZZ35fomnR/T5gYnRg2/yRTTrtXiEl1tiVkeRt0eMO6HxEZqw=="], + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], diff --git a/package.json b/package.json index a4393d5..38addf7 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,11 @@ "preview": "vite preview" }, "dependencies": { + "@radix-ui/react-accordion": "^1.2.3", "@radix-ui/react-dropdown-menu": "^2.1.6", "@radix-ui/react-scroll-area": "^1.2.3", "@radix-ui/react-tooltip": "^1.1.8", - "@tailwindcss/vite": "^4.0.5", + "@tailwindcss/vite": "^4.0.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.475.0", diff --git a/src/components/BottomBar.tsx b/src/components/BottomBar.tsx index a1fdb11..f7c6979 100644 --- a/src/components/BottomBar.tsx +++ b/src/components/BottomBar.tsx @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; import { Send, AlignJustify, BadgeCheck, House, CircleHelp, ChartGantt, PhoneCall } from "lucide-react"; -import { Link, useLocation } from "react-router"; +import { Link, useLocation, useNavigate } from "react-router"; import { DropdownMenu, @@ -14,6 +14,7 @@ import { export default function BottomBar() { const location = useLocation(); + const navigate = useNavigate(); const [email, setEmail] = useState('me@imnya.ng'); @@ -34,11 +35,19 @@ export default function BottomBar() { randomEmail(); }, []); + return (
{email} +
+ + + + + +
@@ -46,43 +55,73 @@ export default function BottomBar() { - - {location.hash === "#top" ? ( - - ) : ( - - )} - Home + +
+ {location.hash === "#top" ? ( + + ) : ( + + )} + Home +
+ +

Alt + 1

- - {location.hash === "#about" ? ( - - ) : ( - - )} - About + +
+ {location.hash === "#about" ? ( + + ) : ( + + )} + About +
+ +

Alt + 2

- - {location.hash === "#timeline" ? ( - - ) : ( - - )} - Timeline + +
+ {location.hash === "#project" ? ( + + ) : ( + + )} + Project +
+ +

Alt + 3

- - {location.hash === "#contact" ? ( - - ) : ( - - )} - Contact + +
+ {location.hash === "#timeline" ? ( + + ) : ( + + )} + Timeline +
+ +

Alt + 4

+ +
+ + +
+ {location.hash === "#contact" ? ( + + ) : ( + + )} + Contact +
+ +

Alt + 5

diff --git a/src/components/Home/About.tsx b/src/components/Home/About.tsx index 7fe3a01..0a8571c 100644 --- a/src/components/Home/About.tsx +++ b/src/components/Home/About.tsx @@ -2,38 +2,6 @@ import { useEffect, useState, useRef } from "react"; import { Link } from "react-router"; export default function About() { - const [count, setCount] = useState(0); - const [isVisible, setIsVisible] = useState(false); - const aboutRef = useRef(null); - - useEffect(() => { - const observer = new IntersectionObserver( - ([entry]) => { - if (entry.isIntersecting) { - setIsVisible(true); - } - }, - { threshold: 0.1 } - ); - - if (aboutRef.current) { - observer.observe(aboutRef.current); - } - - return () => { - if (aboutRef.current) { - observer.unobserve(aboutRef.current); - } - }; - }, []); - - useEffect(() => { - if (isVisible && count < 15) { - const timer = setTimeout(() => setCount(count + 1), count === 0 ? 600 : 25); - return () => clearTimeout(timer); - } - }, [isVisible, count]); - const [posts, setPosts] = useState([]); useEffect(() => { @@ -55,15 +23,11 @@ export default function About() { }, []); return ( -
+
-

About

+

πŸ€” About

μ•ˆλ…•ν•˜μ„Έμš”! μ €λŠ” μ•”λƒ₯μ΄λΌλŠ” μ΄λ¦„μœΌλ‘œ ν™œλ™ν•˜κ³  μžˆλŠ” 학생 개발자 λ‚¨ν˜„μ„μž…λ‹ˆλ‹€.

-

ν˜„μž¬ νŒ€ Sqlare, TEAM ORYGON:IXμ—μ„œ ν™œλ™ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

-
-
- ν˜„μž¬κΉŒμ§€μ˜ μˆ˜μƒ κ²½λ ₯ -

{count}회

+

With Sqlare, TEAM. ORYGON:IX

졜근 λΈ”λ‘œκ·Έ κΈ€ diff --git a/src/components/Home/Project.tsx b/src/components/Home/Project.tsx index ca54a9d..8377e69 100644 --- a/src/components/Home/Project.tsx +++ b/src/components/Home/Project.tsx @@ -2,7 +2,7 @@ export default function Project() { return (
-

Project

+

πŸ“– Project

Soonβ„’

diff --git a/src/components/Home/Timeline.tsx b/src/components/Home/Timeline.tsx index 8b98a50..37e5249 100644 --- a/src/components/Home/Timeline.tsx +++ b/src/components/Home/Timeline.tsx @@ -1,172 +1,214 @@ -import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area" +import { Accordion, AccordionContent, AccordionItem } from "@/components/ui/accordion"; +import * as AccordionPrimitive from "@radix-ui/react-accordion"; +import { Plus } from "lucide-react"; import { Link } from "react-router"; - +import { useEffect, useState, useRef } from "react"; const events = [ - { - date: "2025-01-19", - description: - "2024 Sunrin LOGCON(TeamLog 주졜) 쀑등뢀 3μœ„", - category: "Award", - link: "https://teamlog.kr" - }, - { - date: "2025-01-12", - description: - "2024 Sunrin Layer7 CTF 쀑등뢀 2μœ„", - category: "Award", - link: "https://layer7.kr" - }, - { - date: "2025-01-10", - description: - "선린인터넷고 쀑학생 νŠΉλ³„κ΅μœ‘ 이수", - category: "Education", - link: "https://layer7.kr" - }, - { - date: "2024-12-14", - description: - "2024 κΈ€λ‘œλ²ŒμŠ€νƒ€νŠΈμ—…ν•™κ΅ K-μ²­μ†Œλ…„μŠ€νƒ€νŠΈμ—… κ²½μ§„λŒ€νšŒ μš°μˆ˜μƒ μˆ˜μƒ", - category: "Award", - link: "https://www.ncf.or.kr/projects/'2024-%EA%B8%80%EB%A1%9C%EB%B2%8C%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85%ED%95%99%EA%B5%90-k-%EC%B2%AD%EC%86%8C%EB%85%84%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85-%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C'-%EC%B0%B8%EA%B0%80%EC%9E%90-%EB%AA%A8%EC%A7%91", - }, - { - date: "2024-12-07", - description: "κΈ€λ‘œλ²Œ μŠ€νƒ€νŠΈμ—… 학ꡐ νŒ€ 1μœ„", - category: "Award", - link: "https://ncf.or.kr", - }, - { - date: "2024-12-07", - description: "κΈ€λ‘œλ²Œ μŠ€νƒ€νŠΈμ—… 학ꡐ 개인 μ΅œμš°μˆ˜μƒ", - category: "Award", - link: "https://ncf.or.kr", - }, - { - date: "2024-08-18", - description: "29회 ν•΄ν‚ΉμΊ ν”„ CTF 1μœ„ (고민쀑독)", - category: "Award & Conference", - link: "https://ctf.hackingcamp.org/", - }, - { - date: "2024-08-01", - description: - "κΈ€λ‘œλ²Œ μŠ€νƒ€νŠΈμ—… 학ꡐ 2κΈ° λ² νŠΈλ‚¨ ν•΄μ™Έ μ—°μˆ˜ 데λͺ¨λ°μ΄ λŒ€μƒ (1μœ„)", - category: "Award", - link: "http://ncf.or.kr", - }, - { - date: "2024-05-16", - description: "κΈ€λ‘œλ²Œ μŠ€νƒ€νŠΈμ—… 학ꡐ 2κΈ° 합격", - category: "Education", - link: "http://ncf.or.kr", - }, - { - date: "2024-05-11", - description: "LG AI μ²­μ†Œλ…„ μΊ ν”„ 1κΈ° LG 탐색상 μˆ˜μƒ", - category: "Award", - link: "https://lgaiyouthcamp.or.kr/", - }, - { - date: "2024-05-11", - description: "LG AI μ²­μ†Œλ…„ μΊ ν”„ 1κΈ° 수료", - category: "Award", - link: "https://lgaiyouthcamp.or.kr/", - }, - { - date: "2024-03-24", - description: "Dreamhack #133", - link: "https://dreamhack.io/users/40116/wargame", - }, - { - date: "2023-11-14", - description: "μΈμ²œμƒμ •μ€‘ν•™κ΅ 2023학년도 SW 문제 ν•΄κ²° ν™œλ™ μš°μˆ˜μƒ(2μœ„) μˆ˜μ—¬", - category: "Award", - }, - { - date: "2023-09-02", - description: - "선린인터넷고등학ꡐ 제6회 μ†Œν”„νŠΈμ›¨μ–΄λ‚˜λˆ”μΆ•μ œ Layer7 λΆ€μ„œ κ³Όμ • 이수", - category: "Education", - }, - { - date: "2023-07-24", - description: "ν•œκ΅­μ •λ³΄κΈ°μˆ μ—°κ΅¬μ›μ΄ μ£Όλ„ν•˜λŠ” 사이버 κ°€λ””μ–Έμ¦ˆ λ³΄μ•ˆμΊ ν”„ 수료", - category: "Education", - }, - { - date: "2023-05-15", - description: "ν•œκ΅­ μ½”λ“œνŽ˜μ–΄ μ˜ˆμ„  μ§„μΆœ", - category: "Award", - }, - { - date: "2022-12-20", - description: "2022 SW영재 μ°½μž‘λŒ€νšŒ 은상 μˆ˜μƒ", - category: "Award", - }, - { - date: "2022-09-27", - description: "2022 μ‚Όμ„± μ£Όλ‹ˆμ–΄ SW μ°½μž‘λŒ€νšŒ λ³Έμ„  μ§„μΆœ", - category: "Award", - }, - { - date: "2022-05-23", - description: "2022학년도 μ„μ •μ΄ˆSWμ˜μž¬ν•™κΈ‰ 첫 μˆ˜μ—…", - category: "Education", - }, - { - date: "2022-07-26", - description: "제 14회 λ§‘μ€ν•˜λŠ˜ λ§‘μ€μ›ƒμŒ 곡λͺ¨μ „μ—μ„œ λ§‘μ€μ›ƒμŒμƒ μˆ˜μ—¬", - category: "Award", - }, - { - date: "2021-11-14", - description: "Become a ZEPETO Creator 이수", - category: "Education", - }, - { - date: "2021-05-19", - description: - "μ†Œν”„νŠΈμ›¨μ–΄μ™€ μ „μžμ‹ λ¬Έμ΄ μ£Όκ΄€ν•œ μ†Œν”„νŠΈμ›¨μ–΄μž¬λ‹¨ 꿈찾기 μΊ ν”„ 이수", - category: "Education", - }, - { - date: "2018-01-27", - description: - "제4회 λ§‘μ€ν•˜λŠ˜ λ§‘μ€μ›ƒμŒ 어린이 문예곡λͺ¨μ „μ—μ„œ μœ„λ‹‰μŠ€μƒ(2μœ„) μˆ˜μ—¬", - category: "Award", - }, + { + date: "2025-01-19", + description: + "2024 Sunrin LOGCON(TeamLog 주졜) 쀑등뢀 3μœ„", + category: "Award", + link: "https://teamlog.kr" + }, + { + date: "2025-01-12", + description: + "2024 Sunrin Layer7 CTF 쀑등뢀 2μœ„", + category: "Award", + link: "https://layer7.kr" + }, + { + date: "2025-01-10", + description: + "선린인터넷고 쀑학생 νŠΉλ³„κ΅μœ‘ 이수", + category: "Education", + link: "https://layer7.kr" + }, + { + date: "2024-12-14", + description: + "2024 κΈ€λ‘œλ²ŒμŠ€νƒ€νŠΈμ—…ν•™κ΅ K-μ²­μ†Œλ…„μŠ€νƒ€νŠΈμ—… κ²½μ§„λŒ€νšŒ μš°μˆ˜μƒ μˆ˜μƒ", + category: "Award", + link: "https://www.ncf.or.kr/projects/'2024-%EA%B8%80%EB%A1%9C%EB%B2%8C%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85%ED%95%99%EA%B5%90-k-%EC%B2%AD%EC%86%8C%EB%85%84%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85-%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C'-%EC%B0%B8%EA%B0%80%EC%9E%90-%EB%AA%A8%EC%A7%91", + }, + { + date: "2024-12-07", + description: "κΈ€λ‘œλ²Œ μŠ€νƒ€νŠΈμ—… 학ꡐ νŒ€ 1μœ„", + category: "Award", + link: "https://ncf.or.kr", + }, + { + date: "2024-12-07", + description: "κΈ€λ‘œλ²Œ μŠ€νƒ€νŠΈμ—… 학ꡐ 개인 μ΅œμš°μˆ˜μƒ", + category: "Award", + link: "https://ncf.or.kr", + }, + { + date: "2024-08-18", + description: "29회 ν•΄ν‚ΉμΊ ν”„ CTF 1μœ„ (고민쀑독)", + category: "Award & Conference", + link: "https://ctf.hackingcamp.org/", + }, + { + date: "2024-08-01", + description: + "κΈ€λ‘œλ²Œ μŠ€νƒ€νŠΈμ—… 학ꡐ 2κΈ° λ² νŠΈλ‚¨ ν•΄μ™Έ μ—°μˆ˜ 데λͺ¨λ°μ΄ λŒ€μƒ (1μœ„)", + category: "Award", + link: "http://ncf.or.kr", + }, + { + date: "2024-05-16", + description: "κΈ€λ‘œλ²Œ μŠ€νƒ€νŠΈμ—… 학ꡐ 2κΈ° 합격", + category: "Education", + link: "http://ncf.or.kr", + }, + { + date: "2024-05-11", + description: "LG AI μ²­μ†Œλ…„ μΊ ν”„ 1κΈ° LG 탐색상 μˆ˜μƒ", + category: "Award", + link: "https://lgaiyouthcamp.or.kr/", + }, + { + date: "2024-05-11", + description: "LG AI μ²­μ†Œλ…„ μΊ ν”„ 1κΈ° 수료", + category: "Award & Education", + link: "https://lgaiyouthcamp.or.kr/", + }, + { + date: "2023-11-14", + description: "μΈμ²œμƒμ •μ€‘ν•™κ΅ 2023학년도 SW 문제 ν•΄κ²° ν™œλ™ μš°μˆ˜μƒ(2μœ„) μˆ˜μ—¬", + category: "Award", + }, + { + date: "2023-09-02", + description: + "선린인터넷고등학ꡐ 제6회 μ†Œν”„νŠΈμ›¨μ–΄λ‚˜λˆ”μΆ•μ œ Layer7 λΆ€μ„œ κ³Όμ • 이수", + category: "Education", + }, + { + date: "2023-07-24", + description: "ν•œκ΅­μ •λ³΄κΈ°μˆ μ—°κ΅¬μ›μ΄ μ£Όλ„ν•˜λŠ” 사이버 κ°€λ””μ–Έμ¦ˆ λ³΄μ•ˆμΊ ν”„ 수료", + category: "Education", + }, + { + date: "2023-05-15", + description: "ν•œκ΅­ μ½”λ“œνŽ˜μ–΄ μ˜ˆμ„  μ§„μΆœ", + category: "Award", + }, + { + date: "2022-12-20", + description: "2022 SW영재 μ°½μž‘λŒ€νšŒ 은상 μˆ˜μƒ", + category: "Award", + }, + { + date: "2022-09-27", + description: "2022 μ‚Όμ„± μ£Όλ‹ˆμ–΄ SW μ°½μž‘λŒ€νšŒ λ³Έμ„  μ§„μΆœ", + category: "Award", + }, + { + date: "2022-05-23", + description: "2022학년도 μ„μ •μ΄ˆSWμ˜μž¬ν•™κΈ‰ 첫 μˆ˜μ—…", + category: "Education", + }, + { + date: "2022-07-26", + description: "제 14회 λ§‘μ€ν•˜λŠ˜ λ§‘μ€μ›ƒμŒ 곡λͺ¨μ „μ—μ„œ λ§‘μ€μ›ƒμŒμƒ μˆ˜μ—¬", + category: "Award", + }, + { + date: "2021-11-14", + description: "Become a ZEPETO Creator 이수", + category: "Education", + }, + { + date: "2021-05-19", + description: + "μ†Œν”„νŠΈμ›¨μ–΄μ™€ μ „μžμ‹ λ¬Έμ΄ μ£Όκ΄€ν•œ μ†Œν”„νŠΈμ›¨μ–΄μž¬λ‹¨ 꿈찾기 μΊ ν”„ 이수", + category: "Education", + }, + { + date: "2018-01-27", + description: + "제4회 λ§‘μ€ν•˜λŠ˜ λ§‘μ€μ›ƒμŒ 어린이 문예곡λͺ¨μ „μ—μ„œ μœ„λ‹‰μŠ€μƒ(2μœ„) μˆ˜μ—¬", + category: "Award", + }, ]; - export default function Timeline() { - return ( -
-
-

Timeline (Beta)

- -
+ const [count, setCount] = useState(0); + const [isVisible, setIsVisible] = useState(false); + const TimelineRef = useRef(null); - {Array.from(new Set(events.map(event => new Date(event.date).getFullYear()))).sort((a, b) => b - a).map(year => ( -
-

{year}

- {events.filter(event => new Date(event.date).getFullYear() === year).map((event, index) => ( -
-

{new Date(event.date).toLocaleDateString('ko-KR', { month: '2-digit', day: '2-digit' })}

- {event.link ? ( - {event.description} - ) : ( - {event.description} - )} -
- ))} -
+ useEffect(() => { + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) { + setIsVisible(true); + } + }, + { threshold: 0.1 } + ); + + if (TimelineRef.current) { + observer.observe(TimelineRef.current); + } + + return () => { + if (TimelineRef.current) { + observer.unobserve(TimelineRef.current); + } + }; + }, []); + + useEffect(() => { + if (isVisible && count < events.length) { + const timer = setTimeout(() => setCount(count + 1), count === 0 ? 300 : 25); + return () => clearTimeout(timer); + } + }, [isVisible, count]); + + return ( +
+
+

🌠 Timeline

+

ν˜„μž¬κΉŒμ§€ {count}개의 κ°œμ„±μžˆλŠ” 쑰각듀이 λͺ¨μ˜€μ–΄μš”!

+
+ + {Array.from(new Set(events.map(event => new Date(event.date).getFullYear()))).sort((a, b) => b - a).map(year => ( + + + + {year} + + + + {events.filter(event => new Date(event.date).getFullYear() === year).map((event, index) => ( +
+

{new Date(event.date).toLocaleDateString('en-US', { month: 'short', day: '2-digit' })} ㆍ {event.category}

+ {event.link ? ( + {event.description} + ) : ( + {event.description} + )} +
))} -
- - -
-
- ); + + + ))} + +
+
+ ); } diff --git a/src/components/ui/accordion.tsx b/src/components/ui/accordion.tsx new file mode 100644 index 0000000..cb108df --- /dev/null +++ b/src/components/ui/accordion.tsx @@ -0,0 +1,64 @@ +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Accordion({ + ...props +}: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..cabfbfc --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,76 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/index.css b/src/index.css index f66632a..f0f5051 100644 --- a/src/index.css +++ b/src/index.css @@ -1,9 +1,8 @@ -@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css"); - -@plugin "tailwindcss-animate"; - -@custom-variant dark (&:is(.dark *)); @import "tailwindcss"; +@plugin "tailwindcss-animate"; +@custom-variant dark (&:is(.dark *)); + +@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css"); * { font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif; @@ -93,6 +92,26 @@ --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); + --animate-accordion-down: accordion-down 0.2s ease-out; + --animate-accordion-up: accordion-up 0.2s ease-out; + + @keyframes accordion-down { + from { + height: 0; + } + to { + height: var(--radix-accordion-content-height); + } + } + + @keyframes accordion-up { + from { + height: var(--radix-accordion-content-height); + } + to { + height: 0; + } + } } @layer base { @@ -126,4 +145,8 @@ box-shadow: 0 0 0 1000px hsl(var(--background)) inset !important; -webkit-text-fill-color: hsl(var(--foreground)) !important; } +} + +.fixed-width-number { + font-feature-settings: "tnum"; } \ No newline at end of file diff --git a/src/routes/Home.css b/src/routes/Home.css index fffd3ce..c475dd2 100644 --- a/src/routes/Home.css +++ b/src/routes/Home.css @@ -2,7 +2,6 @@ scroll-snap-type: y mandatory; overflow-y: scroll; height: 100vh; - scroll-behavior: smooth; } .section { scroll-snap-align: start; @@ -11,4 +10,4 @@ flex-direction: column; justify-content: center; align-items: center; -} \ No newline at end of file +}