/** * [디자인] 탭 — 고른 섹션의 레이아웃 배리에이션을 바꾸는 자리. * * 사장님은 코드 이름이 아니라 모양으로 고른다. 그래서 카드마다 와이어프레임을 붙이고, * "언제 이걸 고르면 좋은지"를 한 줄로 적는다. */ import { Check, ChevronDown, LayoutTemplate, MousePointerClick, Palette, RotateCcw, Shapes, } from 'lucide-react'; import {INDUSTRY_CONFIGS} from '@/data/industryData'; import {queueSiteTemplateSave} from '@/features/publish/siteTemplate'; import {cn} from '@/lib/utils'; import {useBuilderStore} from '@/stores/builder'; import {COLOR_PALETTE_PRESETS} from './colorPalettes'; import {TemplatePreview} from './TemplatePreview'; import {resolveVariant, variantsFor} from './canvas/registry'; import {VariantThumb} from './canvas/thumbs'; /** * 접히는 묶음. * * ★ [디자인] 탭은 290px 한 칸이다. 여기에 템플릿 미리보기 셋 + 팔레트 열두 칸 + * 이 섹션의 배리에이션이 세로로 쌓이면 스크롤이 세 화면을 넘고, 정작 방금 고른 섹션의 * 배리에이션이 맨 아래로 밀린다. 큰 것(템플릿·색)은 접어 두고 필요할 때 편다. * ★ `
` 다 — 상태를 리액트로 들면 탭을 오갈 때마다 접힘이 초기화된다. */ function Group({ title, icon: Icon, count, open, children, }: { title: string; icon: typeof Palette; count?: string; open?: boolean; children: React.ReactNode; }) { return (
{title} {count && {count}}
{children}
); } /** * 템플릿 고르기. * * ★ 이 자리가 없었다. 템플릿은 온보딩 4단계에서 한 번 고르면 끝이었고, 에디터의 [디자인] 탭에는 * 팔레트와 섹션 배리에이션만 있었다 — 사장님은 **디자인을 바꾸러 들어와서 디자인을 못 바꿨다.** * 스토어의 `selectTemplate` 과 서버 저장(`queueSiteTemplateSave`)은 처음부터 있었고 UI 만 없었다. * ★ 미리보기는 위저드와 **같은 컴포넌트**다(TemplatePreview). 두 벌로 그리면 고를 때 본 것과 * 에디터에서 본 것이 갈린다. */ function TemplatePicker({open}: {open?: boolean}) { const industry = useBuilderStore((s) => s.industry); const templateId = useBuilderStore((s) => s.templateId); const placeId = useBuilderStore((s) => s.placeId); const selectTemplate = useBuilderStore((s) => s.selectTemplate); const templates = INDUSTRY_CONFIGS[industry].templates; /** * ★ 저장된 templateId 가 지금 목록에 **없을 수 있다.** 실제로 있었다 — * `stay-warm-wood` 처럼 예전 이름이 sites.template_id 에 남아 있으면 * `resolveTemplate` 은 말없이 첫 템플릿으로 떨어지는데, 이 목록에서는 아무것도 * 선택돼 보이지 않아 "고를 수 없는 화면"이 된다. 떨어지는 자리를 여기서도 같게 본다. */ const activeId = templates.some((t) => t.id === templateId) ? templateId : templates[0].id; return (
{templates.map((template) => { const isActive = activeId === template.id; return ( ); })}
); } function ColorPalettePicker({open}: {open?: boolean}) { const industry = useBuilderStore((s) => s.industry); const selectedId = useBuilderStore((s) => s.colorPaletteId); const selectColorPalette = useBuilderStore((s) => s.selectColorPalette); const palettes = COLOR_PALETTE_PRESETS.filter((palette) => palette.industry === industry); return (
{palettes.map((palette) => { const isActive = selectedId === palette.id; return ( ); })}
{selectedId && ( )}
); } export function SectionDesignPanel() { const industry = useBuilderStore((s) => s.industry); const sections = useBuilderStore((s) => s.sections); const selectedSectionId = useBuilderStore((s) => s.selectedSectionId); const setSectionVariant = useBuilderStore((s) => s.setSectionVariant); const resetSectionVariants = useBuilderStore((s) => s.resetSectionVariants); const section = sections.find((s) => s.id === selectedSectionId); const variants = section ? variantsFor(section.type, industry) : []; const current = section ? resolveVariant(section, industry) : undefined; if (!section) { return (

섹션을 먼저 고르세요

왼쪽 목록이나 미리보기에서 섹션을 누르면
그 섹션의 레이아웃을 바꿀 수 있습니다.

); } return (
{/* 큰 것부터 좁혀 간다 — 템플릿(전체) → 팔레트(색) → 이 섹션의 레이아웃. */}
{section.name} {variants.length}종
{variants.length === 0 ? (

이 섹션은 아직 고를 수 있는 레이아웃이 하나뿐입니다.

) : (
    {variants.map((variant) => { const isActive = current?.id === variant.id; return (
  • ); })}
)}

레이아웃만 바뀝니다 —{' '} 입력한 내용과 사진, 섹션 순서는 그대로{' '} 유지됩니다.

); }