feat: 댓글 카드 검색어 쉼표 OR 검색 지원

검색 입력을 쉼표로 구분하면 각 단어 중 하나라도 포함된 댓글을 표시한다.
공백은 구분자가 아니므로 여러 단어를 이어 쓴 구절 검색은 그대로 동작한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hehihoho3@gmail.com 2026-07-29 14:24:47 +09:00
parent aecbdb4753
commit b6bfa5046d
2 changed files with 15 additions and 7 deletions

View File

@ -61,6 +61,11 @@
const raw = ($('ccExclude') && $('ccExclude').value) || ''; const raw = ($('ccExclude') && $('ccExclude').value) || '';
return raw.split(/[,\s]+/).map(s => s.trim().toLowerCase()).filter(Boolean); return raw.split(/[,\s]+/).map(s => s.trim().toLowerCase()).filter(Boolean);
} }
// 검색어: 쉼표로 구분하면 OR 검색(하나라도 포함되면 표시). 공백은 구분자가 아님 → 구절 검색 유지.
function getSearchTerms() {
const raw = ($('ccSearch') && $('ccSearch').value) || '';
return raw.split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
}
function excludeComments(list, terms) { function excludeComments(list, terms) {
if (!terms || !terms.length) return list; if (!terms || !terms.length) return list;
return list.filter(c => { return list.filter(c => {
@ -95,12 +100,14 @@
const sort = $('ccSort').value; const sort = $('ccSort').value;
const minLikes = parseInt($('ccMinLikes').value, 10) || 0; const minLikes = parseInt($('ccMinLikes').value, 10) || 0;
const repliesOnly = $('ccRepliesOnly').checked; const repliesOnly = $('ccRepliesOnly').checked;
const q = ($('ccSearch').value || '').trim().toLowerCase(); const terms = getSearchTerms();
let list = cards.filter(c => let list = cards.filter(c => {
(c.likeCount || 0) >= minLikes && if ((c.likeCount || 0) < minLikes) return false;
(!repliesOnly || (c.replyCount || 0) > 0) && if (repliesOnly && (c.replyCount || 0) <= 0) return false;
(!q || toPlainText(c.text).toLowerCase().includes(q)) // 내용에만 매칭 if (!terms.length) return true;
); const t = toPlainText(c.text).toLowerCase(); // 내용에만 매칭
return terms.some(term => t.includes(term)); // 쉼표 구분 = OR
});
if (sort === 'likes') list.sort((a, b) => (b.likeCount || 0) - (a.likeCount || 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 === '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)); else if (sort === 'latest') list.sort((a, b) => new Date(b.publishedAt) - new Date(a.publishedAt));

View File

@ -138,7 +138,8 @@
</div> </div>
<div class="cc-toolbar" id="ccFilters" style="display:none;"> <div class="cc-toolbar" id="ccFilters" style="display:none;">
<input type="text" id="ccSearch" placeholder="댓글 내용 검색" aria-label="댓글 내용 검색" style="min-width:180px;" /> <input type="text" id="ccSearch" placeholder="댓글 내용 검색 (쉼표로 여러 개 = OR)"
aria-label="댓글 내용 검색 (쉼표로 구분하면 하나라도 포함된 댓글 표시)" title="쉼표로 구분하면 OR 검색 (예: 웃김, 재밌, 대박)" style="min-width:220px;" />
<input type="text" id="ccExclude" placeholder="제외 단어 (쉼표로 구분)" aria-label="제외 단어 (쉼표로 구분)" style="min-width:180px;" /> <input type="text" id="ccExclude" placeholder="제외 단어 (쉼표로 구분)" aria-label="제외 단어 (쉼표로 구분)" style="min-width:180px;" />
<select id="ccSort" aria-label="정렬 기준"> <select id="ccSort" aria-label="정렬 기준">
<option value="likes">좋아요순</option> <option value="likes">좋아요순</option>