반응형
Markdown 파일에서 제목, 날짜, 내용의 일부만 읽어와서 표시하도록 JavaScript 코드를 업데이트하겠습니다. 이를 위해 각 Markdown 파일에서 첫 번째 제목(#
), 날짜(*yyyy-mm-dd*
), 그리고 내용의 첫 번째 단락만 가져오도록 하겠습니다.
디렉터리 구조
/blog
index.html
blog.css
blog.js
/assets/markdown/posts
post1.md
post2.md
...
HTML (index.html
)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog Page</title>
<link rel="stylesheet" href="../common/css/common.css">
<link rel="stylesheet" href="blog.css">
</head>
<body>
<!-- 공통 헤더 -->
<header>
<nav>
<ul>
<li><a href="../home/index.html">Home</a></li>
<li><a href="../profile/index.html">Profile</a></li>
<li><a href="../blog/index.html">Blog</a></li>
</ul>
</nav>
</header>
<!-- 메인 콘텐츠 -->
<main>
<section class="blog-posts">
<h2>Blog Posts</h2>
<div class="title-divider"></div>
<div id="posts-container"></div>
<div id="pagination"></div>
</section>
</main>
<!-- 공통 푸터 -->
<footer>
<p>© 2024 Your Name. All rights reserved.</p>
</footer>
<script src="blog.js"></script>
</body>
</html>
CSS (blog.css
)
/* 공통 스타일을 사용하기 위해 common.css 포함 */
@import url('../common/css/common.css');
/* 블로그 페이지 스타일 */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background: #f4f4f9;
}
header nav ul {
display: flex;
justify-content: center;
background: #333;
padding: 0;
}
header nav ul li {
list-style: none;
margin: 0;
}
header nav ul li a {
display: block;
padding: 15px 20px;
color: white;
text-decoration: none;
}
header nav ul li a:hover {
background: #575757;
}
.blog-posts {
max-width: 800px;
margin: 40px auto;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
text-align: center; /* 섹션 글자 가운데 정렬 */
}
.blog-posts h2 {
margin-bottom: 10px;
}
.title-divider {
width: 80px;
height: 4px;
background-color: #007BFF;
margin: 10px auto 20px auto;
border-radius: 2px;
}
#posts-container {
margin-top: 20px; /* 목록과 제목 구분 */
}
.post {
border-bottom: 1px solid #ddd;
padding: 20px 0;
text-align: left; /* 포스트 내용은 왼쪽 정렬 */
}
.post:last-child {
border-bottom: none;
}
.post-title {
font-size: 1.5em;
margin: 0;
}
.post-date {
color: #999;
font-size: 0.9em;
}
.post-summary {
margin: 10px 0;
}
.read-more {
color: #007BFF;
text-decoration: none;
}
.read-more:hover {
text-decoration: underline;
}
/* 페이징 스타일 */
.pagination {
display: flex;
justify-content: center;
margin-top: 20px;
gap: 5px;
}
.pagination button {
background: #007BFF;
color: white;
border: none;
padding: 10px 15px;
cursor: pointer;
border-radius: 5px;
}
.pagination button:hover {
background: #0056b3;
}
.pagination button.disabled {
background: #ccc;
cursor: not-allowed;
}
.pagination .arrow {
font-size: 1.2em;
}
JavaScript (blog.js
)
// blog.js
// Markdown을 HTML로 변환하는 함수
function markdownToHtml(markdown) {
const titleMatch = markdown.match(/^# (.*$)/m);
const dateMatch = markdown.match(/^\*([0-9-]+)\*/m);
const contentMatch = markdown.match(/(?:#.*?\n|\*.*?\n)([^#\*]*)/s);
const title = titleMatch ? titleMatch[1] : 'No title';
const date = dateMatch ? dateMatch[1] : 'No date';
const content = contentMatch ? contentMatch[1].trim().split('\n').slice(0, 2).join(' ') : 'No content';
return `
<h3 class="post-title">${title}</h3>
<p class="post-date">${date}</p>
<p class="post-summary">${content}</p>
<a class="read-more" href="#">Read more</a>
`;
}
// Markdown 파일을 비동기적으로 읽어오는 함수
async function fetchMarkdown(file) {
const response = await fetch(file);
const markdown = await response.text();
return markdownToHtml(markdown);
}
// 디렉토리 목록을 비동기적으로 가져오는 함수
async function fetchMarkdownFiles() {
// 실제로는 서버에서 파일 목록을 받아와야 합니다.
// 이 예제에서는 하드코딩된 파일 목록을 사용합니다.
return [
'assets/markdown/posts/post1.md',
'assets/markdown/posts/post2.md',
// 다른 게시물 파일들을 추가할 수 있습니다
];
}
// 블로그 게시물 목록을 생성하는 함수
async function createBlogPosts(page = 1) {
const postsContainer = document.getElementById('posts-container');
postsContainer.innerHTML = ''; // 이전 게시물 초기화
const postFiles = await fetchMarkdownFiles();
const postsPerPage = 5;
const startIndex = (page - 1) * postsPerPage;
const endIndex = startIndex + postsPerPage;
const paginatedPosts = postFiles.slice(startIndex, endIndex);
for (const file of paginatedPosts) {
const postHtml = await fetchMarkdown(file);
const postElement = document.createElement('div');
postElement.classList.add('post');
postElement.innerHTML = postHtml;
postsContainer.appendChild(postElement);
}
// 페이징 생성
createPagination(postFiles.length, postsPerPage, page);
}
// 페이징 생성 함수
function createPagination(totalPosts, postsPerPage, currentPage) {
const paginationContainer = document.getElementById('pagination');
paginationContainer.innerHTML = ''; // 이전 페이징 초기화
const totalPages = Math.ceil(totalPosts / postsPerPage);
const maxVisiblePages = 5; // 한번에 보여줄 최대 페이지 수
let startPage = Math.max(currentPage - Math.floor(maxVisiblePages / 2), 1);
let endPage = Math.min(startPage + maxVisiblePages - 1, totalPages);
if (endPage - startPage < maxVisiblePages - 1) {
startPage = Math.max(endPage - maxVisiblePages + 1, 1);
}
if (currentPage > 1) {
const prevButton = document.createElement('button');
prevButton.innerHTML = '«';
prevButton.classList.add('arrow');
prevButton.addEventListener('click', () => createBlogPosts(currentPage - 1));
paginationContainer.appendChild(prevButton);
}
for (let page = startPage; page <= endPage; page++) {
const button = document.createElement('button');
button.innerText = page;
button.classList.add(page === currentPage ? 'disabled' : '');
button.disabled = page === currentPage;
button.addEventListener('click', () => createBlogPosts(page));
paginationContainer.appendChild(button);
}
if (currentPage < totalPages) {
const nextButton = document.createElement('button');
nextButton.innerHTML = '»';
nextButton.classList.add('arrow');
nextButton.addEventListener('click', () => createBlogPosts(currentPage + 1));
paginationContainer.appendChild(nextButton);
}
}
// DOMContentLoaded 이벤트가 발생하면 createBlogPosts 함수 호출
document.addEventListener('DOMContentLoaded', () => {
createBlogPosts();
});
Markdown 파일 예시 (post1.md
)
# First Blog Post
*2024-06-01*
This is the summary of the first blog post. It contains an introduction and a few details about the post.
[Read more](post1.html)
주요 변경 사항 설명
- markdownToHtml 함수:
- Markdown 파일의 첫 번째 제목(
#
), 날짜(*yyyy-mm-dd*
), 그리고 첫 번째 단락의 일부만 추출하여 HTML로 변환합니다.
- Markdown 파일의 첫 번째 제목(
- 제목, 날짜, 내용 일부를 HTML 구조로 반환합니다.
fetchMarkdownFiles 함수:
- 실제 서버에서 파일 목록을 받아와야 하지만, 예제에서는 하드코딩된 파일 목록을 사용합니다.
- 서버에서 파일 목록을 가져오는 부분은 필요에 따라 구현합니다.
createBlogPosts 함수:
- 지정된 페이지의 Markdown 파일 목록을 읽어와서 각 게시물의 일부만 표시합니다.
- postsPerPage로 페이지당 표시할 게시물 수를 설정합니다.
createPagination 함수:
- 전체 게시물 수에 따라 페이징 버튼을 생성합니다.
- 각 버튼을 클릭하면 해당 페이지의 게시물이 표시됩니다.
- 좌우 버튼을 통해 페이지 이동이 가능하도록 구현하였습니다.
이제 Blog 페이지는 assets/markdown/posts
디렉토리의 Markdown 파일에서 제목, 날짜, 내용 일부만 읽어와서 목록으로 표시하며, 페이지당 5개의 게시물을 표시하고, 페이징 기능을 제공합니다. 제목과 목록 부분이 분리되어 명확하게 보이도록 스타일을 설정했습니다.
반응형
'Javascript 프로젝트 > GitHub 웹 페이지' 카테고리의 다른 글
[GitHub 웹페이지] Profile 페이지 (0) | 2024.06.10 |
---|---|
[GitHub 웹페이지] 6. 프로필 페이지 - 와이어프레임 (0) | 2024.06.09 |
[GitHub 웹페이지] 5. 블로그 페이지 - 와이어프레임 (0) | 2024.06.09 |
[GitHub 웹페이지] 4. 홈페이지 - 와이어프레임 (0) | 2024.06.09 |
[GitHub 웹페이지] 2. 규칙 정하기 - Git Commit Message (0) | 2024.06.09 |