fix: 종목명 글씨 자동맞춤 깜빡임 제거(길이기반 CSS) + ★ 보유 왼쪽 이동

JS 폭측정 자동맞춤은 리셋→축소 플래시가 패널 swap/자동갱신마다 깜빡여서 제거.
대신 이름 길이로 글씨크기 클래스(stock-sm 10자+/stock-xs 14자+) 서버 렌더 시 확정 → 깜빡임 없음.
당일거래 마크(★)는 line2 보유 왼쪽으로 이동.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hyowons
2026-06-08 16:37:10 +09:00
parent 5a5fe3129e
commit f146c939c0
+7 -22
View File
@@ -2517,6 +2517,9 @@ def _buy_rank_badge(buy_amount: int) -> str:
def _render_holding_row(r: dict, total_value: int, show_day_change: bool = False, key_suffix: str = '') -> str:
stock = html.escape(r['stock'])
# 종목명 길이 기반 글씨크기 — 길면 줄여서 한 줄에 맞춤(ellipsis 최소화, 렌더 시 확정이라 깜빡임 없음).
_nlen = len(r.get('stock', '') or '')
stock_cls = 'stock stock-xs' if _nlen >= 14 else ('stock stock-sm' if _nlen >= 10 else 'stock')
code = html.escape(r.get('code', '') or '')
accounts = html.escape('+'.join(r.get('accounts', [])))
qty = r.get('qty', 0)
@@ -2667,8 +2670,8 @@ def _render_holding_row(r: dict, total_value: int, show_day_change: bool = False
return f'''<details class="row {pcls} mode-held" data-row-key="{row_key}" data-rt-qty="{qty}" data-rt-cost="{eval_value - profit}" data-rt-px="{price}" data-rt-prevclose="{price - day_change}">
<summary>
<div class="left">
<div class="line1 line1-held">{_buy_rank_badge(buy_amount)}<span class="stock">{stock}</span></div>
<div class="line2"><span class="badge held">보유 {qty:,}</span>{_pending_badges_html(r)}<span class="muted small wt-chip">비중 <span class="rt-weight">{weight:.2f}</span>%</span>{star}</div>
<div class="line1 line1-held">{_buy_rank_badge(buy_amount)}<span class="{stock_cls}">{stock}</span></div>
<div class="line2">{star}<span class="badge held">보유 {qty:,}</span>{_pending_badges_html(r)}<span class="muted small wt-chip">비중 <span class="rt-weight">{weight:.2f}</span>%</span></div>
<div class="line3">{tag_chip}<span class="code">{accounts}</span></div>
{summary_journal_html}
</div>
@@ -4034,6 +4037,8 @@ details.row + .section-label { margin-top: 14px; padding-top: 24px; border-top-c
/* 보유행 1: 뱃지+당일마크+종목명+계좌 고정(nowrap). 이름 길면 .stock ellipsis 줄어듦. */
.line1-held { flex-wrap: nowrap; }
.stock { font-size: 14px; font-weight: 600; color: #f0f0f0; letter-spacing: -0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.stock.stock-sm { font-size: 12px; } /* 이름 10+ */
.stock.stock-xs { font-size: 10.5px; } /* 이름 14+ */
.code { font-size: 11px; color: #5a5f6c; font-weight: 400; flex: none; }
.line2 { display: flex; align-items: center; gap: 8px; font-size: 12px; min-width: 0; }
@@ -9077,25 +9082,6 @@ window.openPinModal = openPinModal;
})();</script>
<style>.rt-vi-badge{display:inline-block;margin-left:6px;padding:0 5px;border-radius:4px;font-size:10px;font-weight:700;color:#1a1205;background:#ffd166;vertical-align:middle}</style>'''
# 종목명 자동맞춤 — 길어서 잘릴 것 같으면 글씨를 줄여 한 줄에 맞춤(ellipsis 대신). 폭 실측 필요해 JS.
# 실시간 가격 갱신(1초)으로 재측정되면 레이아웃 부하 → MutationObserver는 '행 추가(패널 swap)'에만 반응하도록 필터.
stock_fit_script = r'''<script>(function(){
function fit(el){
el.style.fontSize=''; // 먼저 기본 크기로 복원(넓어지면 원복)
var min=10, size=parseFloat(getComputedStyle(el).fontSize)||14, guard=0;
while(el.scrollWidth>el.clientWidth+1 && size>min && guard++<14){ size-=0.5; el.style.fontSize=size+'px'; }
}
function fitAll(){ document.querySelectorAll('.line1-held .stock').forEach(fit); }
var t=null;
function schedule(){ if(t)clearTimeout(t); t=setTimeout(fitAll,80); }
function hasRow(n){ return n.nodeType===1 && ((n.matches&&n.matches('.line1-held'))||(n.querySelector&&n.querySelector('.line1-held .stock'))); }
new MutationObserver(function(ms){
for(var i=0;i<ms.length;i++){ var a=ms[i].addedNodes; for(var j=0;j<a.length;j++){ if(hasRow(a[j])){ schedule(); return; } } }
}).observe(document.body,{childList:true,subtree:true});
addEventListener('resize',schedule);
if(document.readyState!=='loading') schedule(); else addEventListener('DOMContentLoaded',schedule);
})();</script>'''
return f'''<!doctype html>
<html lang="ko">
<head>
@@ -9156,7 +9142,6 @@ window.openPinModal = openPinModal;
{order_modal_script}
{stock_name_tip_script}
{realtime_script}
{stock_fit_script}
</body>
</html>'''