위젯 기능 추가

This commit is contained in:
Macbook
2026-06-14 01:03:51 +09:00
parent 95595f7e9e
commit 6936792ad4
57 changed files with 6728 additions and 540 deletions
+46 -1
View File
@@ -10,7 +10,7 @@ import type { AuthSession } from '../utils/auth';
import type { TradeAlertPopupLayout, TradeAlertPopupPosition } from '../utils/tradeAlertPopupLayout';
import { canAccessMenu } from '../utils/permissions';
export type MenuPage = 'dashboard' | 'chart' | 'paper' | 'virtual' | 'trend-search' | 'verification-board' | 'strategy' | 'strategy-editor' | 'strategy-evaluation' | 'backtest' | 'analysis-report' | 'notifications' | 'settings';
export type MenuPage = 'dashboard' | 'chart' | 'paper' | 'virtual' | 'trend-search' | 'verification-board' | 'strategy' | 'strategy-editor' | 'strategy-evaluation' | 'backtest' | 'analysis-report' | 'notifications' | 'settings' | 'widget-dashboard';
interface TopMenuBarProps {
activePage: MenuPage;
@@ -42,6 +42,10 @@ interface TopMenuBarProps {
onLogout?: () => void;
/** 브라우저 전체화면 (모든 화면에서 사용) */
onFullscreen?: () => void;
/** 플로팅 위젯 레이아웃 선택 열기 */
onOpenFloatingWidgets?: () => void;
/** 실행 중인 플로팅 위젯 창 수 */
floatingWidgetCount?: number;
/** 메뉴별 접근 허용 (없으면 전체 표시) */
menuPermissions?: Record<string, boolean>;
}
@@ -196,8 +200,28 @@ const IcVerificationBoard = () => (
</svg>
);
const IcWidget = () => (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="1" y="1" width="6" height="6" rx="1"/>
<rect x="9" y="1" width="6" height="4" rx="1"/>
<rect x="1" y="9" width="6" height="6" rx="1"/>
<rect x="9" y="7" width="6" height="8" rx="1"/>
</svg>
);
const IcFloatingWidgetAdd = () => (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="1" y="1" width="6" height="6" rx="1"/>
<rect x="9" y="1" width="6" height="6" rx="1"/>
<rect x="1" y="9" width="6" height="6" rx="1"/>
<line x1="12" y1="12" x2="12" y2="15"/>
<line x1="10.5" y1="13.5" x2="13.5" y2="13.5"/>
</svg>
);
const MENU_ITEMS: { page: MenuPage; label: string; icon: React.ReactNode }[] = [
{ page: 'dashboard', label: '대시보드', icon: <IcDashboard /> },
{ page: 'widget-dashboard', label: '위젯', icon: <IcWidget /> },
{ page: 'chart', label: '실시간차트', icon: <IcChart /> },
{ page: 'paper', label: '투자관리', icon: <IcPaper /> },
{ page: 'virtual', label: '가상매매', icon: <IcVirtual /> },
@@ -228,6 +252,8 @@ export const TopMenuBar = memo(function TopMenuBar({
onLoginClick,
onLogout,
onFullscreen,
onOpenFloatingWidgets,
floatingWidgetCount = 0,
menuPermissions,
}: TopMenuBarProps) {
const [isFullscreen, setIsFullscreen] = useState(() => !!document.fullscreenElement);
@@ -281,6 +307,25 @@ export const TopMenuBar = memo(function TopMenuBar({
{/* 우측 영역 */}
<div className="tmb-right">
{onOpenFloatingWidgets && (
<div className="tmb-floating-widget-wrap">
<button
type="button"
className="tmb-floating-widget-btn"
onClick={onOpenFloatingWidgets}
title="플로팅 위젯 추가"
aria-label="플로팅 위젯 추가"
>
<IcFloatingWidgetAdd />
</button>
{floatingWidgetCount > 0 && (
<span className="tmb-floating-widget-count" aria-hidden>
{floatingWidgetCount > 9 ? '9+' : floatingWidgetCount}
</span>
)}
</div>
)}
{onOpenAppDownload && (
<>
<button