오늘의 목표
- 블로그 grid layout 영역 세부 사항 마무리
수행 내역
- modal 열었을 때 input 영역 focus
- modal 영역 esc, enter keydown event listener 추가
- esc로 모달 창 닫기
- enter 키로 입력 내용 저장
- 모달 창 닫을 때 event listner return
- 모달 영역 스타일 지정 (Mac UI 참고)
import { useEffect, useRef, useState } from 'react';
import { useLogBook } from '../../context/LogBookContext';
const BlogElementModal = ({ item, releaseModal }) => {
const { elements, setElements } = useLogBook();
const currentContent = item ? elements.find((element) => element.i === item.i)?.content : '';
const [modalContent, setModalContent] = useState(currentContent ? currentContent : '');
const inputRef = useRef();
const alertRef = useRef();
useEffect(() => {
if (['title', 'link', 'image'].includes(type)) {
inputRef.current.focus();
}
const handleKeyDown = (e) => {
if (e.key === 'Escape') {
releaseModal();
} else if (e.key === 'Enter') {
handleClickConfirm();
}
};
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [modalContent]);
const handleModalClick = (e) => e.stopPropagation();
const handleChangeInput = (e) => {
setModalContent(e.target.value);
alertRef.current.style.display = 'none';
};
const handleClickConfirm = () => {
if (!modalContent.trim()) {
alertRef.current.style.display = 'block';
inputRef.current.focus();
return;
}
setElements((prev) =>
prev.map((element) =>
element.i === item.i ? { ...element, content: modalContent } : element
)
);
releaseModal();
};
const handleClickCancel = () => releaseModal();
const modalData = {
title: {
title: '제목 블럭의 내용을 입력해 주세요',
placeholder: '제목을 입력하세요',
},
post: {
title: '포스트 블럭의 내용을 입력해 주세요',
placeholder: '포스트 내용을 입력하세요',
},
link: {
title: '블럭에 추가하시려는 링크를 입력해 주세요',
placeholder: '링크를 입력하세요 (예: <https://example.com>)',
},
image: {
title: '이미지의 링크를 입력해 주세요',
placeholder: '이미지 URL을 입력하세요',
},
map: {
title: '지도를 첨부해 주세요',
placeholder: '지도 정보를 입력하세요',
},
};
const type = item?.i.split('-')[0];
const { title, placeholder } = modalData[type] || {};
return (
<div id='BlogElementModal' onClick={handleModalClick}>
<div className='modal-top'>
<img className='modal-icon' src={`/img/icon-${type}.png`} alt='모달 아이콘' />
<button className='close-modal-btn' onClick={releaseModal}>
모달 닫기
</button>
</div>
<div className='modal-inner'>
<h1>{title}</h1>
{['title', 'link', 'image'].includes(type) ? (
<div className='modal-content-area'>
<input
className={`input-${type}-element`}
type='text'
value={modalContent}
onChange={handleChangeInput}
ref={inputRef}
placeholder={placeholder}
/>
<p className='empty-content-alert' ref={alertRef}>
내용을 입력해 주세요
</p>
</div>
) : (
<p>{placeholder}</p>
)}
<ModalBtnArea
handleClickConfirm={handleClickConfirm}
handleClickCancel={handleClickCancel}
/>
</div>
</div>
);
};
const ModalBtnArea = ({ handleClickConfirm, handleClickCancel }) => (
<div className='modal-btn-area'>
<button className='btn-confirm' onClick={handleClickConfirm}>
확인
</button>
<button className='btn-cancel' onClick={handleClickCancel}>
취소
</button>
</div>
);
export default BlogElementModal;
문제 및 이슈
참고자료
지원요청
내일 계획
- 저장 버튼을 이용해 customize 된 블로그 영역의 내용을 (backend가 없으므로 context의 state에 임시로 저장) 다른 페이지 방문 후 다시 돌아와도 유지되도록 저장 기능 구현
- user profile 영역은 userData, grid layout 영역은 blogData
- 타인의 프로필을 클릭했을 때 블로그로 링크 되는 a 태그 생성