06 Projects
06. Projects.jsx — 프로젝트 섹션
이번 단계에서 할 일
프로젝트 목록을 데이터 배열로 관리하고,
map으로 화면에 출력하는 방법을 배웁니다.
피그마 디자인 분석
1│ ─── Projects ──────────────────────────────────── │2│ │3│ ┌──────────────────────┬───────────────────────┐ │4│ │ ● Project 01 │ │ │5│ │ │ │ │6│ │ 동대문구청 │ 이미지 영역 │ │7│ │ │ │ │8│ │ 기술스택 : html,css… │ │ │9│ │ 배포매체 : desktop… │ │ │10│ │ 작업기간 : 2주 │ │ │11│ │ 기여도 : 100% │ │ │12│ │ │ │ │13│ │ [기획서] [깃허브] [페이지] │ │ │14│ └──────────────────────┴───────────────────────┘ │| 요소 | 값 |
|---|---|
| 주황 점 색상 | #f26440 |
| Project 번호 색 | #c7c7c7 |
| 프로젝트 타이틀 | 32px |
| 설명 텍스트 | 18px, #555555 |
| 버튼 배경 | #000000 |
새로운 개념: 데이터와 화면 분리
데이터(배열)와 화면(JSX)을 분리하면:
- 프로젝트가 늘어나도 배열에 항목만 추가하면 됩니다
- 코드가 훨씬 깔끔해집니다
1// 데이터만 따로 (내용)2const PROJECTS = [3 { id: 1, title: '동대문구청', ... },4 { id: 2, title: '두 번째 프로젝트', ... }, // 추가도 쉬움5]6
7// 화면만 따로 (형태)8{PROJECTS.map((project) => (9 <ProjectItem project={project} />10))}STEP 1 — Projects.jsx 작성
1import SectionTitle from './SectionTitle'2
3/* ─── 프로젝트 데이터 (컴포넌트 밖에 위치) ─── */4// 나중에 프로젝트를 추가할 때 이 배열에만 항목을 추가하면 됩니다5const PROJECTS = [6 {7 id: 1,8 number: 'Project 01',9 title: '동대문구청',10 stack: 'html, css, photoshop, figma',11 deploy: 'desktop, mobile',12 period: '2주',13 contribution: '100%',14 browsers: 'Chrome / Edge / Opera / Safari',15 pages: '메인페이지 / 접근성 준수',16 links: {17 plan: '#',18 github: '#',19 live: '#',20 },21 },22 // 프로젝트 추가 시 여기에 객체를 하나 더 작성하세요23]24
25/* ─── 프로젝트 한 항목을 보여주는 컴포넌트 ─── */26const ProjectItem = ({ project }) => {27 return (28 <div className="project-item">29
30 {/* 왼쪽: 설명 */}31 <div className="project-desc">32
33 {/* 번호 (● Project 01) */}34 <div className="project-number">35 <span className="project-dot" />36 <span className="project-number__text">{project.number}</span>37 </div>38
39 {/* 프로젝트 이름 */}40 <h3 className="project-title">{project.title}</h3>41
42 {/* 상세 정보 */}43 <div className="project-info">44 <div className="project-info__row">45 <span className="project-info__label">기술스택 :</span>46 <span>{project.stack}</span>47 </div>48 <div className="project-info__row">49 <span className="project-info__label">배포매체 :</span>50 <span>{project.deploy}</span>51 </div>52 <div className="project-info__row">53 <span className="project-info__label">작업기간 :</span>54 <span>{project.period}</span>55 </div>56 <div className="project-info__row">57 <span className="project-info__label">본인기여도 :</span>58 <span>{project.contribution}</span>59 </div>60 <div className="project-info__row">61 <span className="project-info__label">브라우저 호환성 :</span>62 <span>{project.browsers}</span>63 </div>64 <div className="project-info__row">65 <span className="project-info__label">페이지수 / 특징 :</span>66 <span>{project.pages}</span>67 </div>68 </div>69
70 {/* 버튼 3개 */}71 <div className="project-buttons">72 <a href={project.links.plan} className="project-btn">기획서 보기</a>73 <a href={project.links.github} className="project-btn">깃허브 보기</a>74 <a href={project.links.live} className="project-btn">페이지 보기</a>75 </div>76
77 </div>78
79 {/* 오른쪽: 이미지 자리 */}80 <div className="project-image">81 {/* 실제 이미지가 있으면: <img src="..." alt="..." /> */}82 </div>83
84 </div>85 )86}87
88/* ─── Projects 메인 컴포넌트 ─── */89const Projects = () => {90 return (91 <section className="projects" id="projects">92
93 <SectionTitle94 title="Projects"95 subtitle="끈기와 열정으로 성장하는 오성의입니다."96 />97
98 {/* PROJECTS 배열을 반복해서 ProjectItem을 출력 */}99 {PROJECTS.map((project) => (100 <ProjectItem key={project.id} project={project} />101 ))}102
103 </section>104 )105}106
107export default Projects코드 설명
객체 배열에서 map 사용
1const PROJECTS = [2 { id: 1, title: '동대문구청', ... },3 { id: 2, title: '두 번째 프로젝트', ... },4]5
6{PROJECTS.map((project) => (7 <ProjectItem key={project.id} project={project} />8))}project는 배열의 각 객체 (예:{ id: 1, title: '동대문구청' })project.id,project.title처럼.으로 값에 접근key={project.id}— 각 항목의 고유 번호를 key로 사용
props로 객체 전달
1// 통째로 넘기기2<ProjectItem project={project} />3
4// 컴포넌트 안에서 꺼내 쓰기5const ProjectItem = ({ project }) => {6 return <h3>{project.title}</h3>7}객체 전체를 project 라는 이름으로 전달하면
컴포넌트 안에서 project.title, project.stack 등으로 씁니다.
왜 PROJECTS 를 대문자로?
관례상 변하지 않는 상수 데이터는 대문자로 씁니다.
1const PROJECTS = [...] // 대문자: 변하지 않는 데이터2const [active, setActive] = useState('Home') // 소문자: 변하는 상태STEP 2 — CSS 추가
1/* src/index.css 에 추가 */2
3/* ── Projects ────────────────────────────── */4
5.projects {6 padding: 80px 24px;7}8
9/* 프로젝트 한 항목: 2단 레이아웃 */10.project-item {11 display: grid;12 grid-template-columns: 1fr 1fr; /* 설명 50% : 이미지 50% */13 margin-bottom: 40px;14 border: 1px solid #f0f0f0;15}16
17/* 왼쪽 설명 영역 */18.project-desc {19 padding: 40px;20 background-color: #ffffff;21}22
23/* ● 번호 부분 */24.project-number {25 display: flex;26 align-items: center;27 gap: 8px;28 margin-bottom: 16px;29}30
31/* 주황 점 */32.project-dot {33 display: inline-block;34 width: 7px;35 height: 7px;36 border-radius: 50%; /* 원 모양 */37 background-color: #f26440;38}39
40/* "Project 01" 텍스트 */41.project-number__text {42 font-size: 12px;43 color: #c7c7c7;44}45
46/* 프로젝트 이름 */47.project-title {48 font-size: 32px;49 font-weight: 700;50 color: #000;51 margin-bottom: 24px;52}53
54/* 상세 정보 목록 */55.project-info {56 display: flex;57 flex-direction: column;58 gap: 8px;59 margin-bottom: 32px;60}61
62/* 정보 한 줄 */63.project-info__row {64 display: flex;65 gap: 8px;66 font-size: 18px;67 color: #555555;68}69
70/* 라벨 (기술스택 :) */71.project-info__label {72 min-width: 140px;73 flex-shrink: 0; /* 라벨이 줄어들지 않게 */74}75
76/* 버튼 3개 묶음 */77.project-buttons {78 display: flex;79 gap: 16px;80}81
82/* 검정 버튼 */83.project-btn {84 display: inline-flex;85 align-items: center;86 justify-content: center;87 width: 160px;88 height: 52px;89 background-color: #000;90 color: #fff;91 font-size: 18px;92 transition: background-color 0.2s;93}94
95.project-btn:hover {96 background-color: #333;97}98
99/* 오른쪽 이미지 영역 */100.project-image {101 background-color: #e8e8e8;102 min-height: 447px;103}브라우저 확인
저장 후 브라우저에서:
- “Projects” 큰 제목이 보입니다
- 왼쪽에 프로젝트 설명, 오른쪽에 회색 이미지 자리가 있습니다
- 3개의 검정 버튼이 보입니다
프로젝트 추가하는 방법
PROJECTS 배열에 객체 하나를 추가하면 자동으로 새 항목이 생깁니다.
1const PROJECTS = [2 {3 id: 1,4 title: '동대문구청',5 // ...6 },7 // ↓ 이렇게 추가8 {9 id: 2,10 number: 'Project 02',11 title: '두 번째 프로젝트',12 stack: 'React, CSS',13 deploy: 'web',14 period: '1개월',15 contribution: '80%',16 browsers: 'Chrome / Edge',17 pages: '5페이지',18 links: { plan: '#', github: '#', live: '#' },19 },20]