실시간 차트 알림표시 위치 아이콘 버튼

This commit is contained in:
Macbook
2026-06-12 22:06:22 +09:00
parent 6118230471
commit 65fe1404b8
6 changed files with 47 additions and 32 deletions
+12
View File
@@ -12394,6 +12394,18 @@ html.theme-light .tam-disclaimer { color: #90a4ae; }
flex: 1; flex: 1;
line-height: 1.35; line-height: 1.35;
} }
/* 실시간 차트 상단 툴바 — 알림 팝업 위치 선택 */
.tv-toolbar-right .tmb-notify-layout-trigger {
width: 30px;
height: 30px;
border: none;
background: transparent;
}
.tv-toolbar-right .tmb-notify-layout-trigger:hover,
.tv-toolbar-right .tmb-notify-layout-trigger--open {
background: var(--bg3);
border: none;
}
.tmb-notify-layout-cols-row { .tmb-notify-layout-cols-row {
display: flex; display: flex;
align-items: center; align-items: center;
-1
View File
@@ -671,7 +671,6 @@ function App() {
saveAllIndicatorDefaults={saveAllIndicatorDefaults} saveAllIndicatorDefaults={saveAllIndicatorDefaults}
indicatorSettingsRevision={indicatorSettingsRevision} indicatorSettingsRevision={indicatorSettingsRevision}
onOpenNotificationsPage={openNotificationsPage} onOpenNotificationsPage={openNotificationsPage}
onOpenAppDownload={() => setAppDownloadOpen(true)}
/> />
</Suspense> </Suspense>
) : null; ) : null;
+7 -3
View File
@@ -58,7 +58,6 @@ import { fmtListTimestamp } from '../utils/backtestUiUtils';
export interface ChartWorkspaceViewProps { export interface ChartWorkspaceViewProps {
onOpenNotificationsPage: () => void; onOpenNotificationsPage: () => void;
onOpenAppDownload: () => void;
symbol: string; symbol: string;
timeframe: Timeframe; timeframe: Timeframe;
chartType: ChartType; chartType: ChartType;
@@ -315,7 +314,7 @@ export interface ChartWorkspaceViewProps {
function ChartWorkspaceViewInner(props: ChartWorkspaceViewProps) { function ChartWorkspaceViewInner(props: ChartWorkspaceViewProps) {
const { const {
onOpenNotificationsPage, onOpenAppDownload, onOpenNotificationsPage,
symbol, timeframe, chartType, theme, mode, logScale, showGrid, symbol, timeframe, chartType, theme, mode, logScale, showGrid,
toolbarActiveIndicators, layoutDef, syncOptions, activeSlot, toolbarActiveIndicators, layoutDef, syncOptions, activeSlot,
activeSlotSymbol, activeSlotTf, slot0InitProps, slotInitProps, activeSlotSymbol, activeSlotTf, slot0InitProps, slotInitProps,
@@ -383,7 +382,6 @@ function ChartWorkspaceViewInner(props: ChartWorkspaceViewProps) {
<> <>
<ChartToolbarNotify <ChartToolbarNotify
onOpenNotifyList={onOpenNotificationsPage} onOpenNotifyList={onOpenNotificationsPage}
onOpenAppDownload={onOpenAppDownload}
symbol={symbol} timeframe={layoutDef.count > 1 ? activeSlotTf : timeframe} chartType={chartType} symbol={symbol} timeframe={layoutDef.count > 1 ? activeSlotTf : timeframe} chartType={chartType}
theme={theme} mode={mode} logScale={logScale} showGrid={showGrid} theme={theme} mode={mode} logScale={logScale} showGrid={showGrid}
activeIndicators={toolbarActiveIndicators} activeIndicators={toolbarActiveIndicators}
@@ -516,6 +514,12 @@ function ChartWorkspaceViewInner(props: ChartWorkspaceViewProps) {
chartQuoteError={error} chartQuoteError={error}
priceExtremeLabelsVisible={chartPriceExtremeLabelsVisible} priceExtremeLabelsVisible={chartPriceExtremeLabelsVisible}
onTogglePriceExtremeLabels={handleTogglePriceExtremeLabels} onTogglePriceExtremeLabels={handleTogglePriceExtremeLabels}
tradeAlertPopupPosition={appDefaults.tradeAlertPopupPosition}
tradeAlertPopupLayout={appDefaults.tradeAlertPopupLayout}
tradeAlertPopupGridCols={appDefaults.tradeAlertPopupGridCols}
onTradeAlertPopupPosition={v => saveAppDef({ tradeAlertPopupPosition: v })}
onTradeAlertPopupLayout={v => saveAppDef({ tradeAlertPopupLayout: v })}
onTradeAlertPopupGridCols={v => saveAppDef({ tradeAlertPopupGridCols: v })}
/> />
{isMobile && (showMarketPanel || mobileRightOpen) && ( {isMobile && (showMarketPanel || mobileRightOpen) && (
-3
View File
@@ -164,7 +164,6 @@ export interface UseChartWorkspaceParams {
saveAllIndicatorDefaults: ReturnType<typeof import('../hooks/useIndicatorSettings').useIndicatorSettings>['saveAllIndicatorDefaults']; saveAllIndicatorDefaults: ReturnType<typeof import('../hooks/useIndicatorSettings').useIndicatorSettings>['saveAllIndicatorDefaults'];
indicatorSettingsRevision: number; indicatorSettingsRevision: number;
onOpenNotificationsPage: () => void; onOpenNotificationsPage: () => void;
onOpenAppDownload: () => void;
} }
export interface SettingsPageChartBindings { export interface SettingsPageChartBindings {
@@ -223,7 +222,6 @@ export function useChartWorkspace({
saveAllIndicatorDefaults: _saveAllIndicatorDefaults, saveAllIndicatorDefaults: _saveAllIndicatorDefaults,
indicatorSettingsRevision, indicatorSettingsRevision,
onOpenNotificationsPage, onOpenNotificationsPage,
onOpenAppDownload,
}: UseChartWorkspaceParams) { }: UseChartWorkspaceParams) {
void _saveAllIndicatorDefaults; void _saveAllIndicatorDefaults;
const initial = loadState(); const initial = loadState();
@@ -1969,7 +1967,6 @@ export function useChartWorkspace({
const viewProps: ChartWorkspaceViewProps = { const viewProps: ChartWorkspaceViewProps = {
onOpenNotificationsPage, onOpenNotificationsPage,
onOpenAppDownload,
symbol, timeframe, chartType, theme, mode, logScale, showGrid, symbol, timeframe, chartType, theme, mode, logScale, showGrid,
toolbarActiveIndicators, layoutDef, syncOptions, activeSlot, toolbarActiveIndicators, layoutDef, syncOptions, activeSlot,
activeSlotSymbol, activeSlotTf, slot0InitProps, slotInitProps, activeSlotSymbol, activeSlotTf, slot0InitProps, slotInitProps,
@@ -51,10 +51,8 @@ import Toolbar, { type ToolbarProps } from './Toolbar';
export const ChartToolbarNotify: React.FC<ToolbarProps & { export const ChartToolbarNotify: React.FC<ToolbarProps & {
onOpenNotifyList: () => void; onOpenNotifyList: () => void;
onOpenAppDownload?: () => void;
}> = ({ }> = ({
onOpenNotifyList, onOpenNotifyList,
onOpenAppDownload,
...toolbarProps ...toolbarProps
}) => { }) => {
const { unreadCount } = useTradeNotification(); const { unreadCount } = useTradeNotification();
@@ -63,7 +61,6 @@ export const ChartToolbarNotify: React.FC<ToolbarProps & {
{...toolbarProps} {...toolbarProps}
tradeNotifyUnread={unreadCount} tradeNotifyUnread={unreadCount}
onOpenTradeNotifications={onOpenNotifyList} onOpenTradeNotifications={onOpenNotifyList}
onOpenAppDownload={onOpenAppDownload}
/> />
); );
}; };
+27 -21
View File
@@ -42,6 +42,7 @@ import {
type ChartLiveQuote, type ChartLiveQuote,
} from '../utils/chartLiveQuote'; } from '../utils/chartLiveQuote';
import LayoutPicker from './LayoutPicker'; import LayoutPicker from './LayoutPicker';
import TradeAlertPopupMenubarSelect from './TradeAlertPopupMenubarSelect';
import { DEFAULT_SYNC, type LayoutDef, type SyncOptions } from '../utils/layoutTypes'; import { DEFAULT_SYNC, type LayoutDef, type SyncOptions } from '../utils/layoutTypes';
import { loadStrategies } from '../utils/backendApi'; import { loadStrategies } from '../utils/backendApi';
@@ -91,8 +92,6 @@ export interface ToolbarProps {
/** 매매 시그널 알림 (미확인 개수) */ /** 매매 시그널 알림 (미확인 개수) */
tradeNotifyUnread?: number; tradeNotifyUnread?: number;
onOpenTradeNotifications?: () => void; onOpenTradeNotifications?: () => void;
/** 모바일 앱 다운로드 */
onOpenAppDownload?: () => void;
/** 자석모드 현재 상태 */ /** 자석모드 현재 상태 */
magnetMode?: 'off' | 'weak' | 'strong'; magnetMode?: 'off' | 'weak' | 'strong';
/** 자석모드 토글 (off↔strong) */ /** 자석모드 토글 (off↔strong) */
@@ -146,6 +145,13 @@ export interface ToolbarProps {
/** 9·20일 신고가·신저가 차트 표시 (실시간 차트 상단 툴바) */ /** 9·20일 신고가·신저가 차트 표시 (실시간 차트 상단 툴바) */
priceExtremeLabelsVisible?: boolean; priceExtremeLabelsVisible?: boolean;
onTogglePriceExtremeLabels?: () => void; onTogglePriceExtremeLabels?: () => void;
/** 매매 알림 팝업 표시 위치·방식 */
tradeAlertPopupPosition?: string;
tradeAlertPopupLayout?: string;
tradeAlertPopupGridCols?: number;
onTradeAlertPopupPosition?: (v: import('../utils/tradeAlertPopupLayout').TradeAlertPopupPosition) => void;
onTradeAlertPopupLayout?: (v: import('../utils/tradeAlertPopupLayout').TradeAlertPopupLayout) => void;
onTradeAlertPopupGridCols?: (v: number) => void;
} }
// ─── SVG 아이콘 ──────────────────────────────────────────────────────────── // ─── SVG 아이콘 ────────────────────────────────────────────────────────────
@@ -229,14 +235,6 @@ const IcBell = () => (
<circle cx="7.5" cy="13" r="0.8" fill="currentColor" stroke="none"/> <circle cx="7.5" cy="13" r="0.8" fill="currentColor" stroke="none"/>
</svg> </svg>
); );
/** 모바일 앱 다운로드 */
const IcAppDownload = () => (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round">
<rect x="4" y="1.5" width="7" height="12" rx="1.5"/>
<line x1="7.5" y1="9" x2="7.5" y2="12"/>
<polyline points="5.5,10.5 7.5,12.5 9.5,10.5"/>
</svg>
);
/** 매매 시그널 알림 (번개 아이콘으로 가격 알림 벨과 구분) */ /** 매매 시그널 알림 (번개 아이콘으로 가격 알림 벨과 구분) */
const IcTradeSignal = () => ( const IcTradeSignal = () => (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"> <svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
@@ -814,7 +812,7 @@ const Toolbar: React.FC<ToolbarProps> = ({
onFitContent, onScrollToNow, onAddIndicator, onAddIndicators, onIndicatorOrderChange, onRemoveByType, onFitContent, onScrollToNow, onAddIndicator, onAddIndicators, onIndicatorOrderChange, onRemoveByType,
onAutoFib, onClearFib, onScreenshot, onAutoFib, onClearFib, onScreenshot,
onToggleStats, onToggleWatch, onToggleAlert, onToggleStats, onToggleWatch, onToggleAlert,
tradeNotifyUnread = 0, onOpenTradeNotifications, onOpenAppDownload, tradeNotifyUnread = 0, onOpenTradeNotifications,
magnetMode = 'off', onToggleMagnet, magnetMode = 'off', onToggleMagnet,
onUndo, onRedo, canUndo, canRedo, onClearDrawings, onUndo, onRedo, canUndo, canRedo, onClearDrawings,
onToggleGrid, onToggleGrid,
@@ -837,6 +835,12 @@ const Toolbar: React.FC<ToolbarProps> = ({
chartQuoteError = null, chartQuoteError = null,
priceExtremeLabelsVisible = false, priceExtremeLabelsVisible = false,
onTogglePriceExtremeLabels, onTogglePriceExtremeLabels,
tradeAlertPopupPosition,
tradeAlertPopupLayout,
tradeAlertPopupGridCols,
onTradeAlertPopupPosition,
onTradeAlertPopupLayout,
onTradeAlertPopupGridCols,
}) => { }) => {
const [showMarket, setShowMarket] = React.useState(false); const [showMarket, setShowMarket] = React.useState(false);
const [showTfMenu, setShowTfMenu] = React.useState(false); const [showTfMenu, setShowTfMenu] = React.useState(false);
@@ -1371,17 +1375,18 @@ const Toolbar: React.FC<ToolbarProps> = ({
</svg> </svg>
</button> </button>
)} )}
{onOpenAppDownload && (
<button
className="tv-icon-btn"
onClick={onOpenAppDownload}
title="GoldenChart 모바일 앱 다운로드"
aria-label="앱 다운로드"
>
<IcAppDownload />
</button>
)}
{onOpenTradeNotifications && ( {onOpenTradeNotifications && (
<>
{(onTradeAlertPopupPosition || onTradeAlertPopupLayout) && (
<TradeAlertPopupMenubarSelect
position={tradeAlertPopupPosition}
layout={tradeAlertPopupLayout}
gridCols={tradeAlertPopupGridCols}
onPositionChange={onTradeAlertPopupPosition}
onLayoutChange={onTradeAlertPopupLayout}
onGridColsChange={onTradeAlertPopupGridCols}
/>
)}
<span className="tv-trade-notify-wrap"> <span className="tv-trade-notify-wrap">
<button <button
className="tv-icon-btn" className="tv-icon-btn"
@@ -1396,6 +1401,7 @@ const Toolbar: React.FC<ToolbarProps> = ({
</span> </span>
)} )}
</span> </span>
</>
)} )}
<button className="tv-icon-btn" onClick={onToggleAlert} title="가격 알림"> <button className="tv-icon-btn" onClick={onToggleAlert} title="가격 알림">
<IcBell /> <IcBell />