diff --git a/src/main/java/com/hlab/yanalyst/web/WebController.java b/src/main/java/com/hlab/yanalyst/web/WebController.java
index fa05177..9e505ce 100644
--- a/src/main/java/com/hlab/yanalyst/web/WebController.java
+++ b/src/main/java/com/hlab/yanalyst/web/WebController.java
@@ -71,6 +71,12 @@ public class WebController {
return "rework";
}
+ @GetMapping("/comment-cards")
+ public String commentCards(Model model) {
+ model.addAttribute("currentPage", "comment-cards");
+ return "comment-cards";
+ }
+
@GetMapping("/production")
public String production(Model model) {
model.addAttribute("currentPage", "production");
diff --git a/src/main/resources/static/js/comment-cards.js b/src/main/resources/static/js/comment-cards.js
new file mode 100644
index 0000000..ecd934c
--- /dev/null
+++ b/src/main/resources/static/js/comment-cards.js
@@ -0,0 +1,116 @@
+(function () {
+ window.__cards = [];
+ let mosaicOn = false;
+
+ const $ = (id) => document.getElementById(id);
+
+ function timeAgo(iso) {
+ if (!iso) return '';
+ const then = new Date(iso).getTime();
+ if (isNaN(then)) return '';
+ const sec = Math.floor((Date.now() - then) / 1000);
+ const units = [['년', 31536000], ['개월', 2592000], ['일', 86400], ['시간', 3600], ['분', 60]];
+ for (const [label, s] of units) {
+ const v = Math.floor(sec / s);
+ if (v >= 1) return v + label + ' 전';
+ }
+ return '방금 전';
+ }
+
+ // YouTube textDisplay(HTML) → 안전한 평문 (태그 제거,
→줄바꿈)
+ function toPlainText(html) {
+ const tmp = document.createElement('div');
+ tmp.innerHTML = String(html).replace(/
/gi, '\n');
+ return tmp.textContent || '';
+ }
+
+ function applyFilterSort(cards) {
+ const sort = $('ccSort').value;
+ const minLikes = parseInt($('ccMinLikes').value, 10) || 0;
+ const repliesOnly = $('ccRepliesOnly').checked;
+ let list = cards.filter(c => (c.likeCount || 0) >= minLikes && (!repliesOnly || (c.replyCount || 0) > 0));
+ if (sort === 'likes') list.sort((a, b) => (b.likeCount || 0) - (a.likeCount || 0));
+ else if (sort === 'replies') list.sort((a, b) => (b.replyCount || 0) - (a.replyCount || 0));
+ else if (sort === 'latest') list.sort((a, b) => new Date(b.publishedAt) - new Date(a.publishedAt));
+ return list;
+ }
+
+ window.renderCards = function () {
+ const grid = $('cardGrid');
+ const list = applyFilterSort(window.__cards);
+ $('ccCount').textContent = list.length + '개';
+ grid.innerHTML = '';
+ list.forEach((c, i) => {
+ const card = document.createElement('div');
+ card.className = 'comment-card' + (mosaicOn ? ' mosaic' : '');
+ card.dataset.index = i;
+
+ const avatarSrc = c.profileImageUrl
+ ? '/api/comment-cards/avatar?url=' + encodeURIComponent(c.profileImageUrl)
+ : '';
+
+ const head = document.createElement('div');
+ head.className = 'cc-head';
+ head.innerHTML =
+ '' +
+ '
+ 유튜브 링크의 댓글을 가져와 카드로 만들고, 프로필·아이디를 모자이크해 영상 소스로 복사하세요. +
+ + + + + + + +