본문 바로가기
Javascript 프로젝트/GitHub 웹 페이지

[GitHub 웹페이지] Profile 페이지

by cogito21_js 2024. 6. 10.
반응형

아래는 Profile 페이지의 코드를 상세히 설명한 내용입니다. HTML, CSS, JavaScript로 구성된 Profile 페이지는 다양한 섹션을 포함하고 있으며, 각 섹션은 Markdown 파일에서 데이터를 동적으로 가져와 렌더링합니다.

### 디렉터리 구조
```
/profile
    index.html
    profile.css
    profile.js
    markdown
        profile.md
```

### HTML (`index.html`)
Profile 페이지의 HTML 구조입니다. 공통된 header와 footer를 사용하고, main 태그 내부에 Markdown 데이터를 렌더링할 수 있는 container를 포함합니다.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Profile Page</title>
    <link rel="stylesheet" href="../common/css/common.css">
    <link rel="stylesheet" href="profile.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 id="profile" class="section">
            <div class="container">
                <h3 class="section-title">Profile</h3>
                <div class="markdown-content" id="profile-content"></div>
            </div>
        </section>
    </main>

    <!-- 공통 푸터 -->
    <footer>
        <p>&copy; 2024 Your Name. All rights reserved.</p>
    </footer>

    <script src="profile.js"></script>
</body>
</html>
```

### CSS (`profile.css`)
Profile 페이지의 CSS입니다. 공통 스타일을 포함한 후, 각 섹션과 요소들의 스타일을 정의합니다.

```css
/* 공통 스타일을 사용하기 위해 common.css 포함 */
@import url('../common/css/common.css');

/* FontAwesome 사용을 위해 */
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css');

/* 공통 섹션 스타일 */
.section {
    padding: 50px 0;
    background: #f9f9f9; /* 기본 배경 색상 */
    text-align: center; /* 글자 가운데 정렬 */
}

.section .container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 섹션에 그림자 추가 */
    background: #fff; /* 섹션 배경 색상 */
    border-radius: 10px; /* 모서리를 둥글게 */
    padding: 20px;
}

.section-title {
    font-size: 2em;
    margin-bottom: 20px;
    color: #333; /* 제목 색상 */
    border-bottom: 2px solid #eee; /* 제목 아래에 구분선 */
    padding-bottom: 10px;
}

/* Markdown 콘텐츠 스타일 */
.markdown-content h4.markdown-header {
    font-weight: bold;
    margin-top: 20px;
    color: #444; /* 헤더 색상 */
}

.markdown-content ul {
    list-style: disc;
    padding-left: 20px;
    margin-bottom: 20px;
    text-align: left; /* 리스트 아이템은 왼쪽 정렬 */
}

.markdown-content li.markdown-list {
    margin-bottom: 10px;
}

.markdown-content a.markdown-link {
    color: #004080;
    text-decoration: none;
    transition: color 0.3s ease, transform 0.3s ease;
}

.markdown-content a.markdown-link:hover {
    color: #007BFF;
    transform: scale(1.1);
    text-decoration: underline;
}

.markdown-content strong.markdown-bold {
    font-weight: bold;
}

.markdown-content em.markdown-italic {
    font-style: italic;
}

.markdown-content p.markdown-paragraph {
    margin-bottom: 15px;
}

/* Profile Section 스타일 */
.section#profile {
    background: linear-gradient(to right, #f0f8ff, #e0f7fa);
}

.section#profile .profile-card {
    padding: 20px;
    background: #f9f9f9;
    border: 1px solid #ddd;
    border-radius: 5px;
    margin-bottom: 20px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.section#profile .profile-links {
    display: flex;
    justify-content: center;
    gap: 15px;
    margin-top: 10px;
}

.profile-link {
    display: flex;
    align-items: center;
    text-decoration: none;
    color: #004080;
    font-size: 1.1em;
    transition: color 0.3s ease, transform 0.3s ease;
}

.profile-link i {
    margin-right: 5px;
}

.profile-link:hover {
    color: #007BFF;
    transform: scale(1.1);
    text-decoration: underline;
}
```

### JavaScript (`profile.js`)
Profile 페이지의 JavaScript입니다. Markdown 파일을 비동기적으로 읽어와서 HTML로 변환한 후 페이지에 삽입합니다.

```javascript
// profile.js

