feat: 품목 관리 및 마스터 데이터 관리 시스템 구현
주요 기능: - 품목 CRUD 기능 (생성, 조회, 수정) - 품목 마스터 데이터 관리 시스템 - BOM(Bill of Materials) 관리 기능 - 도면 캔버스 기능 - 품목 속성 및 카테고리 관리 - 스크린 인쇄 생산 관리 페이지 기술 개선: - localStorage SSR 호환성 수정 (9개 useState 초기화) - Shadcn UI 컴포넌트 추가 (table, tabs, alert, drawer 등) - DataContext 및 DeveloperModeContext 추가 - API 라우트 구현 (items, master-data) - 타입 정의 및 유틸리티 함수 추가 빌드 테스트: ✅ 성공 (3.1초) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
40
src/components/organisms/PageHeader.tsx
Normal file
40
src/components/organisms/PageHeader.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
'use client';
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { LucideIcon } from "lucide-react";
|
||||
|
||||
interface PageHeaderProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
actions?: ReactNode;
|
||||
icon?: LucideIcon;
|
||||
versionBadge?: ReactNode;
|
||||
}
|
||||
|
||||
export function PageHeader({ title, description, actions, icon: Icon, versionBadge }: PageHeaderProps) {
|
||||
return (
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||
<div className="flex items-start gap-3">
|
||||
{Icon && (
|
||||
<div className="p-2 bg-primary/10 rounded-lg hidden md:block">
|
||||
<Icon className="w-6 h-6 text-primary" />
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<h1 className="text-xl md:text-2xl">{title}</h1>
|
||||
{versionBadge}
|
||||
</div>
|
||||
{description && (
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 flex-wrap items-center">
|
||||
{actions}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
50
src/components/organisms/PageLayout.tsx
Normal file
50
src/components/organisms/PageLayout.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
'use client';
|
||||
|
||||
import { ReactNode, useEffect, useRef } from "react";
|
||||
import { useDeveloperMode, ComponentMetadata } from '@/contexts/DeveloperModeContext';
|
||||
|
||||
interface PageLayoutProps {
|
||||
children: ReactNode;
|
||||
maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full";
|
||||
devMetadata?: ComponentMetadata;
|
||||
versionInfo?: ReactNode;
|
||||
}
|
||||
|
||||
export function PageLayout({ children, maxWidth = "full", devMetadata, versionInfo }: PageLayoutProps) {
|
||||
const { setCurrentMetadata } = useDeveloperMode();
|
||||
const metadataRef = useRef<ComponentMetadata | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Only update if metadata actually changed
|
||||
if (devMetadata && JSON.stringify(devMetadata) !== JSON.stringify(metadataRef.current)) {
|
||||
metadataRef.current = devMetadata;
|
||||
setCurrentMetadata(devMetadata);
|
||||
}
|
||||
|
||||
// 컴포넌트 언마운트 시 메타데이터 초기화
|
||||
return () => {
|
||||
setCurrentMetadata(null);
|
||||
metadataRef.current = null;
|
||||
};
|
||||
}, []); // Empty dependency array - only run on mount/unmount
|
||||
|
||||
const maxWidthClasses = {
|
||||
sm: "max-w-3xl",
|
||||
md: "max-w-5xl",
|
||||
lg: "max-w-6xl",
|
||||
xl: "max-w-7xl",
|
||||
"2xl": "max-w-[1600px]",
|
||||
full: "w-full"
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`p-4 md:p-6 space-y-4 md:space-y-6 ${maxWidthClasses[maxWidth]} mx-auto w-full relative`}>
|
||||
{versionInfo && (
|
||||
<div className="absolute top-4 right-4 z-10">
|
||||
{versionInfo}
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user