feat(projects): 등록한 프로젝트 수정 기능 추가
- 상세(모달/단독) 소유자 영역에 '수정' 버튼 → 등록 모달을 현재 값으로 채워 재사용 - POST /projects/:id/edit 라우트 + db.updateProject(소유자 조건으로 타인 수정 차단) - 등록/수정 공용 모달을 _project_form_modal.ejs 로 추출(dashboard·project 에서 include) - pencil 아이콘 추가, modals.js 에 openEdit/openShare 초기화 로직 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -50,11 +50,53 @@ function closeDetail() {
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
// 폼 모달의 공개범위 토글을 지정 값으로 맞춘다(등록/수정 공용).
|
||||
function setVis(m, isPublic) {
|
||||
const input = $('input[name="is_public"]', m);
|
||||
if (input) input.value = isPublic ? "1" : "0";
|
||||
$$("[data-vis]", m).forEach((b) => {
|
||||
const pub = b.getAttribute("data-vis") === "public";
|
||||
b.classList.toggle("on-public", pub && isPublic);
|
||||
b.classList.toggle("on-private", !pub && !isPublic);
|
||||
});
|
||||
const hint = $(".share-vishint", m);
|
||||
if (hint) hint.textContent = isPublic ? "피드에 공개되어 동료가 볼 수 있어요" : "나만 볼 수 있어요 · 언제든 공유로 전환 가능";
|
||||
}
|
||||
function fieldSet(m, name, value) {
|
||||
const el = $('[name="' + name + '"]', m);
|
||||
if (el) el.value = value == null ? "" : value;
|
||||
}
|
||||
|
||||
// 등록 모드로 초기화해서 연다.
|
||||
function openShare() {
|
||||
const m = $("#shareModal"); if (!m) return;
|
||||
const form = $("form", m); if (form) form.setAttribute("action", "/projects");
|
||||
const h = $("#shareTitle", m); if (h) h.textContent = "새 프로젝트 등록";
|
||||
const sub = $("#shareSubmit", m); if (sub) sub.textContent = "등록";
|
||||
["title", "description", "tags", "repo_url", "app_url", "lang", "return_to"].forEach((n) => fieldSet(m, n, ""));
|
||||
setVis(m, true);
|
||||
m.hidden = false; document.body.style.overflow = "hidden";
|
||||
const t = $('input[name="title"]', m); if (t) t.focus();
|
||||
}
|
||||
|
||||
// 수정 모드: 상세의 '수정' 버튼 data-* 로 폼을 채우고 연다.
|
||||
function openEdit(btn) {
|
||||
const m = $("#shareModal"); if (!m || !btn) return;
|
||||
const form = $("form", m);
|
||||
if (form) form.setAttribute("action", "/projects/" + btn.getAttribute("data-id") + "/edit");
|
||||
const h = $("#shareTitle", m); if (h) h.textContent = "프로젝트 수정";
|
||||
const sub = $("#shareSubmit", m); if (sub) sub.textContent = "저장";
|
||||
fieldSet(m, "title", btn.getAttribute("data-title"));
|
||||
fieldSet(m, "description", btn.getAttribute("data-desc"));
|
||||
fieldSet(m, "tags", btn.getAttribute("data-tags"));
|
||||
fieldSet(m, "repo_url", btn.getAttribute("data-repo"));
|
||||
fieldSet(m, "app_url", btn.getAttribute("data-app"));
|
||||
fieldSet(m, "lang", btn.getAttribute("data-lang"));
|
||||
fieldSet(m, "return_to", btn.getAttribute("data-return"));
|
||||
setVis(m, btn.getAttribute("data-public") === "1");
|
||||
m.hidden = false; document.body.style.overflow = "hidden";
|
||||
const t = $('input[name="title"]', m); if (t) { t.focus(); t.select(); }
|
||||
}
|
||||
function closeShare() {
|
||||
const m = $("#shareModal"); if (!m || m.hidden) return;
|
||||
m.hidden = true; document.body.style.overflow = "";
|
||||
@@ -71,6 +113,8 @@ export function initModals() {
|
||||
}
|
||||
if (e.target.closest("[data-close-detail]")) { e.preventDefault(); closeDetail(); return; }
|
||||
if (e.target.closest("[data-open-share]")) { e.preventDefault(); openShare(); return; }
|
||||
const editBtn = e.target.closest("[data-open-edit]");
|
||||
if (editBtn) { e.preventDefault(); openEdit(editBtn); return; }
|
||||
if (e.target.closest("[data-close-share]")) { e.preventDefault(); closeShare(); return; }
|
||||
if (e.target.closest("#readmeImport")) { e.preventDefault(); importReadme(); return; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user