feat(ui): roll out light/dark theme to board, publish, rework, discover, etc.

- board: tokenized kanban columns/cards; page-header + 사용법 modal (drag guide)
- publish: tokenized table/tabs; accent tab-active; page-header + 사용법 modal
- rework: tokenized the many dark-assuming inline styles so the editor renders
  correctly in the light theme
- discover/channels/production/channel_detail: tokenized dark-assuming colors
  (white text, translucent-white surfaces, #1e1e2d) for light-theme readability

Verified board/publish/rework/discover render cleanly in light.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hehihoho3@gmail.com 2026-06-13 06:07:51 +09:00
parent 616003479b
commit 52c6b51e61
7 changed files with 136 additions and 64 deletions

View File

@ -8,29 +8,51 @@
<body>
<div layout:fragment="content">
<header class="mb-4 flex items-center justify-between">
<div class="page-header">
<div>
<h1 class="text-2xl font-bold mb-1">작업 보드</h1>
<p class="text-muted">카드를 드래그해 단계를 옮기세요. 수집 → 검토 → 작업대상 → 완료.</p>
<h1>칸반 보드</h1>
<p class="sub">카드를 드래그해 단계를 옮기세요. 수집 → 검토 → 작업대상 → 완료.</p>
</div>
<div class="actions">
<button class="btn btn-secondary" onclick="openHelp()"><i data-lucide="help-circle" style="width:15px;"></i> 사용법</button>
<button class="btn btn-secondary" onclick="loadBoard()"><i data-lucide="refresh-cw" style="width:15px;"></i> 새로고침</button>
</div>
</div>
<!-- 사용법 모달 -->
<div id="helpModal" class="modal-overlay" onclick="if(event.target===this) closeHelp()">
<div class="modal-card">
<div class="modal-head"><h3>📖 칸반 보드 사용법</h3><button class="modal-close" onclick="closeHelp()">&times;</button></div>
<div class="modal-body">
<div class="help-item">
<div class="hi-ic"><i data-lucide="columns-3"></i></div>
<div><div class="hi-t">단계(컬럼)</div><div class="hi-d"><b>수집됨 → 검토중 → 작업대상 → 완료</b> 순으로 영상의 진행 상태를 나타냅니다. <b>제외</b>는 작업하지 않을 영상입니다.</div></div>
</div>
<div class="help-item">
<div class="hi-ic"><i data-lucide="move"></i></div>
<div><div class="hi-t">드래그로 단계 이동</div><div class="hi-d">카드를 <b>끌어다 다른 컬럼에 놓으면</b> 상태가 바로 바뀝니다(저장됨). 상단 숫자는 컬럼별 카드 수입니다.</div></div>
</div>
<div class="help-item">
<div class="hi-ic"><i data-lucide="wand-2"></i></div>
<div><div class="hi-t">카드</div><div class="hi-d">썸네일·제목·지표(조회·시간당·길이)와 배율을 보여줍니다. <b>🪄 아이콘</b>으로 재가공 에디터로 이동합니다.</div></div>
</div>
</div>
</div>
</div>
<button class="btn btn-secondary px-4 py-2 flex items-center gap-1" onclick="loadBoard()">
<i data-lucide="refresh-cw" style="width:16px;"></i> 새로고침
</button>
</header>
<div id="board" style="display:grid; grid-template-columns: repeat(5, minmax(220px, 1fr)); gap:1rem; align-items:start; overflow-x:auto;">
<!-- columns injected -->
</div>
<style>
.kb-col { background: rgba(255,255,255,0.02); border:1px solid var(--glass-border); border-radius: var(--radius-md); display:flex; flex-direction:column; min-height:200px; }
.kb-col-head { padding:12px; border-bottom:1px solid var(--glass-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; }
.kb-col { background: var(--surface-2); border:1px solid var(--border); border-radius: var(--r); display:flex; flex-direction:column; min-height:200px; }
.kb-col-head { padding:12px; border-bottom:1px solid var(--border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--surface-2); border-radius:var(--r) var(--r) 0 0; }
.kb-body { padding:10px; display:flex; flex-direction:column; gap:8px; min-height:120px; flex:1; transition: background 0.15s; }
.kb-body.drag-over { background: rgba(124,58,237,0.12); }
.kb-card { background: var(--glass-bg,#1e1e2d); border:1px solid var(--glass-border); border-radius:8px; padding:8px; cursor:grab; transition: transform 0.1s, border-color 0.15s; }
.kb-card:hover { border-color:#7C3AED88; }
.kb-body.drag-over { background: var(--accent-soft); }
.kb-card { background: var(--surface); border:1px solid var(--border); border-radius:9px; padding:9px; cursor:grab; box-shadow:var(--shadow); transition: transform 0.1s, border-color 0.15s; }
.kb-card:hover { border-color: var(--accent); }
.kb-card.dragging { opacity:0.5; }
.kb-count { font-size:0.75rem; background:rgba(255,255,255,0.08); padding:2px 8px; border-radius:999px; }
.kb-count { font-size:0.75rem; font-weight:600; background:var(--surface); border:1px solid var(--border); color:var(--text-2); padding:2px 9px; border-radius:999px; }
</style>
<script th:inline="javascript">
@ -46,6 +68,14 @@
let dragId = null;
function esc(s){ return (s==null?'':String(s)).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
function fmt(n){ return (n==null)?'-':Number(n).toLocaleString(); }
function durBadge(v){
if(v.isShorts) return 'Shorts';
const s = v.durationSec;
if(s==null || s<=0) return '';
const m = Math.floor(s/60), sec = s%60;
return m+':'+String(sec).padStart(2,'0');
}
async function api(url, opts){
const res = await fetch(url, opts);
const json = await res.json().catch(()=>({}));
@ -56,6 +86,12 @@
function cardHtml(v){
const ratio = v.viewsPerSubRatio!=null ? Number(v.viewsPerSubRatio).toFixed(1)+'x' : '';
const ratioColor = (v.viewsPerSubRatio>=10)?'#ef4444':((v.viewsPerSubRatio>=2)?'#f59e0b':'#10b981');
const db = durBadge(v);
const metrics = [
v.viewCount!=null ? '👁 '+fmt(v.viewCount) : '',
v.viewsPerHour!=null ? '⚡ '+fmt(Math.round(v.viewsPerHour))+'/h' : '',
db ? '⏱ '+db : ''
].filter(Boolean).join('&nbsp;&nbsp;·&nbsp;&nbsp;');
return `<div class="kb-card" draggable="true" data-id="${v.id}">
<div style="display:flex; gap:8px;">
<img src="${esc(v.thumbnailUrl)}" style="width:64px; height:36px; object-fit:cover; border-radius:4px; flex-shrink:0;">
@ -63,6 +99,7 @@
<div class="text-sm font-bold" style="display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; line-height:1.3;">${esc(v.title)}</div>
</div>
</div>
${metrics?`<div class="text-muted mt-2" style="font-size:0.68rem; line-height:1.4;">${metrics}</div>`:''}
<div class="flex items-center justify-between mt-2">
<span class="text-muted" style="font-size:0.7rem;">${esc(v.channelTitle||'')}</span>
<div class="flex items-center gap-2">
@ -145,6 +182,10 @@
});
}
function openHelp(){ document.getElementById('helpModal').classList.add('open'); }
function closeHelp(){ document.getElementById('helpModal').classList.remove('open'); }
document.addEventListener('keydown', e => { if(e.key === 'Escape') closeHelp(); });
loadBoard();
/*]]>*/
</script>

View File

@ -70,7 +70,7 @@
<!-- Video List Table -->
<div class="card p-0" style="overflow-x: auto;">
<table class="w-full" style="border-collapse: collapse; text-align: left;">
<thead style="background: rgba(255,255,255,0.02); border-bottom: 1px solid var(--glass-border);">
<thead style="background: var(--surface-2); border-bottom: 1px solid var(--glass-border);">
<tr>
<th class="p-4 text-sm font-bold text-muted">Video</th>
<th class="p-4 text-sm font-bold text-muted text-center">Script</th>
@ -315,10 +315,10 @@
options: {
responsive: true, maintainAspectRatio: false,
interaction: { mode: 'index', intersect: false },
plugins: { legend: { labels: { color: '#cbd5e1' } } },
plugins: { legend: { labels: { color: 'var(--text-2)' } } },
scales: {
x: { ticks: { color: '#94a3b8' }, grid: { color: 'rgba(255,255,255,0.05)' } },
y: { position: 'left', ticks: { color: '#a78bfa' }, grid: { color: 'rgba(255,255,255,0.05)' }, title: { display: true, text: '구독자', color: '#a78bfa' } },
x: { ticks: { color: '#94a3b8' }, grid: { color: 'var(--surface-2)' } },
y: { position: 'left', ticks: { color: '#a78bfa' }, grid: { color: 'var(--surface-2)' }, title: { display: true, text: '구독자', color: '#a78bfa' } },
y1: { position: 'right', ticks: { color: '#34d399' }, grid: { drawOnChartArea: false }, title: { display: true, text: '조회수', color: '#34d399' } }
}
}

View File

@ -40,13 +40,13 @@
onchange="updateSelectedCount(); event.stopPropagation();">
<div class="custom-checkbox flex items-center justify-center" style="
width: 24px; height: 24px;
border: 2px solid rgba(255,255,255,0.2);
border: 2px solid var(--border-strong);
border-radius: 6px;
background: rgba(255,255,255,0.05);
background: var(--surface-2);
transition: all 0.2s ease;
pointer-events: none;
">
<i data-lucide="check" style="width: 16px; height: 16px; color: white; display: none;"></i>
<i data-lucide="check" style="width: 16px; height: 16px; color: var(--text); display: none;"></i>
</div>
</div>
@ -75,13 +75,13 @@
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.5rem;">
<div class="p-4"
style="background: rgba(255,255,255,0.03); border-radius: 8px; text-align: center;">
style="background: var(--surface-2); border-radius: 8px; text-align: center;">
<div class="text-muted mb-4" style="font-size: 0.75rem">Videos</div>
<div class="font-bold" th:text="${#numbers.formatInteger(channel.videoCount ?: 0, 0, 'COMMA')}">450
</div>
</div>
<div class="p-4"
style="background: rgba(255,255,255,0.03); border-radius: 8px; text-align: center;">
style="background: var(--surface-2); border-radius: 8px; text-align: center;">
<div class="text-muted mb-4" style="font-size: 0.75rem">Total Views</div>
<div class="font-bold" th:text="${#numbers.formatInteger(channel.viewCount ?: 0, 0, 'COMMA')}">45K
</div>
@ -224,8 +224,8 @@
} else {
card.style.borderColor = 'var(--glass-border)';
card.style.background = 'var(--glass-bg)';
customCb.style.background = 'rgba(255,255,255,0.05)';
customCb.style.borderColor = 'rgba(255,255,255,0.2)';
customCb.style.background = 'var(--surface-2)';
customCb.style.borderColor = 'var(--border-strong)';
checkIcon.style.display = 'none';
}
});

View File

@ -67,7 +67,7 @@
<!-- 결과 테이블 -->
<div class="card p-0" style="overflow-x:auto;">
<table class="w-full" style="border-collapse:collapse; text-align:left;">
<thead style="background:rgba(255,255,255,0.02); border-bottom:1px solid var(--glass-border);">
<thead style="background:var(--surface-2); border-bottom:1px solid var(--glass-border);">
<tr>
<th class="p-3 text-sm font-bold text-muted">썸네일</th>
<th class="p-3 text-sm font-bold text-muted">제목</th>
@ -89,7 +89,7 @@
<!-- 영상 모달 -->
<div id="videoModal" style="display:none; position:fixed; z-index:1000; left:0; top:0; width:100%; height:100%; background:rgba(0,0,0,0.85); align-items:center; justify-content:center;" onclick="if(event.target===this) closeVideoModal()">
<div style="position:relative; width:95%; max-width:900px; background:var(--glass-bg,#1e1e2d); border-radius:12px; padding:16px; border:1px solid var(--glass-border);">
<div style="position:relative; width:95%; max-width:900px; background:var(--glass-bg,var(--surface)); border-radius:12px; padding:16px; border:1px solid var(--glass-border);">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:12px;">
<h3 class="text-lg font-bold truncate pr-4" id="modalTitle">Video</h3>
<button onclick="closeVideoModal()" class="text-muted hover:text-white" style="font-size:28px; line-height:1; background:none; border:none; cursor:pointer;">&times;</button>
@ -99,8 +99,8 @@
</div>
<style>
.row-sel { padding:4px 6px; background:rgba(255,255,255,0.05); border:1px solid var(--glass-border); border-radius:6px; color:white; font-size:0.8rem; outline:none; }
.row-sel option { background:#1e1e2d; color:white; }
.row-sel { padding:4px 6px; background:var(--surface-2); border:1px solid var(--glass-border); border-radius:6px; color:var(--text); font-size:0.8rem; outline:none; }
.row-sel option { background:var(--surface); color:var(--text); }
</style>
<script th:inline="javascript">
@ -172,11 +172,11 @@
</td>
<td class="p-3" style="max-width:280px;">
<div class="font-bold text-sm" style="display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;">
<a href="https://www.youtube.com/watch?v=${v.videoId}" target="_blank" class="hover:underline text-white">${esc(v.title)}</a>${shortsBadge}
<a href="https://www.youtube.com/watch?v=${v.videoId}" target="_blank" class="hover:underline">${esc(v.title)}</a>${shortsBadge}
</div>
</td>
<td class="p-3 text-sm text-muted" style="max-width:130px;">
<a href="${v.ytChannelId?('https://www.youtube.com/channel/'+v.ytChannelId):'#'}" target="_blank" class="hover:underline truncate" style="color:#e2e8f0;">${esc(v.channelTitle||'-')}</a>
<a href="${v.ytChannelId?('https://www.youtube.com/channel/'+v.ytChannelId):'#'}" target="_blank" class="hover:underline truncate" style="color:var(--text-2);">${esc(v.channelTitle||'-')}</a>
</td>
<td class="p-3 text-sm">${fmt(v.subscriberCount)}</td>
<td class="p-3 text-sm">${fmt(v.viewCount)}</td>

View File

@ -20,7 +20,7 @@
<div class="card p-0" style="overflow-x: auto;">
<h3 class="p-4 text-lg font-bold border-b border-[var(--glass-border)]">Crawl History</h3>
<table class="w-full" style="border-collapse: collapse; text-align: left;">
<thead style="background: rgba(255,255,255,0.02); border-bottom: 1px solid var(--glass-border);">
<thead style="background: var(--surface-2); border-bottom: 1px solid var(--glass-border);">
<tr>
<th class="p-4 text-sm font-bold text-muted">ID</th>
<th class="p-4 text-sm font-bold text-muted">Crawled Date</th>
@ -32,7 +32,7 @@
<tr th:each="history : ${historyList}"
th:onclick="'location.href=\'/production/' + ${history.id} + '\''"
style="border-bottom: 1px solid var(--glass-border); cursor: pointer; transition: background 0.2s;"
onmouseover="this.style.background='rgba(255,255,255,0.03)'"
onmouseover="this.style.background='var(--surface-2)'"
onmouseout="this.style.background='transparent'">
<td class="p-4 text-sm" th:text="${history.id}">1</td>
<td class="p-4 text-sm text-muted"

View File

@ -8,29 +8,55 @@
<body>
<div layout:fragment="content">
<header class="mb-4">
<h1 class="text-2xl font-bold mb-1">발행 큐</h1>
<p class="text-muted">재가공한 영상의 발행 패키지를 단계별로 관리합니다. (실제 업로드는 수동 — 여기서 준비·추적)</p>
</header>
<div class="page-header">
<div>
<h1>발행 큐</h1>
<p class="sub">재가공한 영상의 발행 패키지를 단계별로 관리합니다. (실제 업로드는 수동 — 여기서 준비·추적)</p>
</div>
<div class="actions">
<button class="btn btn-secondary" onclick="openHelp()"><i data-lucide="help-circle" style="width:15px;"></i> 사용법</button>
</div>
</div>
<div class="flex gap-2 mb-4" id="tabs">
<button class="btn btn-secondary px-4 py-2 tab active" data-status="" onclick="setTab(this,'')">전체</button>
<button class="btn btn-secondary px-4 py-2 tab" data-status="DRAFT" onclick="setTab(this,'DRAFT')">작성중</button>
<button class="btn btn-secondary px-4 py-2 tab" data-status="READY" onclick="setTab(this,'READY')">발행대기</button>
<button class="btn btn-secondary px-4 py-2 tab" data-status="PUBLISHED" onclick="setTab(this,'PUBLISHED')">발행완료</button>
<span id="cnt" class="text-sm text-muted" style="margin-left:auto; align-self:center;"></span>
<!-- 사용법 모달 -->
<div id="helpModal" class="modal-overlay" onclick="if(event.target===this) closeHelp()">
<div class="modal-card">
<div class="modal-head"><h3>📖 발행 큐 사용법</h3><button class="modal-close" onclick="closeHelp()">&times;</button></div>
<div class="modal-body">
<div class="help-item">
<div class="hi-ic"><i data-lucide="list-checks"></i></div>
<div><div class="hi-t">상태 탭</div><div class="hi-d"><b>작성중 → 발행대기 → 발행완료</b>로 발행 준비 단계를 거릅니다. 탭으로 상태별로 필터합니다.</div></div>
</div>
<div class="help-item">
<div class="hi-ic"><i data-lucide="pencil"></i></div>
<div><div class="hi-t">발행안 만들기</div><div class="hi-d">발행 패키지는 <b>재가공 화면 하단</b>에서 제목·설명·해시태그·플랫폼·예약을 저장하면 생성됩니다. 표의 <b>✏️</b>로 다시 편집합니다.</div></div>
</div>
<div class="help-item">
<div class="hi-ic"><i data-lucide="upload-cloud"></i></div>
<div><div class="hi-t">업로드 & 기록</div><div class="hi-d">실제 업로드는 <b>플랫폼에서 수동</b>으로 합니다. 업로드 후 URL을 기록하면 ‘발행완료’로 추적됩니다. <b>📋</b>로 설명+해시태그를 복사하세요.</div></div>
</div>
</div>
</div>
</div>
<div class="flex gap-2 mb-4" id="tabs" style="flex-wrap:wrap; align-items:center;">
<button class="btn btn-secondary tab active" data-status="" onclick="setTab(this,'')">전체</button>
<button class="btn btn-secondary tab" data-status="DRAFT" onclick="setTab(this,'DRAFT')">작성중</button>
<button class="btn btn-secondary tab" data-status="READY" onclick="setTab(this,'READY')">발행대기</button>
<button class="btn btn-secondary tab" data-status="PUBLISHED" onclick="setTab(this,'PUBLISHED')">발행완료</button>
<span id="cnt" class="badge badge-muted" style="margin-left:auto;"></span>
</div>
<div class="card p-0" style="overflow-x:auto;">
<table class="w-full" style="border-collapse:collapse; text-align:left;">
<thead style="background:rgba(255,255,255,0.02); border-bottom:1px solid var(--glass-border);">
<thead>
<tr>
<th class="p-3 text-sm font-bold text-muted">상태</th>
<th class="p-3 text-sm font-bold text-muted">플랫폼</th>
<th class="p-3 text-sm font-bold text-muted">제목</th>
<th class="p-3 text-sm font-bold text-muted">예약</th>
<th class="p-3 text-sm font-bold text-muted">발행 URL</th>
<th class="p-3 text-sm font-bold text-muted">관리</th>
<th>상태</th>
<th>플랫폼</th>
<th>제목</th>
<th>예약</th>
<th>발행 URL</th>
<th>관리</th>
</tr>
</thead>
<tbody id="body">
@ -40,7 +66,8 @@
</div>
<style>
.tab.active { border-color:#7C3AED; color:#fff; }
.tab { padding:0.5rem 1rem; }
.tab.active { background:var(--accent-soft); border-color:var(--accent); color:var(--accent); }
</style>
<script th:inline="javascript">
@ -74,7 +101,7 @@
body.innerHTML = data.map(p=>{
const st = ST[p.status] || {t:p.status,cls:'badge-muted'};
const sched = p.scheduledAt ? String(p.scheduledAt).substring(0,16).replace('T',' ') : '-';
const urlCell = p.publishedUrl ? `<a href="${esc(p.publishedUrl)}" target="_blank" class="hover:underline" style="color:#60a5fa;">열기</a>` : '-';
const urlCell = p.publishedUrl ? `<a href="${esc(p.publishedUrl)}" target="_blank" class="hover:underline" style="color:var(--accent);">열기</a>` : '-';
return `<tr style="border-bottom:1px solid var(--glass-border);">
<td class="p-3"><span class="badge ${st.cls}">${st.t}</span></td>
<td class="p-3 text-sm">${esc(p.platform||'')}</td>
@ -96,6 +123,10 @@
navigator.clipboard.writeText(text).then(()=>alert('설명+해시태그가 복사되었습니다.'));
}
function openHelp(){ document.getElementById('helpModal').classList.add('open'); }
function closeHelp(){ document.getElementById('helpModal').classList.remove('open'); }
document.addEventListener('keydown', e => { if(e.key === 'Escape') closeHelp(); });
load();
/*]]>*/
</script>

View File

@ -60,32 +60,32 @@
<div id="transcribeStatus" class="text-sm mb-2" style="display:none;"></div>
<!-- 영상 싱크 세그먼트 리스트 (CapCut형) -->
<div id="segmentList" style="display:none; max-height:340px; overflow:auto; border:1px solid var(--glass-border); border-radius:var(--radius-md); background:rgba(255,255,255,0.02);"></div>
<div id="segmentList" style="display:none; max-height:340px; overflow:auto; border:1px solid var(--glass-border); border-radius:var(--radius-md); background:var(--surface-2);"></div>
<!-- 평문 폴백 (URL 자막 추출 시) -->
<textarea id="transcript" readonly placeholder="‘영상 업로드·전사’로 영상에서 싱크된 자막을 추출하거나, URL자막으로 YouTube 자막을 가져오세요."
style="width:100%; min-height:140px; resize:vertical; padding:12px; background:rgba(255,255,255,0.03); border:1px solid var(--glass-border); border-radius:var(--radius-md); color:#cbd5e1; outline:none; font-size:0.9rem; line-height:1.6;"></textarea>
style="width:100%; min-height:140px; resize:vertical; padding:12px; background:var(--surface-2); border:1px solid var(--glass-border); border-radius:var(--radius-md); color:var(--text-2); outline:none; font-size:0.9rem; line-height:1.6;"></textarea>
<!-- 내보내기 (배속 + 말 없는 구간 제거 + SRT/영상) -->
<div id="exportBar" style="display:none; margin-top:14px; padding-top:12px; border-top:1px solid var(--glass-border);">
<div class="flex items-center gap-2 mb-3" style="flex-wrap:wrap;">
<label class="text-sm text-muted">배속</label>
<input id="srtSpeed" type="number" value="1.0" step="0.1" min="0.1" max="2.0"
style="width:64px; padding:7px; background:rgba(255,255,255,0.05); border:1px solid var(--glass-border); border-radius:var(--radius-md); color:white; outline:none; font-size:0.9rem;">
style="width:64px; padding:7px; background:var(--surface-2); border:1px solid var(--glass-border); border-radius:var(--radius-md); color:var(--text); outline:none; font-size:0.9rem;">
<span class="text-xs text-muted">배속 적용 시 타임스탬프 자동 보정 (0.5~2.0)</span>
</div>
<div style="background:rgba(255,255,255,0.03); border:1px solid var(--glass-border); border-radius:var(--radius-md); padding:10px 12px;">
<div style="background:var(--surface-2); border:1px solid var(--glass-border); border-radius:var(--radius-md); padding:10px 12px;">
<div class="flex items-center gap-2 mb-2" style="flex-wrap:wrap;">
<label class="flex items-center gap-1 text-sm" style="cursor:pointer;">
<input type="checkbox" id="trimOn" onchange="onTrimToggle()"> 말 없는 구간 제거
</label>
<span class="text-xs text-muted">앞뒤 여백</span>
<input id="trimPad" type="number" value="0.15" step="0.05" min="0" onchange="if(trimApplied)previewTrim()"
style="width:60px; padding:5px; background:rgba(255,255,255,0.05); border:1px solid var(--glass-border); border-radius:6px; color:white; font-size:0.85rem;">
style="width:60px; padding:5px; background:var(--surface-2); border:1px solid var(--glass-border); border-radius:6px; color:var(--text); font-size:0.85rem;">
<span class="text-xs text-muted">최소 간격</span>
<input id="trimGap" type="number" value="0.3" step="0.1" min="0" onchange="if(trimApplied)previewTrim()"
style="width:60px; padding:5px; background:rgba(255,255,255,0.05); border:1px solid var(--glass-border); border-radius:6px; color:white; font-size:0.85rem;">
style="width:60px; padding:5px; background:var(--surface-2); border:1px solid var(--glass-border); border-radius:6px; color:var(--text); font-size:0.85rem;">
</div>
<div id="trimInfo" class="text-xs text-muted"></div>
</div>
@ -104,11 +104,11 @@
</div>
<style>
.seg-row { display:flex; gap:10px; padding:7px 12px; cursor:pointer; border-bottom:1px solid rgba(255,255,255,0.05); font-size:0.9rem; line-height:1.5; }
.seg-row:hover { background:rgba(255,255,255,0.05); }
.seg-row { display:flex; gap:10px; padding:7px 12px; cursor:pointer; border-bottom:1px solid var(--surface-2); font-size:0.9rem; line-height:1.5; }
.seg-row:hover { background:var(--surface-2); }
.seg-row.active { background:rgba(96,165,250,0.18); }
.seg-time { color:#60a5fa; font-variant-numeric:tabular-nums; flex-shrink:0; font-size:0.82rem; padding-top:1px; }
.seg-text { color:#e2e8f0; }
.seg-text { color:var(--text-2); }
</style>
<!-- 재작성 에디터 -->
@ -120,7 +120,7 @@
</button>
</div>
<textarea id="reworkText" placeholder="원본을 참고해 각색/수정한 스크립트를 여기에 작성하세요. 저장하면 상태가 TARGET(작업대상)으로 바뀝니다."
style="width:100%; min-height:280px; resize:vertical; padding:12px; background:rgba(255,255,255,0.05); border:1px solid var(--glass-border); border-radius:var(--radius-md); color:white; outline:none; font-size:0.95rem; line-height:1.7;"></textarea>
style="width:100%; min-height:280px; resize:vertical; padding:12px; background:var(--surface-2); border:1px solid var(--glass-border); border-radius:var(--radius-md); color:var(--text); outline:none; font-size:0.95rem; line-height:1.7;"></textarea>
<div class="text-sm text-muted mt-2" id="saveInfo"></div>
</div>
@ -181,8 +181,8 @@
</div>
<style>
.pub-in { width:100%; padding:9px; background:rgba(255,255,255,0.05); border:1px solid var(--glass-border); border-radius:var(--radius-md); color:white; outline:none; font-size:0.9rem; }
.pub-in option { background:#1e1e2d; color:white; }
.pub-in { width:100%; padding:9px; background:var(--surface-2); border:1px solid var(--glass-border); border-radius:var(--radius-md); color:var(--text); outline:none; font-size:0.9rem; }
.pub-in option { background:var(--surface); color:var(--text); }
</style>
<script th:inline="javascript">
@ -303,7 +303,7 @@
document.getElementById('trimOn').checked = true;
const sp = curSpeed();
const kept = (p.keptDuration||0) / sp;
info.style.color = '#cbd5e1';
info.style.color = 'var(--text-2)';
info.innerHTML = '제거 ' + (p.removedCount||0) + '구간 · 결과 길이 ≈ <b>' + kept.toFixed(1) + 's</b>'
+ (sp!==1 ? (' (배속 ' + sp + 'x 포함)') : '')
+ ' · SRT/영상이 이 타임라인으로 출력됩니다';