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

Refactor/#216 에디터 컴포넌트 리팩토링 #217

Merged
merged 18 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
aa7117e
feat: 순서 리스트 처리를 위한 listIndex 속성 추가
Ludovico7 Nov 26, 2024
2e4e057
feat: 순서 리스트 처리를 위한 전체 순회 메서드 구현
Ludovico7 Nov 26, 2024
1856a28
fix: 아이콘 블록에 해당 블록의 listIndex 사용하도록 수정
Ludovico7 Nov 26, 2024
dbf18cb
feat: 블록 옵션창으로 삭제, 복제 할때도 리스트 순서 관리하도록 수정
Ludovico7 Nov 26, 2024
9ca1659
feat: 키입력 핸들러에 순서 리스트 처리시 순서 조정하도록 수정
Ludovico7 Nov 26, 2024
e7f9899
Merge branch 'dev' into Feature/#011_순서있는_리스트_숫자_구현
Ludovico7 Nov 26, 2024
56735a4
fix: 블록에 글자가 있을때 삭제해도 순서 유지
Ludovico7 Nov 27, 2024
72abe88
refactor: useCopyAndPaste 커스텀 훅으로 분리
Ludovico7 Nov 27, 2024
c6da022
refactor: handleBlockClick, handleBlockInput, handleKeyDown을 useBlock…
Ludovico7 Nov 27, 2024
0d4492d
design: 메뉴 블록 항상 왼쪽 상단에 위치하도록 수정
Ludovico7 Nov 27, 2024
e1d68a5
refactor: 페이지 아이콘 모달 템플릿처럼 보이는 디자인 수정
Ludovico7 Nov 27, 2024
a31ef9f
design: 아이콘 옵션 모달 디자인 수정
Ludovico7 Nov 27, 2024
9b15e86
design: 페이지 타이틀에도 아이콘 보이도록 디자인 수정
Ludovico7 Nov 27, 2024
3e9d248
design: 페이지 컨트롤 버튼 디자인 수정
Ludovico7 Nov 27, 2024
6c733c7
chore: lint 설정
Ludovico7 Nov 27, 2024
55a4885
design: 아이콘 모달 padding 수정
Ludovico7 Nov 27, 2024
f90607c
fix: remote 연산시 순서 리스트 반영 안되는 문제 수정
Ludovico7 Nov 27, 2024
c7c2cb3
design: 피드백 반영해서 아이콘 설명 제거
Ludovico7 Nov 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions @noctaCrdt/Crdt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@
this.LinkedList = new LinkedListClass();
}

localInsert(index: number, value: string, blockId?: BlockId, pageId?: string): any {

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'index' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'value' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'blockId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'pageId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

Unexpected any. Specify a different type

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'index' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'value' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'blockId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'pageId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 29 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

Unexpected any. Specify a different type
// 기본 CRDT에서는 구현하지 않고, 하위 클래스에서 구현
throw new Error("Method not implemented.");
}

localDelete(index: number, blockId?: BlockId, pageId?: string): any {

Check warning on line 34 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'index' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 34 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'blockId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 34 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'pageId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 34 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

Unexpected any. Specify a different type

Check warning on line 34 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'index' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 34 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'blockId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 34 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'pageId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 34 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

Unexpected any. Specify a different type
// 기본 CRDT에서는 구현하지 않고, 하위 클래스에서 구현
throw new Error("Method not implemented.");
}

remoteInsert(operation: any): void {

Check warning on line 39 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'operation' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 39 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'operation' is defined but never used. Allowed unused args must match /^_/u
// 기본 CRDT에서는 구현하지 않고, 하위 클래스에서 구현
throw new Error("Method not implemented.");
}
Expand Down Expand Up @@ -114,7 +114,7 @@
updatedBlock.indent = block.indent;
updatedBlock.style = block.style;
updatedBlock.type = block.type;
// this.LinkedList.nodeMap[JSON.stringify(block.id)] = block;
updatedBlock.listIndex = block.listIndex || undefined;
return { node: updatedBlock, pageId };
}

Expand All @@ -125,7 +125,7 @@
updatedBlock.indent = block.indent;
updatedBlock.style = block.style;
updatedBlock.type = block.type;
// this.LinkedList.nodeMap[JSON.stringify(block.id)] = block;
updatedBlock.listIndex = block.listIndex || undefined;
return { node: updatedBlock, pageId };
}

Expand All @@ -136,14 +136,10 @@
newNode.next = operation.node.next;
newNode.prev = operation.node.prev;
newNode.indent = operation.node.indent;
newNode.listIndex = operation.node.listIndex || undefined;
this.LinkedList.insertById(newNode);

this.clock = Math.max(this.clock, operation.node.id.clock) + 1;
/*
if (this.clock <= newNode.id.clock) {
this.clock = newNode.id.clock + 1;
}
*/
}

