포트폴리오를 열심히 가공하고 있는 와중에 갑자기 내 포트폴리오는 디자인만 신경쓰느라 재밌는 요소가 없다는 걸 깨달았다.
'스크롤'을 해서 내용을 보지 않고 '클릭'으로 스택들을 볼 수 있도록 캐러셀로 구현해보기로 마음 먹었다.
원본 UI
초기 계획은 아래 사진처럼 큰 박스에 기술스택 상세내용을 적고, 박스 왼쪽에는 스택 아이콘을 나열해서 아이콘을 클릭하면 해당 스택의 상세내용이 박스에 나타날 수 있도록 구현하고, 이전 화살표를 누르면 이전 스택으로, 다음 화살표를 누르면 다음 스택으로 이동하는 방식으로 구현할 예정이었다.
박스 안에 스택 상세내용 부분은 캐러셀로 만든 다음, 이동 버튼을 누르면 css의 transform을 이용해서 스택 박스가 이동하도록 구현 하였다.
먼저, 박스 안에 기술 스택들을 다 우겨넣는다.
css로 캐러셀을 만들어준다.
// SkillWrapper > SkillDesc > EachCard const SkillWrapper = styled.div` display: flex; width: 300px; height: 400px; overflow: hidden; margin-left: 15px; border: 2px solid #C09984; border-radius: 10px; `; const SkillDesc = styled.div` display: flex; `; const EachCard = styled.div` display: flex; flex-direction: column; width: 300px; height: 400px; `;
EachCard에 transform: translateX();을 넣어주면 캐러셀이 오른쪽이나 왼쪽으로 이동할 것이다.
박스 왼쪽에 스택 아이콘들을 나열해준다.
스택 아이콘을 클릭하면 박스 안에는 클릭한 스택의 상세내용이 보여져야 한다. 그러기 위해서 useReducer로 css의 transform 값을 동적으로 바꿔준다.
(여기서 data는 내가 미리 만들어놓은 기술스택의 데이터들이다.)
{data.map((d) => { <div onClick={() => { dispatch({ type: d.id })} }> 스택 아이콘 </div> })
export const SkillInit = { current: data[0].id, // 1 }; export const SkillReducer = (state, action) => { const WIDTH = -300; switch (action.type) { case 1: return { current: WIDTH * 0, // -300 * 0 }; break; case 2: return { current: WIDTH * 1, // -300 * 1 }; break; case 3: return { current: WIDTH * 2, // -300 * 2 }; break; case 4: return { current: WIDTH * 3, // -300 * 3 }; break; case 5: return { current: WIDTH * 4, // -300 * 4 }; break; case 6: return { current: WIDTH * 5, // -300 * 5 }; break; default: return; break; } };
(1부터 6까지의 숫자를 반복문으로 돌려서 코드를 줄여보려고 했는데 동작하질 않는다. 왜 안되는지 모르겠다.)
↑이렇게 코드를 짠 후, 데이터의 아이디와 맞는 스택의 아이콘을 클릭해보면 그 case에 맞춰서 값이 계산 된다. 예를 들어 css의 데이터 아이디가 2일 때, css 아이콘을 클릭하면 case 2가 실행 되어 -300 곱하기 1이 current 키에 들어간다. 이제 이 current 값을 transform 값에 넘겨주면 된다.
transform을 적용할 요소에 인라인 스타일로 current값을 넣어준다.
<EachCard style={{ transform: `translateX(${state.current}px)` }}>
이전 버튼과 다음 버튼을 클릭 하면 현재 보여지고 있는 스택의 이전 스택으로, 혹은 다음 스택으로 이동할 수 있게 구현해보았다.
이전에 스택 아이콘을 클릭하면 300을 곱하는 값을 반환했다면 이전 다음 버튼은 300을 빼거나 더해주면 된다.
current값에서 300을 빼거나 더해주는데 이 current값이 첫번째 값(0)일때 이전 버튼을 누르면 마지막 스택으로 이동해야하고, 마지막 값(-1500)일때 다음 버튼을 누르면 다시 첫번째 스택으로 이동해야 한다.
export const SkillInit = { current: data[0].id, // 1 }; export const SkillReducer = (state, action) => { const WIDTH = -300; switch (action.type) { ... case 'PREV': return { current: state.current === 0 ? -1500 : state.current + Math.abs(WIDTH), }; break; case 'NEXT': return { current: state.current === -1500 ? 0 : state.current - Math.abs(WIDTH), }; break; default: return; break; } };
예를 들어, 첫번째 스택 html이 보여지고 있는 상태에서 이전 버튼을 누르면 마지막 스택인 Sass으로 가야한다. 즉, 현재 current의 값이 0일때, 이전 버튼을 누르면 current값이 더해지는 것이 아니라 바로 -1500으로 바뀌어야 한다. 그리고 나머지 스택들은 현재 스택의 값에서 이전 스택으로 이동할때는 +300을 해주면 된다.
state.current === 0 ? -1500 : state.current + Math.abs(WIDTH)
다음 버튼을 클릭하는 것도 똑같이 동작하며, 다른점이 있다면 다음 버튼은 값을 더하는 것이 아니고 빼줘야한다.
current: state.current === -1500 ? 0 : state.current - Math.abs(WIDTH)
구현 한 것은 정말 마음에 드는데 큰 화면에서 포트폴리오를 볼 때 양쪽 여백이 너무 커서 비어보이는 것이다.😑
그래서 더 보기 깨끗하게 다시 만들 예정이다. 아쉽긴 하지만 캐러셀을 만드는 건 하룻밤밖에 안 걸렸기 때문에 괜찮다! 아쉽지 않다!~!