| <!DOCTYPE html> | 
| <html lang="en"> | 
| <head> | 
| <meta charset="UTF-8" /> | 
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | 
| <meta http-equiv="X-UA-Compatible" content="ie=edge" /> | 
| <title>Board with Local Storage</title> | 
| <link | 
| href="https://fonts.googleapis.com/css?family=Jua&display=swap" | 
| rel="stylesheet" | 
| /> | 
| <style> | 
| * { | 
| box-sizing: border-box; | 
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, | 
| Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | 
| font-family: 'Jua', sans-serif; | 
| } | 
| body { | 
| padding: 0px; | 
| margin: 0px; | 
| display: flex; | 
| justify-content: center; | 
| align-items: center; | 
| flex-direction: column; | 
| width: 100%; | 
| height: 95vh; | 
| background-color: #f6f9fc; | 
| } | 
|  | 
| .main__container { | 
| height: 700px; | 
| padding-top: 10px; | 
| padding-bottom: 10px; | 
| } | 
|  | 
| .board__container, | 
| .contents__container, | 
| .editor__container { | 
| width: 700px; | 
| display: flex; | 
| justify-content: flex-start; | 
| align-items: center; | 
| flex-direction: column; | 
| background-color: #ffffff; | 
| } | 
|  | 
| .board__container { | 
| margin: 10px 0px 0px 0px; | 
| height: 220px; | 
| padding-top: 10px; | 
| padding-bottom: 10px; | 
| border-radius: 15px; | 
| box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1); | 
| position: relative; | 
| } | 
|  | 
| .contents__container { | 
| margin: 10px 0px; | 
| height: 220px; | 
| padding-top: 10px; | 
| padding-bottom: 10px; | 
| border-radius: 15px; | 
| box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1); | 
| } | 
|  | 
| .editor__container { | 
| margin: 10px 0px; | 
| height: 220px; | 
| padding-top: 10px; | 
| padding-bottom: 10px; | 
| border-radius: 15px; | 
| box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1); | 
| } | 
|  | 
| /* Board Lists */ | 
| .board { | 
| width: 600px; | 
| text-align: center; | 
| margin-bottom: 15px; | 
| } | 
|  | 
| .board__index-container { | 
| position: absolute; | 
| bottom: 10px; | 
| } | 
|  | 
| .board__index-link { | 
| all: unset; | 
| margin-right: 5px; | 
| } | 
|  | 
| .board__index-link:hover { | 
| cursor: pointer; | 
| color: blue; | 
| } | 
|  | 
| /* Contents */ | 
| .contents__titles { | 
| width: 600px; | 
| display: flex; | 
| justify-content: space-between; | 
| align-items: center; | 
| padding-bottom: 10px; | 
| border-bottom: 2px solid rgba(0, 0, 0, 0.08); | 
| margin-bottom: 20px; | 
| } | 
|  | 
| .contents__column { | 
| width: 200px; | 
| display: flex; | 
| justify-content: space-around; | 
| align-items: center; | 
| } | 
|  | 
| .contents__content { | 
| width: 600px; | 
| display: flex; | 
| justify-content: start; | 
| align-items: center; | 
| } | 
|  | 
| /* Editor */ | 
| .editor__form { | 
| width: 600px; | 
| display: flex; | 
| justify-content: center; | 
| align-items: center; | 
| flex-direction: column; | 
| } | 
|  | 
| input { | 
| all: unset; | 
| border-radius: 5px; | 
| border: 1px solid rgba(0, 0, 0, 0.5); | 
| } | 
|  | 
| .editor__title-input, | 
| .editor__content-input { | 
| width: 100%; | 
| padding: 5px 10px; | 
| margin-bottom: 10px; | 
| } | 
|  | 
| .editor__content-input { | 
| height: 100px; | 
| } | 
|  | 
| .editor__btn { | 
| all: unset; | 
| border: 1px solid rgba(0, 0, 0, 0.5); | 
| border-radius: 5px; | 
| padding: 5px 10px; | 
| } | 
|  | 
| button:active { | 
| transform: scale(0.93); | 
| } | 
| </style> | 
| </head> | 
| <body> | 
| <main class="main__container"> | 
| <div class="board__container"> | 
| <table class="board"> | 
| <thead class="board__table-head"> | 
| <tr class="board__titles"> | 
| <th class="board__column">번호</th> | 
| <th class="board__column">제목</th> | 
| <th class="board__column">작성자</th> | 
| <th class="board__column">작성일</th> | 
| <th class="board__column">조회</th> | 
| </tr> | 
| </thead> | 
| <tbody class="board__contents" id="board-body"></tbody> | 
| </table> | 
| <div class="board__index-container" id="index-container"></div> | 
| </div> | 
| <div class="contents__container"></div> | 
| <div class="editor__container"> | 
| <form action="#" class="editor__form" id="editor-form"> | 
| <input | 
| type="text" | 
| class="editor__title-input" | 
| id="editor-title-input" | 
| placeholder="제목" | 
| /> | 
| <input | 
| type="text" | 
| class="editor__content-input" | 
| id="editor-content-input" | 
| placeholder="내용" | 
| /> | 
| <button class="editor__btn" id="editor-submit-btn">작성 완료</button> | 
| </form> | 
| </div> | 
| </main> | 
| <script> | 
| const boardTableBody = document.querySelector('#board-body'); | 
|  | 
| const contentsContainer = document.querySelector('.contents__container'); | 
|  | 
| const editorForm = document.querySelector('#editor-form'); | 
| const titleInput = document.querySelector('#editor-title-input'); | 
| const contentInput = document.querySelector('#editor-content-input'); | 
|  | 
| const BOARDLIST_LS = 'boardLists'; | 
| const boardListsObj = []; | 
| let nums = 0; | 
| let author = 'David'; | 
| let date = new Date(); | 
| let views = Math.floor(Math.random() * 99) + 1; | 
|  | 
| function onTitleClick(e) { | 
| contentsContainer.textContent = ''; | 
| const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS)); | 
| const index = e.target.parentNode.id.replace(/[a-z|-]/gi, ''); | 
|  | 
| const contentsTitles = document.createElement('div'); | 
| contentsTitles.classList.add('contents__titles'); | 
|  | 
| const contentsColumnFirst = document.createElement('div'); | 
| contentsColumnFirst.classList.add('contents__column'); | 
|  | 
| const contentsTitle = document.createElement('div'); | 
| contentsTitle.classList.add('contents__title'); | 
| contentsTitle.textContent = lists[index].title; | 
|  | 
| // contents__titles > column >author, date, views | 
| const contentsColumnSecond = document.createElement('div'); | 
| contentsColumnSecond.classList.add('contents__column'); | 
|  | 
| const contentsAuthor = document.createElement('div'); | 
| contentsAuthor.classList.add('contents__author'); | 
| contentsAuthor.textContent = lists[index].author; | 
|  | 
| const contentsDate = document.createElement('div'); | 
| contentsDate.classList.add('contents__date'); | 
| contentsDate.textContent = lists[index].date; | 
|  | 
| const contentsViews = document.createElement('div'); | 
| contentsViews.classList.add('contents__views'); | 
| contentsViews.textContent = lists[index].views; | 
|  | 
| const contentsContent = document.createElement('div'); | 
| contentsContent.classList.add('contents__content'); | 
| contentsContent.textContent = lists[index].content; | 
|  | 
| contentsColumnFirst.appendChild(contentsTitle); | 
|  | 
| contentsColumnSecond.appendChild(contentsAuthor); | 
| contentsColumnSecond.appendChild(contentsDate); | 
| contentsColumnSecond.appendChild(contentsViews); | 
|  | 
| contentsTitles.appendChild(contentsColumnFirst); | 
| contentsTitles.appendChild(contentsColumnSecond); | 
|  | 
| contentsContainer.appendChild(contentsTitles); | 
| contentsContainer.appendChild(contentsContent); | 
| } | 
|  | 
| function assignIndex() { | 
| const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS)); | 
| if (!lists) { | 
| nums = 0; | 
| } else { | 
| nums = parseInt(lists[lists.length - 1].num) + 1; | 
| } | 
| } | 
|  | 
| function onEditorFormSubmit(e) { | 
| e.preventDefault(); | 
|  | 
| const title = titleInput.value; | 
| const content = contentInput.value; | 
|  | 
| const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS)); | 
| if (!lists) { | 
| const objArr = []; | 
| objArr.push({ | 
| num: `${nums++}`, | 
| title: `${title}`, | 
| author: `${author}`, | 
| date: `${date.getFullYear()}.${date.getMonth() + | 
| 1}.${date.getDate()}.`, | 
| views: `${views++}`, | 
| content: `${content}` | 
| }); | 
|  | 
| localStorage.setItem(BOARDLIST_LS, JSON.stringify(objArr)); | 
| } else { | 
| lists.push({ | 
| num: `${nums++}`, | 
| title: `${title}`, | 
| author: `${author}`, | 
| date: `${date.getFullYear()}.${date.getMonth() + | 
| 1}.${date.getDate()}.`, | 
| views: `${views++}`, | 
| content: `${content}` | 
| }); | 
|  | 
| localStorage.setItem(BOARDLIST_LS, JSON.stringify(lists)); | 
| } | 
|  | 
| titleInput.value = ''; | 
| contentInput.value = ''; | 
| titleInput.focus(); | 
| window.location.reload(); | 
| } | 
|  | 
| function showBoardLists() { | 
| const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS)); | 
|  | 
| lists.forEach((list, index) => { | 
| if (index < 5) { | 
| const tr = document.createElement('tr'); | 
| tr.classList.add('board__content'); | 
|  | 
| const tdNum = document.createElement('td'); | 
| tdNum.classList.add('board__content-column'); | 
| tdNum.textContent = list.num; | 
|  | 
| const aTitle = document.createElement('a'); | 
| aTitle.href = '#'; | 
| aTitle.id = `link-to-content${index}`; | 
|  | 
| const tdTitle = document.createElement('td'); | 
| tdTitle.classList.add('board__content-column'); | 
| tdTitle.textContent = list.title; | 
|  | 
| aTitle.appendChild(tdTitle); | 
|  | 
| const tdAuthor = document.createElement('td'); | 
| tdAuthor.classList.add('board__content-column'); | 
| tdAuthor.textContent = list.author; | 
|  | 
| const tdDate = document.createElement('td'); | 
| tdDate.classList.add('board__content-column'); | 
| tdDate.textContent = list.date; | 
|  | 
| const tdViews = document.createElement('td'); | 
| tdViews.classList.add('board__content-column'); | 
| tdViews.textContent = list.views; | 
|  | 
| tr.appendChild(tdNum); | 
| tr.appendChild(aTitle); | 
| tr.appendChild(tdAuthor); | 
| tr.appendChild(tdDate); | 
| tr.appendChild(tdViews); | 
|  | 
| boardTableBody.appendChild(tr); | 
| const linkToContent = document.querySelector( | 
| `#link-to-content${index}` | 
| ); | 
| linkToContent.addEventListener('click', onTitleClick); | 
| } else if (index === 5) { | 
| const boardIndexMax = Math.ceil(lists.length / 5); | 
| for (let i = 0; i < boardIndexMax; i++) { | 
| const indexContainer = document.querySelector('#index-container'); | 
|  | 
| const aIndex = document.createElement('a'); | 
| aIndex.classList.add('board__index-link'); | 
|  | 
| const spanIndexText = document.createElement('span'); | 
| spanIndexText.classList.add('board__index'); | 
| spanIndexText.textContent = i + 1; | 
|  | 
| aIndex.appendChild(spanIndexText); | 
| indexContainer.appendChild(aIndex); | 
|  | 
| aIndex.addEventListener('click', () => { | 
| showBoardListsNewPage(i); | 
| }); | 
| } | 
| } | 
| }); | 
| } | 
|  | 
| function showBoardListsNewPage(pageIndex) { | 
| boardTableBody.textContent = ''; | 
| const lists = JSON.parse(localStorage.getItem(BOARDLIST_LS)); | 
| const limitPage = pageIndex * 5; | 
|  | 
| lists.forEach((list, index) => { | 
| if (index >= limitPage && index < limitPage + 5) { | 
| const tr = document.createElement('tr'); | 
| tr.classList.add('board__content'); | 
|  | 
| const tdNum = document.createElement('td'); | 
| tdNum.classList.add('board__content-column'); | 
| tdNum.textContent = list.num; | 
|  | 
| const aTitle = document.createElement('a'); | 
| aTitle.href = '#'; | 
| aTitle.id = `link-to-content${index}`; | 
|  | 
| const tdTitle = document.createElement('td'); | 
| tdTitle.classList.add('board__content-column'); | 
| tdTitle.textContent = list.title; | 
|  | 
| aTitle.appendChild(tdTitle); | 
|  | 
| const tdAuthor = document.createElement('td'); | 
| tdAuthor.classList.add('board__content-column'); | 
| tdAuthor.textContent = list.author; | 
|  | 
| const tdDate = document.createElement('td'); | 
| tdDate.classList.add('board__content-column'); | 
| tdDate.textContent = list.date; | 
|  | 
| const tdViews = document.createElement('td'); | 
| tdViews.classList.add('board__content-column'); | 
| tdViews.textContent = list.views; | 
|  | 
| tr.appendChild(tdNum); | 
| tr.appendChild(aTitle); | 
| tr.appendChild(tdAuthor); | 
| tr.appendChild(tdDate); | 
| tr.appendChild(tdViews); | 
|  | 
| boardTableBody.appendChild(tr); | 
| const linkToContent = document.querySelector( | 
| `#link-to-content${index}` | 
| ); | 
| linkToContent.addEventListener('click', onTitleClick); | 
| } | 
| }); | 
| } | 
|  | 
| editorForm.addEventListener('submit', onEditorFormSubmit); | 
|  | 
| if (boardTableBody) { | 
| assignIndex(); | 
| showBoardLists(); | 
| } | 
| </script> | 
| </body> | 
| </html> |