feat(ui): discover filter chips + help modals, localize, tokenize long pages
- discover: filter converted to toggle chips + inline selects (matches 수집함); page-header + 사용법 modal (배율 지표/필터/고른 뒤 안내) - rework: 사용법 modal (전사·세그먼트·무음제거·내보내기·발행 guide) + page-header - dashboard: h1 "Dashboard" -> "대시보드" - channel_detail: sort-active header uses accent color (was invisible text-white) - multi_channel_videos/videos/production_detail: tokenize dark-assuming colors and title-link text-white for light-theme readability Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
52c6b51e61
commit
1ebe2dda44
@ -239,10 +239,10 @@
|
|||||||
if (icon) {
|
if (icon) {
|
||||||
const colName = th.getAttribute('onclick').match(/'([^']+)'/)[1];
|
const colName = th.getAttribute('onclick').match(/'([^']+)'/)[1];
|
||||||
if (colName === sortState.column) {
|
if (colName === sortState.column) {
|
||||||
th.classList.add('text-white');
|
th.style.color = 'var(--accent)';
|
||||||
icon.setAttribute('data-lucide', sortState.direction === 'asc' ? 'chevron-up' : 'chevron-down');
|
icon.setAttribute('data-lucide', sortState.direction === 'asc' ? 'chevron-up' : 'chevron-down');
|
||||||
} else {
|
} else {
|
||||||
th.classList.remove('text-white');
|
th.style.color = '';
|
||||||
icon.setAttribute('data-lucide', 'arrow-up-down');
|
icon.setAttribute('data-lucide', 'arrow-up-down');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
<header class="mb-4">
|
<header class="mb-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-xl font-bold mb-1">Dashboard</h1>
|
<h1 class="text-xl font-bold mb-1">대시보드</h1>
|
||||||
<p class="text-muted">수집 → 큐레이션 → 재가공 → 발행 파이프라인 현황</p>
|
<p class="text-muted">수집 → 큐레이션 → 재가공 → 발행 파이프라인 현황</p>
|
||||||
</div>
|
</div>
|
||||||
<button id="refreshBtn" class="btn btn-secondary px-3 py-2 flex items-center gap-1" onclick="loadDashboard()">
|
<button id="refreshBtn" class="btn btn-secondary px-3 py-2 flex items-center gap-1" onclick="loadDashboard()">
|
||||||
|
|||||||
@ -8,59 +8,77 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div layout:fragment="content">
|
<div layout:fragment="content">
|
||||||
<header class="mb-4">
|
<div class="page-header">
|
||||||
<h1 class="text-2xl font-bold mb-2">발굴 (Discovery)</h1>
|
<div>
|
||||||
<p class="text-muted">수집한 영상 중 재가공할 떡상 후보를 빠르게 골라냅니다. (제외 처리한 영상은 숨겨집니다)</p>
|
<h1>발굴</h1>
|
||||||
</header>
|
<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 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()">×</button></div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="help-item">
|
||||||
|
<div class="hi-ic"><i data-lucide="trending-up"></i></div>
|
||||||
|
<div><div class="hi-t">배율(떡상 지표)</div><div class="hi-d"><b>조회수 ÷ 구독자</b>로, 구독자 대비 조회수가 폭발한 정도입니다. 높을수록 ‘떡상’(10x↑ 빨강, 2x↑ 주황). 작은 채널의 대박 영상을 찾는 데 유용합니다.</div></div>
|
||||||
|
</div>
|
||||||
|
<div class="help-item">
|
||||||
|
<div class="hi-ic"><i data-lucide="filter"></i></div>
|
||||||
|
<div><div class="hi-t">필터</div><div class="hi-d"><b>기간·최소 배율·출처</b>로 좁히고 <b>정렬</b>을 바꿉니다. 칩 <b>Shorts</b>·<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>
|
||||||
|
|
||||||
|
<!-- 필터 툴바 -->
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div style="display:flex; flex-wrap:wrap; gap:16px; align-items:flex-end;">
|
<div class="toolbar">
|
||||||
<div style="display:flex; flex-direction:column; gap:4px; min-width:120px;">
|
<label class="chip"><input type="checkbox" id="fShorts" onchange="loadVideos()"> Shorts</label>
|
||||||
<label class="text-sm text-muted">기간</label>
|
<label class="chip"><input type="checkbox" id="fUnprocessed" onchange="loadVideos()"> 미처리만</label>
|
||||||
<select id="fPeriod" onchange="loadVideos()" class="filter-sel">
|
<span class="sep"></span>
|
||||||
|
<label class="field">기간
|
||||||
|
<select id="fPeriod" onchange="loadVideos()">
|
||||||
<option value="">전체</option>
|
<option value="">전체</option>
|
||||||
<option value="7">최근 7일</option>
|
<option value="7">최근 7일</option>
|
||||||
<option value="14">최근 14일</option>
|
<option value="14">최근 14일</option>
|
||||||
<option value="30">최근 30일</option>
|
<option value="30">최근 30일</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</label>
|
||||||
<div style="display:flex; flex-direction:column; gap:4px; min-width:120px;">
|
<label class="field">최소 배율
|
||||||
<label class="text-sm text-muted">최소 배율</label>
|
<select id="fMinRatio" onchange="loadVideos()">
|
||||||
<select id="fMinRatio" onchange="loadVideos()" class="filter-sel">
|
|
||||||
<option value="">전체</option>
|
<option value="">전체</option>
|
||||||
<option value="2">≥ 2x</option>
|
<option value="2">≥ 2x</option>
|
||||||
<option value="3">≥ 3x</option>
|
<option value="3">≥ 3x</option>
|
||||||
<option value="5">≥ 5x</option>
|
<option value="5">≥ 5x</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</label>
|
||||||
<div style="display:flex; flex-direction:column; gap:4px; min-width:120px;">
|
<label class="field">출처
|
||||||
<label class="text-sm text-muted">출처</label>
|
<select id="fSource" onchange="loadVideos()">
|
||||||
<select id="fSource" onchange="loadVideos()" class="filter-sel">
|
|
||||||
<option value="">전체</option>
|
<option value="">전체</option>
|
||||||
<option value="CHANNEL">채널 수집</option>
|
<option value="CHANNEL">채널 수집</option>
|
||||||
<option value="SEARCH">검색 수집</option>
|
<option value="SEARCH">검색 수집</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</label>
|
||||||
<div style="display:flex; flex-direction:column; gap:4px; min-width:160px;">
|
<label class="field">정렬
|
||||||
<label class="text-sm text-muted">정렬</label>
|
<select id="fSort" onchange="loadVideos()">
|
||||||
<select id="fSort" onchange="loadVideos()" class="filter-sel">
|
|
||||||
<option value="viewsPerSubRatio">배율(조회/구독) ↓</option>
|
<option value="viewsPerSubRatio">배율(조회/구독) ↓</option>
|
||||||
<option value="viewsPerHour">시간당 조회수 ↓</option>
|
<option value="viewsPerHour">시간당 조회수 ↓</option>
|
||||||
<option value="viewCount">조회수 ↓</option>
|
<option value="viewCount">조회수 ↓</option>
|
||||||
<option value="publishedAt">최신순 ↓</option>
|
<option value="publishedAt">최신순 ↓</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
|
||||||
<label class="flex items-center gap-2 cursor-pointer" style="height:42px;">
|
|
||||||
<input type="checkbox" id="fShorts" onchange="loadVideos()"> <span class="text-sm">Shorts만</span>
|
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2 cursor-pointer" style="height:42px;">
|
<span class="spacer"></span>
|
||||||
<input type="checkbox" id="fUnprocessed" onchange="loadVideos()"> <span class="text-sm">미처리만(NEW/검토중)</span>
|
<span id="resultCount" class="badge badge-muted"></span>
|
||||||
</label>
|
<button class="btn btn-secondary" onclick="loadVideos()" title="새로고침"><i data-lucide="refresh-cw" style="width:15px;"></i></button>
|
||||||
<button class="btn btn-secondary px-4 py-2 flex items-center gap-1" onclick="loadVideos()">
|
|
||||||
<i data-lucide="refresh-cw" style="width:16px;"></i> 새로고침
|
|
||||||
</button>
|
|
||||||
<span id="resultCount" class="text-sm text-muted" style="margin-left:auto; height:42px; display:flex; align-items:center;"></span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -214,6 +232,10 @@
|
|||||||
document.getElementById('videoModal').style.display = 'none';
|
document.getElementById('videoModal').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(); closeVideoModal(); } });
|
||||||
|
|
||||||
loadVideos();
|
loadVideos();
|
||||||
/*]]>*/
|
/*]]>*/
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
<div class="card p-6 mb-6">
|
<div class="card p-6 mb-6">
|
||||||
<div class="text-sm font-bold text-muted mb-4">Tracking <span th:text="${channels != null ? #lists.size(channels) : 0}">0</span> Channels</div>
|
<div class="text-sm font-bold text-muted mb-4">Tracking <span th:text="${channels != null ? #lists.size(channels) : 0}">0</span> Channels</div>
|
||||||
<div class="flex flex-wrap gap-4" th:if="${channels != null}">
|
<div class="flex flex-wrap gap-4" th:if="${channels != null}">
|
||||||
<div th:each="channel : ${channels}" class="flex items-center gap-2 p-2 rounded-lg bg-[rgba(255,255,255,0.02)] border border-[var(--glass-border)]">
|
<div th:each="channel : ${channels}" class="flex items-center gap-2 p-2 rounded-lg bg-[var(--surface-2)] border border-[var(--glass-border)]">
|
||||||
<img th:src="${channel.thumbnailUrl}" alt="Thumbnail"
|
<img th:src="${channel.thumbnailUrl}" alt="Thumbnail"
|
||||||
style="width: 32px; height: 32px; border-radius: 50%; object-fit: cover;" th:if="${channel.thumbnailUrl != null}">
|
style="width: 32px; height: 32px; border-radius: 50%; object-fit: cover;" th:if="${channel.thumbnailUrl != null}">
|
||||||
<span class="text-sm font-medium" th:text="${channel.title}">Channel Name</span>
|
<span class="text-sm font-medium" th:text="${channel.title}">Channel Name</span>
|
||||||
@ -36,20 +36,20 @@
|
|||||||
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 140px;">
|
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 140px;">
|
||||||
<label class="text-sm font-bold text-muted">Period</label>
|
<label class="text-sm font-bold text-muted">Period</label>
|
||||||
<select id="periodDays" class="w-full"
|
<select id="periodDays" class="w-full"
|
||||||
style="padding: 8px; height: 42px; background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: white; outline: none;">
|
style="padding: 8px; height: 42px; background: var(--surface-2); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: var(--text); outline: none;">
|
||||||
<option value="1" style="background: #1e1e2d; color: white;">Within 1 Day</option>
|
<option value="1" style="background: var(--surface); color: var(--text);">Within 1 Day</option>
|
||||||
<option value="7" style="background: #1e1e2d; color: white;" selected>Within 7 Days</option>
|
<option value="7" style="background: var(--surface); color: var(--text);" selected>Within 7 Days</option>
|
||||||
<option value="10" style="background: #1e1e2d; color: white;">Within 10 Days</option>
|
<option value="10" style="background: var(--surface); color: var(--text);">Within 10 Days</option>
|
||||||
<option value="15" style="background: #1e1e2d; color: white;">Within 15 Days</option>
|
<option value="15" style="background: var(--surface); color: var(--text);">Within 15 Days</option>
|
||||||
<option value="30" style="background: #1e1e2d; color: white;">Within 30 Days</option>
|
<option value="30" style="background: var(--surface); color: var(--text);">Within 30 Days</option>
|
||||||
<option value="0" style="background: #1e1e2d; color: white;">전부 (All)</option>
|
<option value="0" style="background: var(--surface); color: var(--text);">전부 (All)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Format -->
|
<!-- Format -->
|
||||||
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 160px;">
|
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 160px;">
|
||||||
<label class="text-sm font-bold text-muted">Format</label>
|
<label class="text-sm font-bold text-muted">Format</label>
|
||||||
<div class="flex gap-4 w-full" style="padding: 8px; background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-md); justify-content: center; height: 42px; align-items: center;">
|
<div class="flex gap-4 w-full" style="padding: 8px; background: var(--surface-2); border: 1px solid var(--glass-border); border-radius: var(--radius-md); justify-content: center; height: 42px; align-items: center;">
|
||||||
<label class="flex items-center gap-1 cursor-pointer hover:text-white">
|
<label class="flex items-center gap-1 cursor-pointer hover:text-white">
|
||||||
<input type="radio" name="format" value="SHORTS" checked> Shorts
|
<input type="radio" name="format" value="SHORTS" checked> Shorts
|
||||||
</label>
|
</label>
|
||||||
@ -63,10 +63,10 @@
|
|||||||
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 120px;">
|
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 120px;">
|
||||||
<label class="text-sm font-bold text-muted">Load Size</label>
|
<label class="text-sm font-bold text-muted">Load Size</label>
|
||||||
<select id="pageSize" class="w-full"
|
<select id="pageSize" class="w-full"
|
||||||
style="padding: 8px; height: 42px; background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: white; outline: none;">
|
style="padding: 8px; height: 42px; background: var(--surface-2); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: var(--text); outline: none;">
|
||||||
<option value="20" style="background: #1e1e2d; color: white;">20 items</option>
|
<option value="20" style="background: var(--surface); color: var(--text);">20 items</option>
|
||||||
<option value="50" style="background: #1e1e2d; color: white;" selected>50 items</option>
|
<option value="50" style="background: var(--surface); color: var(--text);" selected>50 items</option>
|
||||||
<option value="100" style="background: #1e1e2d; color: white;">100 items</option>
|
<option value="100" style="background: var(--surface); color: var(--text);">100 items</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -95,7 +95,7 @@
|
|||||||
<!-- Video List Table -->
|
<!-- Video List Table -->
|
||||||
<div class="card p-0" style="overflow-x: auto;">
|
<div class="card p-0" style="overflow-x: auto;">
|
||||||
<table class="w-full" style="border-collapse: collapse; text-align: left;">
|
<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>
|
<tr>
|
||||||
<th class="p-4 text-sm font-bold text-muted"><input type="checkbox" id="selectAll" onclick="toggleSelectAll(this.checked)" title="전체 선택"></th>
|
<th class="p-4 text-sm font-bold text-muted"><input type="checkbox" id="selectAll" onclick="toggleSelectAll(this.checked)" title="전체 선택"></th>
|
||||||
<th class="p-4 text-sm font-bold text-muted">Thumbnail</th>
|
<th class="p-4 text-sm font-bold text-muted">Thumbnail</th>
|
||||||
@ -130,7 +130,7 @@
|
|||||||
|
|
||||||
<!-- Video Player Modal -->
|
<!-- Video Player Modal -->
|
||||||
<div id="videoModal" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.85); align-items: center; justify-content: center;" onclick="if(event.target === this) closeVideoModal()">
|
<div id="videoModal" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: 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: 1200px; background-color: var(--glass-bg, #1e1e2d); border-radius: 12px; padding: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); border: 1px solid var(--glass-border);">
|
<div style="position: relative; width: 95%; max-width: 1200px; background-color: var(--glass-bg, var(--surface)); border-radius: 12px; padding: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); border: 1px solid var(--glass-border);">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
|
<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 Player</h3>
|
<h3 class="text-lg font-bold truncate pr-4" id="modalTitle">Video Player</h3>
|
||||||
<button onclick="closeVideoModal()" class="text-muted hover:text-white" style="font-size: 28px; line-height: 1; background: none; border: none; cursor: pointer;">×</button>
|
<button onclick="closeVideoModal()" class="text-muted hover:text-white" style="font-size: 28px; line-height: 1; background: none; border: none; cursor: pointer;">×</button>
|
||||||
@ -327,14 +327,14 @@
|
|||||||
'<div style="position: relative; display: inline-block; cursor: pointer;" data-videoid="' + video.videoId + '" data-videotitle="' + safeTitle + '" onclick="openVideoModal(this.dataset.videoid, this.dataset.videotitle)">' +
|
'<div style="position: relative; display: inline-block; cursor: pointer;" data-videoid="' + video.videoId + '" data-videotitle="' + safeTitle + '" onclick="openVideoModal(this.dataset.videoid, this.dataset.videotitle)">' +
|
||||||
'<img src="' + video.thumbnailUrl + '" alt="Thumb" style="width: 120px; height: 68px; object-fit: cover; border-radius: 6px; transition: transform 0.2s;" onmouseover="this.style.transform=\'scale(1.05)\'" onmouseout="this.style.transform=\'scale(1)\'">' +
|
'<img src="' + video.thumbnailUrl + '" alt="Thumb" style="width: 120px; height: 68px; object-fit: cover; border-radius: 6px; transition: transform 0.2s;" onmouseover="this.style.transform=\'scale(1.05)\'" onmouseout="this.style.transform=\'scale(1)\'">' +
|
||||||
'<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.6); border-radius: 50%; padding: 8px; display: flex; align-items: center; justify-content: center;">' +
|
'<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.6); border-radius: 50%; padding: 8px; display: flex; align-items: center; justify-content: center;">' +
|
||||||
'<i data-lucide="play" style="color: white; width: 16px; height: 16px; fill: white;"></i>' +
|
'<i data-lucide="play" style="color: var(--text); width: 16px; height: 16px; fill: white;"></i>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</td>' +
|
'</td>' +
|
||||||
'<td class="p-4">' +
|
'<td class="p-4">' +
|
||||||
'<div class="flex items-start justify-between gap-2" style="max-width: 300px;">' +
|
'<div class="flex items-start justify-between gap-2" style="max-width: 300px;">' +
|
||||||
'<div class="font-bold text-sm" style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; flex: 1;">' +
|
'<div class="font-bold text-sm" style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; flex: 1;">' +
|
||||||
'<a href="https://www.youtube.com/watch?v=' + video.videoId + '" target="_blank" class="hover:underline text-white">' + video.title + '</a>' +
|
'<a href="https://www.youtube.com/watch?v=' + video.videoId + '" target="_blank" class="hover:underline">' + video.title + '</a>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<button onclick="copyToClipboard(\'https://www.youtube.com/watch?v=' + video.videoId + '\')" class="text-muted hover:text-white flex-shrink-0" title="URL 복사" style="background: none; border: none; cursor: pointer; padding: 2px;">' +
|
'<button onclick="copyToClipboard(\'https://www.youtube.com/watch?v=' + video.videoId + '\')" class="text-muted hover:text-white flex-shrink-0" title="URL 복사" style="background: none; border: none; cursor: pointer; padding: 2px;">' +
|
||||||
'<i data-lucide="copy" style="width: 14px; height: 14px;"></i>' +
|
'<i data-lucide="copy" style="width: 14px; height: 14px;"></i>' +
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
<button id="thumbnailToggle" onclick="toggleThumbnails()"
|
<button id="thumbnailToggle" onclick="toggleThumbnails()"
|
||||||
style="position: relative; width: 48px; height: 26px; background-color: #374151; border-radius: 13px; border: none; cursor: pointer; transition: background-color 0.3s;">
|
style="position: relative; width: 48px; height: 26px; background-color: #374151; border-radius: 13px; border: none; cursor: pointer; transition: background-color 0.3s;">
|
||||||
<span id="toggleKnob"
|
<span id="toggleKnob"
|
||||||
style="position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; background-color: white; border-radius: 50%; transition: transform 0.3s;"></span>
|
style="position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; background-color: var(--text); border-radius: 50%; transition: transform 0.3s;"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<!-- Video List Table -->
|
<!-- Video List Table -->
|
||||||
<div class="card p-0" style="overflow-x: auto;">
|
<div class="card p-0" style="overflow-x: auto;">
|
||||||
<table class="w-full" style="border-collapse: collapse; text-align: left;">
|
<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>
|
<tr>
|
||||||
<th class="p-4 text-sm font-bold text-muted sortable" data-sort="rank"
|
<th class="p-4 text-sm font-bold text-muted sortable" data-sort="rank"
|
||||||
onclick="sortTable('rank')" style="cursor: pointer;">
|
onclick="sortTable('rank')" style="cursor: pointer;">
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr th:each="video : ${history.videos}"
|
<tr th:each="video : ${history.videos}"
|
||||||
style="border-bottom: 1px solid var(--glass-border); transition: background 0.2s;"
|
style="border-bottom: 1px solid var(--glass-border); 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'">
|
onmouseout="this.style.background='transparent'">
|
||||||
|
|
||||||
<td class="p-4" data-label="Rank" th:data-value="${video.rank}">
|
<td class="p-4" data-label="Rank" th:data-value="${video.rank}">
|
||||||
@ -207,13 +207,13 @@
|
|||||||
|
|
||||||
<!-- Popup Container (Centered Box) -->
|
<!-- Popup Container (Centered Box) -->
|
||||||
<div
|
<div
|
||||||
style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 900px; max-height: 85vh; background-color: #1a1b26; border-radius: 12px; box-shadow: 0 25px 50px rgba(0,0,0,0.5); display: flex; flex-direction: column; overflow: hidden; border: 1px solid rgba(255,255,255,0.1);">
|
style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 900px; max-height: 85vh; background-color: #1a1b26; border-radius: 12px; box-shadow: 0 25px 50px rgba(0,0,0,0.5); display: flex; flex-direction: column; overflow: hidden; border: 1px solid var(--hover-strong);">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div
|
<div
|
||||||
style="display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; background-color: #1a1b26; border-bottom: 1px solid rgba(255,255,255,0.1);">
|
style="display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; background-color: #1a1b26; border-bottom: 1px solid var(--hover-strong);">
|
||||||
<h3
|
<h3
|
||||||
style="font-size: 18px; font-weight: bold; color: white; margin: 0; display: flex; align-items: center; gap: 8px;">
|
style="font-size: 18px; font-weight: bold; color: var(--text); margin: 0; display: flex; align-items: center; gap: 8px;">
|
||||||
<i data-lucide="file-text" style="color: #6366f1; width: 20px; height: 20px;"></i>
|
<i data-lucide="file-text" style="color: #6366f1; width: 20px; height: 20px;"></i>
|
||||||
Transcript
|
Transcript
|
||||||
</h3>
|
</h3>
|
||||||
@ -239,13 +239,13 @@
|
|||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<div
|
<div
|
||||||
style="padding: 16px 24px; background-color: #1a1b26; border-top: 1px solid rgba(255,255,255,0.1); display: flex; justify-content: flex-end; gap: 12px;">
|
style="padding: 16px 24px; background-color: #1a1b26; border-top: 1px solid var(--hover-strong); display: flex; justify-content: flex-end; gap: 12px;">
|
||||||
<button onclick="copyScript()"
|
<button onclick="copyScript()"
|
||||||
style="padding: 8px 16px; background-color: #374151; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 500; display: flex; align-items: center; gap: 6px;">
|
style="padding: 8px 16px; background-color: #374151; color: var(--text); border: none; border-radius: 8px; cursor: pointer; font-weight: 500; display: flex; align-items: center; gap: 6px;">
|
||||||
<i data-lucide="copy" style="width: 16px; height: 16px;"></i> Copy All
|
<i data-lucide="copy" style="width: 16px; height: 16px;"></i> Copy All
|
||||||
</button>
|
</button>
|
||||||
<button onclick="closeScriptModal()"
|
<button onclick="closeScriptModal()"
|
||||||
style="padding: 8px 24px; background: linear-gradient(135deg, #6366f1, #8b5cf6); color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 500;">Close</button>
|
style="padding: 8px 24px; background: linear-gradient(135deg, #6366f1, #8b5cf6); color: var(--text); border: none; border-radius: 8px; cursor: pointer; font-weight: 500;">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -261,13 +261,13 @@
|
|||||||
|
|
||||||
<!-- Popup Container (Centered Box) -->
|
<!-- Popup Container (Centered Box) -->
|
||||||
<div
|
<div
|
||||||
style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 1200px; max-height: 85vh; background-color: #1a1b26; border-radius: 12px; box-shadow: 0 25px 50px rgba(0,0,0,0.5); display: flex; flex-direction: column; overflow: hidden; border: 1px solid rgba(255,255,255,0.1);">
|
style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 1200px; max-height: 85vh; background-color: #1a1b26; border-radius: 12px; box-shadow: 0 25px 50px rgba(0,0,0,0.5); display: flex; flex-direction: column; overflow: hidden; border: 1px solid var(--hover-strong);">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div
|
<div
|
||||||
style="display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; background-color: #1a1b26; border-bottom: 1px solid rgba(255,255,255,0.1);">
|
style="display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; background-color: #1a1b26; border-bottom: 1px solid var(--hover-strong);">
|
||||||
<h3
|
<h3
|
||||||
style="font-size: 18px; font-weight: bold; color: white; margin: 0; display: flex; align-items: center; gap: 8px;">
|
style="font-size: 18px; font-weight: bold; color: var(--text); margin: 0; display: flex; align-items: center; gap: 8px;">
|
||||||
<i data-lucide="book-open" style="color: #34d399; width: 20px; height: 20px;"></i>
|
<i data-lucide="book-open" style="color: #34d399; width: 20px; height: 20px;"></i>
|
||||||
Script Summaries
|
Script Summaries
|
||||||
</h3>
|
</h3>
|
||||||
@ -281,7 +281,7 @@
|
|||||||
<div style="display: flex; flex: 1; overflow: hidden;">
|
<div style="display: flex; flex: 1; overflow: hidden;">
|
||||||
<!-- Left Column: old_script_summary -->
|
<!-- Left Column: old_script_summary -->
|
||||||
<div
|
<div
|
||||||
style="flex: 1; padding: 24px; overflow-y: auto; border-right: 1px solid rgba(255,255,255,0.1); background-color: rgba(22,22,30,0.5);">
|
style="flex: 1; padding: 24px; overflow-y: auto; border-right: 1px solid var(--hover-strong); background-color: rgba(22,22,30,0.5);">
|
||||||
<h4 style="font-size: 14px; font-weight: bold; color: #facc15; margin: 0 0 16px 0;">
|
<h4 style="font-size: 14px; font-weight: bold; color: #facc15; margin: 0 0 16px 0;">
|
||||||
old_script_summary</h4>
|
old_script_summary</h4>
|
||||||
<div id="oldSummaryContent"
|
<div id="oldSummaryContent"
|
||||||
@ -318,9 +318,9 @@
|
|||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<div
|
<div
|
||||||
style="padding: 16px 24px; background-color: #1a1b26; border-top: 1px solid rgba(255,255,255,0.1); display: flex; justify-content: flex-end;">
|
style="padding: 16px 24px; background-color: #1a1b26; border-top: 1px solid var(--hover-strong); display: flex; justify-content: flex-end;">
|
||||||
<button onclick="closeSummaryModal()" class="btn btn-primary"
|
<button onclick="closeSummaryModal()" class="btn btn-primary"
|
||||||
style="padding: 8px 24px; background: linear-gradient(135deg, #6366f1, #8b5cf6); color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 500;">Close</button>
|
style="padding: 8px 24px; background: linear-gradient(135deg, #6366f1, #8b5cf6); color: var(--text); border: none; border-radius: 8px; cursor: pointer; font-weight: 500;">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -337,13 +337,13 @@
|
|||||||
|
|
||||||
<!-- Popup Container (Centered Box) -->
|
<!-- Popup Container (Centered Box) -->
|
||||||
<div
|
<div
|
||||||
style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 95%; max-width: 1600px; height: 90vh; background-color: #1a1b26; border-radius: 12px; box-shadow: 0 25px 50px rgba(0,0,0,0.5); display: flex; flex-direction: column; overflow: hidden; border: 1px solid rgba(255,255,255,0.1);">
|
style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 95%; max-width: 1600px; height: 90vh; background-color: #1a1b26; border-radius: 12px; box-shadow: 0 25px 50px rgba(0,0,0,0.5); display: flex; flex-direction: column; overflow: hidden; border: 1px solid var(--hover-strong);">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div
|
<div
|
||||||
style="display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; background-color: #1a1b26; border-bottom: 1px solid rgba(255,255,255,0.1);">
|
style="display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; background-color: #1a1b26; border-bottom: 1px solid var(--hover-strong);">
|
||||||
<h3
|
<h3
|
||||||
style="font-size: 18px; font-weight: bold; color: white; margin: 0; display: flex; align-items: center; gap: 8px;">
|
style="font-size: 18px; font-weight: bold; color: var(--text); margin: 0; display: flex; align-items: center; gap: 8px;">
|
||||||
<i data-lucide="file-check" style="color: #22d3ee; width: 20px; height: 20px;"></i>
|
<i data-lucide="file-check" style="color: #22d3ee; width: 20px; height: 20px;"></i>
|
||||||
Final Script
|
Final Script
|
||||||
</h3>
|
</h3>
|
||||||
@ -375,17 +375,17 @@
|
|||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<div
|
<div
|
||||||
style="padding: 16px 24px; background-color: #1a1b26; border-top: 1px solid rgba(255,255,255,0.1); display: flex; justify-content: flex-end; gap: 12px;">
|
style="padding: 16px 24px; background-color: #1a1b26; border-top: 1px solid var(--hover-strong); display: flex; justify-content: flex-end; gap: 12px;">
|
||||||
<button onclick="saveFinalScript()"
|
<button onclick="saveFinalScript()"
|
||||||
style="padding: 8px 16px; background-color: #059669; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 500; display: flex; align-items: center; gap: 6px;">
|
style="padding: 8px 16px; background-color: #059669; color: var(--text); border: none; border-radius: 8px; cursor: pointer; font-weight: 500; display: flex; align-items: center; gap: 6px;">
|
||||||
<i data-lucide="save" style="width: 16px; height: 16px;"></i> Save
|
<i data-lucide="save" style="width: 16px; height: 16px;"></i> Save
|
||||||
</button>
|
</button>
|
||||||
<button onclick="copyFinalScript()"
|
<button onclick="copyFinalScript()"
|
||||||
style="padding: 8px 16px; background-color: #374151; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 500; display: flex; align-items: center; gap: 6px;">
|
style="padding: 8px 16px; background-color: #374151; color: var(--text); border: none; border-radius: 8px; cursor: pointer; font-weight: 500; display: flex; align-items: center; gap: 6px;">
|
||||||
<i data-lucide="copy" style="width: 16px; height: 16px;"></i> Copy All
|
<i data-lucide="copy" style="width: 16px; height: 16px;"></i> Copy All
|
||||||
</button>
|
</button>
|
||||||
<button onclick="closeFinalScriptModal()"
|
<button onclick="closeFinalScriptModal()"
|
||||||
style="padding: 8px 24px; background: linear-gradient(135deg, #6366f1, #8b5cf6); color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 500;">Close</button>
|
style="padding: 8px 24px; background: linear-gradient(135deg, #6366f1, #8b5cf6); color: var(--text); border: none; border-radius: 8px; cursor: pointer; font-weight: 500;">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -8,13 +8,47 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div layout:fragment="content">
|
<div layout:fragment="content">
|
||||||
<header class="mb-4">
|
<div class="page-header">
|
||||||
<div class="flex items-center gap-2 mb-2">
|
<div>
|
||||||
<a th:href="@{/collection}" class="text-muted hover:text-white"><i data-lucide="arrow-left" style="width:20px;"></i></a>
|
<div class="flex items-center gap-2 mb-1">
|
||||||
<h1 class="text-2xl font-bold">재가공 작업공간</h1>
|
<a th:href="@{/collection}" class="text-muted hover:text-white"><i data-lucide="arrow-left" style="width:20px;"></i></a>
|
||||||
|
<h1>재가공 작업공간</h1>
|
||||||
|
</div>
|
||||||
|
<p class="sub" id="metaLine">로딩 중...</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-muted" id="metaLine">로딩 중...</p>
|
<div class="actions">
|
||||||
</header>
|
<button class="btn btn-secondary" onclick="openHelp()"><i data-lucide="help-circle" 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()">×</button></div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="help-item">
|
||||||
|
<div class="hi-ic"><i data-lucide="upload"></i></div>
|
||||||
|
<div><div class="hi-t">영상 업로드 · 전사</div><div class="hi-d">영상 파일을 올리면 <b>Whisper</b>가 말소리를 <b>시간 싱크 자막</b>으로 추출합니다. 언어는 자동감지(틀리면 옆에서 ko/en/zh/ja 선택). ‘URL자막’은 YouTube 자막을 평문으로(시간 없음) 가져옵니다.</div></div>
|
||||||
|
</div>
|
||||||
|
<div class="help-item">
|
||||||
|
<div class="hi-ic"><i data-lucide="list-video"></i></div>
|
||||||
|
<div><div class="hi-t">세그먼트 리스트</div><div class="hi-d"><b>[00:12] 자막</b> 줄을 클릭하면 영상이 그 지점으로 이동하고, 재생 중 현재 자막이 하이라이트됩니다.</div></div>
|
||||||
|
</div>
|
||||||
|
<div class="help-item">
|
||||||
|
<div class="hi-ic"><i data-lucide="scissors"></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="file-down"></i></div>
|
||||||
|
<div><div class="hi-t">내보내기 → CapCut</div><div class="hi-d"><b>SRT 자막</b>과 <b>영상</b>을 내보내 CapCut에 <b>둘 다 import</b>하면 자막·컷·배속이 맞춰집니다.</div></div>
|
||||||
|
</div>
|
||||||
|
<div class="help-item">
|
||||||
|
<div class="hi-ic"><i data-lucide="send"></i></div>
|
||||||
|
<div><div class="hi-t">재작성 · 발행</div><div class="hi-d">‘재작성(내 버전)’에 각색해 저장하면 상태가 <b>TARGET</b>으로 바뀝니다. 하단 <b>발행 준비</b>에서 제목·해시태그를 저장하면 발행 큐로 들어갑니다.</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="display:grid; grid-template-columns: 360px 1fr; gap:1.5rem; align-items:start;">
|
<div style="display:grid; grid-template-columns: 360px 1fr; gap:1.5rem; align-items:start;">
|
||||||
<!-- 좌: 영상 + 정보 -->
|
<!-- 좌: 영상 + 정보 -->
|
||||||
@ -506,6 +540,10 @@
|
|||||||
} catch(e){ alert('발행 완료 처리 실패: ' + e.message); }
|
} catch(e){ alert('발행 완료 처리 실패: ' + e.message); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(); });
|
||||||
|
|
||||||
(async ()=>{ await load(); await loadPublish(document.getElementById('vTitle').textContent); })();
|
(async ()=>{ await load(); await loadPublish(document.getElementById('vTitle').textContent); })();
|
||||||
/*]]>*/
|
/*]]>*/
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -18,14 +18,14 @@
|
|||||||
<label class="text-sm font-bold text-muted">Keyword</label>
|
<label class="text-sm font-bold text-muted">Keyword</label>
|
||||||
<input type="text" id="keyword" placeholder="Search keyword..."
|
<input type="text" id="keyword" placeholder="Search keyword..."
|
||||||
class="p-2 w-full"
|
class="p-2 w-full"
|
||||||
style="background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: white; outline: none; transition: border-color 0.2s;"
|
style="background: var(--surface-2); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: var(--text); outline: none; transition: border-color 0.2s;"
|
||||||
onfocus="this.style.borderColor='#3b82f6'" onblur="this.style.borderColor='var(--glass-border)'">
|
onfocus="this.style.borderColor='#3b82f6'" onblur="this.style.borderColor='var(--glass-border)'">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Country -->
|
<!-- Country -->
|
||||||
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 180px;">
|
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 180px;">
|
||||||
<label class="text-sm font-bold text-muted">Country</label>
|
<label class="text-sm font-bold text-muted">Country</label>
|
||||||
<div class="flex gap-4 w-full" style="padding: 8px; background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-md); justify-content: center; height: 42px; align-items: center;">
|
<div class="flex gap-4 w-full" style="padding: 8px; background: var(--surface-2); border: 1px solid var(--glass-border); border-radius: var(--radius-md); justify-content: center; height: 42px; align-items: center;">
|
||||||
<label class="flex items-center gap-1 cursor-pointer hover:text-white">
|
<label class="flex items-center gap-1 cursor-pointer hover:text-white">
|
||||||
<input type="checkbox" name="region" value="JP" checked> JP
|
<input type="checkbox" name="region" value="JP" checked> JP
|
||||||
</label>
|
</label>
|
||||||
@ -42,20 +42,20 @@
|
|||||||
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 140px;">
|
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 140px;">
|
||||||
<label class="text-sm font-bold text-muted">Period</label>
|
<label class="text-sm font-bold text-muted">Period</label>
|
||||||
<select id="periodDays" class="w-full"
|
<select id="periodDays" class="w-full"
|
||||||
style="padding: 8px; height: 42px; background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: white; outline: none;">
|
style="padding: 8px; height: 42px; background: var(--surface-2); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: var(--text); outline: none;">
|
||||||
<option value="1" style="background: #1e1e2d; color: white;">Within 1 Day</option>
|
<option value="1" style="background: var(--surface); color: var(--text);">Within 1 Day</option>
|
||||||
<option value="7" style="background: #1e1e2d; color: white;">Within 7 Days</option>
|
<option value="7" style="background: var(--surface); color: var(--text);">Within 7 Days</option>
|
||||||
<option value="10" style="background: #1e1e2d; color: white;">Within 10 Days</option>
|
<option value="10" style="background: var(--surface); color: var(--text);">Within 10 Days</option>
|
||||||
<option value="15" style="background: #1e1e2d; color: white;">Within 15 Days</option>
|
<option value="15" style="background: var(--surface); color: var(--text);">Within 15 Days</option>
|
||||||
<option value="30" style="background: #1e1e2d; color: white;">Within 30 Days</option>
|
<option value="30" style="background: var(--surface); color: var(--text);">Within 30 Days</option>
|
||||||
<option value="0" style="background: #1e1e2d; color: white;">전부 (All)</option>
|
<option value="0" style="background: var(--surface); color: var(--text);">전부 (All)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Format -->
|
<!-- Format -->
|
||||||
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 160px;">
|
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 160px;">
|
||||||
<label class="text-sm font-bold text-muted">Format</label>
|
<label class="text-sm font-bold text-muted">Format</label>
|
||||||
<div class="flex gap-4 w-full" style="padding: 8px; background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-md); justify-content: center; height: 42px; align-items: center;">
|
<div class="flex gap-4 w-full" style="padding: 8px; background: var(--surface-2); border: 1px solid var(--glass-border); border-radius: var(--radius-md); justify-content: center; height: 42px; align-items: center;">
|
||||||
<label class="flex items-center gap-1 cursor-pointer hover:text-white">
|
<label class="flex items-center gap-1 cursor-pointer hover:text-white">
|
||||||
<input type="radio" name="format" value="SHORTS" checked> Shorts
|
<input type="radio" name="format" value="SHORTS" checked> Shorts
|
||||||
</label>
|
</label>
|
||||||
@ -69,10 +69,10 @@
|
|||||||
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 120px;">
|
<div style="display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 120px;">
|
||||||
<label class="text-sm font-bold text-muted">Load Size</label>
|
<label class="text-sm font-bold text-muted">Load Size</label>
|
||||||
<select id="pageSize" class="w-full"
|
<select id="pageSize" class="w-full"
|
||||||
style="padding: 8px; height: 42px; background: rgba(255,255,255,0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: white; outline: none;">
|
style="padding: 8px; height: 42px; background: var(--surface-2); border: 1px solid var(--glass-border); border-radius: var(--radius-md); color: var(--text); outline: none;">
|
||||||
<option value="20" style="background: #1e1e2d; color: white;">20 items</option>
|
<option value="20" style="background: var(--surface); color: var(--text);">20 items</option>
|
||||||
<option value="50" style="background: #1e1e2d; color: white;" selected>50 items</option>
|
<option value="50" style="background: var(--surface); color: var(--text);" selected>50 items</option>
|
||||||
<option value="100" style="background: #1e1e2d; color: white;">100 items</option>
|
<option value="100" style="background: var(--surface); color: var(--text);">100 items</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -101,7 +101,7 @@
|
|||||||
<!-- Video List Table -->
|
<!-- Video List Table -->
|
||||||
<div class="card p-0" style="overflow-x: auto;">
|
<div class="card p-0" style="overflow-x: auto;">
|
||||||
<table class="w-full" style="border-collapse: collapse; text-align: left;">
|
<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>
|
<tr>
|
||||||
<th class="p-4 text-sm font-bold text-muted"><input type="checkbox" id="selectAll" onclick="toggleSelectAll(this.checked)" title="전체 선택"></th>
|
<th class="p-4 text-sm font-bold text-muted"><input type="checkbox" id="selectAll" onclick="toggleSelectAll(this.checked)" title="전체 선택"></th>
|
||||||
<th class="p-4 text-sm font-bold text-muted">Thumbnail</th>
|
<th class="p-4 text-sm font-bold text-muted">Thumbnail</th>
|
||||||
@ -135,7 +135,7 @@
|
|||||||
|
|
||||||
<!-- Video Player Modal -->
|
<!-- Video Player Modal -->
|
||||||
<div id="videoModal" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.85); align-items: center; justify-content: center;" onclick="if(event.target === this) closeVideoModal()">
|
<div id="videoModal" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: 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: 1200px; background-color: var(--glass-bg, #1e1e2d); border-radius: 12px; padding: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); border: 1px solid var(--glass-border);">
|
<div style="position: relative; width: 95%; max-width: 1200px; background-color: var(--glass-bg, var(--surface)); border-radius: 12px; padding: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); border: 1px solid var(--glass-border);">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
|
<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 Player</h3>
|
<h3 class="text-lg font-bold truncate pr-4" id="modalTitle">Video Player</h3>
|
||||||
<button onclick="closeVideoModal()" class="text-muted hover:text-white" style="font-size: 28px; line-height: 1; background: none; border: none; cursor: pointer;">×</button>
|
<button onclick="closeVideoModal()" class="text-muted hover:text-white" style="font-size: 28px; line-height: 1; background: none; border: none; cursor: pointer;">×</button>
|
||||||
@ -362,14 +362,14 @@
|
|||||||
'<div style="position: relative; display: inline-block; cursor: pointer;" data-videoid="' + video.videoId + '" data-videotitle="' + safeTitle + '" onclick="openVideoModal(this.dataset.videoid, this.dataset.videotitle)">' +
|
'<div style="position: relative; display: inline-block; cursor: pointer;" data-videoid="' + video.videoId + '" data-videotitle="' + safeTitle + '" onclick="openVideoModal(this.dataset.videoid, this.dataset.videotitle)">' +
|
||||||
'<img src="' + video.thumbnailUrl + '" alt="Thumb" style="width: 120px; height: 68px; object-fit: cover; border-radius: 6px; transition: transform 0.2s;" onmouseover="this.style.transform=\'scale(1.05)\'" onmouseout="this.style.transform=\'scale(1)\'">' +
|
'<img src="' + video.thumbnailUrl + '" alt="Thumb" style="width: 120px; height: 68px; object-fit: cover; border-radius: 6px; transition: transform 0.2s;" onmouseover="this.style.transform=\'scale(1.05)\'" onmouseout="this.style.transform=\'scale(1)\'">' +
|
||||||
'<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.6); border-radius: 50%; padding: 8px; display: flex; align-items: center; justify-content: center;">' +
|
'<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.6); border-radius: 50%; padding: 8px; display: flex; align-items: center; justify-content: center;">' +
|
||||||
'<i data-lucide="play" style="color: white; width: 16px; height: 16px; fill: white;"></i>' +
|
'<i data-lucide="play" style="color: var(--text); width: 16px; height: 16px; fill: white;"></i>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</td>' +
|
'</td>' +
|
||||||
'<td class="p-4">' +
|
'<td class="p-4">' +
|
||||||
'<div class="flex items-start justify-between gap-2" style="max-width: 300px;">' +
|
'<div class="flex items-start justify-between gap-2" style="max-width: 300px;">' +
|
||||||
'<div class="font-bold text-sm" style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; flex: 1;">' +
|
'<div class="font-bold text-sm" style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; flex: 1;">' +
|
||||||
'<a href="https://www.youtube.com/watch?v=' + video.videoId + '" target="_blank" class="hover:underline text-white">' + video.title + '</a>' +
|
'<a href="https://www.youtube.com/watch?v=' + video.videoId + '" target="_blank" class="hover:underline">' + video.title + '</a>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<button onclick="copyToClipboard(\'https://www.youtube.com/watch?v=' + video.videoId + '\')" class="text-muted hover:text-white flex-shrink-0" title="URL 복사" style="background: none; border: none; cursor: pointer; padding: 2px; margin-top: 2px;">' +
|
'<button onclick="copyToClipboard(\'https://www.youtube.com/watch?v=' + video.videoId + '\')" class="text-muted hover:text-white flex-shrink-0" title="URL 복사" style="background: none; border: none; cursor: pointer; padding: 2px; margin-top: 2px;">' +
|
||||||
'<i data-lucide="copy" style="width: 14px; height: 14px;"></i>' +
|
'<i data-lucide="copy" style="width: 14px; height: 14px;"></i>' +
|
||||||
@ -379,7 +379,7 @@
|
|||||||
'<td class="p-4 text-sm text-muted">' +
|
'<td class="p-4 text-sm text-muted">' +
|
||||||
'<div class="flex items-center gap-2">' +
|
'<div class="flex items-center gap-2">' +
|
||||||
'<a href="https://www.youtube.com/channel/' + video.channelId + '" target="_blank" class="hover:underline font-semibold" style="color: #e2e8f0;">' + video.channelTitle + '</a>' +
|
'<a href="https://www.youtube.com/channel/' + video.channelId + '" target="_blank" class="hover:underline font-semibold" style="color: #e2e8f0;">' + video.channelTitle + '</a>' +
|
||||||
'<button onclick="registerChannel(\'https://www.youtube.com/channel/' + video.channelId + '\')" class="text-xs" style="background: #3b82f6; color: white; border: none; padding: 2px 6px; border-radius: 4px; cursor: pointer; transition: background 0.2s;" onmouseover="this.style.background=\'#2563eb\'" onmouseout="this.style.background=\'#3b82f6\'">등록</button>' +
|
'<button onclick="registerChannel(\'https://www.youtube.com/channel/' + video.channelId + '\')" class="text-xs" style="background: #3b82f6; color: var(--text); border: none; padding: 2px 6px; border-radius: 4px; cursor: pointer; transition: background 0.2s;" onmouseover="this.style.background=\'#2563eb\'" onmouseout="this.style.background=\'#3b82f6\'">등록</button>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
tagsHtml +
|
tagsHtml +
|
||||||
'</td>' +
|
'</td>' +
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user