"use client"; import React from "react"; import { LayoutDefinition, LayoutType, LayoutCategory } from "@/types/layout"; /** * 레이아웃 레지스트리 클래스 * 동적으로 레이아웃 컴포넌트를 등록, 관리, 조회할 수 있는 중앙 레지스트리 */ export class LayoutRegistry { private static layouts = new Map(); private static eventListeners: Array<(event: LayoutRegistryEvent) => void> = []; /** * 레이아웃 등록 */ static registerLayout(definition: LayoutDefinition): void { this.layouts.set(definition.id, definition); this.emitEvent({ type: "layout_registered", data: definition, timestamp: new Date(), }); console.log(`✅ 레이아웃 등록: ${definition.id} (${definition.name})`); // 개발자 도구 등록 (개발 모드에서만) if (process.env.NODE_ENV === "development") { this.registerGlobalDevTools(); } } /** * 레이아웃 등록 해제 */ static unregisterLayout(id: string): void { const definition = this.layouts.get(id); if (definition) { this.layouts.delete(id); this.emitEvent({ type: "layout_unregistered", data: definition, timestamp: new Date(), }); console.log(`❌ 레이아웃 등록 해제: ${id}`); } } /** * 레이아웃 조회 */ static getLayout(layoutType: string): LayoutDefinition | undefined { return this.layouts.get(layoutType); } /** * 카테고리별 레이아웃 조회 */ static getLayoutsByCategory(category: LayoutCategory): LayoutDefinition[] { return Array.from(this.layouts.values()).filter((layout) => layout.category === category); } /** * 모든 레이아웃 조회 */ static getAllLayouts(): LayoutDefinition[] { return Array.from(this.layouts.values()); } /** * 활성화된 레이아웃만 조회 */ static getActiveLayouts(): LayoutDefinition[] { return Array.from(this.layouts.values()).filter((layout) => layout.isActive !== false); } /** * 레이아웃 검색 */ static searchLayouts(query: string): LayoutDefinition[] { const searchTerm = query.toLowerCase(); return Array.from(this.layouts.values()).filter( (layout) => layout.name.toLowerCase().includes(searchTerm) || layout.nameEng?.toLowerCase().includes(searchTerm) || layout.description?.toLowerCase().includes(searchTerm) || layout.tags?.some((tag) => tag.toLowerCase().includes(searchTerm)), ); } /** * 레이아웃 존재 여부 확인 */ static hasLayout(layoutType: string): boolean { return this.layouts.has(layoutType); } /** * 등록된 레이아웃 타입 목록 */ static getRegisteredTypes(): string[] { return Array.from(this.layouts.keys()); } /** * 레이아웃 수정 */ static updateLayout(id: string, updates: Partial): boolean { const existing = this.layouts.get(id); if (existing) { const updated = { ...existing, ...updates }; this.layouts.set(id, updated); this.emitEvent({ type: "layout_updated", data: updated, timestamp: new Date(), }); console.log(`🔄 레이아웃 수정: ${id}`); return true; } return false; } /** * 대량 레이아웃 등록 */ static registerLayouts(definitions: LayoutDefinition[]): void { definitions.forEach((definition) => { this.registerLayout(definition); }); } /** * 레지스트리 초기화 */ static clear(): void { this.layouts.clear(); this.emitEvent({ type: "registry_cleared", data: null, timestamp: new Date(), }); console.log("🧹 레이아웃 레지스트리 초기화"); } /** * 이벤트 리스너 등록 */ static addEventListener(listener: (event: LayoutRegistryEvent) => void): void { this.eventListeners.push(listener); } /** * 이벤트 리스너 제거 */ static removeEventListener(listener: (event: LayoutRegistryEvent) => void): void { const index = this.eventListeners.indexOf(listener); if (index > -1) { this.eventListeners.splice(index, 1); } } /** * 이벤트 발생 */ private static emitEvent(event: LayoutRegistryEvent): void { this.eventListeners.forEach((listener) => { try { listener(event); } catch (error) { console.error("레이아웃 레지스트리 이벤트 리스너 오류:", error); } }); } /** * 레지스트리 상태 정보 */ static getRegistryInfo(): { totalLayouts: number; activeLayouts: number; categoryCounts: Record; registeredTypes: string[]; } { const allLayouts = this.getAllLayouts(); const activeLayouts = this.getActiveLayouts(); const categoryCounts = allLayouts.reduce( (acc, layout) => { acc[layout.category] = (acc[layout.category] || 0) + 1; return acc; }, {} as Record, ); return { totalLayouts: allLayouts.length, activeLayouts: activeLayouts.length, categoryCounts, registeredTypes: this.getRegisteredTypes(), }; } /** * 개발자 도구를 브라우저 글로벌에 등록 */ private static registerGlobalDevTools(): void { if (typeof window !== "undefined") { (window as any).__LAYOUT_REGISTRY__ = { list: () => { console.table( this.getAllLayouts().map((l) => ({ ID: l.id, Name: l.name, Category: l.category, Zones: l.defaultZones?.length || 0, Tags: l.tags?.join(", ") || "none", Version: l.metadata?.version || "1.0.0", Active: l.isActive !== false ? "✅" : "❌", })), ); return this.getAllLayouts(); }, get: (id: string) => { const layout = this.getLayout(id); if (layout) { console.group(`📦 Layout: ${id}`); console.log("Definition:", layout); console.log("Component:", layout.component); console.log("Config:", layout.defaultConfig); console.log("Zones:", layout.defaultZones); console.groupEnd(); return layout; } else { console.warn(`❌ Layout not found: ${id}`); console.log("Available layouts:", this.getRegisteredTypes()); return null; } }, stats: () => { const info = this.getRegistryInfo(); console.group("📊 Layout Registry Statistics"); console.log(`📦 Total Layouts: ${info.totalLayouts}`); console.log(`✅ Active Layouts: ${info.activeLayouts}`); console.log("📂 Categories:", info.categoryCounts); console.log("🏷️ Registered Types:", info.registeredTypes); console.groupEnd(); return info; }, search: (query: string) => { const results = this.searchLayouts(query); console.log(`🔍 Search results for "${query}":`, results); return results; }, categories: () => { const byCategory = this.getAllLayouts().reduce( (acc, layout) => { if (!acc[layout.category]) acc[layout.category] = []; acc[layout.category].push(layout.id); return acc; }, {} as Record, ); console.table(byCategory); return byCategory; }, clear: () => { console.warn("🧹 Clearing layout registry..."); this.clear(); console.log("✅ Registry cleared"); }, reload: () => { console.log("🔄 Registry reload not implemented yet"); console.log("Try refreshing the page or using HMR"); }, help: () => { console.group("🛠️ Layout Registry DevTools Help"); console.log("__LAYOUT_REGISTRY__.list() - 모든 레이아웃 목록 표시"); console.log("__LAYOUT_REGISTRY__.get(id) - 특정 레이아웃 상세 정보"); console.log("__LAYOUT_REGISTRY__.stats() - 레지스트리 통계"); console.log("__LAYOUT_REGISTRY__.search(query) - 레이아웃 검색"); console.log("__LAYOUT_REGISTRY__.categories() - 카테고리별 레이아웃"); console.log("__LAYOUT_REGISTRY__.clear() - 레지스트리 초기화"); console.log("__LAYOUT_REGISTRY__.help() - 도움말"); console.groupEnd(); }, }; // 첫 등록 시에만 안내 메시지 출력 if (!(window as any).__LAYOUT_REGISTRY_INITIALIZED__) { console.log("🛠️ Layout Registry DevTools initialized!"); console.log("Use __LAYOUT_REGISTRY__.help() for available commands"); (window as any).__LAYOUT_REGISTRY_INITIALIZED__ = true; } } } } // 레지스트리 이벤트 타입 export interface LayoutRegistryEvent { type: "layout_registered" | "layout_unregistered" | "layout_updated" | "registry_cleared"; data: LayoutDefinition | null; timestamp: Date; } // 전역 레이아웃 레지스트리 인스턴스 (싱글톤) export const layoutRegistry = LayoutRegistry; // 기본 내보내기 export default LayoutRegistry;