block types: 구분선/리스트 블록 스토어 및 유닛 테스트 추가
CI / test (push) Failing after 42m43s
CI / pr_and_merge (push) Has been skipped

This commit is contained in:
2025-11-18 19:03:51 +09:00
parent 401dac5b89
commit 0621f95a5b
3 changed files with 243 additions and 3 deletions
+103 -3
View File
@@ -1,8 +1,8 @@
import { createStore } from "zustand";
import { create } from "zustand";
// 블록 타입 정의: 텍스트/버튼/이미지/섹션 블록
export type BlockType = "text" | "button" | "image" | "section";
// 블록 타입 정의: 텍스트/버튼/이미지/섹션/구분선/리스트 블록
export type BlockType = "text" | "button" | "image" | "section" | "divider" | "list";
// 텍스트 블록 속성
export interface TextBlockProps {
@@ -26,6 +26,19 @@ export interface ImageBlockProps {
alt: string;
}
// 구분선 블록 속성
export interface DividerBlockProps {
align: "left" | "center" | "right";
thickness: "thin" | "medium";
}
// 리스트 블록 속성
export interface ListBlockProps {
items: string[];
ordered: boolean;
align: "left" | "center" | "right";
}
// 섹션 블록 속성
export interface SectionBlockProps {
background: "default" | "muted" | "primary";
@@ -41,7 +54,13 @@ export interface SectionBlockProps {
export interface Block {
id: string;
type: BlockType;
props: TextBlockProps | ButtonBlockProps | ImageBlockProps | SectionBlockProps;
props:
| TextBlockProps
| ButtonBlockProps
| ImageBlockProps
| SectionBlockProps
| DividerBlockProps
| ListBlockProps;
// 레이아웃 트리 상 위치 정보 (루트 텍스트/버튼/이미지 블록은 null)
sectionId?: string | null;
columnId?: string | null;
@@ -56,6 +75,8 @@ export interface EditorState {
addTextBlock: () => void;
addButtonBlock: () => void;
addImageBlock: () => void;
addDividerBlock: () => void;
addListBlock: () => void;
addSectionBlock: () => void;
addHeroTemplateSection: () => void;
addFeaturesTemplateSection: () => void;
@@ -814,6 +835,85 @@ const createEditorState = (set: any, get: any): EditorState => ({
}));
},
// 구분선 블록 추가: 기본 정렬/두께와 함께 생성 후 선택 상태로 만든다
addDividerBlock: () => {
const id = createId();
const { selectedBlockId, blocks } = get();
let sectionId: string | null = null;
let columnId: string | null = null;
if (selectedBlockId) {
const target = blocks.find((b: Block) => b.id === selectedBlockId);
if (target) {
if (target.type === "section") {
const sProps = target.props as SectionBlockProps;
sectionId = target.id;
columnId = sProps.columns?.[0]?.id ?? null;
} else {
sectionId = (target as any).sectionId ?? null;
columnId = (target as any).columnId ?? null;
}
}
}
const newBlock: Block = {
id,
type: "divider",
props: {
align: "center",
thickness: "thin",
},
sectionId,
columnId,
};
set((state: EditorState) => ({
blocks: [...state.blocks, newBlock],
selectedBlockId: id,
}));
},
// 리스트 블록 추가: 기본 항목/정렬과 함께 생성 후 선택 상태로 만든다
addListBlock: () => {
const id = createId();
const { selectedBlockId, blocks } = get();
let sectionId: string | null = null;
let columnId: string | null = null;
if (selectedBlockId) {
const target = blocks.find((b: Block) => b.id === selectedBlockId);
if (target) {
if (target.type === "section") {
const sProps = target.props as SectionBlockProps;
sectionId = target.id;
columnId = sProps.columns?.[0]?.id ?? null;
} else {
sectionId = (target as any).sectionId ?? null;
columnId = (target as any).columnId ?? null;
}
}
}
const newBlock: Block = {
id,
type: "list",
props: {
items: ["리스트 아이템 1"],
ordered: false,
align: "left",
},
sectionId,
columnId,
};
set((state: EditorState) => ({
blocks: [...state.blocks, newBlock],
selectedBlockId: id,
}));
},
// 섹션 블록 추가: 배경/패딩 기본값과 함께 생성 후 선택 상태로 만든다
addSectionBlock: () => {
const id = createId();