diff --git a/src/App.jsx b/src/App.jsx
index bcfa62f..64cf6ba 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -10,7 +10,6 @@ import {
Layers3,
Map,
Maximize2,
- Minimize2,
Mountain,
Plus,
Route,
@@ -222,6 +221,7 @@ const defaultContent = {
steps: cheonjiinFlow.map(({ title, feature, note }) => ({ title, feature, note })),
deliverables: cheonjiinDeliverables,
format: 'glb',
+ engine: '',
programType: 'internal',
programNote: '',
predecessors: [],
@@ -233,6 +233,7 @@ const defaultContent = {
description: '설계조건 입력부터 기본설계 성과물 생성',
steps: wayPrimalFlow.map(({ title, feature, note }) => ({ title, feature, note })),
format: '',
+ engine: '',
deliverables: ['기본설계 모델'],
programType: 'internal',
programNote: '',
@@ -253,6 +254,7 @@ function normalizeStoredContent(parsed) {
...(parsed.cheonjiin ?? {}),
programType: getProgramType(parsed.cheonjiin?.programType ?? defaultContent.cheonjiin.programType),
programNote: parsed.cheonjiin?.programNote ?? '',
+ engine: parsed.cheonjiin?.engine ?? '',
predecessors: parsed.cheonjiin?.predecessors ?? [],
successors: parsed.cheonjiin?.successors ?? [],
mergeGroup: parsed.cheonjiin?.mergeGroup ?? '',
@@ -266,6 +268,7 @@ function normalizeStoredContent(parsed) {
...(parsed.wayPrimal ?? {}),
programType: getProgramType(parsed.wayPrimal?.programType ?? defaultContent.wayPrimal.programType),
programNote: parsed.wayPrimal?.programNote ?? '',
+ engine: parsed.wayPrimal?.engine ?? '',
predecessors: parsed.wayPrimal?.predecessors ?? [],
successors: parsed.wayPrimal?.successors ?? [],
mergeGroup: parsed.wayPrimal?.mergeGroup ?? '',
@@ -283,6 +286,7 @@ function normalizeStoredContent(parsed) {
...program,
programType: getProgramType(program.programType),
programNote: program.programNote ?? '',
+ engine: program.engine ?? '',
predecessors: program.predecessors ?? [],
successors: program.successors ?? [],
mergeGroup: program.mergeGroup ?? '',
@@ -568,6 +572,8 @@ function FlowRow({
onStepChange,
format,
onFormatChange,
+ engine = '',
+ onEngineChange,
deliverables = [],
onDeliverableChange,
onLabelChange,
@@ -676,8 +682,11 @@ function FlowRow({
isRowClickable ? 'cursor-pointer transition hover:-translate-y-0.5 hover:shadow-[0_22px_60px_rgba(15,23,42,0.12)]' : ''
}`}
>
-
-
+
+
{isEditing && onLabelChange ? (
onDescriptionChange(event.target.value)}
rows={2}
- className="mt-1 w-full min-w-[360px] resize-none rounded-xl border border-slate-200 bg-white/85 px-3 py-1.5 text-sm font-bold tracking-tight text-slate-800 outline-none focus:border-teal-400"
+ className="mt-1 w-full resize-none rounded-xl border border-slate-200 bg-white/85 px-3 py-1.5 text-sm font-bold tracking-tight text-slate-800 outline-none focus:border-teal-400"
/>
) : (
{description}
@@ -752,54 +761,77 @@ function FlowRow({
onChange={(event) => onProgramNoteChange(event.target.value)}
rows={2}
placeholder="프로그램 노트를 입력하세요"
- className="mt-2 w-full min-w-[360px] resize-none rounded-xl border border-amber-100 bg-amber-50/70 px-3 py-2 text-sm font-bold leading-5 text-slate-800 outline-none focus:border-amber-300"
+ className="mt-2 w-full resize-none rounded-xl border border-amber-100 bg-amber-50/70 px-3 py-2 text-sm font-bold leading-5 text-slate-800 outline-none focus:border-amber-300"
/>
) : programNote ? (
-
+
NOTE
{programNote}
) : null}
-
+
{onFormatChange && (
-
-
포맷
- {isEditing ? (
-
onFormatChange(event.target.value)}
- placeholder="예: glb"
- className="h-8 w-28 rounded-full border border-slate-200 bg-white/85 px-3 text-[12px] font-extrabold text-slate-700 outline-none focus:border-teal-400"
- />
- ) : (
-
- {format || '-'}
-
- )}
+
+
포맷
+
+ {isEditing ? (
+ onFormatChange(event.target.value)}
+ placeholder="예: glb"
+ className="h-8 w-32 rounded-full border border-slate-200 bg-white/85 px-3 text-[12px] font-extrabold text-slate-700 outline-none focus:border-teal-400"
+ />
+ ) : (
+
+ {format || '-'}
+
+ )}
+
)}
{(deliverables.length > 0 || isEditing) && (
-
-
성과물
- {(deliverables.length > 0 ? deliverables : ['']).map((item, index) => (
- isEditing ? (
+
+
성과물
+
+ {(deliverables.length > 0 ? deliverables : ['']).map((item, index) => (
+ isEditing ? (
+ onDeliverableChange?.(index, event.target.value)}
+ placeholder="성과물"
+ className="h-7 w-28 rounded-full border border-slate-200 bg-white/85 px-3 text-[11px] font-extrabold text-slate-700 outline-none focus:border-teal-400"
+ />
+ ) : splitDeliverableText(item).map((deliverable, deliverableIndex) => (
+
+ {deliverable}
+
+ ))
+ ))}
+
+
+ )}
+ {onEngineChange && (
+
+
사용엔진
+
+ {isEditing ? (
onDeliverableChange?.(index, event.target.value)}
- placeholder="성과물"
- className="h-7 w-28 rounded-full border border-slate-200 bg-white/85 px-3 text-[11px] font-extrabold text-slate-700 outline-none focus:border-teal-400"
+ value={engine}
+ onChange={(event) => onEngineChange(event.target.value)}
+ placeholder="예: hmeg, gsim"
+ className="h-8 w-40 rounded-full border border-slate-200 bg-white/85 px-3 text-[12px] font-extrabold text-slate-700 outline-none focus:border-teal-400"
/>
- ) : splitDeliverableText(item).map((deliverable, deliverableIndex) => (
-
- {deliverable}
-
- ))
- ))}
+ ) : (
+
+ {engine || '-'}
+
+ )}
+
)}
{isEditing && onAddStep && (
@@ -1597,16 +1629,30 @@ function ProgramComparePopup({ programs, comparisons, initialPair, onComparisonS
{program.description}
-
- {(program.deliverables ?? []).map((deliverable) => (
-
- {deliverable}
-
- ))}
+
+
+ 포맷
+ {program.format || '-'}
+
+
+
성과물
+
+ {(program.deliverables ?? []).length > 0 ? (
+ (program.deliverables ?? []).map((deliverable) => (
+
+ {deliverable}
+
+ ))
+ ) : (
+ -
+ )}
+
+
+
+ 사용엔진
+ {program.engine || '-'}
+
-
- 포맷: {program.format || '-'}
-
);
};
@@ -2083,8 +2129,7 @@ function RelationTreePanel({
const miniRowGap = fullPage ? 96 : 72;
const miniPadding = 34;
const miniSideLaneWidth = 96;
- const sidebarSizes = [420, 560, 720];
- const resolvedSidebarWidth = sidebarWidth ?? sidebarSizes[0];
+ const resolvedSidebarWidth = sidebarWidth ?? 420;
const miniViewportWidth = Math.max(290, fullPage ? viewportSize.width - 64 : resolvedSidebarWidth - 24);
const miniMaxLevelCount = Math.max(1, ...graphLevels.map((level) => level?.length ?? 0));
const miniGraphWidth = Math.max(
@@ -2138,11 +2183,6 @@ function RelationTreePanel({
const miniScaledWidth = miniGraphWidth * miniGraphScale;
const mapOffset = fullPage ? 0 : Math.max(0, Math.round((miniScaledWidth - miniViewportWidth) / 2 / miniGraphScale));
const mapTranslateX = fullPage ? Math.max(0, Math.round((miniViewportWidth - miniScaledWidth) / 2)) : -mapOffset;
- const canShrinkSidebar = resolvedSidebarWidth > sidebarSizes[0];
- const setSidebarSize = (size) => {
- onSidebarWidthChange?.(size);
- };
-
useEffect(() => {
if (!fullPage) return undefined;
const updateViewportSize = () => {
@@ -2332,29 +2372,19 @@ function RelationTreePanel({
)}
{!fullPage && (
-
-
-
-
+
-
)}
{relations.length > 0 ? (
@@ -2655,6 +2685,7 @@ export default function App() {
programNote: content.cheonjiin.programNote ?? '',
steps: editableCheonjiinFlow,
format: content.cheonjiin.format,
+ engine: content.cheonjiin.engine ?? '',
programType: getProgramType(content.cheonjiin.programType),
predecessors: content.cheonjiin.predecessors ?? [],
successors: content.cheonjiin.successors ?? [],
@@ -2673,6 +2704,7 @@ export default function App() {
programNote: content.wayPrimal.programNote ?? '',
steps: editableWayPrimalFlow,
format: content.wayPrimal.format,
+ engine: content.wayPrimal.engine ?? '',
programType: getProgramType(content.wayPrimal.programType),
predecessors: content.wayPrimal.predecessors ?? [],
successors: content.wayPrimal.successors ?? [],
@@ -2691,6 +2723,7 @@ export default function App() {
programNote: program.programNote ?? '',
steps: normalizeProgramSteps(program),
format: program.format,
+ engine: program.engine ?? '',
programType: getProgramType(program.programType),
predecessors: program.predecessors ?? [],
successors: program.successors ?? [],
@@ -3455,6 +3488,7 @@ export default function App() {
}
],
format: '',
+ engine: '',
deliverables: ['성과물'],
programType: 'internal',
programNote: '',
@@ -3709,7 +3743,17 @@ export default function App() {
return (
-
+
+ {isEditing && (
+
+ )}
- {isEditing && (
-
-
-
- 프로그램 편집
-
-
- 프로그램을 추가하거나 기존 내용을 수정합니다
-
-
-
-
- )}
updateProgramTitle('cheonjiin', 'programType', value)}
format={content.cheonjiin.format}
onFormatChange={(value) => updateFormat('cheonjiin', value)}
+ engine={content.cheonjiin.engine ?? ''}
+ onEngineChange={(value) => updateProgramTitle('cheonjiin', 'engine', value)}
deliverables={content.cheonjiin.deliverables}
onDeliverableChange={(index, value) => updateProgramDeliverable('cheonjiin', index, value)}
onAddStep={() => addStep('cheonjiin')}
@@ -3819,6 +3845,8 @@ export default function App() {
onProgramTypeChange={(value) => updateProgramTitle('wayPrimal', 'programType', value)}
format={content.wayPrimal.format}
onFormatChange={(value) => updateFormat('wayPrimal', value)}
+ engine={content.wayPrimal.engine ?? ''}
+ onEngineChange={(value) => updateProgramTitle('wayPrimal', 'engine', value)}
deliverables={content.wayPrimal.deliverables ?? []}
onDeliverableChange={(index, value) => updateProgramDeliverable('wayPrimal', index, value)}
onAddStep={() => addStep('wayPrimal')}
@@ -3907,6 +3935,8 @@ export default function App() {
onProgramTypeChange={(value) => updateProgram(programIndex, 'programType', value)}
format={program.format}
onFormatChange={(value) => updateProgram(programIndex, 'format', value)}
+ engine={program.engine ?? ''}
+ onEngineChange={(value) => updateProgram(programIndex, 'engine', value)}
deliverables={program.deliverables ?? []}
onDeliverableChange={(index, value) => updateProgramDeliverable(program.id, index, value)}
onAddStep={() => addStep(program.id)}