#4 [REACT.JS] 에디터 구현하기-1
간간히 진행해오던 Nerator 프로젝트에서, 사용자 명함 디자인을 조금 더 자유롭게 조작할 수 있도록 하기 위해 에디터 기능을 직접 개발해보기로 했다.
단순히 텍스트를 입력받아 출력하는 기능에서 벗어나, 사용자가 직접 디자인 요소들을 배치하고 커스터마이징할 수 있도록 하는 것이 이번 구현의 핵심 목표였다.
주요 기능 정의
- 앞면 / 뒷면 구분
- 앞/뒤 면에 따라 속성의 좌표(x, y)를 따로 관리해야 한다.
- UI 상에서도 손쉽게 전환되며 편집할 수 있어야 한다.
- 명함 사이즈 설정 가능
- 사용자가 원하는 사이즈를 직접 입력 가능해야 함
- 디자인 이미지 업로드
- 명함 앞면, 뒷면에 각각 다른 이미지를 업로드하여 미리보기에 반영
- Drag & Drop으로 속성 배치
- 좌표 직접 입력이 아닌, 시각적으로 끌어다 놓는 방식 제공
- 실시간 미리보기 제공
- 배치된 상태가 어떻게 출력될지 바로 확인할 수 있어야 함
- (2차 개발 예정) PDF 저장, 프린트 출력
UI 구성 방향
에디터의 기본 UI 구조는 아래와 같다:
- 왼쪽: 명함 편집 영역 (이미지 + 배치된 속성들)
- 오른쪽: 명함 설정 영역 (크기, 이미지 업로드, 속성 관리 등)
설정 → 반영 → 미리보기 구조로 빠르게 피드백을 받을 수 있도록 구성했다.
1. 명함 사이즈 설정 기능
사용자가 입력한 가로/세로 값을 실시간으로 적용되도록 하기 위해, React의 상태로 값을 관리하고 명함 컴포넌트에 props로 넘겨 스타일에 바로 반영되도록 구성했다.
INPUT 박스에서 값이 변경될 때마다 handleChangeForm 함수를 통해 state로 관리할 수 있도록 해준다.
const handleChangeForm = useCallback(
(parent, e) => {
const { name, value } = e.target;
setForm({
...form,
[parent]: {
...form[parent],
[name]: value,
},
});
},
[form]
);
form 객체는 단일 구조가 아니라 부모-자식 관계를 가진 중첩된 JSON 구조라, 변경하려는 영역의 parent 키와 name 키를 함께 넘겨서 처리하는 방식이다.
명함 자체는 아래와 같이 크기를 적용받는다.
이렇게 이미지의 크기가 변경되면 바로 반영될 수 있도록 해당 명함 카드 컴포넌트에 form의 사이즈를 넘겨줬다.
const Card = styled.div`
width: ${({ size }) => size.w}px;
height: ${({ size }) => size.h}px;
background: white;
`;
Card는 이 props를 받아 바로 크기가 변경되도록 해준다.
2. 앞면 / 뒷면 이미지 업로드
명함에는 앞/뒷면이 있기 때문에, 각각의 이미지를 따로 관리해야 한다.
input의 id 값으로 구분해서 form.image.front, form.image.back 구조로 저장하도록 구성했다.
<div className="child">
<div className="name">앞면</div>
<div className="value">
<input
type={"file"}
id={"front"}
onChange={handleUploadNameTag}
/>
</div>
</div>
<div className="child">
<div className="name">뒷면</div>
<div className="value">
<input
type={"file"}
id={"back"}
onChange={handleUploadNameTag}
/>
</div>
</div>
const handleUploadNameTag = (e) => {
const item = { id: e.target.id, data: e.target.files[0] };
setForm({ ...form, image: { ...form.image, [e.target.id]: item } });
};
그 후 에디터에서 어떤 면을 편집하고 있는지 나타내는 editorView 상태에 따라 이미지를 조건부 렌더링한다.
file의 id 값을 가져와 form에 front, back마다 다른 이미지파일을 가지고 있도록 해줬다.
이제 사용자가 앞/뒤 버튼을 누를때마다 이 이미지를 보여줘야하므로
<Image
data-key="1"
src={
form.image[editorView]?.data &&
URL.createObjectURL(form.image[editorView]?.data)
}
draggable={false}
/>
front와 back 을 관리해주는 editorView가 있다. 이 editorView state 값으로 어떤 이미지 파일을 뿌려주게 해줄지 설정해주는 코드다.
이후 개발 예정 기능
- 속성 Drag & Drop 배치 기능
- 속성별 폰트 / 정렬 / 스타일 설정
- PDF 저장 or 프린트 출력 기능
- 명함 템플릿 저장 및 불러오기 기능
기획 당시에는 단순한 명함 출력 도구 정도로 시작했지만,
직접 배치와 커스터마이징이 가능한 에디터를 구현하다 보니 점점 더 사용자 경험에 집중하게 되었다.
개발자 입장에서 구현 난이도는 다소 올라가지만, 사용자 관점에서는 훨씬 직관적이고 강력한 기능을 제공할 수 있다는 점에서 의미 있는 방향이라 생각했다.
다음엔 속성 Drag & Drop 기능 개발기를 정리해볼 예정이다.