feat(projects): 설명 마크다운 렌더링 + 저장소 README 가져오기

등록 모달의 '한 줄 설명' input 을 여러 줄 textarea 로 바꾸고, 설명을
markdown-it 로 렌더링한다(html:false 로 raw HTML 이스케이프·javascript:
링크 차단 — XSS 안전). 상세 화면은 마크다운으로, 카드 미리보기는 기호를
걷어낸 순수 텍스트(mdPlain) + 3줄 클램프로 표시.

'저장소 README 가져오기' 버튼과 GET /api/readme 라우트를 추가해 repo_url
의 Gitea README 를 설명란으로 불러올 수 있다(gitea.js fetchReadme).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-02 14:18:27 +09:00
parent 4a3e5636c8
commit da1653a8ea
10 changed files with 232 additions and 11 deletions

View File

@@ -38,7 +38,11 @@
<% if (pdTags.length) { %>
<div class="modal-tags"><% pdTags.forEach(function (t) { %><span class="tag"><%= t %></span><% }); %></div>
<% } %>
<p class="modal-desc"><%= p.description || "설명 없음" %></p>
<% if (p.description && p.description.trim()) { %>
<div class="modal-desc md-body"><%- renderMarkdown(p.description) %></div>
<% } else { %>
<p class="modal-desc modal-desc-empty">설명 없음</p>
<% } %>
<div class="modal-actions">
<button type="button" class="modal-action heart<%= p.hearted ? " on" : "" %>" data-react data-id="<%= p.id %>" data-kind="heart">
<span class="ico ico-on"><%- icon("heartFill", { size: 15 }) %></span><span class="ico ico-off"><%- icon("heart", { size: 15 }) %></span>

View File

@@ -69,7 +69,7 @@
<%- icon(p.is_public ? "globe" : "lock", { size: 11 }) %><%= p.is_public ? "공개" : "비공개" %>
</span>
</div>
<div class="pcard-desc"><%= p.description || "설명 없음" %></div>
<div class="pcard-desc"><%= mdPlain(p.description) || "설명 없음" %></div>
<% if (tags.length) { %>
<div class="pcard-tags"><% tags.forEach(function (t) { %><span class="tag"><%= t %></span><% }); %></div>
<% } %>
@@ -153,7 +153,7 @@
</button>
</div>
</div>
<div class="fcard-desc"><%= p.description || "설명 없음" %></div>
<div class="fcard-desc"><%= mdPlain(p.description) || "설명 없음" %></div>
<% if (tags.length) { %>
<div class="fcard-tags"><% tags.forEach(function (t) { %><span class="tag"><%= t %></span><% }); %></div>
<% } %>
@@ -211,8 +211,11 @@
<input class="share-input" name="title" required placeholder="예) 방화벽 정책 DSL 변환기" />
</label>
<label>
<span class="share-label">한 줄 설명</span>
<input class="share-input" name="description" placeholder="무엇을 하는 프로젝트인가요?" />
<span class="share-label share-label-row">
<span>설명 <span class="hint">Markdown 지원 · 제목·목록·코드·링크</span></span>
<button type="button" class="readme-btn" id="readmeImport"><%- icon("repo", { size: 12 }) %>저장소 README 가져오기</button>
</span>
<textarea class="share-input share-textarea" name="description" rows="5" placeholder="무엇을 하는 프로젝트인가요?&#10;&#10;## 예시&#10;- Markdown 문법을 그대로 쓸 수 있어요&#10;- 저장소 URL 을 넣으면 README 를 가져올 수 있어요"></textarea>
</label>
<label>
<span class="share-label">태그 <span class="hint">쉼표로 구분 · 최대 5개</span></span>