feat(ai-cases): PDF 상세 1·2·3단 보기(학습센터와 동일 localStorage 키)
Made-with: Cursor
This commit is contained in:
@@ -106,7 +106,7 @@ ai_platform/
|
|||||||
│ ├─ partials/mgmt_perf_dashboard_container.ejs
|
│ ├─ partials/mgmt_perf_dashboard_container.ejs
|
||||||
│ ├─ ai-prompts.ejs # 프롬프트 라이브러리 (카드·미리보기·복사)
|
│ ├─ ai-prompts.ejs # 프롬프트 라이브러리 (카드·미리보기·복사)
|
||||||
│ ├─ ai-cases.ejs # AI 성공 사례 목록(카드)
|
│ ├─ ai-cases.ejs # AI 성공 사례 목록(카드)
|
||||||
│ ├─ ai-case-detail.ejs # AI 성공 사례 상세(마크다운)
|
│ ├─ ai-case-detail.ejs # AI 성공 사례 상세(마크다운 또는 PDF·페이지 이미지, 1·2·3단 보기)
|
||||||
│ ├─ ai-cases-write.ejs # AI 성공 사례 관리자 등록·편집
|
│ ├─ ai-cases-write.ejs # AI 성공 사례 관리자 등록·편집
|
||||||
│ ├─ ax-apply.ejs # AX 과제 신청
|
│ ├─ ax-apply.ejs # AX 과제 신청
|
||||||
│ ├─ lecture-youtube.ejs # 유튜브 강의 상세 (iframe 임베드)
|
│ ├─ lecture-youtube.ejs # 유튜브 강의 상세 (iframe 임베드)
|
||||||
|
|||||||
@@ -596,6 +596,14 @@ button {
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-case-tools-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-case-tool-sep {
|
.ai-case-tool-sep {
|
||||||
color: #d1d5db;
|
color: #d1d5db;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
|
|||||||
@@ -19,20 +19,28 @@
|
|||||||
<a href="/ai-cases" class="back-link">← AI 성공 사례로 돌아가기</a>
|
<a href="/ai-cases" class="back-link">← AI 성공 사례로 돌아가기</a>
|
||||||
<h1><%= story.title %></h1>
|
<h1><%= story.title %></h1>
|
||||||
<p class="description"><%= story.excerpt || (story.department + ' · ' + story.author) %></p>
|
<p class="description"><%= story.excerpt || (story.department + ' · ' + story.author) %></p>
|
||||||
<div class="ppt-tools ai-case-ppt-tools">
|
<div class="ppt-tools ai-case-ppt-tools ppt-tools-row">
|
||||||
<span>총 <b><%= slides.length %></b>페이지</span>
|
<div class="ai-case-tools-meta">
|
||||||
<span class="ai-case-tool-sep" aria-hidden="true">|</span>
|
<span>총 <b><%= slides.length %></b>페이지</span>
|
||||||
<span><%= story.department %> · <%= story.author %><% if (story.publishedAt) { %> · <%= story.publishedAt %><% } %></span>
|
<span class="ai-case-tool-sep" aria-hidden="true">|</span>
|
||||||
<% if (typeof adminMode !== 'undefined' && adminMode) { %>
|
<span><%= story.department %> · <%= story.author %><% if (story.publishedAt) { %> · <%= story.publishedAt %><% } %></span>
|
||||||
<span class="ai-case-tool-sep" aria-hidden="true">|</span>
|
<% if (typeof adminMode !== 'undefined' && adminMode) { %>
|
||||||
<a href="/ai-cases/write?edit=<%= story.slug %>" class="ai-case-inline-link">편집</a>
|
<span class="ai-case-tool-sep" aria-hidden="true">|</span>
|
||||||
<% } %>
|
<a href="/ai-cases/write?edit=<%= story.slug %>" class="ai-case-inline-link">편집</a>
|
||||||
<span class="ai-case-tool-sep" aria-hidden="true">|</span>
|
<% } %>
|
||||||
<a href="<%= pdfUrlRaw %>" download class="ai-case-inline-link">다운로드</a>
|
<span class="ai-case-tool-sep" aria-hidden="true">|</span>
|
||||||
<% if (typeof adminMode !== 'undefined' && adminMode) { %>
|
<a href="<%= pdfUrlRaw %>" download class="ai-case-inline-link">다운로드</a>
|
||||||
<span class="ai-case-tool-sep" aria-hidden="true">|</span>
|
<% if (typeof adminMode !== 'undefined' && adminMode) { %>
|
||||||
<button type="button" class="ai-case-inline-link js-ai-case-delete" data-id="<%= story.id %>" data-title="<%= story.title %>">삭제</button>
|
<span class="ai-case-tool-sep" aria-hidden="true">|</span>
|
||||||
<% } %>
|
<button type="button" class="ai-case-inline-link js-ai-case-delete" data-id="<%= story.id %>" data-title="<%= story.title %>">삭제</button>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<div class="slide-layout-toggle" role="group" aria-label="페이지 한 화면 열 개수">
|
||||||
|
<span class="slide-layout-toggle-label">보기</span>
|
||||||
|
<button type="button" class="slide-layout-btn" data-cols="1" aria-pressed="true">1단</button>
|
||||||
|
<button type="button" class="slide-layout-btn" data-cols="2" aria-pressed="false">2단</button>
|
||||||
|
<button type="button" class="slide-layout-btn" data-cols="3" aria-pressed="false">3단</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% if ((story.tags || []).length) { %>
|
<% if ((story.tags || []).length) { %>
|
||||||
<div class="tag-row ai-case-tag-row">
|
<div class="tag-row ai-case-tag-row">
|
||||||
@@ -44,25 +52,17 @@
|
|||||||
<% if (!slideImageUrls || slideImageUrls.length === 0) { %>
|
<% if (!slideImageUrls || slideImageUrls.length === 0) { %>
|
||||||
<p class="admin-warn">PDF를 페이지 이미지로 보여 주지 못했습니다. <a href="<%= pdfUrlRaw %>" target="_blank" rel="noopener noreferrer">원본 PDF로 보기</a>. 서버에는 <code>pdftoppm</code>(Poppler)이 필요하고, 저장된 PDF 주소는 브라우저에서 열리는 것과 같이 <code>/public/...</code> 또는 그와 같은 경로의 전체 URL이어야 합니다.</p>
|
<p class="admin-warn">PDF를 페이지 이미지로 보여 주지 못했습니다. <a href="<%= pdfUrlRaw %>" target="_blank" rel="noopener noreferrer">원본 PDF로 보기</a>. 서버에는 <code>pdftoppm</code>(Poppler)이 필요하고, 저장된 PDF 주소는 브라우저에서 열리는 것과 같이 <code>/public/...</code> 또는 그와 같은 경로의 전체 URL이어야 합니다.</p>
|
||||||
<% } %>
|
<% } %>
|
||||||
<section class="slide-list">
|
<section class="slide-list slide-list--cols-1" id="slide-list">
|
||||||
<% slides.forEach((slide, index) => { %>
|
<% slides.forEach((slide, index) => { %>
|
||||||
<article class="slide-card">
|
<article class="slide-card">
|
||||||
<header>
|
<header>
|
||||||
<h2>페이지 <%= index + 1 %></h2>
|
<h2>페이지 <%= index + 1 %></h2>
|
||||||
<% if (slide.title) { %><p><%= slide.title %></p><% } %>
|
|
||||||
</header>
|
</header>
|
||||||
<% if (slideImageUrls[index]) { %>
|
<% if (slideImageUrls[index]) { %>
|
||||||
<div class="slide-image-wrap">
|
<div class="slide-image-wrap">
|
||||||
<img src="<%= slideImageUrls[index] %>" alt="페이지 <%= index + 1 %>" class="slide-image" />
|
<img src="<%= slideImageUrls[index] %>" alt="페이지 <%= index + 1 %>" class="slide-image" />
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% if (slide.lines && slide.lines.length > 0) { %>
|
|
||||||
<ul>
|
|
||||||
<% slide.lines.forEach((line) => { %>
|
|
||||||
<li><%= line %></li>
|
|
||||||
<% }) %>
|
|
||||||
</ul>
|
|
||||||
<% } %>
|
|
||||||
</article>
|
</article>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</section>
|
</section>
|
||||||
@@ -101,6 +101,43 @@
|
|||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<% if (showPdfViewer) { %>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var KEY = "learningCenterSlideColumns";
|
||||||
|
var list = document.getElementById("slide-list");
|
||||||
|
var buttons = document.querySelectorAll(".slide-layout-btn");
|
||||||
|
if (!list || !buttons.length) return;
|
||||||
|
|
||||||
|
function applyCols(n) {
|
||||||
|
list.classList.remove("slide-list--cols-1", "slide-list--cols-2", "slide-list--cols-3");
|
||||||
|
list.classList.add("slide-list--cols-" + n);
|
||||||
|
buttons.forEach(function (btn) {
|
||||||
|
var on = btn.getAttribute("data-cols") === String(n);
|
||||||
|
btn.setAttribute("aria-pressed", on ? "true" : "false");
|
||||||
|
btn.classList.toggle("is-active", on);
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
localStorage.setItem(KEY, String(n));
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var saved = null;
|
||||||
|
try {
|
||||||
|
saved = localStorage.getItem(KEY);
|
||||||
|
} catch (e) {}
|
||||||
|
var initial = saved === "2" || saved === "3" ? saved : "1";
|
||||||
|
applyCols(initial);
|
||||||
|
|
||||||
|
buttons.forEach(function (btn) {
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
var n = btn.getAttribute("data-cols");
|
||||||
|
if (n === "1" || n === "2" || n === "3") applyCols(n);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<% } %>
|
||||||
<% if (typeof adminMode !== 'undefined' && adminMode) { %>
|
<% if (typeof adminMode !== 'undefined' && adminMode) { %>
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user