2f398ae0b3
- 제어모드 IDE: ControlCardPanel, control/ide/* (Canvas/LeftRail/RightRail/PanZoomStage/V3RuleNode 등), schemas, lib/api/control - 레지스트리 정리: aggregation-widget, status-count, section-card/paper, table-list(legacy/v2), tabs-widget 폐기 → table/_shared/ 로 통합 - InvLegacyButtonConfigPanel cp 마이그레이션 - canonical data view cleanup 후속 노트
138 lines
4.3 KiB
TypeScript
138 lines
4.3 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import {
|
|
Eye, Pencil, Play, History, Zap, LayoutDashboard,
|
|
Save, Undo2, FolderOpen, Search, X,
|
|
} from 'lucide-react';
|
|
import { useControlMode } from '../hooks/useControlMode';
|
|
import { listPresence, type PresenceUser } from '@/lib/api/control';
|
|
|
|
interface ContextBarProps {
|
|
selectedCard: Record<string, any>;
|
|
onExit: () => void; // 카드 닫기 (제어 유지)
|
|
onCtrlExit: () => void; // 제어 종료
|
|
}
|
|
|
|
const MODE_TABS = [
|
|
{ k: 'view' as const, Ic: Eye, label: 'READ' },
|
|
{ k: 'edit' as const, Ic: Pencil, label: 'EDIT' },
|
|
{ k: 'run' as const, Ic: Play, label: 'RUN' },
|
|
{ k: 'history' as const, Ic: History, label: 'HISTORY' },
|
|
];
|
|
|
|
export function ContextBar({ selectedCard, onExit, onCtrlExit }: ContextBarProps) {
|
|
const mode = useControlMode((s) => s.mode);
|
|
const setMode = useControlMode((s) => s.setMode);
|
|
|
|
const [presence, setPresence] = useState<PresenceUser[]>([]);
|
|
useEffect(() => {
|
|
let alive = true;
|
|
listPresence('').then((p) => { if (alive) setPresence(p); });
|
|
return () => { alive = false; };
|
|
}, []);
|
|
|
|
const tableName = selectedCard.primary_table ?? selectedCard.PRIMARY_TABLE ?? '';
|
|
const cardTitle = selectedCard.title ?? selectedCard.TITLE ?? '카드';
|
|
const dirtyCount = 0; // TODO 단계 6에서 store 도입
|
|
|
|
return (
|
|
<div className="ctrl-ide-ctxbar">
|
|
{/* 좌측 — 배지 + brumb */}
|
|
<div className="ctrl-ide-badge">
|
|
<Zap size={10} strokeWidth={2.5} />
|
|
CONTROL IDE
|
|
</div>
|
|
<span className="ctrl-ide-sep">/</span>
|
|
<button className="ctrl-ide-tool" disabled>
|
|
<LayoutDashboard size={11} />
|
|
운영 대시보드
|
|
</button>
|
|
<span className="ctrl-ide-sep">/</span>
|
|
<div className="ctrl-ide-crumb-card">
|
|
{cardTitle}
|
|
{tableName && <span className="ctrl-ide-crumb-tbl">{tableName}</span>}
|
|
</div>
|
|
|
|
<div style={{ flex: 1 }} />
|
|
|
|
{/* presence stack — 빈 배열이면 미렌더 */}
|
|
{presence.length > 0 && (
|
|
<>
|
|
<div className="ctrl-presence">
|
|
{presence.slice(0, 4).map((p, i) => (
|
|
<span
|
|
key={i}
|
|
className={`ctrl-presence-avatar${p.mode === 'edit' ? ' is-edit' : ''}`}
|
|
style={{ background: `rgb(${p.color})` }}
|
|
title={`${p.name} · ${p.mode === 'edit' ? '편집중' : '보는중'}`}
|
|
>
|
|
{p.short}
|
|
</span>
|
|
))}
|
|
{presence.length > 4 && (
|
|
<span className="ctrl-presence-more">+{presence.length - 4}</span>
|
|
)}
|
|
</div>
|
|
<span className="ctrl-ide-vsep" aria-hidden="true" />
|
|
</>
|
|
)}
|
|
|
|
{/* cmd-k */}
|
|
<button className="ctrl-ide-tool ctrl-ide-cmdk" title="명령 팔레트 (⌘K)">
|
|
<Search size={10} />
|
|
⌘K
|
|
</button>
|
|
<span className="ctrl-ide-vsep" aria-hidden="true" />
|
|
|
|
{/* mode 4-segmented tabs */}
|
|
<div className="ctrl-ide-mode-tabs">
|
|
{MODE_TABS.map(({ k, Ic, label }) => (
|
|
<button
|
|
key={k}
|
|
className={`ctrl-ide-mode-tab${mode === k ? ' on' : ''}`}
|
|
onClick={() => setMode(k)}
|
|
>
|
|
<Ic size={10} />
|
|
{label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* toolbar */}
|
|
<button className="ctrl-ide-tool" title="불러오기">
|
|
<FolderOpen size={11} />
|
|
<span>불러오기</span>
|
|
</button>
|
|
<button className={`ctrl-ide-tool${dirtyCount > 0 ? ' primary' : ''}`} title="저장">
|
|
<Save size={11} />
|
|
<span>{dirtyCount > 0 ? `저장 · ${dirtyCount}` : '저장'}</span>
|
|
</button>
|
|
<button className="ctrl-ide-tool" title="되돌리기">
|
|
<Undo2 size={11} />
|
|
</button>
|
|
|
|
<span className="ctrl-ide-vsep" aria-hidden="true" />
|
|
|
|
{/* 카드 닫기 (제어 유지) */}
|
|
<button
|
|
onClick={onExit}
|
|
title="닫고 대시보드로 (제어 유지)"
|
|
className="ctrl-ide-tool ctrl-ide-close"
|
|
>
|
|
<X size={11} />
|
|
<span>닫기</span>
|
|
</button>
|
|
|
|
{/* 제어 종료 */}
|
|
<button
|
|
onClick={onCtrlExit}
|
|
title="제어 모드 종료"
|
|
className="ctrl-ide-tool ctrl-ide-exit"
|
|
>
|
|
제어 종료
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|