무작정 벨로그 클론코딩 -1

오늘처음해요·2024년 2월 18일
0

진행하는 팀 플젝과는 별개로 벨로그 클론 코딩을 해보자

드랍박스 구현하기

기존의 페이지

내가 만든 페이지

우측 드랍박스 만들다가 하루가 다 갔다

import { useEffect, useState } from 'react';

const useDetectClose = (elem, initialState) => {
  const [isOpen, setIsOpen] = useState(initialState);

  useEffect(() => {
    const onClick = (e) => {
      if (elem.current && !elem.current.contains(e.target)) {
        setIsOpen(false);
      }
    };
    window.addEventListener('click', onClick);
    return () => {
      window.removeEventListener('click', onClick);
    };
  }, [elem, isOpen]);
  return [isOpen, setIsOpen];
};

export default useDetectClose;
import { useRef } from 'react';
import useDetectClose from '../hooks/useDetectClose';
import arrowIcon from '../assets/icons/arrow_drop_down.svg';

const DropDown = ({ title, menuList }) => {
  const dropDownRef = useRef();
  const [isOpen, setIsOpen] = useDetectClose(dropDownRef, false);

  return (
    <div
      className="dropdown"
      ref={dropDownRef}
      onClick={() => setIsOpen(!isOpen)}
    >
      <button>{title}</button>
      <ul className={[`dropdown-menus`, isOpen ? 'show' : ''].join(' ')}>
        {menuList.map((it, idx) => (
          <div key={idx}>
            <li>{it}</li>
          </div>
        ))}
      </ul>
      <img src={arrowIcon} />
    </div>
  );
};

export default DropDown;

블로그를 참고해서

드랍 박스 외부를 클릭하는 것을 감지하기 위한 커스텀 훅을 만들고

드랍박스를 만들었다

velog에서는 좌측 홈탭이 변할 때 슬라이드 에니메이션을 넣어놨던데 어떻게 구현해야 할 지 좀 고민이 된다

https://github.com/today-is-first/velog-clone


피드 페이지 구현하기

원래 페이지 피드

내가 만든 페이지 피드

뭔가 이상한 점을 발견한 사람도 있을 것이다

이렇게 하면 좀 더 잘보인다
이미지와 preview 텍스트 사이에 공백이 발생한다

아무리 margin:0; padding:0;을 줘도 이 공백은 해결되지 않았다

이유는 img 태그는 기본적으로 인라인 속성이기 때문에
baseline이 존재한다 => baseline 밑으로 내려올 수 있는 알파벳 소문자(ex: g, y) 같은 것들을 정렬을 하기 위해 맨 밑에 여백이 생기게 된다

{
	baseline : top;
    ||
    display : flex;
}

해결하고 싶으면 베이스 라인을 위로 올리던가 display를 바꾸면 된다

수정본


작성하기 페이지 구현하기

원래 페이지

내가 만든 페이지

사실 벨로그 작성하기 페이지의 핵심은 작성하는 글이 바로 오른쪽에 마크다운으로 구현되어서 보여진다는 것이지만

그렇게까지 구현할 생각은 없어서 CRUD를 위한 페이지로 만들었다

좀 까다로웠던 점은 <textarea>로 마크업한 제목이 2줄,3줄 점점 늘어나면 textarea도 따라서 커져야했다

정적인 css만으로는 구현할 수 없었고 react의 도움이 필요했다

import { useState, useEffect, useRef } from 'react';

function AutoResizeText({ placeholder }) {
  const textareaRef = useRef(null);
  const [text, setText] = useState('');

  useEffect(() => {
    const textarea = textareaRef.current;
    if (textarea) {
      textarea.style.height = 'auto';
      textarea.style.height = `${textarea.scrollHeight}px`;
    }
  }, [text]);

  const handleChange = (e) => {
    setText(e.target.value);
  };

  return (
    <textarea
      placeholder={placeholder}
      ref={textareaRef}
      value={text}
      onChange={handleChange}
      style={{ overflowY: 'hidden' }}
      rows="1"
    />
  );
}

export default AutoResizeText;

컴포넌트화를 통해 구현할 수 있었다

클론 코딩하면서 생각난 두 번째 고민은

.new-feed {
  background-color: #121212;
  & textarea,
  & input {
    background-color: #363636;
    color: #f1f3f5;
    font-family: 'Pretendard-Regular';
    resize: none;
    border: none;
    outline: none;
    caret-color: #f1f3f5;
    height: auto;
  }

  & textarea::placeholder {
    color: #f1f3f5be;
  }

  & input::placeholder {
    color: #f1f3f5be;
  }
  & .feed-wrapper {
    background-color: #363636;
    display: flex;
    flex-direction: column;
    max-width: 55rem;
    margin: auto;
    padding: 3.2rem 8rem 6rem;
    & .split {
      margin: 0;
      font-size: 5rem;
      color: #6a6a6a;
    }
    & .feed-title textarea {
      min-width: 55rem;
      font-size: 4rem;
      font-weight: 900;
    }
    & .feed-tags {
      border-bottom: 1px solid rgb(172, 172, 172, 0.2);
      & input {
        min-width: 27rem;
        font-size: 1.8rem;
        margin-bottom: 1.2rem;
      }
    }
    & .feed-content {
      margin: 2rem 0;
      & textarea {
        min-width: 55rem;
        min-height: 100vh;
        font-size: 3rem;
      }
    }
  }
  & .new-feed-footer {
    position: fixed;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 100%;
    max-width: 71rem;
    display: flex;
    justify-content: space-between;
    padding: 1rem;
    align-items: center;
    background-color: #96f2d7;
    font-size: 1.7rem;
    font-weight: 700;
    color: #121212;
    z-index: 100;
    min-height: 5rem;
    box-sizing: border-box;
    padding: 0 3rem;
    & button {
      border: none;
      cursor: pointer;
      background-color: #96f2d7;
      color: #121212;
      font-size: 1.7rem;
      font-weight: 700;
    }
    & .save {
      border: 1px solid #121212;
      border-radius: 0.5rem;
      padding: 0.5rem 1.2rem;
    }
    & .submit {
      margin-left: 2rem;
      background-color: #121212;
      border-radius: 0.5rem;
      color: #96f2d7;
      padding: 0.5rem 1.2rem;
    }
  }
}

한 페이지를 구현하려고 이렇게 많은 css를 쓰는 게 맞나...?
내가 css를 너무 못다루나 라는 생각이 들었다

나름 & 활용해서 최대한 코드 재사용을 해보려고 하는데
익숙치 않은 건지 너무 어렵다


계속 페이지 껍데기만 구현하는 느낌이라 내일부터는 CRUD에 도전해보겠다

0개의 댓글