✅ 목표
모든 섹션과 컴포넌트가 다양한 디바이스에서 자연스럽게 동작하는지 점검하고,
다크 모드 대응 상태를 확인한 뒤, GitHub와 Vercel을 연동하여 실제 배포를 진행합니다.
sm, md, lg, xl 등의 반응형 유틸리티를 각 섹션과 컴포넌트에 적용flex, grid, gap-x-, gap-y- 등 레이아웃 정렬 요소도 반응형 기준으로 조절darkMode: 'class'가 적용되어 있어야 함 (tailwind.config.js)/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",
content: [
"./src/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {},
},
plugins: [],
};
bg-*, text-*, border-* 등 스타일에 dark: 접두어로 다크 테마 전용 스타일 지정✅ 1. Hero.tsx
export default function Hero() {
return (
<section
id="hero"
className="min-h-screen flex flex-col justify-center items-center text-center px-4 sm:px-6 md:px-12 lg:px-24 bg-white dark:bg-zinc-900"
>
<h1 className="text-4xl sm:text-5xl md:text-6xl font-bold text-zinc-900 dark:text-white mb-4">
안녕하세요, 프론트엔드 개발자입니다.
</h1>
<p className="text-base sm:text-lg md:text-xl text-zinc-700 dark:text-zinc-300 max-w-2xl">
사용자 경험을 최우선으로 생각하며, 성능과 유지보수가 쉬운 코드를 지향합니다.
</p>
</section>
);
}
✅ 2. About.tsx
export default function About() {
return (
<section
id="about"
className="py-20 px-4 sm:px-6 md:px-12 lg:px-24 bg-white dark:bg-zinc-900"
>
<h2 className="text-3xl sm:text-4xl font-bold text-center text-zinc-900 dark:text-white mb-8">
🙋♂️ 소개
</h2>
<p className="text-base sm:text-lg leading-relaxed text-zinc-700 dark:text-zinc-300 max-w-3xl mx-auto text-center">
안녕하세요! 저는 프론트엔드 개발자 승준입니다. React와 Next.js를 기반으로 안정적이고 빠른 사용자 경험을 구현하는 데 집중하고 있습니다.
</p>
</section>
);
}
✅ 3. Projects.tsx (+ ProjectCard 컴포넌트 포함)
📁 Projects.tsx
import { projects } from "@/data/projects";
import ProjectCard from "@/components/ProjectCard";
export default function Projects() {
return (
<section
id="projects"
className="py-20 px-4 sm:px-6 md:px-12 lg:px-24 bg-zinc-50 dark:bg-zinc-800"
>
<h2 className="text-3xl sm:text-4xl font-bold text-center text-zinc-900 dark:text-white mb-12">
📁 프로젝트
</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-8">
{projects.map((project) => (
<ProjectCard key={project.title} {...project} />
))}
</div>
</section>
);
}
📁 ProjectCard.tsx
export default function ProjectCard({ title, description, tags, github, demo, image }: any) {
return (
<div className="bg-white dark:bg-zinc-700 rounded-lg shadow-md dark:shadow-zinc-900 p-6 transition hover:-translate-y-1 hover:shadow-lg dark:hover:shadow-zinc-800">
<img src={image} alt={title} className="w-full h-48 object-cover rounded-md mb-4" />
<h3 className="text-xl font-semibold text-zinc-900 dark:text-white">{title}</h3>
<p className="text-zinc-600 dark:text-zinc-300 mt-2 mb-4">{description}</p>
<ul className="flex flex-wrap gap-2 text-sm mb-4">
{tags.map((tag: string) => (
<li key={tag} className="px-2 py-1 bg-zinc-100 dark:bg-zinc-600 text-zinc-800 dark:text-white rounded-full">
#{tag}
</li>
))}
</ul>
<div className="flex gap-4">
<a href={github} target="_blank" className="text-blue-500 dark:text-blue-300 underline text-sm">GitHub</a>
{demo && (
<a href={demo} target="_blank" className="text-blue-500 dark:text-blue-300 underline text-sm">Demo</a>
)}
</div>
</div>
);
}
✅ 4. Skills.tsx (+ SkillBadge)
📁 Skills.tsx
import { skills } from "@/data/skills";
export default function Skills() {
return (
<section
id="skills"
className="px-4 sm:px-6 md:px-12 lg:px-24 py-20 bg-white dark:bg-zinc-900"
>
<h2 className="text-3xl sm:text-4xl font-bold text-center mb-12 text-zinc-900 dark:text-white">
🛠 기술 스택
</h2>
<ul className="flex flex-wrap justify-center gap-4">
{skills.map((skill) => (
<li
key={skill}
className="bg-zinc-100 dark:bg-zinc-700 text-zinc-800 dark:text-white px-4 py-2 rounded-full text-sm sm:text-base"
>
{skill}
</li>
))}
</ul>
</section>
);
}
✅ 5. Contact.tsx
export default function Contact() {
return (
<section
id="contact"
className="px-4 sm:px-6 md:px-12 lg:px-24 py-20 bg-zinc-50 dark:bg-zinc-800"
>
<h2 className="text-3xl sm:text-4xl font-bold text-center mb-12 text-zinc-900 dark:text-white">
📬 연락하기
</h2>
<form className="max-w-xl mx-auto space-y-4">
<input
type="text"
placeholder="이름"
className="w-full px-4 py-2 rounded bg-white dark:bg-zinc-700 border border-zinc-300 dark:border-zinc-600 text-zinc-800 dark:text-white"
/>
<input
type="email"
placeholder="이메일"
className="w-full px-4 py-2 rounded bg-white dark:bg-zinc-700 border border-zinc-300 dark:border-zinc-600 text-zinc-800 dark:text-white"
/>
<textarea
placeholder="메시지"
className="w-full px-4 py-2 rounded bg-white dark:bg-zinc-700 border border-zinc-300 dark:border-zinc-600 text-zinc-800 dark:text-white h-40 resize-none"
/>
<button
type="submit"
className="w-full bg-zinc-900 text-white dark:bg-white dark:text-zinc-900 font-semibold py-2 px-6 rounded hover:opacity-90"
>
보내기
</button>
</form>
</section>
);
}
✅ 사전 준비
.gitignore, README.md 등 필수 파일 포함 확인✅ Vercel 등록 및 배포
1. https://vercel.com 접속
2. GitHub 계정 연동
3. “New Project” 클릭 → 배포할 GitHub 저장소 선택
4. 프레임워크 자동 감지 (Next.js 선택됨)
5. 설정 그대로 진행 → Deploy
✅ 배포 후 확인할 사항
| 체크 항목 | 설명 |
|---|---|
| ☐ 반응형 레이아웃 | 모바일, 태블릿, 데스크탑 환경에서 UI가 잘 정렬되는지 확인 |
| ☐ 다크 모드 적용 | 시스템 설정 또는 토글을 통해 다크 모드 전환 시 스타일 정상 적용되는지 |
| ☐ 내비게이션 링크 | 각 섹션으로 스크롤 이동이 잘 되는지 |
| ☐ 프로젝트 링크 | GitHub, 데모 링크 등 외부 링크가 정상 작동하는지 |
| ☐ 404 페이지 | 존재하지 않는 주소 접속 시 not-found.tsx가 정상 렌더링되는지 |
| ☐ 빌드 경고/에러 | Vercel 대시보드에서 빌드 로그 확인 (warning이 없는지 체크) |
| ☐ 배포 속도 | 첫 화면 로딩 속도 및 이미지/글자 지연 여부 확인 |
포트폴리오의 완성도를 높이기 위해 디바이스 호환성, 테마 대응, 배포 안정성을 점검했습니다.
Next.js + Tailwind CSS + Vercel 조합으로 프로젝트를 끝까지 마무리하면서 실서비스 형태의 결과물을 얻게 되었습니다.