164 lines
7.4 KiB
HTML
164 lines
7.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{{ .Title }}</title>
|
|
<!-- Tailwind CSS CDN -->
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<!-- TradingView Lightweight Charts v4 (v5는 API 호환성 문제로 고정) -->
|
|
<script src="https://unpkg.com/lightweight-charts@4.2.1/dist/lightweight-charts.standalone.production.js"></script>
|
|
<link rel="stylesheet" href="/static/css/custom.css">
|
|
<style>
|
|
/* 상승/하락 색상 (한국 주식 관행) */
|
|
.price-up { color: #ef4444; } /* 빨강 */
|
|
.price-down { color: #3b82f6; } /* 파랑 */
|
|
.price-flat { color: #6b7280; } /* 회색 */
|
|
|
|
/* 사이드바 토글 애니메이션 */
|
|
#sidebarWrapper {
|
|
display: flex;
|
|
overflow: hidden;
|
|
transition: width 0.25s ease, opacity 0.25s ease, margin 0.25s ease;
|
|
width: 240px;
|
|
opacity: 1;
|
|
}
|
|
#sidebarWrapper.sidebar-hidden {
|
|
width: 0;
|
|
opacity: 0;
|
|
margin-right: 0 !important;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-50 min-h-screen">
|
|
|
|
<!-- 네비게이션 -->
|
|
<nav class="bg-white shadow-sm sticky top-0 z-50">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex items-center justify-between h-14">
|
|
<!-- 사이드바 토글 버튼 -->
|
|
<button id="sidebarToggle" title="사이드바 열기/닫기"
|
|
class="mr-2 p-1.5 rounded-lg text-gray-500 hover:bg-gray-100 transition-colors shrink-0">
|
|
<!-- 사이드바 열림: 왼쪽 화살표(닫기) -->
|
|
<svg id="sidebarIconOpen" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/>
|
|
</svg>
|
|
<!-- 사이드바 닫힘: 오른쪽 화살표(열기) -->
|
|
<svg id="sidebarIconClose" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
|
</svg>
|
|
</button>
|
|
<!-- 로고 -->
|
|
<a href="/" class="text-lg font-bold text-gray-800 hover:text-blue-600 shrink-0 mr-2">
|
|
📈 주식 시세
|
|
</a>
|
|
<!-- 네비 메뉴 -->
|
|
<nav class="flex items-center gap-0.5 shrink-0">
|
|
<a href="/" class="text-sm px-3 py-1.5 rounded-lg font-medium transition-colors
|
|
{{ if eq .ActiveMenu "시세" }}bg-blue-50 text-blue-600{{ else }}text-gray-500 hover:bg-gray-100 hover:text-gray-800{{ end }}">시세</a>
|
|
<a href="/theme" class="text-sm px-3 py-1.5 rounded-lg font-medium transition-colors
|
|
{{ if eq .ActiveMenu "테마" }}bg-blue-50 text-blue-600{{ else }}text-gray-500 hover:bg-gray-100 hover:text-gray-800{{ end }}">테마</a>
|
|
<a href="/kospi200" class="text-sm px-3 py-1.5 rounded-lg font-medium transition-colors
|
|
{{ if eq .ActiveMenu "코스피200" }}bg-blue-50 text-blue-600{{ else }}text-gray-500 hover:bg-gray-100 hover:text-gray-800{{ end }}">코스피200</a>
|
|
{{ if .LoggedIn }}
|
|
<a href="/asset" class="text-sm px-3 py-1.5 rounded-lg font-medium transition-colors
|
|
{{ if eq .ActiveMenu "자산" }}bg-blue-50 text-blue-600{{ else }}text-gray-500 hover:bg-gray-100 hover:text-gray-800{{ end }}">자산</a>
|
|
<a href="/autotrade" class="text-sm px-3 py-1.5 rounded-lg font-medium transition-colors
|
|
{{ if eq .ActiveMenu "자동매매" }}bg-blue-50 text-blue-600{{ else }}text-gray-500 hover:bg-gray-100 hover:text-gray-800{{ end }}">자동매매</a>
|
|
{{ end }}
|
|
</nav>
|
|
<!-- 검색창 -->
|
|
<div class="flex-1 max-w-md mx-4 relative">
|
|
<input
|
|
id="searchInput"
|
|
type="text"
|
|
placeholder="종목명 또는 코드 검색"
|
|
autocomplete="off"
|
|
class="w-full px-4 py-2 text-sm border border-gray-300 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-400"
|
|
>
|
|
<!-- 자동완성 드롭다운 -->
|
|
<div id="searchDropdown" class="hidden absolute top-full left-0 right-0 mt-1 bg-white border border-gray-200 rounded-lg shadow-lg z-50 max-h-60 overflow-y-auto"></div>
|
|
</div>
|
|
<!-- 로그인/로그아웃 버튼 -->
|
|
{{ if .LoggedIn }}
|
|
<form method="POST" action="/logout" class="shrink-0">
|
|
<button type="submit"
|
|
class="text-xs px-3 py-1.5 rounded-lg text-gray-500 hover:bg-gray-100 hover:text-gray-800 font-medium transition-colors">
|
|
로그아웃
|
|
</button>
|
|
</form>
|
|
{{ else }}
|
|
<a href="/login" class="shrink-0 text-xs px-3 py-1.5 rounded-lg text-blue-600 hover:bg-blue-50 font-medium transition-colors">
|
|
로그인
|
|
</a>
|
|
{{ end }}
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- 지수 티커 바 -->
|
|
<div class="bg-gray-800 text-white text-xs">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-8 flex items-center gap-6 overflow-x-auto" id="indexTicker">
|
|
<span class="text-gray-400 shrink-0">로딩 중...</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 메인 콘텐츠 -->
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 flex gap-6 items-start">
|
|
<div id="sidebarWrapper">
|
|
{{ block "sidebar" . }}{{ end }}
|
|
</div>
|
|
<main class="flex-1 min-w-0">
|
|
{{ block "content" . }}{{ end }}
|
|
</main>
|
|
</div>
|
|
|
|
<!-- 공통 JavaScript -->
|
|
<script src="/static/js/websocket.js"></script>
|
|
<script src="/static/js/search.js"></script>
|
|
<script src="/static/js/indices.js"></script>
|
|
{{ block "scripts" . }}{{ end }}
|
|
|
|
<script>
|
|
(function () {
|
|
const wrapper = document.getElementById('sidebarWrapper');
|
|
const toggle = document.getElementById('sidebarToggle');
|
|
const iconOpen = document.getElementById('sidebarIconOpen');
|
|
const iconClose = document.getElementById('sidebarIconClose');
|
|
if (!wrapper || !toggle) return;
|
|
|
|
// 사이드바가 없는 페이지(sidebar 블록이 비어 있음)는 버튼 숨김
|
|
if (!wrapper.children.length) {
|
|
toggle.classList.add('hidden');
|
|
return;
|
|
}
|
|
|
|
const STORAGE_KEY = 'sidebar_visible';
|
|
|
|
function applyState(visible) {
|
|
if (visible) {
|
|
wrapper.classList.remove('sidebar-hidden');
|
|
iconOpen.classList.remove('hidden');
|
|
iconClose.classList.add('hidden');
|
|
} else {
|
|
wrapper.classList.add('sidebar-hidden');
|
|
iconOpen.classList.add('hidden');
|
|
iconClose.classList.remove('hidden');
|
|
}
|
|
localStorage.setItem(STORAGE_KEY, visible ? '1' : '0');
|
|
}
|
|
|
|
// 저장된 상태 복원 (기본값: 표시)
|
|
const saved = localStorage.getItem(STORAGE_KEY);
|
|
applyState(saved !== '0');
|
|
|
|
toggle.addEventListener('click', () => {
|
|
const isHidden = wrapper.classList.contains('sidebar-hidden');
|
|
applyState(isHidden); // 현재 숨겨져 있으면 보이게
|
|
});
|
|
})();
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|