Files
ai-dev-portal/public/js/feed.js
2620227 40f8352a28 feat: 헤더 매뉴얼 버튼 · 프로필 검색 · 상세 뒤로가기 뎁스 정리
- 헤더 프로필 왼쪽에 '매뉴얼' 버튼 추가(MANUAL_URL 환경변수, 기본 gitea MANUAL)
- 검색을 페이지 내 data-search 카드 전체 대상으로 일반화 → 프로필에서 그 사람
  프로젝트도 검색(자리표시자도 페이지별로: 공유/내/○○ 님의 프로젝트)
- 상세 페이지 뒤로가기: ?from= 내부경로 기반으로 프로필→상세는 프로필로 복귀
- '사내 개발 포털' +4pt, 도구 카드 이름·설명 +2pt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:43:32 +09:00

66 lines
2.8 KiB
JavaScript

// 피드 검색·정렬·즐겨찾기 필터 + 내 프로젝트 필터 (모두 클라이언트 처리).
import { $, $$ } from "./util.js";
function applyFeed() {
// 검색 대상 = 현재 페이지의 검색 가능한 카드 전체(대시보드=공유 프로젝트, 프로필=그 사람 프로젝트).
const cards = $$(".fcard[data-search]");
if (!cards.length) return;
const q = (($("#feedSearch") && $("#feedSearch").value) || "").trim().toLowerCase();
const starOnly = $("#feedStarFilter") && $("#feedStarFilter").classList.contains("on");
let visible = 0;
cards.forEach((c) => {
const hit = !q || (c.getAttribute("data-search") || "").indexOf(q) >= 0;
const st = !starOnly || c.getAttribute("data-starred") === "true";
const show = hit && st;
c.style.display = show ? "" : "none";
if (show) visible++;
});
const empty = $("#feedEmpty");
if (empty) {
empty.hidden = visible !== 0;
empty.textContent = starOnly && visible === 0
? "아직 즐겨찾기한 프로젝트가 없어요 · 카드의 ⭐ 버튼으로 추가하세요"
: "“" + (($("#feedSearch") && $("#feedSearch").value) || "") + "” 와 일치하는 프로젝트가 없습니다.";
}
}
function sortFeed(mode) {
const grid = $("#feedGrid"); if (!grid) return;
const cards = $$(".fcard", grid);
cards.sort((a, b) => {
if (mode === "popular") {
return (+b.getAttribute("data-pop") || 0) - (+a.getAttribute("data-pop") || 0)
|| (b.getAttribute("data-created") || "").localeCompare(a.getAttribute("data-created") || "");
}
return (b.getAttribute("data-created") || "").localeCompare(a.getAttribute("data-created") || "");
});
cards.forEach((c) => grid.appendChild(c));
}
export function initFeed() {
const search = $("#feedSearch");
if (search) search.addEventListener("input", applyFeed);
const sl = $("#sortLatest"), sp = $("#sortPopular");
if (sl) sl.addEventListener("click", () => { sl.classList.add("on"); if (sp) sp.classList.remove("on"); sortFeed("latest"); });
if (sp) sp.addEventListener("click", () => { sp.classList.add("on"); if (sl) sl.classList.remove("on"); sortFeed("popular"); });
const sf = $("#feedStarFilter");
if (sf) sf.addEventListener("click", () => { sf.classList.toggle("on"); applyFeed(); });
}
export function initMyFilter() {
const tabs = $$("[data-myfilter]");
if (!tabs.length) return;
tabs.forEach((tab) => {
tab.addEventListener("click", () => {
const f = tab.getAttribute("data-myfilter"); // all | public | private
tabs.forEach((t) => t.classList.toggle("on", t === tab));
$$("#myProjGrid .pcard").forEach((c) => {
const vis = c.getAttribute("data-vis");
c.style.display = (f === "all" || vis === f) ? "" : "none";
});
const add = $("#addCard");
if (add) add.style.display = f === "all" ? "" : "none";
});
});
}