Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/#162 블록 옵션창 구현 #170

Merged
merged 20 commits into from
Nov 22, 2024

Conversation

pipisebastian
Copy link
Member

@pipisebastian pipisebastian commented Nov 21, 2024

📝 변경 사항

🔍 변경 사항 설명

  • 연규님의 풀리퀘를 풀받은 상태에서 작업했습니다. 연규님 PR 먼저 봐주시면 좋을 것 같아요!
  • 블록 옵션창 구현 -> [...] 버튼을 길게 누르면 드래그기능을, 짧게 누르면 옵션 모달창이 뜨도록 했습니다.
  • useBlockOption hook으로 블록 전환/애니메이션/복제/삭제를 관리하도록 구현했습니다. 새고로침할때도 받아오는거 확인했습니다
  • OptionModal.tsx파일에서는 constants 파일에 정의해놓은 상수값을 활용했는데, 사실 constant값을 완벽하게 활용했다! 라고는 하지 못합니다.. 코드 리팩토링은 추후 개선해보겠습니다.

1. 블록 복제

  • 블록 복제의 경우 sendBlockInsertOperation 로 새로운 블록을 만들고
  • 블록 내부 char들을 sendCharInsertOperation 로 복사합니다.
  • 여기서 sendBlockUpdateOperation 를 해줘서 블록의 속성 (animation, type ... )을 업데이트 해줬습니다.
  • 저는 sendBlockInsertOperation가 내부 스타일까지 복사가 되는 줄 알았는데 prev, next 관계만 넣어주는거였더라구요,,, 그래서 기존에 존재하는 sendBlockUpdateOperation을 사용했는데, 혹시 더 좋은 방식이 있거나, 기존에 생각해두신게 있으시다면 말씀해주세요!

2. 블록 옵션창 위치 계산

  • 블록 옵션창은 사진과 가같이 page 컴포넌트를 벗어날 수 있습니다.
image
  • relative, absolute를 하면 page 내부에 옵션창(모달)이 가려지기에 옵션창(모달)을 fixed으로 해줬고, react portal을 활용했습니다.
  • 그런데 react portal + fixed로 하면 부모요소의 위치를 알 수 없습니다. 여기서 부모요소란 [...] 버튼입니다. [...]버튼을 기준으로 매번 블록 옵션창이 이동해야하기 때문입니다.
  • 부모요소 좌표를 가져오기 위해서는 useRef와 getBoundingClientRect()을 사용하기로 했고, 여기서 page가 위치가 바뀔때마다 매번 블록 옵션창의 위치를 계산하는건 비효율적이라 생각했습니다.
  • 이를 해결하기 위해, 문제가 되는 조건을 아예 빼버리자! 라고 생각했고, 블록 옵션창이 한번 생성되면 위치를 변화시키지 않게 했습니다.
  • 즉, page컴포넌트를 이동시키려하면 블록 옵션창을 닫게 했습니다.
  useEffect(() => {
    const handleClickOutside = (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      const isMainModalClick = modalRef.current?.contains(target);
      const isSubModalClick = subModalRef.current?.contains(target);

      if (!isMainModalClick && !isSubModalClick) {
        setHoveredCategory(null);
        onClose();
      }
    };

    document.addEventListener("mousedown", handleClickOutside); // 외부 다른 영역을 클릭했을때
    document.addEventListener("pointerdown", handleClickOutside); // 뒤에서 설명...

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
      document.removeEventListener("pointerdown", handleClickOutside);
    };
  }, [onClose]);
  • 그런데 여기서 mousedown이벤트만 동작한다면 해당 부분은 잡았을때는 블록 옵션창이 꺼지지 않았습니다. 이는 해당 컴포넌트가 조건이 pointerdown이었기에, mousedown 뿐만아니라 pointerdown 이벤트에서도 같이 등록을 해주었습니다.
image
  • 그렇지만 이게 React스러운 코드일까? 라는 의문이 있습니다.. 이것도 추후 개선해보겠습니다..

🙏 질문 사항

  • 열심히 구현하신 crdt에 숟가락을 슬쩍 얹었습니다..
  • 아직 복제, 삭제 로직은 넣지 않았는데, 전체적으로 문제가 없는지 확인부탁드립니다!

📷 스크린샷 (선택)

블록 애니메이샨 / 블록 타입 전환

2024-11-22.3.54.46.mov

블록 삭제

2024-11-22.4.44.06.mov

블록 복제

2024-11-22.6.01.21.mov

✅ 작성자 체크리스트

  • Self-review: 코드가 스스로 검토됨
  • Unit tests 추가 또는 수정
  • 로컬에서 모든 기능이 정상 작동함
  • 린터 및 포맷터로 코드 정리됨
  • 의존성 업데이트 확인
  • 문서 업데이트 또는 주석 추가 (필요 시)

@pipisebastian pipisebastian added FE 프론트엔드 작업 Feat 새로운 기능 추가나 기존 기능 확장 작업 labels Nov 21, 2024
@pipisebastian pipisebastian self-assigned this Nov 21, 2024
Copy link
Collaborator

@Ludovico7 Ludovico7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다 approve 하겠습니다!

Comment on lines +8 to +16
{ id: "p", label: "p" },
{ id: "h1", label: "h1" },
{ id: "h2", label: "h2" },
{ id: "h3", label: "h3" },
{ id: "ul", label: "ul" },
{ id: "ol", label: "ol" },
{ id: "checkbox", label: "checkbox" },
{ id: "blockquote", label: "blockquote" },
] as { id: ElementType; label: string }[],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분에서 id와 별개로 이름을 h1 -> 제목1, h2 -> 제목2, checkbox -> 체크박스 등으로 한글 이름을 사용하는것도 좋아보입니다!

)}
</ModalPortal>
);
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Collaborator

@hyonun321 hyonun321 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생많으셨습니다. 저희 주요 핵심기능들이 완성되어가고있군요!

저도 좀더 디벨롭 해보겠습니다! 감사합니다.

@@ -72,17 +104,24 @@ export const Block: React.FC<BlockProps> = memo(
style={{
transform: CSS.Transform.toString(transform),
transition,
opacity: isDragging ? 0.5 : 1,
opacity: isDragging ? 0.5 : undefined,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 1이였는데 undefiend가 된 이유가 궁금합니닷!

opacity가 undefined가 되면 없어지는건가요?

label: "삭제",
options: null,
},
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good !!! 👍

@github-actions github-actions bot merged commit 70ea86a into dev Nov 22, 2024
6 checks passed
};

const modifiedListeners = {
...listeners,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 리스너 함수를 가져와서 이벤트를 덮어 쓸 수가 있군요..! 한수 배웠습니다 !

duration: 3,
ease: "linear",
repeat: Infinity,
times: [0, 0.33, 0.66, 1],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 그라데이션 애니메이션 너무 좋습니다! 색상도 고르신것 같은데 배경과 잘 어울리도록 추후 다크모드때 어떻게 변경할지 고민해 봐야겠네요 !

@pipisebastian pipisebastian deleted the Feature/#162_블록_옵션창_구현 branch November 26, 2024 04:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FE 프론트엔드 작업 Feat 새로운 기능 추가나 기존 기능 확장 작업
Projects
None yet
3 participants