기존의 페이지
내가 만든 페이지
우측 드랍박스 만들다가 하루가 다 갔다
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에 도전해보겠다