remoteDelete(operation: RemoteBlockDeleteOperation): void {
Expand All @@ -153,11 +149,6 @@
this.LinkedList.deleteNode(targetNodeId);
}
this.clock = Math.max(this.clock, clock) + 1;
/*
if (this.clock <= clock) {
this.clock = clock + 1;
}
*/
}

localReorder(params: {
Expand Down
170 changes: 112 additions & 58 deletions @noctaCrdt/LinkedList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,65 +55,9 @@ export abstract class LinkedList<T extends Node<NodeId>> {
delete this.nodeMap[JSON.stringify(id)];
}

reorderNodes({ targetId, beforeId, afterId }: ReorderNodesProps): void {
const targetNode = this.getNode(targetId);
if (!targetNode) return;

// 1. 기존 연결 해제
if (targetNode.prev) {
const prevNode = this.getNode(targetNode.prev);
if (prevNode) {
prevNode.next = targetNode.next;
}
} else {
this.head = targetNode.next;
}

if (targetNode.next) {
const nextNode = this.getNode(targetNode.next);
if (nextNode) {
nextNode.prev = targetNode.prev;
}
}

// 2. 새로운 위치에 연결
if (!beforeId) {
// 맨 앞으로 이동
const oldHead = this.head;
this.head = targetId;
targetNode.prev = null;
targetNode.next = oldHead;

if (oldHead) {
const headNode = this.getNode(oldHead);
if (headNode) {
headNode.prev = targetId;
}
}
} else if (!afterId) {
// 맨 끝으로 이동
const beforeNode = this.getNode(beforeId);
if (beforeNode) {
beforeNode.next = targetId;
targetNode.prev = beforeId;
targetNode.next = null;
}
} else {
// 중간으로 이동
const beforeNode = this.getNode(beforeId);
const afterNode = this.getNode(afterId);

if (beforeNode && afterNode) {
targetNode.prev = beforeId;
targetNode.next = afterId;
beforeNode.next = targetId;
afterNode.prev = targetId;
}
}
updateAllOrderedListIndices() {}

// 노드맵 갱신
this.setNode(targetId, targetNode);
}
reorderNodes({ targetId, beforeId, afterId }: ReorderNodesProps): void {}

findByIndex(index: number): T {
if (index < 0) {
Expand Down Expand Up @@ -299,6 +243,116 @@ export abstract class LinkedList<T extends Node<NodeId>> {
}

export class BlockLinkedList extends LinkedList<Block> {
updateAllOrderedListIndices() {
let currentNode = this.getNode(this.head);
let currentIndex = 1;

while (currentNode) {
if (currentNode.type === "ol") {
const prevNode = currentNode.prev ? this.getNode(currentNode.prev) : null;

if (!prevNode || prevNode.type !== "ol") {
// 이전 노드가 없거나 ol이 아닌 경우 1부터 시작
currentIndex = 1;
} else if (prevNode.indent !== currentNode.indent) {
// indent가 다른 경우
if (currentNode.indent > prevNode.indent) {
// indent가 증가한 경우 1부터 시작
currentIndex = 1;
} else {
// indent가 감소한 경우 같은 indent를 가진 이전 ol의 번호 다음부터 시작
let prevSameIndentNode = prevNode;
while (
prevSameIndentNode &&
(prevSameIndentNode.indent !== currentNode.indent || prevSameIndentNode.type !== "ol")
) {
if (prevSameIndentNode.prev) {
prevSameIndentNode = this.getNode(prevSameIndentNode.prev)!;
} else {
break;
}
}

if (prevSameIndentNode && prevSameIndentNode.type === "ol") {
currentIndex = prevSameIndentNode.listIndex! + 1;
} else {
currentIndex = 1;
}
}
} else {
// 같은 indent의 연속된 ol인 경우 번호 증가
currentIndex = prevNode.listIndex!;
currentIndex += 1;
}

currentNode.listIndex = currentIndex;
}

currentNode = currentNode.next ? this.getNode(currentNode.next) : null;
}
}

reorderNodes({ targetId, beforeId, afterId }: ReorderNodesProps) {
const targetNode = this.getNode(targetId);
if (!targetNode) return;

// 1. 현재 위치에서 노드 제거
if (targetNode.prev) {
const prevNode = this.getNode(targetNode.prev);
if (prevNode) prevNode.next = targetNode.next;
}

if (targetNode.next) {
const nextNode = this.getNode(targetNode.next);
if (nextNode) nextNode.prev = targetNode.prev;
}

if (this.head === targetId) {
this.head = targetNode.next;
}

// 2. 새로운 위치에 노드 삽입
if (!beforeId) {
// 맨 앞으로 이동
const oldHead = this.head;
this.head = targetId;
targetNode.prev = null;
targetNode.next = oldHead;

if (oldHead) {
const headNode = this.getNode(oldHead);
if (headNode) headNode.prev = targetId;
}
} else if (!afterId) {
// 맨 끝으로 이동
const beforeNode = this.getNode(beforeId);
if (beforeNode) {
beforeNode.next = targetId;
targetNode.prev = beforeId;
targetNode.next = null;
}
} else {
// 중간으로 이동
const beforeNode = this.getNode(beforeId);
const afterNode = this.getNode(afterId);

if (beforeNode && afterNode) {
targetNode.prev = beforeId;
targetNode.next = afterId;
beforeNode.next = targetId;
afterNode.prev = targetId;
}
}

// 노드맵 갱신
this.setNode(targetId, targetNode);

// ordered list가 포함된 경우 전체 인덱스 재계산
if (targetNode.type === "ol") {
this.updateAllOrderedListIndices();
}
}

deserializeNodeId(data: any): BlockId {
return BlockId.deserialize(data);
}
Expand Down
3 changes: 3 additions & 0 deletions @noctaCrdt/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export class Block extends Node<BlockId> {
style: string[];
icon: string;
crdt: BlockCRDT;
listIndex?: number;

constructor(value: string, id: BlockId) {
super(value, id);
Expand All @@ -70,6 +71,7 @@ export class Block extends Node<BlockId> {
style: this.style,
icon: this.icon,
crdt: this.crdt.serialize(),
listIndex: this.listIndex ? this.listIndex : null,
};
}

Expand All @@ -84,6 +86,7 @@ export class Block extends Node<BlockId> {
block.style = data.style;
block.icon = data.icon;
block.crdt = BlockCRDT.deserialize(data.crdt);
block.listIndex = data.listIndex ? data.listIndex : null;
return block;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ export const IconBox = css({
borderRadius: "4px",
width: "24px",
height: "24px",

transition: "all 0.1s ease-in-out",
cursor: "pointer",
"&:hover": {
transform: "scale(1.05)",
opacity: 0.8,
transform: "translateY(-2px) scale(1.1)",
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@ import { PageIconType } from "@noctaCrdt/Interfaces";
import { RiCloseLine } from "react-icons/ri";
import { iconGroups, iconComponents } from "@constants/PageIconButton.config";
import { css } from "@styled-system/css";
import {
IconModal,
IconModalContainer,
IconModalClose,
IconName,
IconButton,
} from "./pageIconModal.style";
import { IconModal, IconModalContainer, IconModalClose, IconButton } from "./pageIconModal.style";

export interface PageIconModalProps {
isOpen: boolean;
Expand All @@ -32,11 +26,10 @@ export const PageIconModal = ({ onClose, onSelect, currentType }: PageIconModalP
marginBottom: "12px",
})}
>
<h3 className={IconName}>{group.title}</h3>
<div
className={css({
display: "grid",
gap: "8px",
gap: "12px",
gridTemplateColumns: "repeat(3, 1fr)",
})}
>
Expand All @@ -51,14 +44,6 @@ export const PageIconModal = ({ onClose, onSelect, currentType }: PageIconModalP
className={IconButton(isSelected)}
>
<IconComponent color={color} size="24px" />
<span
className={css({
color: "gray.600",
fontSize: "xs",
})}
>
{iconType}
</span>
</button>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const IconModal = css({
zIndex: 9000,
position: "absolute",
top: 14,
left: 14,
left: 5,
});

export const IconModalContainer = css({
Expand All @@ -13,27 +13,29 @@ export const IconModalContainer = css({
borderRadius: "4px",
width: "100%",
maxHeight: "80vh",
padding: "16px",
padding: "16px 16px 0px 16px",
backgroundColor: "white",
boxShadow: "lg",
overflowY: "auto",
});

export const IconModalClose = css({
display: "flex",
zIndex: 1002,
position: "absolute",
top: "8px",
right: "8px",
top: "-4px",
right: "-4px",
justifyContent: "center",
alignItems: "center",
border: "none",
borderRadius: "md",
width: "24px",
height: "24px",
width: "32px",
height: "32px",
opacity: 0.5,
backgroundColor: "transparent",
cursor: "pointer",
_hover: {
backgroundColor: "gray.100",
opacity: 1,
},
});

Expand All @@ -52,11 +54,12 @@ export const IconButton = (isSelected: boolean) =>
justifyContent: "space-between",
alignItems: "center",
border: "none",
borderRadius: "md",
borderRadius: "4px",
padding: "8px",
backgroundColor: isSelected ? "gray.100" : "transparent",
backgroundColor: isSelected ? "rgba(220, 215, 255, 0.35)" : "transparent",
transition: "all 0.1s ease-in-out",
cursor: "pointer",
_hover: {
backgroundColor: isSelected ? "gray.100" : "gray.50",
transform: "translateY(-2px) scale(1.1)",
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { css } from "@styled-system/css";
export const pageItemContainer = css({
display: "flex",
position: "relative",
gap: "sm",
gap: "lg",
alignItems: "center",
width: "100%",
height: "56px",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ export const PageItem = ({
}
};

const handleCloseModal = () => {
const handleCloseModal = (e: React.MouseEvent) => {
closeModal();
e.stopPropagation();
};

const handleSelectIcon = (e: React.MouseEvent, type: PageIconType) => {
Expand Down
Loading