Community

개발자 99% 커뮤니티에서 수다 떨어요!

← Go back
[일반 부문] ⚡️애니메이션과 🌸반응형 뿜뿜! 싱크로율 일등을 자신하는 트위터입니댜
#twitter_clone
3년 전
161,014
6

1. 결과물 주소:

🚀 배포된 앱 URL: https://twitter.junho.io/landing

🐙 깃허브 레포: https://github.com/junhoyeo/twitter

2. 자기소개:

안녕하세요! 작년에 특성화고 2학년을 자퇴하고 (약간의 우여곡절 끝에) 지금은 초기 스타트업에서 프론트엔드 엔지니어로 일하고 있는 여준호라고 합니다. 페이스북 광고로 컨테스트가 열린다는 소식을 보고 "아닛 애플워치를 준다고?!" 하면서 참여하게 되었습니다.

3. 서비스 소개: 처음에는 단순히 트위터의 UI를 그대로 베끼려고 했었는데요. 뭔가 심심한 느낌이 들어 Framer Motion을 사용해 애니메이션을 조금씩 구현하게 되었어요.

기술 스택은 TypeScript(컴포넌트타이핑으로 개발 효율화)와 Next.js(SSR은 사실상 안쓰게 되었으니...빠른 프론트엔드 개발, 서버시스 함수 작성, Vercel 배포), Recoil(북마크 상태 관리), Framer Motion(애니메이션), Styled Components(스타일링을 위한 CSS-IN-JS 솔루션)로 이루어져 있습니다!

1) 랜딩 페이지

undefined

트위터의 랜딩 페이지를 그대로 클론해서 만들었습니다. 타이포그래피에는 첫 로딩 시 reveal 애니메이션을 추가했습니다. 구글과 깃허브 계정을 사용해서 소셜 로그인할 수 있도록 했습니다(이메일 로그인은 과감하게 뺐습니다 라고 읽고 사실 UI 만들 시간이 부족해서 일단 빠빠이,,,)

2) 홈 페이지

undefined

- 홈 페이지에는 서비스에 있는 모든 트윗 목록이 표시됩니다.
- Framer Motion의 AnimatePresence를 사용해서 투명도와 X축 애니메이션을 더했습니다. 초기 로딩이 끝나면 쫘르륵 아래에서부터 올라옵니다! 🔥
- 데이터를 가져오기 위해 사이트가 로딩 중일 때는 빙글빙글 스피너가 돌아갑니다! 헤헤 이것도 트위터에 있는 디자인을 그대로 구현해 봤습니다(대신 트위터보다 조금 더 빙글빙글 돌지요).
- 다시 보니 위 스크린샷에선 로딩이 되게 오래 걸리게 나오는데... GIF 변환이 잘 안 되었나 봐요🥺

undefined

다른 페이지들과 마찬가지로 이렇게 반응형 레이아웃을 구현해 두었는데요!
- 태블릿에서는 오른쪽 사이드바가 없어지고, 왼쪽 사이드바가 줄어든 형태로 보여집니다.
- 모바일에서는 아래쪽에 탭 바로 collapsed 된 상태를 볼 수 있어요!

3) 트윗 생성

undefined

기존에 있던 폼도 트위터와 동일한 UI로 만들어 보았습니다.

- 입력한 텍스트에 개행이 추가될 때마다 textarea가 넘치는 대신, 높이가 자동으로 늘어나게 했습니다(요건 도무지 구현할 시간이 없어서 오픈소스인 react-textarea-autosize 를 사용했습니다)!
- 사용자가 폼에 포커스하기 전에는 공개 설정 텍스트가 숨겨지도록 했어요.
- 나중에는 트위터처럼 입력하는 글자 수에 따라 동그라미가 점점 채워지는 UI를 더해보려고 합니다.

undefined

아, 그리고 왼쪽 사이드메뉴에서 트윗 버튼을 누르면 나오는 모달로 어디서든 빠르게 아이디어를 남길 수 있답니다!

4) 트윗에 좋아요 누르기

undefined

- 트위터 하면 역시 이 좋아요 애니메이션이죠! 그대로 가져왔습니다 후후
- 애니메이션을 매끄럽게 보여주기 위해서 좋아요에 대한 상태를 3개로 나눴습니다.

  • UNDETERMINED: 좋아요를 누르지 않은 상태
    ANIMATED: 애니메이션이 실행 중인 상태(애니메이션이 자바스크립트를 사용해서 동작하다 보니 타이밍 조절을 위해 이 상태를 코드로 표현할 필요가 생겼습니다)
    LIKED: 처음부터 좋아요가 눌려 있었거나, 애니메이션이 끝나고 좋아요가 눌린 상태
  • 로딩 시점에 좋아요가 눌러져 있지 않은 트윗 - UNDETERMINED
    로딩 시점에 좋아요가 눌러져 있는 트윗 - LIKED
    로딩 시점에 좋아요가 눌러져 있지 않은 트윗에 좋아요를 누른 경우 - UNDETERMINED 👉 ANIMATED 👉 LIKED (애니메이션이 끝나면 그 콜백에서 LIKED로 바뀌는 함수가 있어요!)
    로딩 시점에 좋아요가 눌러져 있는 트윗에서 좋아요를 해제한 경우 - LIKED 👉 UNDETERMINED (해제 애니메이션은 존재하지 않아요)

