From 053d02e1d4b5278d91a57f6de053cf4d026ba96e Mon Sep 17 00:00:00 2001 From: yunseeo Date: Thu, 8 Feb 2024 01:18:04 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=EB=AA=A8=EB=8B=AC=20=EA=B8=B0=EC=B4=88?= =?UTF-8?q?=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/component/Section/NewsItem.js | 15 +++ src/index.js | 155 ++---------------------------- src/modal/Modal.js | 52 ++++++++++ src/styles/index.css | 29 ++++++ 4 files changed, 104 insertions(+), 147 deletions(-) create mode 100644 src/modal/Modal.js diff --git a/src/component/Section/NewsItem.js b/src/component/Section/NewsItem.js index 7ed2433..49485e5 100644 --- a/src/component/Section/NewsItem.js +++ b/src/component/Section/NewsItem.js @@ -2,6 +2,7 @@ import Image from "./Image"; import Title from "./Title"; import Content from "./Content"; import AuthorDate from "./AuthorDate"; +import Modal from "../../modal/Modal"; class NewsItem { constructor(article, index) { @@ -21,6 +22,20 @@ class NewsItem { const authorDateComponent = new AuthorDate(article.author, article.publishedAt); this.element.appendChild(authorDateComponent.getElement()); + + this.element.addEventListener("click", this.handleArticleClick.bind(this)); + } + + handleArticleClick() { + const existingData = JSON.parse(localStorage.getItem('savedData')); + const modal = new Modal(); + if (existingData) { + // 기존 데이터가 있을 경우, 모달에 데이터를 채워 넣습니다. + modal.titleInput.value = existingData.title || ""; + modal.contentInput.value = existingData.content || ""; + } + this.element.appendChild(modal.modalElement); + modal.openModal(); } getElement() { diff --git a/src/index.js b/src/index.js index f63a696..a400ad0 100644 --- a/src/index.js +++ b/src/index.js @@ -1,144 +1,5 @@ import "./styles"; require("dotenv").config(); -//import TAP_NAME from "./assets/TAB_NAME"; - -/*class App { - constructor() { - this.apiKey = process.env.API_KEY || '40a4a566f0eb4cb5aa724df7ddc58ad7'; - this.selectedTap = null; - - const appElement = document.getElementById("app"); - - const headerElement = document.createElement("header"); - headerElement.innerHTML = "

LINKHU-news

"; - appElement.appendChild(headerElement); - - const navElement = document.createElement("nav"); - const navListElement = document.createElement("ul"); - - TAP_NAME.forEach((tap) => { - const tapItem = document.createElement("li"); - tapItem.textContent = tap.ko; - tapItem.dataset.tap = tap.en; - tapItem.addEventListener("click", this.handleTapClick.bind(this)); - - const underline = document.createElement('div'); - underline.classList.add('underline'); - tapItem.appendChild(underline); - - navListElement.appendChild(tapItem); - - if (tap.en === 'all') { - tapItem.classList.add('active'); - underline.style.width = '100%'; - } - }); - - navElement.appendChild(navListElement); - appElement.appendChild(navElement); - - this.sectionElement = document.createElement("section"); - appElement.appendChild(this.sectionElement); - - this.fetchData(); - } - - async fetchData() { - try { - let apiUrl; - - if (this.selectedTap && this.selectedTap !== "all") { - apiUrl = `http://newsapi.org/v2/top-headlines?country=kr&category=${this.selectedTap}&apiKey=${this.apiKey}`; - } else { - apiUrl = `http://newsapi.org/v2/top-headlines?country=kr&apiKey=${this.apiKey}` - } - - const response = await fetch(apiUrl); - - if (!response.ok) { - throw new Error(`Failed to fetch data. Status: ${response.status}`); - } - - const data = await response.json(); - console.log("API Response:", data); - this.displayData(data); - - } catch (error) { - console.error("Error fetching data:", error.message); - } - } - - displayData(data) { - this.sectionElement.innerHTML = ""; - - const articles = data.articles; - if (articles && articles.length > 0) { - - const shuffledArticles = this.shuffleArray(articles).slice(0, 2); - - shuffledArticles.forEach((article, index) => { - const articleContainer = document.createElement("div"); - articleContainer.id = `article-${index+1}`; - - - if (article.urlToImage) { - const imageElement = document.createElement("img"); - imageElement.src = article.urlToImage; - const imageAltText = article.title ? article.title : "Article Image"; - imageElement.alt = imageAltText; - articleContainer.appendChild(imageElement); - } - - const titleElement = document.createElement("h2"); - titleElement.textContent = article.title; - articleContainer.appendChild(titleElement); - - const contentElement = document.createElement("p"); - contentElement.textContent = article.description; - articleContainer.appendChild(contentElement); - - const authorDateElement = document.createElement("p"); - authorDateElement.innerHTML = `Author: ${article.author || 'Unknown'} | Date: ${new Date(article.publishedAt).toLocaleDateString()}`; - articleContainer.appendChild(authorDateElement); - - this.sectionElement.appendChild(articleContainer); - }); - } else { - - const noDataElement = document.createElement("p"); - noDataElement.textContent = "No articles available for this category."; - this.sectionElement.appendChild(noDataElement); - } - } - - - handleTapClick(event) { - this.selectedTap = event.target.dataset.tap; - console.log(`Selected Tap: ${this.selectedTap}`); - - const navItems = document.querySelectorAll('nav li'); - navItems.forEach(item => item.classList.remove('active')); - - event.target.classList.add('active'); - - this.fetchData(); - - const activeItem = event.target; - const underline = activeItem.querySelector('.underline'); - underline.style.width = '100%'; - } - - shuffleArray(array) { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } - return array; - } -} - -const app = new App();*/ - import Header from "./component/Header"; import TabList from "./component/Tabs/TabList"; @@ -146,11 +7,11 @@ import NewsList from "./component/Section/NewsList"; class App { constructor() { - this.apiKey = process.env.API_KEY || '40a4a566f0eb4cb5aa724df7ddc58ad7'; + this.apiKey = process.env.API_KEY || '40a4a566f0eb4cb5aa724df7ddc58ad7'; //process.env.API_KEY가 정의 안되어 있으면 '40a4~'어쩌고를 사용해라. this.selectedTap = null; this.header = new Header(); - this.tabList = new TabList(this.fetchData.bind(this)); + this.tabList = new TabList(this.fetchData.bind(this)); //this는 app을 가르키도록 bind. 고정. this.newsList = new NewsList(); const appElement = document.getElementById("app"); @@ -158,28 +19,28 @@ class App { appElement.appendChild(this.tabList.getElement()); appElement.appendChild(this.newsList.getElement()); - this.fetchData(); + this.fetchData(); //페이지 처음 혹은 새로고침 시에만 실행됨. 어떤 탭도 선택 X인 상태. } - async fetchData(selectedTap) { + async fetchData(selectedTap) { try { let apiUrl; if (selectedTap && selectedTap !== "all") { apiUrl = `http://newsapi.org/v2/top-headlines?country=kr&category=${selectedTap}&apiKey=${this.apiKey}`; - } else { + } else { //selectedTap이 정의되지 않은 상태. undefined. apiUrl = `http://newsapi.org/v2/top-headlines?country=kr&apiKey=${this.apiKey}`; } - const response = await fetch(apiUrl); + const response = await fetch(apiUrl); //promise객체 반환 fetch니까. if (!response.ok) { throw new Error(`Failed to fetch data. Status: ${response.status}`); } - const data = await response.json(); + const data = await response.json(); //await 제거 시, 아직 response.json() 프로미스 다 json으로 반환할 때까지 완료 안했는데 다음줄 코드 실행해버리므로 화면에 에러메시지 뜨는 거임. console.log("API Response:", data); - this.newsList.update(data.articles); + this.newsList.update(data.articles); //NewsList.js에 있는 update메서드 사용. } catch (error) { console.error("Error fetching data:", error.message); diff --git a/src/modal/Modal.js b/src/modal/Modal.js new file mode 100644 index 0000000..252b890 --- /dev/null +++ b/src/modal/Modal.js @@ -0,0 +1,52 @@ +class Modal { + constructor() { + this.modalElement = document.createElement("div"); + this.modalElement.className = "modal"; + + this.modalTitle = document.createElement("div"); + this.modalTitle.textContent = "의견 남기기"; + this.modalElement.appendChild(this.modalTitle); + + this.titleInput = document.createElement("input"); + this.titleInput.placeholder = "제목"; + this.modalElement.appendChild(this.titleInput); + + this.contentInput = document.createElement("textarea"); + this.contentInput.placeholder = "내용"; + this.modalElement.appendChild(this.contentInput); + + this.saveButton = document.createElement("button"); + this.saveButton.textContent = "저장"; + this.saveButton.addEventListener("click", this.handleSave.bind(this)); + this.modalElement.appendChild(this.saveButton); + } + + handleSave() { + const title = this.titleInput.value; + const content = this.contentInput.value; + + if (title && content) { + localStorage.setItem('savedData', JSON.stringify({ title, content })); + this.closeModal(); + } else { + //alert("제목과 내용을 입력해주세요."); + this.closeModal(); + } + } + + openModal() { + const sectionElement = document.querySelector("section"); + sectionElement.appendChild(this.modalElement); + this.modalElement.style.display = "block"; + } + + closeModal() { + const sectionElement = document.querySelector("section"); + sectionElement.removeChild(this.modalElement); + this.modalElement.style.display = "none"; + this.titleInput.value = ""; + this.contentInput.value = ""; + } +} + +export default Modal; \ No newline at end of file diff --git a/src/styles/index.css b/src/styles/index.css index 3e548f4..5f88a9d 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -153,4 +153,33 @@ p { .active::after{ text-decoration: underline; +} + +/* modal.css */ +.modal { + display: none; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: white; + padding: 20px; + border: 1px solid #ccc; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + z-index: 1000; +} + +.modal input, +.modal textarea, +.modal button { + margin-bottom: 10px; + width: 100%; +} + +.modal button { + background-color: #4caf50; + color: white; + border: none; + padding: 10px; + cursor: pointer; } \ No newline at end of file From 875670075d43b7413412e3542c1193632fc26993 Mon Sep 17 00:00:00 2001 From: yunseeo Date: Thu, 8 Feb 2024 15:04:13 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=EC=88=98=EC=A0=95=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/component/Section/NewsItem.js | 8 +++-- src/modal/ExistingModal.js | 56 +++++++++++++++++++++++++++++++ src/styles/index.css | 32 +++++++++++++----- 3 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 src/modal/ExistingModal.js diff --git a/src/component/Section/NewsItem.js b/src/component/Section/NewsItem.js index 49485e5..a29d659 100644 --- a/src/component/Section/NewsItem.js +++ b/src/component/Section/NewsItem.js @@ -3,6 +3,7 @@ import Title from "./Title"; import Content from "./Content"; import AuthorDate from "./AuthorDate"; import Modal from "../../modal/Modal"; +import ExistingModal from "../../modal/ExistingModal"; class NewsItem { constructor(article, index) { @@ -28,12 +29,13 @@ class NewsItem { handleArticleClick() { const existingData = JSON.parse(localStorage.getItem('savedData')); - const modal = new Modal(); - if (existingData) { + //const modal = new Modal(); + const modal = existingData ? new ExistingModal(existingData) : new Modal(); + /*if (existingData) { // 기존 데이터가 있을 경우, 모달에 데이터를 채워 넣습니다. modal.titleInput.value = existingData.title || ""; modal.contentInput.value = existingData.content || ""; - } + }*/ this.element.appendChild(modal.modalElement); modal.openModal(); } diff --git a/src/modal/ExistingModal.js b/src/modal/ExistingModal.js new file mode 100644 index 0000000..ad0f863 --- /dev/null +++ b/src/modal/ExistingModal.js @@ -0,0 +1,56 @@ +import Modal from "./Modal"; + +class ExistingModal extends Modal { + constructor(existingData) { + super(); + + if (existingData) { + this.titleInput.value = existingData.title || ""; + this.contentInput.value = existingData.content || ""; + + /*const editButton = document.createElement("button"); + editButton.textContent = "수정"; + editButton.addEventListener("click", () => { + this.handleEdit(); // 수정 기능을 호출하면서 기존 데이터를 전달합니다. + }); + this.modalElement.appendChild(editButton);*/ + + this.saveButton.textContent = "수정"; + + const deleteButton = document.createElement("button"); + deleteButton.textContent = "삭제"; + deleteButton.addEventListener("click", () => { + this.handleDelete(); // 삭제 기능을 호출하면서 기존 데이터를 전달합니다. + }); + this.modalElement.appendChild(deleteButton); + } + } + + handleSave() { + // 수정 기능 구현 + const updatedTitle = this.titleInput.value; + const updatedContent = this.contentInput.value; + + // 로컬 스토리지에서 기존 데이터를 가져와 업데이트합니다. + const updatedData = { + title: updatedTitle, + content: updatedContent + }; + + // 기존 데이터를 업데이트한 후 로컬 스토리지에 저장합니다. + localStorage.setItem('savedData', JSON.stringify(updatedData)); + + // 모달을 닫습니다. + this.closeModal(); + } + + handleDelete() { + // 삭제 기능 구현 + localStorage.removeItem('savedData'); + + // 모달을 닫습니다. + this.closeModal(); + } +} + +export default ExistingModal; \ No newline at end of file diff --git a/src/styles/index.css b/src/styles/index.css index 5f88a9d..2ac4e48 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -155,7 +155,6 @@ p { text-decoration: underline; } -/* modal.css */ .modal { display: none; position: fixed; @@ -163,7 +162,7 @@ p { left: 50%; transform: translate(-50%, -50%); background-color: white; - padding: 20px; + padding: 30px; border: 1px solid #ccc; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); z-index: 1000; @@ -172,14 +171,31 @@ p { .modal input, .modal textarea, .modal button { - margin-bottom: 10px; + margin-bottom: 15px; width: 100%; + padding: 10px; + box-sizing: border-box; +} + +.modal input[type="text"] { + height: 40px; +} + +.modal textarea { + height: 120px; } .modal button { - background-color: #4caf50; - color: white; - border: none; - padding: 10px; - cursor: pointer; + font-size: 14px; + width: 48%; + display: inline-block; + vertical-align: top; +} + +.modal button + button { + margin-left: 4%; +} + +.modal .buttons-container { + text-align: center; } \ No newline at end of file From 2c44ce5ef2cc3db588da15a6405354ecdd1faa46 Mon Sep 17 00:00:00 2001 From: yunseeo Date: Fri, 9 Feb 2024 00:12:53 +0900 Subject: [PATCH 3/4] =?UTF-8?q?css=20=EC=88=98=EC=A0=95=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/component/Section/NewsItem.js | 6 --- src/modal/ExistingModal.js | 16 ++---- src/modal/Modal.js | 29 ++++++++--- src/styles/index.css | 82 ++++++++++++++++++++++++------- 4 files changed, 89 insertions(+), 44 deletions(-) diff --git a/src/component/Section/NewsItem.js b/src/component/Section/NewsItem.js index a29d659..a69c578 100644 --- a/src/component/Section/NewsItem.js +++ b/src/component/Section/NewsItem.js @@ -29,13 +29,7 @@ class NewsItem { handleArticleClick() { const existingData = JSON.parse(localStorage.getItem('savedData')); - //const modal = new Modal(); const modal = existingData ? new ExistingModal(existingData) : new Modal(); - /*if (existingData) { - // 기존 데이터가 있을 경우, 모달에 데이터를 채워 넣습니다. - modal.titleInput.value = existingData.title || ""; - modal.contentInput.value = existingData.content || ""; - }*/ this.element.appendChild(modal.modalElement); modal.openModal(); } diff --git a/src/modal/ExistingModal.js b/src/modal/ExistingModal.js index ad0f863..39f1ef4 100644 --- a/src/modal/ExistingModal.js +++ b/src/modal/ExistingModal.js @@ -8,47 +8,37 @@ class ExistingModal extends Modal { this.titleInput.value = existingData.title || ""; this.contentInput.value = existingData.content || ""; - /*const editButton = document.createElement("button"); - editButton.textContent = "수정"; - editButton.addEventListener("click", () => { - this.handleEdit(); // 수정 기능을 호출하면서 기존 데이터를 전달합니다. - }); - this.modalElement.appendChild(editButton);*/ + this.modalTitle.textContent = "의견 수정하기" this.saveButton.textContent = "수정"; const deleteButton = document.createElement("button"); deleteButton.textContent = "삭제"; + deleteButton.classList.add("delete-button"); deleteButton.addEventListener("click", () => { - this.handleDelete(); // 삭제 기능을 호출하면서 기존 데이터를 전달합니다. + this.handleDelete(); }); this.modalElement.appendChild(deleteButton); } } handleSave() { - // 수정 기능 구현 const updatedTitle = this.titleInput.value; const updatedContent = this.contentInput.value; - // 로컬 스토리지에서 기존 데이터를 가져와 업데이트합니다. const updatedData = { title: updatedTitle, content: updatedContent }; - // 기존 데이터를 업데이트한 후 로컬 스토리지에 저장합니다. localStorage.setItem('savedData', JSON.stringify(updatedData)); - // 모달을 닫습니다. this.closeModal(); } handleDelete() { - // 삭제 기능 구현 localStorage.removeItem('savedData'); - // 모달을 닫습니다. this.closeModal(); } } diff --git a/src/modal/Modal.js b/src/modal/Modal.js index 252b890..84dec9d 100644 --- a/src/modal/Modal.js +++ b/src/modal/Modal.js @@ -5,20 +5,36 @@ class Modal { this.modalTitle = document.createElement("div"); this.modalTitle.textContent = "의견 남기기"; + this.modalTitle.classList.add("modalTitle"); this.modalElement.appendChild(this.modalTitle); + this.titleInputLabel = document.createElement("div"); + this.titleInputLabel.textContent = "제목"; + this.titleInputLabel.classList.add("modalInputLabel"); + this.modalElement.appendChild(this.titleInputLabel); + this.titleInput = document.createElement("input"); - this.titleInput.placeholder = "제목"; + this.titleInput.classList.add("modalTitleInput"); this.modalElement.appendChild(this.titleInput); + this.contentInputLabel = document.createElement("div"); + this.contentInputLabel.textContent = "내용"; + this.contentInputLabel.classList.add("modalInputLabel"); + this.modalElement.appendChild(this.contentInputLabel); + this.contentInput = document.createElement("textarea"); - this.contentInput.placeholder = "내용"; this.modalElement.appendChild(this.contentInput); this.saveButton = document.createElement("button"); this.saveButton.textContent = "저장"; this.saveButton.addEventListener("click", this.handleSave.bind(this)); this.modalElement.appendChild(this.saveButton); + + this.closeButton = document.createElement("div"); + this.closeButton.textContent = 'x'; + this.closeButton.classList.add("modalCloseButton"); + this.closeButton.addEventListener("click", this.closeModal.bind(this)); + this.modalElement.appendChild(this.closeButton); } handleSave() { @@ -29,7 +45,6 @@ class Modal { localStorage.setItem('savedData', JSON.stringify({ title, content })); this.closeModal(); } else { - //alert("제목과 내용을 입력해주세요."); this.closeModal(); } } @@ -38,15 +53,15 @@ class Modal { const sectionElement = document.querySelector("section"); sectionElement.appendChild(this.modalElement); this.modalElement.style.display = "block"; - } - - closeModal() { + } + + closeModal() { const sectionElement = document.querySelector("section"); sectionElement.removeChild(this.modalElement); this.modalElement.style.display = "none"; this.titleInput.value = ""; this.contentInput.value = ""; - } + } } export default Modal; \ No newline at end of file diff --git a/src/styles/index.css b/src/styles/index.css index 2ac4e48..8a03b57 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -44,12 +44,11 @@ header { nav { background-color: #FFF; - /* 추가된 스타일: 가로 정렬을 위한 Flexbox 사용 */ width: 480px; height: 40px; flex-shrink: 0; display: flex; - align-items: center; /* 세로 중앙 정렬 */ + align-items: center; justify-content: space-between; padding-left: 10px; @@ -66,21 +65,19 @@ nav ul { } nav li { - /*margin-right: 10px; 이러면 마지막 항목도 띄어지니까.*/ cursor: pointer; font-family: Inter; font-size: 20px; font-weight: 400; line-height: normal; letter-spacing: 2px; - /*width: 39.731px;*/ height: 24px; position: relative; } nav li:not(:last-child) { - margin-right: 13px; /* 마지막 요소 이외의 모든 요소에 오른쪽 여백 추가 */ + margin-right: 13px; } nav li::after { @@ -90,13 +87,13 @@ nav li::after { left: 0; width: 0; height: 2px; - background-color: transparent; /* 초기에 투명한 색상 */ - transition: width 0.3s ease; /* 너비 변경에 대한 전환 효과 설정 */ + background-color: transparent; + transition: width 0.3s ease; } nav li.active::after { - width: 100%; /* 클릭된 항목에 대한 밑줄 너비 100%로 변경 */ - background-color: #466AEA; /* 클릭된 항목에 대한 밑줄 색상 변경 */ + width: 100%; + background-color: #466AEA; } nav li.active { @@ -105,7 +102,7 @@ nav li.active { } nav li:hover::before { - background-color: #466AEA; /* 호버 시에 회색 밑줄을 파란색으로 변경 */ + background-color: #466AEA; } img { @@ -134,16 +131,16 @@ section > div > h2 { } section > div > p { - text-align: left; /* 기사 내용을 왼쪽 정렬로 유지 */ + text-align: left; } section > div > p strong { - display: inline-block; /* strong 태그를 블록 요소로 변경하여 왼쪽 정렬 적용 */ - text-align: left; /* strong 태그 내용을 왼쪽 정렬로 유지 */ + display: inline-block; + text-align: left; } section > div > p > strong::after { - content: ' | '; /* 각 strong 태그 뒤에 구분을 위한 구분자 추가 */ + content: ' | '; } p { @@ -160,14 +157,43 @@ p { position: fixed; top: 50%; left: 50%; + width: 400px; + height: 550px; transform: translate(-50%, -50%); background-color: white; padding: 30px; border: 1px solid #ccc; + border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); z-index: 1000; } +.modalTitle { + font-weight: bold; + text-align: left; + margin-bottom: 15px; +} + +.modalInputLabel { + text-align: left; + font-weight: bold; + margin-bottom: 5px; +} + +.modalTitleInput { + background-color: #ddd; + border: none; + border-radius: 10px; +} + +.modal textarea { + background-color: #ddd; + border: none; + border-radius: 10px; + width: 300px; + height: 300px; +} + .modal input, .modal textarea, .modal button { @@ -181,15 +207,16 @@ p { height: 40px; } -.modal textarea { - height: 120px; -} - .modal button { font-size: 14px; width: 48%; display: inline-block; vertical-align: top; + margin-right: 4%; + background-color: #466AEA; + border: none; + color: white; + border-radius: 10px; } .modal button + button { @@ -198,4 +225,23 @@ p { .modal .buttons-container { text-align: center; + margin-top: 15px; +} + +.modal button:last-child { + margin-right: 0; +} + +.modal .delete-button { + background-color: #e26767; +} + +.modalCloseButton { + position: absolute; + top: 10px; + right: 10px; + cursor: pointer; + font-size: 18px; + font-weight: bold; + color: #333; } \ No newline at end of file From fb4ac24212907270dce81ea163666adddb742332 Mon Sep 17 00:00:00 2001 From: yunseeo Date: Fri, 9 Feb 2024 01:15:19 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=EA=B0=81=20=EA=B8=B0=EC=82=AC=20=EA=B3=A0?= =?UTF-8?q?=EC=9C=A0=20=EB=AA=A8=EB=8B=AC=EC=B0=BD=20=EA=B0=96=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/component/Section/NewsItem.js | 11 +++++++---- src/modal/ExistingModal.js | 8 +++++--- src/modal/Modal.js | 14 ++++++++------ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/component/Section/NewsItem.js b/src/component/Section/NewsItem.js index a69c578..1865b30 100644 --- a/src/component/Section/NewsItem.js +++ b/src/component/Section/NewsItem.js @@ -24,12 +24,15 @@ class NewsItem { const authorDateComponent = new AuthorDate(article.author, article.publishedAt); this.element.appendChild(authorDateComponent.getElement()); - this.element.addEventListener("click", this.handleArticleClick.bind(this)); + this.element.addEventListener("click", () => this.handleArticleClick(article)); } - handleArticleClick() { - const existingData = JSON.parse(localStorage.getItem('savedData')); - const modal = existingData ? new ExistingModal(existingData) : new Modal(); + handleArticleClick(article) { + const existingData = JSON.parse(localStorage.getItem(`savedData-${article.title}`)) || {}; + const modal = Object.keys(existingData).length > 0 + ? new ExistingModal(existingData, `savedData-${article.title}`) + : new Modal(`savedData-${article.title}`, article); + this.element.appendChild(modal.modalElement); modal.openModal(); } diff --git a/src/modal/ExistingModal.js b/src/modal/ExistingModal.js index 39f1ef4..14d7153 100644 --- a/src/modal/ExistingModal.js +++ b/src/modal/ExistingModal.js @@ -1,9 +1,11 @@ import Modal from "./Modal"; class ExistingModal extends Modal { - constructor(existingData) { + constructor(existingData, storageKey) { super(); + this.storageKey = storageKey; + if (existingData) { this.titleInput.value = existingData.title || ""; this.contentInput.value = existingData.content || ""; @@ -31,13 +33,13 @@ class ExistingModal extends Modal { content: updatedContent }; - localStorage.setItem('savedData', JSON.stringify(updatedData)); + localStorage.setItem(this.storageKey, JSON.stringify(updatedData)); this.closeModal(); } handleDelete() { - localStorage.removeItem('savedData'); + localStorage.removeItem(this.storageKey); this.closeModal(); } diff --git a/src/modal/Modal.js b/src/modal/Modal.js index 84dec9d..aeb1366 100644 --- a/src/modal/Modal.js +++ b/src/modal/Modal.js @@ -1,5 +1,5 @@ class Modal { - constructor() { + constructor(storageKey, article) { this.modalElement = document.createElement("div"); this.modalElement.className = "modal"; @@ -9,7 +9,7 @@ class Modal { this.modalElement.appendChild(this.modalTitle); this.titleInputLabel = document.createElement("div"); - this.titleInputLabel.textContent = "제목"; + this.titleInputLabel.textContent = "제목"; this.titleInputLabel.classList.add("modalInputLabel"); this.modalElement.appendChild(this.titleInputLabel); @@ -18,7 +18,7 @@ class Modal { this.modalElement.appendChild(this.titleInput); this.contentInputLabel = document.createElement("div"); - this.contentInputLabel.textContent = "내용"; + this.contentInputLabel.textContent = "내용"; this.contentInputLabel.classList.add("modalInputLabel"); this.modalElement.appendChild(this.contentInputLabel); @@ -27,7 +27,7 @@ class Modal { this.saveButton = document.createElement("button"); this.saveButton.textContent = "저장"; - this.saveButton.addEventListener("click", this.handleSave.bind(this)); + this.saveButton.addEventListener("click", this.handleSave.bind(this, storageKey, article)); this.modalElement.appendChild(this.saveButton); this.closeButton = document.createElement("div"); @@ -37,12 +37,14 @@ class Modal { this.modalElement.appendChild(this.closeButton); } - handleSave() { + handleSave(storageKey, article) { const title = this.titleInput.value; const content = this.contentInput.value; if (title && content) { - localStorage.setItem('savedData', JSON.stringify({ title, content })); + const savedData = JSON.parse(localStorage.getItem(storageKey)) || {}; + const updatedData = { ...savedData, title, content }; + localStorage.setItem(storageKey, JSON.stringify(updatedData)); this.closeModal(); } else { this.closeModal();