feat(comment-cards): 단어 클릭 가리기(부분 모자이크) 추가
기본은 댓글 단어 클릭 시 해당 단어만 블러(다시 클릭 해제). '🖍 단어 가리기' 토글을 끄면 카드 클릭=이미지 복사로 전환. 블러는 캡처 PNG에도 그대로 반영됨. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
528b48280c
commit
af53219dcc
@ -2,8 +2,9 @@
|
|||||||
window.__all = []; // 전체 수집 댓글(분석 기준)
|
window.__all = []; // 전체 수집 댓글(분석 기준)
|
||||||
window.__cards = []; // 호환용 별칭
|
window.__cards = []; // 호환용 별칭
|
||||||
window.__videoId = null; // 타임라인 링크용
|
window.__videoId = null; // 타임라인 링크용
|
||||||
let mosaicOn = true; // 모자이크 기본 ON
|
let mosaicOn = true; // 프로필·아이디 모자이크 기본 ON
|
||||||
let roundedOn = false; // 모서리 둥글게 토글(기본: 각진 모서리)
|
let roundedOn = false; // 모서리 둥글게 토글(기본: 각진 모서리)
|
||||||
|
let wordMaskOn = true; // 단어 가리기 기본 ON(단어 클릭=가림). 끄면 카드 클릭=복사.
|
||||||
|
|
||||||
const DISPLAY_CAP = 2000; // 카드 DOM 렌더 상한(브라우저 보호). 분석은 전체 기준.
|
const DISPLAY_CAP = 2000; // 카드 DOM 렌더 상한(브라우저 보호). 분석은 전체 기준.
|
||||||
|
|
||||||
@ -66,6 +67,24 @@
|
|||||||
return function () { clearTimeout(h); h = setTimeout(fn, ms); };
|
return function () { clearTimeout(h); h = setTimeout(fn, ms); };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 댓글 텍스트를 단어 span으로 분해(공백/줄바꿈 보존). 단어 가리기 ON일 때 클릭하면 해당 단어만 블러.
|
||||||
|
function buildWords(el, plain) {
|
||||||
|
el.textContent = '';
|
||||||
|
for (const p of plain.split(/(\s+)/)) {
|
||||||
|
if (!p) continue;
|
||||||
|
if (/^\s+$/.test(p)) { el.appendChild(document.createTextNode(p)); continue; }
|
||||||
|
const s = document.createElement('span');
|
||||||
|
s.className = 'cc-word';
|
||||||
|
s.textContent = p;
|
||||||
|
s.addEventListener('click', (e) => {
|
||||||
|
if (!wordMaskOn) return; // 꺼짐 모드: 무시 → 이벤트 버블 → 카드 클릭=복사
|
||||||
|
e.stopPropagation();
|
||||||
|
s.classList.toggle('masked');
|
||||||
|
});
|
||||||
|
el.appendChild(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function applyFilterSort(cards) {
|
function applyFilterSort(cards) {
|
||||||
const sort = $('ccSort').value;
|
const sort = $('ccSort').value;
|
||||||
const minLikes = parseInt($('ccMinLikes').value, 10) || 0;
|
const minLikes = parseInt($('ccMinLikes').value, 10) || 0;
|
||||||
@ -91,6 +110,7 @@
|
|||||||
if (capped) list = list.slice(0, DISPLAY_CAP);
|
if (capped) list = list.slice(0, DISPLAY_CAP);
|
||||||
$('ccCount').textContent = total.toLocaleString() + '개'
|
$('ccCount').textContent = total.toLocaleString() + '개'
|
||||||
+ (capped ? ' (상위 ' + DISPLAY_CAP.toLocaleString() + '개 표시)' : '');
|
+ (capped ? ' (상위 ' + DISPLAY_CAP.toLocaleString() + '개 표시)' : '');
|
||||||
|
grid.classList.toggle('wordmask', wordMaskOn);
|
||||||
grid.innerHTML = '';
|
grid.innerHTML = '';
|
||||||
list.forEach((c, i) => {
|
list.forEach((c, i) => {
|
||||||
const card = document.createElement('div');
|
const card = document.createElement('div');
|
||||||
@ -115,11 +135,11 @@
|
|||||||
'</div>';
|
'</div>';
|
||||||
head.querySelector('.cc-author').textContent = c.authorName || '';
|
head.querySelector('.cc-author').textContent = c.authorName || '';
|
||||||
head.querySelector('.cc-time').textContent = timeAgo(c.publishedAt);
|
head.querySelector('.cc-time').textContent = timeAgo(c.publishedAt);
|
||||||
head.querySelector('.cc-text').textContent = toPlainText(c.text);
|
buildWords(head.querySelector('.cc-text'), toPlainText(c.text));
|
||||||
|
|
||||||
// 카드 자체를 클릭하면 복사 (클립보드)
|
// 단어 가리기 ON: 카드 클릭 복사 잠금(단어 클릭으로 가림). OFF: 카드 클릭=복사.
|
||||||
card.title = '클릭하면 이미지 복사 · 저장 버튼은 PNG 파일로 내려받기';
|
card.title = '단어 클릭 = 가리기 · 토글을 끄면 카드 클릭 = 복사';
|
||||||
card.addEventListener('click', () => window.copyCard(card));
|
card.addEventListener('click', () => { if (wordMaskOn) return; window.copyCard(card); });
|
||||||
|
|
||||||
// 저장(다운로드) 버튼 — cc-noexport라 캡처 이미지엔 안 찍힘. 캡컷엔 이 파일을 불러오기.
|
// 저장(다운로드) 버튼 — cc-noexport라 캡처 이미지엔 안 찍힘. 캡컷엔 이 파일을 불러오기.
|
||||||
const actions = document.createElement('div');
|
const actions = document.createElement('div');
|
||||||
@ -470,5 +490,10 @@
|
|||||||
$('ccRounded').textContent = roundedOn ? '모서리 각지게' : '모서리 둥글게';
|
$('ccRounded').textContent = roundedOn ? '모서리 각지게' : '모서리 둥글게';
|
||||||
document.querySelectorAll('.comment-card').forEach(el => el.classList.toggle('rounded', roundedOn));
|
document.querySelectorAll('.comment-card').forEach(el => el.classList.toggle('rounded', roundedOn));
|
||||||
});
|
});
|
||||||
|
$('ccWordMask').addEventListener('click', () => {
|
||||||
|
wordMaskOn = !wordMaskOn;
|
||||||
|
$('ccWordMask').textContent = wordMaskOn ? '🖍 단어 가리기: 켜짐' : '🖍 단어 가리기: 꺼짐(복사)';
|
||||||
|
$('cardGrid').classList.toggle('wordmask', wordMaskOn);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -42,6 +42,11 @@
|
|||||||
/* 모자이크 */
|
/* 모자이크 */
|
||||||
.comment-card.mosaic .cc-avatar { filter: blur(6px); }
|
.comment-card.mosaic .cc-avatar { filter: blur(6px); }
|
||||||
.comment-card.mosaic .cc-author { filter: blur(5px); }
|
.comment-card.mosaic .cc-author { filter: blur(5px); }
|
||||||
|
/* 단어 가리기: '단어 가리기 켜짐'일 때 단어에 포인터, 클릭하면 .masked로 블러 */
|
||||||
|
.cc-word { cursor: default; }
|
||||||
|
.cc-grid.wordmask .cc-word { cursor: pointer; }
|
||||||
|
.cc-grid.wordmask .comment-card { cursor: default; }
|
||||||
|
.cc-word.masked { filter: blur(4px); }
|
||||||
.cc-empty { color:var(--text-3); padding:2rem 0; }
|
.cc-empty { color:var(--text-3); padding:2rem 0; }
|
||||||
|
|
||||||
/* ---- 분석 패널 ---- */
|
/* ---- 분석 패널 ---- */
|
||||||
@ -83,7 +88,7 @@
|
|||||||
<h1 style="font-size:1.5rem;font-weight:700;margin-bottom:.3rem;">댓글 카드</h1>
|
<h1 style="font-size:1.5rem;font-weight:700;margin-bottom:.3rem;">댓글 카드</h1>
|
||||||
<p style="color:var(--text-3);margin-bottom:1.2rem;font-size:14px;">
|
<p style="color:var(--text-3);margin-bottom:1.2rem;font-size:14px;">
|
||||||
유튜브 링크의 <b>전체 댓글</b>을 가져와 분석(많이 언급된 타임라인·자주 나온 단어·요약 통계)하고 카드로 만듭니다.
|
유튜브 링크의 <b>전체 댓글</b>을 가져와 분석(많이 언급된 타임라인·자주 나온 단어·요약 통계)하고 카드로 만듭니다.
|
||||||
모자이크는 기본 켜짐, <b>모서리 둥글게</b>로 각진/라운드 전환. <b>카드 클릭=이미지 복사</b>, <b>⬇ 저장=PNG 파일 다운로드</b>(캡컷은 붙여넣기가 안 되니 저장한 파일을 "불러오기" 하세요).
|
모자이크는 기본 켜짐, <b>모서리 둥글게</b>로 각진/라운드 전환. 기본은 <b>단어 클릭=가리기</b>(블러), <b>🖍 단어 가리기</b>를 끄면 <b>카드 클릭=이미지 복사</b>. <b>⬇ 저장=PNG 파일 다운로드</b>(캡컷은 붙여넣기가 안 되니 저장한 파일을 "불러오기" 하세요).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="cc-toolbar">
|
<div class="cc-toolbar">
|
||||||
@ -105,6 +110,7 @@
|
|||||||
<input type="checkbox" id="ccRepliesOnly" /> 답글 있는 것만</label>
|
<input type="checkbox" id="ccRepliesOnly" /> 답글 있는 것만</label>
|
||||||
<button class="cc-btn secondary" id="ccMosaic">모자이크 해제</button>
|
<button class="cc-btn secondary" id="ccMosaic">모자이크 해제</button>
|
||||||
<button class="cc-btn secondary" id="ccRounded">모서리 둥글게</button>
|
<button class="cc-btn secondary" id="ccRounded">모서리 둥글게</button>
|
||||||
|
<button class="cc-btn secondary" id="ccWordMask">🖍 단어 가리기: 켜짐</button>
|
||||||
<span id="ccCount" style="font-size:12px;color:var(--text-3);"></span>
|
<span id="ccCount" style="font-size:12px;color:var(--text-3);"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -117,7 +123,7 @@
|
|||||||
<th:block layout:fragment="script">
|
<th:block layout:fragment="script">
|
||||||
<!-- DOM→이미지 캡처 (Task 5에서 사용). blur 필터 지원 위해 modern-screenshot 사용. -->
|
<!-- DOM→이미지 캡처 (Task 5에서 사용). blur 필터 지원 위해 modern-screenshot 사용. -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/modern-screenshot@4/dist/index.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/modern-screenshot@4/dist/index.js"></script>
|
||||||
<script th:src="@{/js/comment-cards.js(v=20260708c)}"></script>
|
<script th:src="@{/js/comment-cards.js(v=20260708d)}"></script>
|
||||||
</th:block>
|
</th:block>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user