// Markdown을 HTML로 변환하는 함수
function markdownToHtml(markdown) {
  // 제목 변환
  markdown = markdown.replace(/^### (.*$)/gim, '<h4 class="markdown-header">$1</h4>');
  markdown = markdown.replace(/^## (.*$)/gim, '<h3 class="markdown-header">$1</h3>');
  markdown = markdown.replace(/^# (.*$)/gim, '<h2 class="markdown-header">$1</h2>');

  // 리스트 변환
  markdown = markdown.replace(/^\* (.*$)/gim, '<li class="markdown-list">$1</li>');
  markdown = markdown.replace(/^\- (.*$)/gim, '<li class="markdown-list">$1</li>');
  markdown = markdown.replace(/^(\d+)\. (.*$)/gim, '<li class="markdown-list">$2</li>');

  // 링크 변환
  markdown = markdown.replace(/\[([^\[]+)\]\(([^\)]+)\)/gim, '<a class="markdown-link" href="$2">$1</a>');

  // 굵은 글씨 변환
  markdown = markdown.replace(/\*\*(.*)\*\*/gim, '<strong class="markdown-bold">$1</strong>');
  markdown = markdown.replace(/\*(.*)\*/gim, '<em class="markdown-italic">$1</em>');

  // 단락 변환
  markdown = markdown.replace(/^\s*(.*)/gm, '<p class="markdown-paragraph">$1</p>');

  return markdown.trim();
}

// Markdown 파일을 비동기적으로 읽어오는 함수
async function fetchMarkdown(file) {
  const response = await fetch(file);
  const markdown = await response.text();
  return markdownToHtml(markdown);
}

// 프로필 섹션을 별도로 생성하는 함수
function createProfileSection(markdown) {
  const profileHtml = markdownToHtml(markdown);
  const links = profileHtml.match(/<a class="markdown-link" href="([^"]+)">([^<]+)<\/a>/g);
  const linksHtml = links ? links.map(link => {
    const url = link.match(/href="([^"]+)"/)[1];
    const text = link.match(/">([^<]+)<\/a>/)[1];
    let icon;
    if (text.toLowerCase().includes('linkedin')) {
      icon = '<i class="fab fa-linkedin"></i>';
    } else if (text.toLowerCase().includes('github')) {
      icon = '<i class="fab fa-github"></i>';
    } else if (text.toLowerCase().includes('twitter')) {
      icon = '<i class="fab fa-twitter"></i>';
    } else {
      icon = '<i class="fas fa-link"></i>';
    }
    return `<a class="profile-link" href="${url}">${icon} ${text}</a>`;
  }).join(' ') : '';

  const description = profileHtml.replace(/<a class="markdown-link"[^>]*>[^<]*<\/a>/g, '');

  return `
    <div class="profile-card">
      <div class="markdown-content">
        ${description}
      </div>
      <div class="profile-links">
        ${linksHtml}
      </div>
    </div>
  `;
}

// 섹션을 동적으로 생성하는 함수
function createSections(markdown) {
  const sections = markdown.split(/^## /gm).slice(1);
  sections.forEach(section => {
    const lines = section.split('\n');
    const sectionTitle = lines[0].trim();
    const sectionId = sectionTitle.toLowerCase().replace(/\s+/g, '');
    const sectionContent = lines.slice(1).join('\n').trim();

    let htmlContent;
    if (sectionId === 'profile') {


      htmlContent = createProfileSection(sectionContent);
    } else {
      htmlContent = markdownToHtml(sectionContent);
    }

    const sectionHtml = `
      <section id="${sectionId}" class="section">
        <div class="container">
          <h3 class="section-title">${sectionTitle}</h3>
          <div class="markdown-content">
            ${htmlContent}
          </div>
        </div>
      </section>
    `;

    document.getElementById('profile-content').innerHTML += sectionHtml;
  });
}

// Markdown 파일을 읽어와서 페이지에 삽입하는 함수
async function loadMarkdown() {
  const response = await fetch('markdown/profile.md');
  const markdown = await response.text();

  // 섹션 생성
  createSections(markdown);
}

// DOMContentLoaded 이벤트가 발생하면 loadMarkdown 함수 호출
document.addEventListener('DOMContentLoaded', () => {
  loadMarkdown();
});
```

### Markdown 파일 예시 (`profile.md`)
```markdown
## Profile
### John Doe
- LinkedIn: [linkedin.com/in/johndoe](https://www.linkedin.com/in/johndoe)
- GitHub: [github.com/johndoe](https://github.com/johndoe)

### Bio
John Doe is a software engineer with over 10 years of experience...

## Experience
### Senior Developer at XYZ Company
*2020-2024*

- Description of responsibilities and achievements.
- Description of responsibilities and achievements.
- Description of responsibilities and achievements.

## Education
### Bachelor's Degree in Computer Science, University A
*2008-2012*

- Summary of the degree and key learnings.
- Summary of the degree and key learnings.
- Summary of the degree and key learnings.

## Projects
### Project 1
Description of the project, technologies used, and outcomes.
[GitHub](https://github.com/username/project1)
[Live Demo](https://username.github.io/project1)

## Skills
- HTML
- CSS
- JavaScript
- React
- Node.js

## Extra Activities
### Volunteer Web Developer
*Organization XYZ*

- Description of activities and impact.
- Description of activities and impact.
- Description of activities and impact.
```

이 코드는 `profile.md` 파일을 읽어와서 HTML로 변환한 후, Profile 페이지에 동적으로 삽입합니다. 각 섹션은 Markdown 파일에서 정의된 내용을 기반으로 렌더링됩니다.

반응형