저장팝업 텍스트 색상 수정

This commit is contained in:
Macbook
2026-05-26 23:50:13 +09:00
parent 94e96b9a9b
commit fe812389cc
13 changed files with 728 additions and 62 deletions
@@ -0,0 +1,165 @@
import React, { useEffect, useMemo, useState } from 'react';
import { INDICATOR_REGISTRY, type IndicatorDef } from '../utils/indicatorRegistry';
import { MAIN_INDICATOR_LABELS } from '../utils/indicatorMainTab';
interface IndicatorCustomTabEditorProps {
mode: 'create' | 'edit';
initialName: string;
initialTypes: string[];
onSave: (name: string, indicatorTypes: string[]) => void;
onClose: () => void;
}
function indicatorLabel(def: IndicatorDef): { ko: string; en: string } {
const main = MAIN_INDICATOR_LABELS[def.type];
return main ?? { ko: def.description, en: def.name };
}
const IndicatorCustomTabEditor: React.FC<IndicatorCustomTabEditorProps> = ({
mode,
initialName,
initialTypes,
onSave,
onClose,
}) => {
const [name, setName] = useState(initialName);
const [selected, setSelected] = useState<Set<string>>(() => new Set(initialTypes));
const [search, setSearch] = useState('');
useEffect(() => {
const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, [onClose]);
const filtered = useMemo(() => {
const q = search.toLowerCase().trim();
if (!q) return INDICATOR_REGISTRY;
return INDICATOR_REGISTRY.filter(d => {
const lbl = indicatorLabel(d);
return (
lbl.ko.toLowerCase().includes(q)
|| lbl.en.toLowerCase().includes(q)
|| d.shortName.toLowerCase().includes(q)
|| d.type.toLowerCase().includes(q)
);
});
}, [search]);
const toggle = (type: string) => {
setSelected(prev => {
const next = new Set(prev);
if (next.has(type)) next.delete(type);
else next.add(type);
return next;
});
};
const handleSave = () => {
const trimmed = name.trim();
if (!trimmed) {
window.alert('탭 이름을 입력해 주세요.');
return;
}
if (selected.size === 0) {
window.alert('탭에 표시할 지표를 하나 이상 선택해 주세요.');
return;
}
const ordered = INDICATOR_REGISTRY
.filter(d => selected.has(d.type))
.map(d => d.type);
onSave(trimmed, ordered);
};
return (
<div
className="ind-tab-editor-overlay"
onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}
>
<div className="ind-tab-editor" onMouseDown={e => e.stopPropagation()}>
<div className="ind-tab-editor-header">
<span className="ind-tab-editor-title">
{mode === 'create' ? '탭 추가' : '탭 수정'}
</span>
<button type="button" className="gc-popup-close" onClick={onClose} aria-label="닫기"></button>
</div>
<div className="ind-tab-editor-body">
<label className="ind-tab-editor-field">
<span className="ind-tab-editor-label"> </span>
<input
className="ind-tab-editor-input"
value={name}
onChange={e => setName(e.target.value)}
placeholder="예: 내 지표"
autoFocus
/>
</label>
<div className="ind-tab-editor-field">
<div className="ind-tab-editor-label-row">
<span className="ind-tab-editor-label">
({selected.size})
</span>
<button
type="button"
className="ind-tab-editor-link"
onClick={() => setSelected(new Set(INDICATOR_REGISTRY.map(d => d.type)))}
>
</button>
<button
type="button"
className="ind-tab-editor-link"
onClick={() => setSelected(new Set())}
>
</button>
</div>
<input
className="ind-tab-editor-input"
value={search}
onChange={e => setSearch(e.target.value)}
placeholder="지표 검색..."
/>
</div>
<div className="ind-tab-editor-list">
{filtered.length === 0 ? (
<div className="ind-panel-empty"> </div>
) : (
filtered.map(def => {
const lbl = indicatorLabel(def);
const checked = selected.has(def.type);
return (
<label key={def.type} className={`ind-tab-editor-item${checked ? ' checked' : ''}`}>
<input
type="checkbox"
checked={checked}
onChange={() => toggle(def.type)}
/>
<span className="ind-tab-editor-item-info">
<span className="ind-tab-editor-item-name">{lbl.ko}</span>
<span className="ind-tab-editor-item-desc">{lbl.en}</span>
</span>
</label>
);
})
)}
</div>
</div>
<div className="ind-tab-editor-footer">
<button type="button" className="ind-tab-editor-btn cancel" onClick={onClose}>
</button>
<button type="button" className="ind-tab-editor-btn save" onClick={handleSave}>
</button>
</div>
</div>
</div>
);
};
export default IndicatorCustomTabEditor;