5) 다른 트윗을 리트윗 하기

undefined

리트윗 대상인 트윗의 정보를 따로 parent 라는 필드에 저장함으로서 빠르게 구현할 수 있었습니다. 자기 자신 또는 상대방이 남긴 트윗을 횟수에 상관없이 계속 리트윗할 수 있게 했어요.

6) 트윗 삭제하기

undefined

후후 여기가 가장 제 마음에 드는 부분입니다! 가장 시간을 많이 쓴 구현 중 하나기도 하고요...🥲

undefined

트윗의 삭제 절차는 두 단계로 이루어집니다.

  • 현재 사용자의 트윗에는 오른쪽 위에 더보기 버튼이 있습니다. 이걸 누르면 바로 아래에 메뉴 목록이 나타납니다. 웹사이트에서 목록이 아닌 곳을 한번 클릭하면 바로 닫힙니다.
  • 메뉴 목록에서 Delete 버튼을 누르면, 화면 오버레이와 함께 Confirm 모달이 표시됩니다. 다시 나타난 빨간색의 Delete 버튼을 눌러 트윗을 찐으로! 삭제하거나, Cancel 버튼을 눌러 삭제를 취소할 수 있습니다.
  • 삭제된 트윗은 위로 슝 날라가며 삭제됩니다(이때의 카타르시스란,,, 깔깔).

7) 트윗 상세 페이지

undefined

Export 버튼을 누르면 나오는 메뉴에서 'Copy link to tweet'을 눌러 해당 트윗에 대한 고정 URL을 복사할 수 있도록 했어요!
트윗 상세페이지에서는 선택된 트윗을 크게 보여주고, 그 아래로는 전체 트윗 목록을 보여주도록 했답니다:)

8) 사용자 프로필 페이지

undefined

사용자 프로필 UI도 만들어 봤습니다! 후후 트위터 체고

9) Explore 탭에서 실시간 뉴스 보기

undefined

서비스에 있던 모든 탭을 구현하기는 어려웠지만, "빨리 구현할 수 있는 건 최대한 다 넣어보자" 라는 생각으로 트위터를 뜯어봤는데요! 그중 가장 살리고 싶었던 탭은 Explore 였습니다.

- 상단 비디오 섹션에 실시간(?) 동영상을 넣어봤습니다.
- 밑에 있는 정보는 네이버 News API를 사용해 받아온 값입니다. Next.js로 만들고 Vercel로 배포했는데, 서버시스 펑션을 사용할 수 있어서 로직은 여기에 넣었습니다.

10) 관심 있는 트윗 북마크 설정하기

undefined

- 로컬 스토리지에 마음에 드는 트윗을 저장하고, 한번에 모아볼 수 있습니다.
- 상태 관리 라이브러리인 Recoil을 사용해서 구현했습니다.

4. 개발 과정:

1) 일단 제가 Firebase Authentication을 기존에 사용해 본 적이 없어서 개발 전에는 약간 겁도 났었는데요(뭔가 복잡하고 테스트하기 어려울 것 같은... 이런 느낌 아시졓...헿) 생각보다 API가 잘 되어 있어서 큰 어려움은 없었습니다!

2) 가장 구현하기 어려웠던 부분은 각각의 트윗 아이템의 더보기 버튼을 눌렀을 때 메뉴를 표시하는 동작이였습니다. 트윗 아이템의 컨테이너 에 `transform: translate(...)` 애니메이션이 적용되어 있는데, 그 자식 트리에 속한 노드에 `position: fixed` 스타일이 적용된 경우 작동하지 않아 모달이 깨지는 문제가 있었습니다. 결국 노가다 끝에 ref를 사용해 애니메이션이 끝날 때마다 `transform`을 `none`으로 초기화해 주는 다소 야매 같은 해결책을 쓰게 되었습니다.

3) Confirm 모달에서도 비슷한 이슈가 있었는데, 이때는 기존 DOM 트리 밖으로 엘리먼트를 뺄 수 있게 해주는...! Portal 컴포넌트를 구현해서 해결했습니다.

5. 앞으로 계획: 저는 평소에도 사이드 프로젝트를 즐기는 편입니다. 하지만 실제 서비스화까지 가본 적은 많지 않은데요. 아마 인증(운영적으로 설정이 귀찮은 소셜 로그인 연동 등...)을 위해서 백엔드 구축에 비용이 많이 들어서 그런 게 아닐까 싶습니다(반성). 이번 기회를 통해 친해진 Firebase를 사용하면, 클라이언트 개발에만 집중할 수 있겠다는 생각이 듭니다!

앞으로도 꾸준히 성장해 나가며 아이디어가 있을 때마다 빠르고 튼튼하게 시도해볼 수 있는 사람이 되겠습니다 ㅎㅎ

6 comments