feat: 헤더 매뉴얼 버튼 · 프로필 검색 · 상세 뒤로가기 뎁스 정리

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

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 15:43:32 +09:00
parent b512ab2143
commit 40f8352a28
10 changed files with 42 additions and 11 deletions

View File

@@ -35,4 +35,7 @@ export const config = {
// 포털 표시 이름 (변경 가능)
brand: process.env.PORTAL_BRAND || "AI DEV",
// 포털 사용 매뉴얼 링크(헤더 '매뉴얼' 버튼). 도메인 변경 대비 환경변수로 덮어쓰기 가능.
manualUrl: process.env.MANUAL_URL || "https://gitea.bokdev.in/playground/MANUAL",
};

View File

@@ -27,6 +27,7 @@ const OCTICONS = {
check: '<path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L1.72 8.78a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/>',
ext: '<path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"/>',
trash: '<path d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75ZM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.149l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15ZM6.5 1.75V3h3V1.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25Z"/>',
book: '<path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"/>',
};
// 인라인 SVG 아이콘 문자열. fill 기본은 currentColor(부모 색 상속).

View File

@@ -31,6 +31,7 @@ app.use(
// 모든 뷰 공통 노출 (브랜드·사용자·뷰 헬퍼)
app.use((req, res, next) => {
res.locals.brand = config.brand;
res.locals.manualUrl = config.manualUrl;
res.locals.user = req.session.user || null;
res.locals.icon = icon;
res.locals.identicon = identicon;
@@ -124,7 +125,10 @@ app.get("/u/:sabun", requireAuth, async (req, res) => {
const profile = await db.getUserProfile(req.params.sabun);
if (!profile) return res.status(404).send("사용자를 찾을 수 없습니다.");
const projects = await db.listProjectsByOwner(profile.sabun, me);
res.render("profile", { profile, projects, isSelf: profile.sabun === me });
const searchPlaceholder = profile.sabun === me
? "내 프로젝트 검색…"
: `${profile.name} 님의 프로젝트 검색…`;
res.render("profile", { profile, projects, isSelf: profile.sabun === me, searchPlaceholder });
});
// --- 대시보드 ---
@@ -183,7 +187,14 @@ app.get("/projects/:id", requireAuth, async (req, res) => {
// 비공개는 본인만 열람
if (!project.is_public && project.owner_sabun !== me) return res.status(403).send("비공개 프로젝트입니다.");
const comments = await db.listComments(project.id);
res.render("project", { project, comments, starred: project.starred });
// 뒤로가기 대상: ?from= 으로 넘어온 내부 경로(프로필 등)가 있으면 그곳, 없으면 대시보드.
// (뎁스 순서: 프로필 → 프로젝트 상세 로 들어왔으면 프로필로 돌아간다)
const from = req.query.from;
const safeFrom = typeof from === "string" && /^\/[^/]/.test(from) ? from : null; // 내부 절대경로만 허용
const back = safeFrom && safeFrom.startsWith("/u/")
? { href: safeFrom, label: "프로필" }
: { href: "/", label: "대시보드" };
res.render("project", { project, comments, starred: project.starred, back });
});
// --- 반응: ❤️ 좋아요 / ⭐ 즐겨찾기 ---