Skip to content

Commit e452690

Browse files
authored
Feat/#268-K: 기능 블럭 뒤에 p 블럭 추가 및 아이콘에 블럭 생성 기능 구현 (#367)
* refactor: onHandleBlocks 리팩토링 * feat: 기능 블럭 생성되면 뒤에 기본 텍스트 블럭 하나 추가 * feat: 블럭 왼쪽에 hover에 드러나는 + 아이콘 추가 클릭하면 블럭 한개 추가 * refactor: jsx 반환부의 중복 제거 * fix: BlockType switch문의 default tag 제거
1 parent 07af494 commit e452690

File tree

5 files changed

+148
-93
lines changed

5 files changed

+148
-93
lines changed

client/src/components/Block/TextBlock.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import ee from '../Mom/EventEmitter';
1515
interface BlockProps {
1616
id: string;
1717
index: number;
18-
onHandleBlock: React.KeyboardEventHandler;
18+
onHandleBlocks: React.KeyboardEventHandler;
1919
type: BlockType;
2020
setType: (arg: BlockType) => void;
2121
isLocalTypeUpdate: boolean;
@@ -25,7 +25,7 @@ interface BlockProps {
2525
function TextBlock({
2626
id,
2727
index,
28-
onHandleBlock,
28+
onHandleBlocks,
2929
type,
3030
setType,
3131
isLocalTypeUpdate,
@@ -260,7 +260,7 @@ function TextBlock({
260260

261261
const onKeyDown: React.KeyboardEventHandler<HTMLParagraphElement> = (e) => {
262262
onArrowKeyDown(e);
263-
onHandleBlock(e);
263+
onHandleBlocks(e);
264264
};
265265

266266
const commonHandlers = {
Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { BiPlus } from '@react-icons/all-files/bi/BiPlus';
12
import { BLOCK_EVENT } from '@wabinar/constants/socket-message';
23
import ee from 'components/Mom/EventEmitter';
34
import { memo, useEffect, useRef, useState } from 'react';
45
import useSocketContext from 'src/hooks/context/useSocketContext';
56

67
import QuestionBlock from './QuestionBlock';
8+
import style from './style.module.scss';
79
import TextBlock from './TextBlock';
810
import VoteBlock from './VoteBlock';
911

@@ -19,11 +21,18 @@ export enum BlockType {
1921
interface BlockProps {
2022
id: string;
2123
index: number;
22-
onHandleBlock: React.KeyboardEventHandler;
24+
createBlock: (arg: number) => void;
25+
onHandleBlocks: React.KeyboardEventHandler;
2326
registerRef: (arg: React.RefObject<HTMLElement>) => void;
2427
}
2528

26-
function Block({ id, index, onHandleBlock, registerRef }: BlockProps) {
29+
function Block({
30+
id,
31+
index,
32+
createBlock,
33+
onHandleBlocks,
34+
registerRef,
35+
}: BlockProps) {
2736
const { momSocket: socket } = useSocketContext();
2837

2938
const [type, setType] = useState<BlockType>();
@@ -47,31 +56,46 @@ function Block({ id, index, onHandleBlock, registerRef }: BlockProps) {
4756
const setBlockType = (type: BlockType) => {
4857
localUpdateFlagRef.current = true;
4958
setType(type);
59+
60+
if ([BlockType.VOTE, BlockType.QUESTION].includes(type)) {
61+
createBlock(index);
62+
}
63+
};
64+
65+
const onCreate = () => createBlock(index);
66+
67+
const getCurrentBlock = () => {
68+
switch (type) {
69+
case BlockType.H1:
70+
case BlockType.H2:
71+
case BlockType.H3:
72+
case BlockType.P:
73+
return (
74+
<TextBlock
75+
id={id}
76+
index={index}
77+
onHandleBlocks={onHandleBlocks}
78+
type={type}
79+
setType={setBlockType}
80+
isLocalTypeUpdate={localUpdateFlagRef.current}
81+
registerRef={registerRef}
82+
/>
83+
);
84+
case BlockType.VOTE:
85+
return <VoteBlock id={id} registerable={localUpdateFlagRef.current} />;
86+
case BlockType.QUESTION:
87+
return <QuestionBlock id={id} />;
88+
default:
89+
return <></>;
90+
}
5091
};
5192

52-
switch (type) {
53-
case BlockType.H1:
54-
case BlockType.H2:
55-
case BlockType.H3:
56-
case BlockType.P:
57-
return (
58-
<TextBlock
59-
id={id}
60-
index={index}
61-
onHandleBlock={onHandleBlock}
62-
type={type}
63-
setType={setBlockType}
64-
isLocalTypeUpdate={localUpdateFlagRef.current}
65-
registerRef={registerRef}
66-
/>
67-
);
68-
case BlockType.VOTE:
69-
return <VoteBlock id={id} registerable={localUpdateFlagRef.current} />;
70-
case BlockType.QUESTION:
71-
return <QuestionBlock id={id} />;
72-
default:
73-
return <p />;
74-
}
93+
return (
94+
<div className={style['block']}>
95+
<BiPlus size={20} onClick={onCreate} />
96+
{getCurrentBlock()}
97+
</div>
98+
);
7599
}
76100

77101
export default memo(Block);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
@import 'styles/color.module';
2+
3+
@mixin heading-style($border-size, $padding) {
4+
padding: $padding 0px;
5+
border-bottom: $border-size solid $gray-300;
6+
}
7+
8+
.block {
9+
position: relative;
10+
width: 100%;
11+
12+
& > h1,
13+
& > h2,
14+
& > h3,
15+
& > p {
16+
width: 100%;
17+
word-break: break-all;
18+
}
19+
20+
& > *:focus {
21+
outline: none;
22+
}
23+
24+
& > h1 {
25+
font-size: 36px;
26+
font-weight: 700;
27+
@include heading-style(1.5px, 8px);
28+
}
29+
30+
& > h2 {
31+
font-size: 28px;
32+
font-weight: 600;
33+
@include heading-style(1px, 6px);
34+
}
35+
36+
& > h3 {
37+
font-size: 24px;
38+
font-weight: 500;
39+
@include heading-style(0.5px, 4px);
40+
}
41+
42+
& > p {
43+
font-size: initial;
44+
font-weight: 400;
45+
line-height: 30px;
46+
}
47+
48+
& > svg {
49+
position: absolute;
50+
transform: translate(-20px, 2px);
51+
fill: none;
52+
}
53+
54+
& > svg:hover {
55+
fill: $gray-200;
56+
}
57+
}

client/src/components/Mom/index.tsx

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,33 @@ function Mom() {
7676
range.collapse();
7777
};
7878

79-
const onHandleBlock: React.KeyboardEventHandler = (e) => {
79+
const createBlock = (index: number) => {
80+
const blockId = uuid();
81+
82+
let remoteInsertion;
83+
84+
try {
85+
remoteInsertion = localInsertCRDT(index, blockId);
86+
} catch {
87+
initMom();
88+
}
89+
90+
socket.emit(MOM_EVENT.INSERT_BLOCK, blockId, remoteInsertion);
91+
};
92+
93+
const deleteBlock = (id: string, index: number) => {
94+
let remoteDeletion;
95+
96+
try {
97+
remoteDeletion = localDeleteCRDT(index);
98+
} catch {
99+
initMom();
100+
}
101+
102+
socket.emit(MOM_EVENT.DELETE_BLOCK, id, remoteDeletion);
103+
};
104+
105+
const onHandleBlocks: React.KeyboardEventHandler = (e) => {
80106
const target = e.target as HTMLParagraphElement;
81107

82108
const { index: indexString } = target.dataset;
@@ -85,50 +111,29 @@ function Mom() {
85111
if (e.key === 'Enter') {
86112
e.preventDefault();
87113

88-
const blockId = uuid();
89-
90-
let remoteInsertion;
91-
92-
try {
93-
remoteInsertion = localInsertCRDT(index, blockId);
94-
} catch {
95-
initMom();
96-
}
97-
114+
createBlock(index);
98115
updateBlockFocus(index + 1);
99-
100-
socket.emit(MOM_EVENT.INSERT_BLOCK, blockId, remoteInsertion);
101-
102116
return;
103117
}
104118

105119
if (e.key === 'Backspace') {
106120
if (target.innerText.length) return;
107121

108-
const { id } = target.dataset;
109-
110122
e.preventDefault();
111123

112-
if (index === 0) return;
124+
const { id } = target.dataset;
113125

114-
let remoteDeletion;
126+
if (!id || index === 0) return;
115127

116-
try {
117-
remoteDeletion = localDeleteCRDT(index);
118-
} catch {
119-
initMom();
120-
}
128+
deleteBlock(id, index);
121129

122130
updateBlockFocus(index - 1);
123-
124131
setBlocks(spreadCRDT());
125132

126-
if (focusIndex.current === undefined) return;
127-
setBlockFocus(focusIndex.current);
128-
129-
setCaretToEnd();
130-
131-
socket.emit(MOM_EVENT.DELETE_BLOCK, id, remoteDeletion);
133+
if (focusIndex.current !== undefined) {
134+
setBlockFocus(focusIndex.current);
135+
setCaretToEnd();
136+
}
132137
}
133138
};
134139

@@ -236,7 +241,8 @@ function Mom() {
236241
key={id}
237242
id={id}
238243
index={index}
239-
onHandleBlock={onHandleBlock}
244+
createBlock={createBlock}
245+
onHandleBlocks={onHandleBlocks}
240246
registerRef={registerRef(index)}
241247
/>
242248
))}

client/src/components/Mom/style.module.scss

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,47 +36,15 @@
3636
}
3737
}
3838

39-
@mixin heading-style($border-size, $padding) {
40-
padding: $padding 0px;
41-
border-bottom: $border-size solid $gray-300;
42-
}
43-
4439
.mom-body {
4540
box-sizing: border-box;
41+
width: 100%;
4642
height: calc(100% - 70px);
47-
padding: 20px;
43+
padding: 20px 25px;
4844
overflow-y: scroll;
4945
background-color: white;
5046
white-space: pre-wrap;
5147

52-
& > h1 {
53-
font-size: 36px;
54-
font-weight: 700;
55-
@include heading-style(1.5px, 8px);
56-
}
57-
58-
& > h2 {
59-
font-size: 28px;
60-
font-weight: 600;
61-
@include heading-style(1px, 6px);
62-
}
63-
64-
& > h3 {
65-
font-size: 24px;
66-
font-weight: 500;
67-
@include heading-style(0.5px, 4px);
68-
}
69-
70-
& > p {
71-
font-size: initial;
72-
font-weight: 400;
73-
line-height: 30px;
74-
}
75-
76-
& > *:focus {
77-
outline: none;
78-
}
79-
8048
&::-webkit-scrollbar {
8149
width: 5px;
8250
}

0 commit comments

Comments
 (0)