stock AI 어드바이저 추가 및 UX 개선

- Gemini Pro 기반 AI 어드바이저 탭 추가 (TAB_ADVISOR)
  - 보유 종목 현재가 + 뉴스 → 종목별 매도/매수/분할매도 지침
  - 5분 캐시, 강제 새로고침 버튼
  - 경량 마크다운 렌더러 (AdvisorMarkdown)
- 실현손익 수수료 → 수수료 & 세금으로 레이블 변경
- 총 자산 추이 그래프: 0 데이터 제외 (장 미개장일 필터)
- Todo 완료 패널 하단 이동 + 날짜 필터 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-25 03:54:50 +09:00
parent 2c4b1e2e3a
commit d1ecf13400
4 changed files with 596 additions and 17 deletions

View File

@@ -462,6 +462,10 @@
color: var(--muted);
}
.stock-profit.is-negative {
color: #3b82f6;
}
.stock-result {
border: 1px solid var(--line);
border-radius: 14px;
@@ -2650,3 +2654,259 @@
grid-column: span 1;
}
}
/* ═══════════════════════════════════════════════════════════════════════
AI Advisor Tab (TAB_ADVISOR)
═══════════════════════════════════════════════════════════════════════ */
/* ── Tab button ──────────────────────────────────────────────────────── */
.stock-main-tab--advisor {
position: relative;
}
.stock-main-tab--advisor::after {
content: 'AI';
position: absolute;
top: 4px;
right: 4px;
font-size: 8px;
font-weight: 800;
letter-spacing: 0.05em;
background: linear-gradient(135deg, #6366f1, #8b5cf6);
color: #fff;
border-radius: 4px;
padding: 1px 4px;
line-height: 1.4;
}
/* ── Panel layout ────────────────────────────────────────────────────── */
.advisor-panel {
display: flex;
flex-direction: column;
gap: 20px;
}
.advisor-panel__head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
}
.advisor-panel__title-block {
display: flex;
flex-direction: column;
gap: 4px;
}
.advisor-panel__badge {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #818cf8;
background: rgba(129, 140, 248, 0.12);
border: 1px solid rgba(129, 140, 248, 0.3);
border-radius: 6px;
padding: 2px 8px;
width: fit-content;
}
.advisor-panel__title {
margin: 0;
font-size: 18px;
font-weight: 700;
color: var(--text-bright);
}
.advisor-panel__sub {
margin: 0;
font-size: 12px;
color: var(--text-muted);
line-height: 1.5;
max-width: 480px;
}
.advisor-panel__actions {
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.advisor-panel__timestamp {
font-size: 11px;
color: var(--text-muted);
background: rgba(255, 255, 255, 0.04);
border: 1px solid var(--line);
border-radius: 8px;
padding: 4px 10px;
}
/* ── Loading state ───────────────────────────────────────────────────── */
.advisor-panel__loading {
display: flex;
align-items: center;
gap: 16px;
padding: 32px 0;
}
.advisor-loading-spinner {
width: 36px;
height: 36px;
border-radius: 50%;
border: 3px solid rgba(129, 140, 248, 0.15);
border-top-color: #818cf8;
animation: spin 0.9s linear infinite;
flex-shrink: 0;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.advisor-loading-text {
display: flex;
flex-direction: column;
gap: 4px;
}
.advisor-loading-text p {
margin: 0;
font-size: 14px;
color: var(--text-bright);
}
.advisor-loading-sub {
font-size: 12px !important;
color: var(--text-muted) !important;
}
/* ── Error state ─────────────────────────────────────────────────────── */
.advisor-panel__error {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
border-radius: 12px;
background: rgba(249, 182, 177, 0.08);
border: 1px solid rgba(249, 182, 177, 0.3);
color: #f9b6b1;
font-size: 13px;
}
/* ── Empty state ─────────────────────────────────────────────────────── */
.advisor-panel__empty {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 60px 0;
color: var(--text-muted);
}
.advisor-panel__empty-icon {
font-size: 40px;
opacity: 0.4;
}
/* ── Analysis body ───────────────────────────────────────────────────── */
.advisor-panel__body {
display: flex;
flex-direction: column;
gap: 16px;
}
.advisor-panel__disclaimer {
margin: 0;
font-size: 11px;
color: var(--text-muted);
opacity: 0.6;
border-top: 1px solid var(--line);
padding-top: 12px;
}
/* ── Markdown renderer ───────────────────────────────────────────────── */
.adv-md {
display: flex;
flex-direction: column;
gap: 2px;
line-height: 1.75;
}
.adv-md-h2 {
margin: 20px 0 6px;
font-size: 16px;
font-weight: 700;
color: var(--text-bright);
padding-bottom: 6px;
border-bottom: 1px solid var(--line);
}
.adv-md-h3 {
margin: 14px 0 4px;
font-size: 14px;
font-weight: 700;
color: #818cf8;
}
.adv-md-p {
margin: 0;
font-size: 13px;
color: var(--text);
line-height: 1.75;
}
.adv-md-p strong {
color: var(--text-bright);
font-weight: 700;
}
.adv-md-p em {
color: #fbbf24;
font-style: normal;
}
.adv-md-p code {
font-family: monospace;
font-size: 12px;
background: rgba(255, 255, 255, 0.06);
border: 1px solid var(--line);
border-radius: 4px;
padding: 1px 5px;
color: #34d399;
}
.adv-md-hr {
border: none;
border-top: 1px solid var(--line);
margin: 12px 0;
}
.adv-md-gap {
height: 6px;
}
/* ── Responsive ──────────────────────────────────────────────────────── */
@media (max-width: 640px) {
.advisor-panel__head {
flex-direction: column;
}
.advisor-panel__actions {
width: 100%;
justify-content: flex-end;
}
}