Skip to content

[#188] 클래스 블록 생성 시 blockly 기본 블록이 생성되는 문제 해결, 워크스페이스 초기 로딩 시 변경사항 감지 문제 해결 #193

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

Merged
merged 8 commits into from
Dec 1, 2024
21 changes: 15 additions & 6 deletions apps/client/src/core/styleFlyout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ export default class StyleFlyout extends FixedFlyout {
this.show(cssStyleToolboxConfig.contents);
}

// CSS 클래스명에 접두사를 붙이는 메서드
addPrefixToClassName(className: string) {
const CSS_CLASS_PREFIX = 'CSS_';
return `${CSS_CLASS_PREFIX}${className}`;
}

// 마우스 우클릭 시 컨텍스트 메뉴
registerCustomContextMenu() {
const menuId = 'deleteBlock';
Expand Down Expand Up @@ -215,17 +221,20 @@ export default class StyleFlyout extends FixedFlyout {
return toast.error('클래스명은 영문자, 밑줄(_), 하이픈(-), 숫자만 포함해주세요');
}

const createClassType = this.addPrefixToClassName(inputValue);

// 클래스명 중복 검사
const existingBlocks: TBlock[] = cssStyleToolboxConfig!.contents || [];
const isBlockAlreadyAdded = existingBlocks.some((block) => block.type === inputValue);
const isBlockAlreadyAdded = existingBlocks.some((block) => block.type === createClassType);
if (isBlockAlreadyAdded) {
return toast.error(`"${inputValue}" 입력한 클래스명 블록은 이미 존재합니다.`);
}

// 새롭게 생성되는 CSS 클래스 블록 정보
if (!Blockly.Blocks[inputValue!]) {
useCssPropsStore.getState().addNewCssClass(inputValue);
Blockly.Blocks[inputValue!] = {

if (!Blockly.Blocks[createClassType!]) {
useCssPropsStore.getState().addNewCssClass(createClassType);
Blockly.Blocks[createClassType!] = {
init: function () {
this.appendDummyInput().appendField(
new CustomFieldLabelSerializable(inputValue!),
Expand All @@ -240,10 +249,10 @@ export default class StyleFlyout extends FixedFlyout {
// 기존 블록들이 있는 cssStyleToolboxConfig.ts에 새 블록 추가
cssStyleToolboxConfig!.contents = [
...existingBlocks,
{ kind: 'block', type: inputValue, enabled: true },
{ kind: 'block', type: createClassType, enabled: true },
];
const { addClassBlock } = useClassBlockStore.getState();
addClassBlock(inputValue);
addClassBlock(createClassType);

this.show(cssStyleToolboxConfig.contents);
toast.success(`입력한 클래스명 블록 "${inputValue}"이(가) 추가되었습니다.`);
Expand Down
3 changes: 2 additions & 1 deletion apps/client/src/shared/blockly/createCssClassBlock.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { CustomFieldLabelSerializable } from '@/core/customFieldLabelSerializable';
import * as Blockly from 'blockly/core';
import { removeCssClassNamePrefix } from '../utils';

export const createCssClassBlock = (cssClassName: string) => {
if (!Blockly.Blocks[cssClassName]) {
Blockly.Blocks[cssClassName] = {
init: function () {
this.appendDummyInput().appendField(
new CustomFieldLabelSerializable(cssClassName),
new CustomFieldLabelSerializable(removeCssClassNamePrefix(cssClassName)),
'CLASS'
);
this.setOutput(true);
Expand Down
3 changes: 2 additions & 1 deletion apps/client/src/shared/blockly/cssCodeGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { TTotalCssPropertyObj } from '@/shared/types';
import { removeCssClassNamePrefix } from '../utils';

export const cssCodeGenerator = (totalCssPropertyObj: TTotalCssPropertyObj) => {
let cssCode = '';

Object.keys(totalCssPropertyObj)
.filter((className) => className && className.length > 0)
.forEach((className) => {
cssCode += `.${className} {\n`;
cssCode += `.${removeCssClassNamePrefix(className)} {\n`;
Object.keys(totalCssPropertyObj[className].cssOptionObj).forEach((label) => {
if (
totalCssPropertyObj[className].checkedCssPropertyObj[label] &&
Expand Down
8 changes: 6 additions & 2 deletions apps/client/src/shared/hooks/queries/useGetWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from '@/shared/store';

import { WorkspaceApi } from '@/shared/api';
import { getUserId } from '@/shared/utils';
import { getUserId, removeCssClassNamePrefix } from '@/shared/utils';
import toast from 'react-hot-toast';
import { useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
Expand Down Expand Up @@ -47,7 +47,11 @@ export const useGetWorkspace = (workspaceId: string) => {
}

initCssPropertyObj(data.workspaceDto.totalCssPropertyObj);
initClassBlockList(Object.keys(data.workspaceDto.totalCssPropertyObj));
initClassBlockList(
Object.keys(data.workspaceDto.totalCssPropertyObj).map((className) =>
removeCssClassNamePrefix(className)
)
);
setCanvasInfo(data.workspaceDto.canvas);
cssStyleToolboxConfig.contents = data.workspaceDto.classBlockList
? JSON.parse(data.workspaceDto.classBlockList)
Expand Down
3 changes: 2 additions & 1 deletion apps/client/src/shared/store/useClassBlockStore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand';
import { removeCssClassNamePrefix } from '../utils';

type TClassBlock = {
classBlockList: string[];
Expand All @@ -11,7 +12,7 @@ export const useClassBlockStore = create<TClassBlock>((set) => ({
classBlockList: [],
addClassBlock: (newClassBlockName: string) => {
set((state) => ({
classBlockList: [...state.classBlockList, newClassBlockName],
classBlockList: [...state.classBlockList, removeCssClassNamePrefix(newClassBlockName)],
}));
},
removeClassBlock: (classBlockName: string) => {
Expand Down
11 changes: 10 additions & 1 deletion apps/client/src/shared/utils/boolockConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*앞으로 블록 타입을 지정할때는 꼭..! 이 함수를 이용해서 블록 타입명을 지정해주세요.
*/
export const PREVIOUS_TYPE_NAME = 'BOOLOCK_SYSTEM_';
export const CSS_CLASS_PREFIX = 'CSS_';

export const addPreviousTypeName = (type: string) => {
return `${PREVIOUS_TYPE_NAME}${type}`;
Expand All @@ -16,4 +17,12 @@ export const removePreviousTypeName = (type: string): string => {
return type;
};

// TODO: css 클래스명 만들때 해당 previousTypeName으로 시작할 경우 블록 생성이 안 되도록 막는 로직도 추가해주시길 바랍니다.
export const addPrefixToCssClassName = (className: string) => {
return className.startsWith(CSS_CLASS_PREFIX) ? className : `${CSS_CLASS_PREFIX}${className}`;
};

export const removeCssClassNamePrefix = (className: string) => {
return className.startsWith(CSS_CLASS_PREFIX)
? className.replace(CSS_CLASS_PREFIX, '')
: className;
};
3 changes: 3 additions & 0 deletions apps/client/src/shared/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export {
addPreviousTypeName,
removePreviousTypeName,
PREVIOUS_TYPE_NAME,
addPrefixToCssClassName,
removeCssClassNamePrefix,
CSS_CLASS_PREFIX,
} from './boolockConstants';
export { debounce } from './debounce';
export { cssCategoryList } from './cssCategoryList';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
tabToolboxConfig,
} from '@/shared/blockly';
import { useCssPropsStore, useWorkspaceChangeStatusStore, useWorkspaceStore } from '@/shared/store';
import { useEffect, useState } from 'react';
import { useEffect, useRef, useState } from 'react';

import CustomTrashcan from '@/core/customTrashcan';
import CustomZoomControls from '@/core/customZoomControls';
Expand Down Expand Up @@ -55,6 +55,7 @@ export const WorkspaceContent = () => {
const { totalCssPropertyObj } = useCssPropsStore();
const { workspace, setWorkspace, canvasInfo } = useWorkspaceStore();
const { setIsBlockChanged } = useWorkspaceChangeStatusStore();
const isBlockLoadingFinish = useRef<boolean>(false);

useEffect(() => {
const newWorkspace = Blockly.inject('blocklyDiv', {
Expand Down Expand Up @@ -92,8 +93,20 @@ export const WorkspaceContent = () => {
) {
const code = generateFullCode(newWorkspace);
setHtmlCode(code);

if (isBlockLoadingFinish.current) {
setIsBlockChanged(true);
}
}

if (event.type === Blockly.Events.VIEWPORT_CHANGE && isBlockLoadingFinish.current) {
// 캔버스에 있는 블록을 드래그할 때 발생하는 이벤트
setIsBlockChanged(true);
}

if (event.type === Blockly.Events.FINISHED_LOADING) {
isBlockLoadingFinish.current = true;
}
};

newWorkspace.addChangeListener(handleAutoConversion);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Select, TOption } from '@/shared/ui';
import { useClassBlockStore, useCssPropsStore } from '@/shared/store';
import { useEffect, useState } from 'react';
import { addPrefixToCssClassName } from '@/shared/utils';

/**
*
Expand Down Expand Up @@ -30,7 +31,7 @@ export const CssPropsSelectBoxHeader = () => {
<Select
options={selectOptions}
value={currentCssClassName}
onChange={(selected: string) => setCurrentCssClassName(selected)}
onChange={(selected: string) => setCurrentCssClassName(addPrefixToCssClassName(selected))}
placeholder="클래스를 선택해주세요"
/>
</header>
Expand Down