goldenChat base source add

This commit is contained in:
aidev
2026-05-23 15:11:48 +09:00
commit a4ea7762b5
2081 changed files with 1155760 additions and 0 deletions
@@ -0,0 +1,197 @@
/**
* 설정 화면 — 보조지표 기본값 (Main 16종 상단 + 전체 지표, 검색 필터)
*/
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import type { IndicatorConfig } from '../types';
import type { PlotDef, HLineDef } from '../utils/indicatorRegistry';
import { buildMainIndicatorConfig } from '../utils/indicatorMainConfig';
import { indicatorTypesOnChart } from '../utils/indicatorMainConfig';
import IndicatorSettingsForm from './IndicatorSettingsForm';
import { resetConfigToDefaults } from '../utils/indicatorSettingsEditor';
import type { IchimokuCloudColors } from '../utils/ichimokuConfig';
import {
getSettingsIndicatorTypes,
filterSettingsIndicatorTypes,
partitionFilteredTypes,
} from '../utils/indicatorSettingsList';
import IndicatorSettingsListSearch from './IndicatorSettingsListSearch';
import IndicatorSettingsListRow from './IndicatorSettingsListRow';
import { MAIN_INDICATOR_TYPES } from '../utils/indicatorMainTab';
export interface IndicatorMainDefaultsPanelProps {
chartIndicators: IndicatorConfig[];
onAddToChart: (type: string, config?: IndicatorConfig) => void;
onRemoveFromChart: (type: string) => void;
getParams: (type: string, defaults: Record<string, number | string | boolean>) => Record<string, number | string | boolean>;
saveParams: (type: string, params: Record<string, number | string | boolean>) => void;
getVisualConfig: (
type: string,
defaultPlots?: PlotDef[],
defaultHlines?: HLineDef[],
) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors };
saveVisual: (
type: string,
plots?: PlotDef[],
hlines?: HLineDef[],
cloudColors?: IchimokuCloudColors,
) => void;
}
function persistDefaults(
updated: IndicatorConfig,
saveParams: IndicatorMainDefaultsPanelProps['saveParams'],
saveVisual: IndicatorMainDefaultsPanelProps['saveVisual'],
) {
saveParams(updated.type, updated.params);
saveVisual(updated.type, updated.plots, updated.hlines, updated.cloudColors);
}
const ALL_TYPES = getSettingsIndicatorTypes();
const IndicatorMainDefaultsPanel: React.FC<IndicatorMainDefaultsPanelProps> = ({
chartIndicators,
onAddToChart,
onRemoveFromChart,
getParams,
saveParams,
getVisualConfig,
saveVisual,
}) => {
const onChartTypes = useMemo(() => indicatorTypesOnChart(chartIndicators), [chartIndicators]);
const [expandedTypes, setExpandedTypes] = useState<Set<string>>(() => new Set());
const [configs, setConfigs] = useState<Record<string, IndicatorConfig>>({});
const [search, setSearch] = useState('');
const filtered = useMemo(
() => filterSettingsIndicatorTypes(ALL_TYPES, search),
[search],
);
const { main: filteredMain, other: filteredOther } = useMemo(
() => partitionFilteredTypes(filtered),
[filtered],
);
useEffect(() => {
const next: Record<string, IndicatorConfig> = {};
for (const type of ALL_TYPES) {
const cfg = buildMainIndicatorConfig(type, chartIndicators, getParams, getVisualConfig);
if (cfg) next[type] = cfg;
}
setConfigs(next);
}, [chartIndicators, getParams, getVisualConfig]);
const toggleExpand = useCallback((type: string) => {
setExpandedTypes(prev => {
const next = new Set(prev);
if (next.has(type)) next.delete(type);
else next.add(type);
return next;
});
}, []);
const handleConfigChange = useCallback((type: string, updated: IndicatorConfig) => {
setConfigs(prev => ({ ...prev, [type]: updated }));
}, []);
const handleToggleChart = useCallback((type: string, enabled: boolean) => {
if (enabled) {
onAddToChart(type, configs[type]);
} else {
onRemoveFromChart(type);
}
}, [configs, onAddToChart, onRemoveFromChart]);
const handleRowDefaults = useCallback((type: string) => {
const base = configs[type];
if (!base) return;
const reset = resetConfigToDefaults(base);
persistDefaults(reset, saveParams, saveVisual);
handleConfigChange(type, reset);
}, [configs, saveParams, saveVisual, handleConfigChange]);
const handleResetAll = useCallback(() => {
if (!window.confirm('목록에 있는 모든 보조지표 기본값을 초기화할까요?')) return;
const next: Record<string, IndicatorConfig> = {};
for (const type of ALL_TYPES) {
const base = configs[type] ?? buildMainIndicatorConfig(type, [], getParams, getVisualConfig);
if (!base) continue;
const reset = resetConfigToDefaults(base);
next[type] = reset;
persistDefaults(reset, saveParams, saveVisual);
}
setConfigs(next);
}, [configs, getParams, getVisualConfig, saveParams, saveVisual]);
const renderRows = (types: string[]) => types.map(type => {
const cfg = configs[type];
if (!cfg) return null;
return (
<IndicatorSettingsListRow
key={type}
type={type}
config={cfg}
enabled={onChartTypes.has(type)}
expanded={expandedTypes.has(type)}
variant="settings"
onToggleExpand={() => toggleExpand(type)}
onToggleEnabled={on => handleToggleChart(type, on)}
onChange={updated => {
persistDefaults(updated, saveParams, saveVisual);
handleConfigChange(type, updated);
}}
onRowDefaults={() => handleRowDefaults(type)}
/>
);
});
return (
<>
<div className="stg-ind-intro">
<p>
<strong>Main</strong> {MAIN_INDICATOR_TYPES.length} , .
· , · DB .
</p>
<button type="button" className="stg-ind-reset-all" onClick={handleResetAll}>
</button>
</div>
<IndicatorSettingsListSearch
value={search}
onChange={setSearch}
totalCount={ALL_TYPES.length}
filteredCount={filtered.length}
className="stg-ind-search-block"
/>
<div className="stg-ind-list">
{filtered.length === 0 ? (
<div className="no-results ind-settings-no-results">
&apos;{search}&apos;
</div>
) : (
<>
{filteredMain.length > 0 && (
<section className="ind-settings-section">
<h3 className="ind-settings-section-title">
Main <span className="ind-settings-section-count">{filteredMain.length}</span>
</h3>
{renderRows(filteredMain)}
</section>
)}
{filteredOther.length > 0 && (
<section className="ind-settings-section">
<h3 className="ind-settings-section-title">
<span className="ind-settings-section-count">{filteredOther.length}</span>
</h3>
{renderRows(filteredOther)}
</section>
)}
</>
)}
</div>
</>
);
};
export default IndicatorMainDefaultsPanel;