diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a95436 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.superpowers/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..de6aea6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:alpine +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY . /usr/share/nginx/html +RUN rm /usr/share/nginx/html/Dockerfile /usr/share/nginx/html/nginx.conf /usr/share/nginx/html/docker-compose.yml 2>/dev/null || true diff --git a/css/style.css b/css/style.css index a455dfa..96bdadb 100644 --- a/css/style.css +++ b/css/style.css @@ -5,182 +5,276 @@ html { scroll-behavior: smooth; scroll-padding-top: 64px; } body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-size: 16px; - line-height: 1.6; - color: #333; + line-height: 1.7; + color: #2d2d2d; background: #fff; + -webkit-font-smoothing: antialiased; } -a { color: #333; text-decoration: none; } -a:hover { color: #0066cc; } +a { color: #2d2d2d; text-decoration: none; } +a:hover { color: #0055cc; } img { max-width: 100%; display: block; } /* === Layout === */ -.container { max-width: 800px; margin: 0 auto; padding: 0 24px; } +.container { max-width: 960px; margin: 0 auto; padding: 0 40px; } .section { - padding: 64px 0; + padding: 72px 0; border-bottom: 1px solid #eee; } .section:last-child { border-bottom: none; } .section-title { - font-size: 1.25rem; + font-size: 1.35rem; font-weight: 700; - margin-bottom: 24px; + margin-bottom: 28px; color: #111; + letter-spacing: -0.02em; } /* === Nav === */ .nav { position: sticky; top: 0; - background: rgba(255, 255, 255, 0.95); - backdrop-filter: blur(8px); + background: rgba(255, 255, 255, 0.92); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid #eee; z-index: 100; - padding: 0 24px; + padding: 0 40px; } .nav-inner { - max-width: 800px; + max-width: 960px; margin: 0 auto; display: flex; align-items: center; height: 56px; - gap: 24px; + gap: 28px; } .nav-logo { - font-weight: 700; - font-size: 1rem; + font-weight: 800; + font-size: 1.05rem; margin-right: auto; + letter-spacing: -0.03em; } .nav-link { font-size: 0.875rem; - color: #666; + color: #888; + font-weight: 500; transition: color 0.2s; } .nav-link:hover, .nav-link.active { color: #111; } -.nav-external::after { content: " ↗"; font-size: 0.75rem; } +.nav-external::after { content: " ↗"; font-size: 0.7rem; opacity: 0.6; } /* === Hero === */ .hero { - padding: 80px 0 64px; + padding: 100px 0 72px; text-align: center; } -.hero-name { font-size: 2rem; font-weight: 700; color: #111; } -.hero-role { font-size: 1.1rem; color: #666; margin-top: 8px; } +.hero-name { + font-size: 3rem; + font-weight: 800; + color: #111; + letter-spacing: -0.04em; + line-height: 1.1; +} + +.hero-role { + font-size: 1.2rem; + color: #555; + margin-top: 12px; + font-weight: 400; +} .hero-tags { display: flex; - gap: 8px; + gap: 10px; justify-content: center; - margin-top: 16px; + margin-top: 24px; flex-wrap: wrap; } .tag { - padding: 4px 12px; - border-radius: 4px; + padding: 5px 14px; + border-radius: 6px; font-size: 0.85rem; - background: #f0f0f0; - color: #555; + background: #f4f4f5; + color: #444; + font-weight: 500; } .hero-links { display: flex; gap: 12px; justify-content: center; - margin-top: 24px; + margin-top: 32px; } .btn { - padding: 8px 20px; - border-radius: 6px; + padding: 10px 24px; + border-radius: 8px; font-size: 0.875rem; + font-weight: 500; border: 1px solid #ddd; background: #fff; color: #333; cursor: pointer; - transition: background 0.2s, border-color 0.2s; + transition: all 0.2s; text-decoration: none; display: inline-block; } .btn:hover { background: #f5f5f5; border-color: #bbb; } -.btn-primary { background: #111; color: #fff; border-color: #111; } +.btn-primary { + background: #111; + color: #fff; + border-color: #111; +} .btn-primary:hover { background: #333; } /* === Project Card === */ -.project-list { display: flex; flex-direction: column; gap: 16px; } +.project-list { display: flex; flex-direction: column; gap: 20px; } .project-card { - padding: 20px; - border: 1px solid #eee; - border-radius: 8px; - transition: border-color 0.2s; + padding: 24px; + border: 1px solid #e8e8e8; + border-radius: 12px; + transition: border-color 0.2s, box-shadow 0.2s; +} +.project-card:hover { + border-color: #d0d0d0; + box-shadow: 0 2px 12px rgba(0,0,0,0.04); } -.project-card:hover { border-color: #ccc; } .project-card-header { display: flex; align-items: baseline; gap: 12px; - margin-bottom: 8px; + margin-bottom: 10px; +} +.project-card-name { + font-weight: 700; + font-size: 1.1rem; + color: #111; + letter-spacing: -0.02em; } -.project-card-name { font-weight: 600; font-size: 1.05rem; } .project-card-category { font-size: 0.75rem; - color: #999; + color: #0055cc; + font-weight: 600; + background: #eef4ff; + padding: 2px 8px; + border-radius: 4px; +} +.project-card-desc { + color: #555; + font-size: 0.95rem; + margin-bottom: 14px; + line-height: 1.6; } -.project-card-desc { color: #666; font-size: 0.925rem; margin-bottom: 12px; } .project-card-tags { display: flex; gap: 6px; flex-wrap: wrap; } .project-card-tag { - padding: 2px 8px; - background: #f5f5f5; - border-radius: 3px; + padding: 3px 10px; + background: #f4f4f5; + border-radius: 4px; font-size: 0.8rem; - color: #666; + color: #555; + font-weight: 500; } -.project-card-link { - display: inline-block; - margin-top: 12px; - font-size: 0.85rem; - color: #0066cc; +.project-card-links { + display: flex; + gap: 8px; + margin-top: 16px; + flex-wrap: wrap; } -.project-card-link:hover { text-decoration: underline; } + +.btn-sm { + padding: 6px 14px; + border-radius: 6px; + font-size: 0.8rem; + font-weight: 500; + border: 1px solid #ddd; + background: #fff; + color: #333; + text-decoration: none; + display: inline-block; + transition: all 0.2s; +} +.btn-sm:hover { background: #f5f5f5; border-color: #bbb; color: #111; } /* === Skills === */ -.skills-group { margin-bottom: 20px; } +.skills-group { margin-bottom: 24px; } .skills-group:last-child { margin-bottom: 0; } .skills-group-title { - font-size: 0.8rem; + font-size: 0.75rem; text-transform: uppercase; - letter-spacing: 1px; + letter-spacing: 1.5px; color: #999; - margin-bottom: 8px; + margin-bottom: 10px; + font-weight: 600; } .skills-tags { display: flex; gap: 8px; flex-wrap: wrap; } +/* === Experience === */ +.experience-list { display: flex; flex-direction: column; gap: 16px; } + +.experience-item { + padding: 16px 20px; + border-left: 3px solid #e0e0e0; + transition: border-color 0.2s; +} +.experience-item:hover { border-left-color: #0055cc; } + +.experience-header { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; + margin-bottom: 4px; +} + +.experience-title { + font-weight: 600; + font-size: 1rem; + color: #111; +} + +.experience-period { + font-size: 0.8rem; + color: #999; + white-space: nowrap; +} + +.experience-desc { + color: #666; + font-size: 0.9rem; +} + /* === Sitemap Cards === */ .sitemap-header { text-align: center; - padding: 48px 0 32px; + padding: 56px 0 36px; } -.sitemap-title { font-size: 1.5rem; font-weight: 700; } -.sitemap-subtitle { color: #999; margin-top: 4px; } +.sitemap-title { + font-size: 1.75rem; + font-weight: 800; + letter-spacing: -0.03em; +} +.sitemap-subtitle { color: #888; margin-top: 6px; font-size: 0.95rem; } .sitemap-section-title { - font-size: 0.9rem; + font-size: 0.8rem; text-transform: uppercase; - letter-spacing: 1px; + letter-spacing: 1.5px; color: #999; font-weight: 600; margin-bottom: 16px; @@ -189,14 +283,14 @@ img { max-width: 100%; display: block; } .card-grid { display: grid; grid-template-columns: 1fr 1fr; - gap: 12px; - margin-bottom: 40px; + gap: 14px; + margin-bottom: 48px; } .site-card { - border: 1px solid #eee; - padding: 24px; - border-radius: 10px; + border: 1px solid #e8e8e8; + padding: 28px; + border-radius: 12px; text-align: center; text-decoration: none; color: inherit; @@ -204,18 +298,19 @@ img { max-width: 100%; display: block; } display: block; } .site-card:hover { - border-color: #ccc; - box-shadow: 0 2px 8px rgba(0,0,0,0.04); + border-color: #d0d0d0; + box-shadow: 0 4px 16px rgba(0,0,0,0.06); } -.site-card-icon { font-size: 1.5rem; margin-bottom: 8px; } -.site-card-name { font-weight: 600; font-size: 0.95rem; } -.site-card-desc { color: #999; font-size: 0.8rem; margin-top: 4px; } +.site-card-icon { font-size: 1.75rem; margin-bottom: 10px; } +.site-card-name { font-weight: 700; font-size: 1rem; color: #111; } +.site-card-desc { color: #888; font-size: 0.85rem; margin-top: 6px; } .site-card-sublink { display: inline-block; margin-top: 8px; font-size: 0.75rem; - color: #0066cc; + color: #0055cc; + font-weight: 500; } /* Wrapper to keep card + sublink in one grid cell */ @@ -224,28 +319,31 @@ img { max-width: 100%; display: block; } .infra-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; - gap: 10px; + gap: 12px; } .infra-card { - border: 1px solid #eee; - padding: 16px; - border-radius: 8px; + border: 1px solid #e8e8e8; + padding: 20px; + border-radius: 10px; text-align: center; text-decoration: none; color: #666; background: #fafafa; - transition: border-color 0.2s; + transition: border-color 0.2s, box-shadow 0.2s; display: block; } -.infra-card:hover { border-color: #ccc; } -.infra-card-icon { font-size: 1.2rem; } -.infra-card-name { font-size: 0.85rem; margin-top: 4px; } -.infra-card-desc { font-size: 0.7rem; color: #aaa; margin-top: 2px; } +.infra-card:hover { + border-color: #d0d0d0; + box-shadow: 0 2px 8px rgba(0,0,0,0.04); +} +.infra-card-icon { font-size: 1.3rem; } +.infra-card-name { font-size: 0.85rem; margin-top: 6px; font-weight: 600; color: #444; } +.infra-card-desc { font-size: 0.72rem; color: #aaa; margin-top: 3px; } /* === Footer === */ .footer { - padding: 32px 0; + padding: 40px 0; text-align: center; color: #999; font-size: 0.85rem; @@ -255,11 +353,14 @@ img { max-width: 100%; display: block; } /* === Responsive === */ @media (max-width: 640px) { + .container { padding: 0 20px; } + .nav { padding: 0 20px; } .nav-inner { gap: 16px; } .nav-link { font-size: 0.8rem; } - .hero { padding: 48px 0 40px; } - .hero-name { font-size: 1.5rem; } - .section { padding: 40px 0; } + .hero { padding: 60px 0 48px; } + .hero-name { font-size: 2rem; } + .hero-role { font-size: 1rem; } + .section { padding: 48px 0; } .card-grid { grid-template-columns: 1fr; } .infra-grid { grid-template-columns: 1fr 1fr; } } diff --git a/data/projects.js b/data/projects.js index ae4d26a..2977168 100644 --- a/data/projects.js +++ b/data/projects.js @@ -3,28 +3,43 @@ const projects = [ name: "One of the Plans (A301)", description: "Unity 기반 MMORPG 게임 프로젝트. 멀티플레이어 서버는 Go로 구현.", tags: ["Unity", "C#", "Go"], - link: "https://a301.tolelom.xyz", + links: [ + { label: "a301.tolelom.xyz", url: "https://a301.tolelom.xyz" }, + { label: "GitHub", url: "https://github.com/tolelom" } + ], category: "게임" }, { name: "No-Ill", - description: "노인 낙상 감지 및 외로움 방지를 위한 IoT 장치와 보호자 앱.", + description: "노인 낙상 감지 및 외로움 방지를 위한 IoT 장치와 보호자 앱. 센서 기반 낙상 감지 시스템과 보호자용 모니터링 웹/앱을 개발.", tags: ["React", "Go", "IoT"], - link: "https://no-ill.tolelom.xyz", + links: [ + { label: "no-ill.tolelom.xyz", url: "https://no-ill.tolelom.xyz" }, + { label: "no-ill-app.tolelom.xyz", url: "https://no-ill-app.tolelom.xyz" } + ], category: "헬스케어" }, + { + name: "TOL", + description: "한글 프로그래밍 언어 개발 프로젝트. 3인 팀으로 진행하며 프로그래밍 언어 분야에 흥미를 가지게 된 계기. 순수 C++로 언어를 설계하고 구현.", + tags: ["C++", "Express.js", "MongoDB"], + links: [], + category: "언어 개발" + }, { name: "SION", description: "Jetson 키트를 활용한 자율주행 및 모니터링 웹 페이지.", tags: ["Python", "Jetson", "Web"], - link: "https://sion.tolelom.xyz", + links: [ + { label: "sion.tolelom.xyz", url: "https://sion.tolelom.xyz" } + ], category: "IoT" }, { name: "Neo-Slasher", - description: "Unity 기반 액션 게임 프로젝트.", + description: "게임 개발 동아리 ExP에서 8인 팀으로 진행한 액션 게임. 프로그래밍 디렉터로 데이터 관리, 인터페이스 개발 및 전체 프로그래밍 과정을 담당.", tags: ["Unity", "C#"], - link: null, + links: [], category: "게임" } ]; diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..31f18e4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,6 @@ +services: + web: + build: . + restart: unless-stopped + ports: + - "8080:80" diff --git a/index.html b/index.html index 79af005..1ed982e 100644 --- a/index.html +++ b/index.html @@ -10,14 +10,16 @@ +