├── README.md ├── darkmode.js ├── index.html ├── script.js └── style.css /README.md: -------------------------------------------------------------------------------- 1 | # dicoding-bookshelf-apps 2 | Submission dicoding kelas Belajar Membuat Front-End Web untuk Pemula https://www.dicoding.com/academies/315
3 | Starter project dari Dicoding
4 | Demo https://andrarstn.github.io/dicoding-bookshelf-apps/index.html 5 | -------------------------------------------------------------------------------- /darkmode.js: -------------------------------------------------------------------------------- 1 | const displayLocalStorageKey = "DARK_MODE" 2 | 3 | const darkButton = document.querySelector("#darkButton") 4 | 5 | if (localStorage.getItem(displayLocalStorageKey) === null) { 6 | localStorage.setItem(displayLocalStorageKey, 'light'); 7 | }else{ 8 | if (localStorage.getItem(displayLocalStorageKey) == 'dark') { 9 | toDark() 10 | } 11 | } 12 | 13 | darkButton.addEventListener("click", function(){ 14 | toDark() 15 | switchDisplay() 16 | }) 17 | 18 | function toDark() { 19 | darkButton.classList.toggle("light-button") 20 | if(darkButton.innerHTML != "Light Mode"){ 21 | darkButton.innerHTML = "Light Mode" 22 | }else{ 23 | darkButton.innerHTML = "Dark Mode" 24 | } 25 | document.querySelector("body").classList.toggle("body-dark") 26 | document.querySelector("header").classList.toggle("head_bar-dark") 27 | 28 | document.querySelector("#inputSection").classList.toggle("border-dark") 29 | document.querySelector("#searchSection").classList.toggle("border-dark") 30 | document.querySelector("#bookShelfCompleted").classList.toggle("border-dark") 31 | document.querySelector("#bookShelfUncompleted").classList.toggle("border-dark") 32 | 33 | document.querySelector("#h2InputSection").classList.toggle("color-dark") 34 | document.querySelector("#searchSectionH2").classList.toggle("color-dark") 35 | document.querySelector("#completedH2").classList.toggle("color-dark") 36 | document.querySelector("#completeBookshelfList").classList.toggle("color-dark") 37 | document.querySelector("#uncompletedH2").classList.toggle("color-dark") 38 | 39 | let bookItem = document.getElementsByClassName("book_item") 40 | for (let index = 0; index < bookItem.length; index++) { 41 | bookItem[index].classList.toggle("border-dark") 42 | } 43 | 44 | document.querySelector("#inputBookTitle").labels[0].classList.toggle("color-dark") 45 | document.querySelector("#inputBookAuthor").labels[0].classList.toggle("color-dark") 46 | document.querySelector("#inputBookYear").labels[0].classList.toggle("color-dark") 47 | document.querySelector("#inputBookIsComplete").labels[0].classList.toggle("color-dark") 48 | } 49 | 50 | function switchDisplay() { 51 | if (localStorage.getItem(displayLocalStorageKey) == 'light') { 52 | localStorage.setItem(displayLocalStorageKey, 'dark'); 53 | }else{ 54 | localStorage.setItem(displayLocalStorageKey, 'light'); 55 | } 56 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | Bookshelf Apps 11 | 12 | 16 | 17 | 18 | 19 |
20 |

Bookshelf Apps

21 |
22 |
23 |
24 |

Masukkan Buku Baru

25 |
26 |
27 | 28 | 29 | Wajib Diisi 30 |
31 |
32 | 33 | 34 | Wajib Diisi 35 |
36 |
37 | 38 | 39 | Wajib Diisi 40 |
41 |
42 | 43 | 44 |
45 | 46 |
47 |
48 | 49 | 50 | 51 |
52 |

Cari Buku

53 |
54 | 55 | 56 | 57 |
58 | 59 |
60 |
61 | 62 |
63 |

Belum selesai dibaca

64 | 65 |
66 |
67 | 68 |
69 |

Selesai dibaca

70 | 71 |
72 |
73 |
74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const localStorageKey = "BOOKS_DATA" 2 | 3 | const title = document.querySelector("#inputBookTitle") 4 | const errorTitle = document.querySelector("#errorTitle") 5 | const sectionTitle = document.querySelector("#sectionTitle") 6 | 7 | const author = document.querySelector("#inputBookAuthor") 8 | const errorAuthor = document.querySelector("#errorAuthor") 9 | const sectionAuthor = document.querySelector("#sectionAuthor") 10 | 11 | const year = document.querySelector("#inputBookYear") 12 | const errorYear = document.querySelector("#errorYear") 13 | const sectionYear = document.querySelector("#sectionYear") 14 | 15 | const readed = document.querySelector("#inputBookIsComplete") 16 | 17 | const btnSubmit = document.querySelector("#bookSubmit") 18 | 19 | const searchValue = document.querySelector("#searchBookTitle") 20 | const btnSearch = document.querySelector("#searchSubmit") 21 | 22 | let checkInput = [] 23 | let checkTitle = null 24 | let checkAuthor = null 25 | let checkYear = null 26 | 27 | window.addEventListener("load", function(){ 28 | if (localStorage.getItem(localStorageKey) !== null) { 29 | const booksData = getData() 30 | showData(booksData) 31 | } 32 | }) 33 | 34 | btnSearch.addEventListener("click",function(e) { 35 | e.preventDefault() 36 | if (localStorage.getItem(localStorageKey) == null) { 37 | return alert("Tidak ada data buku") 38 | }else{ 39 | const getByTitle = getData().filter(a => a.title == searchValue.value.trim()); 40 | if (getByTitle.length == 0) { 41 | const getByAuthor = getData().filter(a => a.author == searchValue.value.trim()); 42 | if (getByAuthor.length == 0) { 43 | const getByYear = getData().filter(a => a.year == searchValue.value.trim()); 44 | if (getByYear.length == 0) { 45 | alert(`Tidak ditemukan data dengan kata kunci: ${searchValue.value}`) 46 | }else{ 47 | showSearchResult(getByYear); 48 | } 49 | }else{ 50 | showSearchResult(getByAuthor); 51 | } 52 | }else{ 53 | showSearchResult(getByTitle); 54 | } 55 | } 56 | 57 | searchValue.value = '' 58 | }) 59 | 60 | btnSubmit.addEventListener("click", function() { 61 | if (btnSubmit.value == "") { 62 | checkInput = [] 63 | 64 | title.classList.remove("error") 65 | author.classList.remove("error") 66 | year.classList.remove("error") 67 | 68 | errorTitle.classList.add("error-display") 69 | errorAuthor.classList.add("error-display") 70 | errorYear.classList.add("error-display") 71 | 72 | if (title.value == "") { 73 | checkTitle = false 74 | }else{ 75 | checkTitle = true 76 | } 77 | 78 | if (author.value == "") { 79 | checkAuthor = false 80 | }else{ 81 | checkAuthor = true 82 | } 83 | 84 | if (year.value == "") { 85 | checkYear = false 86 | }else{ 87 | checkYear = true 88 | } 89 | 90 | checkInput.push(checkTitle,checkAuthor,checkYear) 91 | let resultCheck = validation(checkInput) 92 | 93 | if (resultCheck.includes(false)) { 94 | return false 95 | }else{ 96 | const newBook = { 97 | id: +new Date(), 98 | title: title.value.trim(), 99 | author: author.value.trim(), 100 | year: year.value, 101 | isCompleted: readed.checked 102 | } 103 | insertData(newBook) 104 | 105 | title.value = '' 106 | author.value = '' 107 | year.value = '' 108 | readed.checked = false 109 | } 110 | }else{ 111 | const bookData = getData().filter(a => a.id != btnSubmit.value); 112 | localStorage.setItem(localStorageKey,JSON.stringify(bookData)) 113 | 114 | const newBook = { 115 | id: btnSubmit.value, 116 | title: title.value.trim(), 117 | author: author.value.trim(), 118 | year: year.value, 119 | isCompleted: readed.checked 120 | } 121 | insertData(newBook) 122 | btnSubmit.innerHTML = "Masukkan Buku" 123 | btnSubmit.value = '' 124 | title.value = '' 125 | author.value = '' 126 | year.value = '' 127 | readed.checked = false 128 | alert("Buku berhasil diedit") 129 | } 130 | }) 131 | 132 | function validation(check) { 133 | let resultCheck = [] 134 | 135 | check.forEach((a,i) => { 136 | if (a == false) { 137 | if (i == 0) { 138 | title.classList.add("error") 139 | errorTitle.classList.remove("error-display") 140 | resultCheck.push(false) 141 | }else if (i == 1) { 142 | author.classList.add("error") 143 | errorAuthor.classList.remove("error-display") 144 | resultCheck.push(false) 145 | }else{ 146 | year.classList.add("error") 147 | errorYear.classList.remove("error-display") 148 | resultCheck.push(false) 149 | } 150 | } 151 | }); 152 | 153 | return resultCheck 154 | } 155 | 156 | function insertData(book) { 157 | let bookData = [] 158 | 159 | 160 | if (localStorage.getItem(localStorageKey) === null) { 161 | localStorage.setItem(localStorageKey, 0); 162 | }else{ 163 | bookData = JSON.parse(localStorage.getItem(localStorageKey)) 164 | } 165 | 166 | bookData.unshift(book) 167 | localStorage.setItem(localStorageKey,JSON.stringify(bookData)) 168 | 169 | showData(getData()) 170 | } 171 | 172 | function getData() { 173 | return JSON.parse(localStorage.getItem(localStorageKey)) || [] 174 | } 175 | 176 | function showData(books = []) { 177 | const inCompleted = document.querySelector("#incompleteBookshelfList") 178 | const completed = document.querySelector("#completeBookshelfList") 179 | 180 | inCompleted.innerHTML = '' 181 | completed.innerHTML = '' 182 | 183 | books.forEach(book => { 184 | if (book.isCompleted == false) { 185 | let el = ` 186 |
187 |

${book.title}

188 |

Penulis: ${book.author}

189 |

Tahun: ${book.year}

190 | 191 |
192 | 193 | 194 | 195 |
196 |
197 | ` 198 | 199 | inCompleted.innerHTML += el 200 | }else{ 201 | let el = ` 202 |
203 |

${book.title}

204 |

Penulis: ${book.author}

205 |

Tahun: ${book.year}

206 | 207 |
208 | 209 | 210 | 211 |
212 |
213 | ` 214 | completed.innerHTML += el 215 | } 216 | }); 217 | } 218 | 219 | function showSearchResult(books) { 220 | const searchResult = document.querySelector("#searchResult") 221 | 222 | searchResult.innerHTML = '' 223 | 224 | books.forEach(book => { 225 | let el = ` 226 |
227 |

${book.title}

228 |

Penulis: ${book.author}

229 |

Tahun: ${book.year}

230 |

${book.isCompleted ? 'Sudah dibaca' : 'Belum dibaca'}

231 |
232 | ` 233 | 234 | searchResult.innerHTML += el 235 | }); 236 | } 237 | 238 | function readedBook(id) { 239 | let confirmation = confirm("Pindahkan ke selesai dibaca?") 240 | 241 | if (confirmation == true) { 242 | const bookDataDetail = getData().filter(a => a.id == id); 243 | const newBook = { 244 | id: bookDataDetail[0].id, 245 | title: bookDataDetail[0].title, 246 | author: bookDataDetail[0].author, 247 | year: bookDataDetail[0].year, 248 | isCompleted: true 249 | } 250 | 251 | const bookData = getData().filter(a => a.id != id); 252 | localStorage.setItem(localStorageKey,JSON.stringify(bookData)) 253 | 254 | insertData(newBook) 255 | }else{ 256 | return 0 257 | } 258 | } 259 | 260 | function unreadedBook(id) { 261 | let confirmation = confirm("Pindahkan ke belum selesai dibaca?") 262 | 263 | if (confirmation == true) { 264 | const bookDataDetail = getData().filter(a => a.id == id); 265 | const newBook = { 266 | id: bookDataDetail[0].id, 267 | title: bookDataDetail[0].title, 268 | author: bookDataDetail[0].author, 269 | year: bookDataDetail[0].year, 270 | isCompleted: false 271 | } 272 | 273 | const bookData = getData().filter(a => a.id != id); 274 | localStorage.setItem(localStorageKey,JSON.stringify(bookData)) 275 | 276 | insertData(newBook) 277 | }else{ 278 | return 0 279 | } 280 | } 281 | 282 | function editBook(id) { 283 | const bookDataDetail = getData().filter(a => a.id == id); 284 | title.value = bookDataDetail[0].title 285 | author.value = bookDataDetail[0].author 286 | year.value = bookDataDetail[0].year 287 | bookDataDetail[0].isCompleted ? readed.checked = true:readed.checked = false 288 | 289 | btnSubmit.innerHTML = "Edit buku" 290 | btnSubmit.value = bookDataDetail[0].id 291 | } 292 | 293 | function deleteBook(id) { 294 | let confirmation = confirm("Yakin akan menghapusnya?") 295 | 296 | if (confirmation == true) { 297 | const bookDataDetail = getData().filter(a => a.id == id); 298 | const bookData = getData().filter(a => a.id != id); 299 | localStorage.setItem(localStorageKey,JSON.stringify(bookData)) 300 | showData(getData()) 301 | alert(`Buku ${bookDataDetail[0].title} telah terhapus`) 302 | }else{ 303 | return 0 304 | } 305 | } -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body, 8 | input, 9 | button { 10 | font-family: "Open Sans", sans-serif; 11 | /* background-color: #2c3e50; */ 12 | } 13 | 14 | input, 15 | button { 16 | font-size: 16px; 17 | } 18 | 19 | .head_bar { 20 | padding: 12px; 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | background-color: #2980b9; 25 | color: white; 26 | } 27 | 28 | main { 29 | max-width: 800px; 30 | width: 80%; 31 | margin: 0 auto; 32 | padding: 16px; 33 | } 34 | 35 | .input_section { 36 | display: flex; 37 | flex-direction: column; 38 | padding: 16px; 39 | border: 1px solid black; 40 | border-radius: 10px; 41 | } 42 | 43 | .input_section > h2 { 44 | text-align: center; 45 | color: #2980b9; 46 | } 47 | 48 | .input_section > form > .input { 49 | margin: 8px 0; 50 | } 51 | 52 | .input_section > form > button { 53 | background-color: #3498db; 54 | color: white; 55 | border: 0; 56 | border-radius: 5px; 57 | display: block; 58 | width: 100%; 59 | padding: 8px; 60 | cursor: pointer; 61 | } 62 | 63 | .input_section > form > button > span { 64 | font-weight: bold; 65 | } 66 | 67 | .input_section > form > .input > input { 68 | display: block; 69 | width: 100%; 70 | padding: 8px; 71 | border-radius: 5px; 72 | } 73 | 74 | .input_section > form > .input > label { 75 | color: #2980b9; 76 | font-weight: bold; 77 | } 78 | 79 | .input_section > form > .input_inline { 80 | margin: 12px 0; 81 | display: flex; 82 | align-items: center; 83 | } 84 | 85 | .input_section > form > .input_inline > label { 86 | color: #2980b9; 87 | font-weight: bold; 88 | margin-right: 10px; 89 | } 90 | 91 | .search_section { 92 | margin: 16px 0; 93 | display: flex; 94 | flex-direction: column; 95 | align-items: center; 96 | padding: 16px; 97 | border: 1px solid black; 98 | border-radius: 10px; 99 | } 100 | 101 | .search_section > h2 { 102 | color: #2980b9; 103 | } 104 | 105 | .search_section > form { 106 | padding: 16px; 107 | width: 100%; 108 | display: grid; 109 | grid-template-columns: auto 1fr 0.5fr; 110 | grid-gap: 10px; 111 | } 112 | 113 | .search_section > form > label { 114 | display: flex; 115 | align-items: center; 116 | } 117 | 118 | .search_section > form > input { 119 | padding: 5px; 120 | border-radius: 5px; 121 | } 122 | 123 | .search_section > form > button { 124 | background-color: #2980b9; 125 | color: white; 126 | border: 0; 127 | border-radius: 5px; 128 | cursor: pointer; 129 | } 130 | 131 | .book_shelf { 132 | margin: 16px 0 0 0; 133 | border: 1px solid black; 134 | padding: 16px; 135 | border-radius: 10px; 136 | } 137 | 138 | .book_shelf > h2 { 139 | color: #2980b9; 140 | } 141 | 142 | .book_shelf > .book_list { 143 | padding: 16px; 144 | } 145 | 146 | .book_shelf > .book_list > .book_item { 147 | padding: 8px 16px 16px 16px; 148 | border: 1px solid black; 149 | border-radius: 5px; 150 | margin: 10px 0; 151 | } 152 | 153 | .book_shelf > .book_list > .book_item > h3, 154 | p { 155 | margin: 8px 0; 156 | } 157 | 158 | .book_shelf > .book_list > .book_item > .action > button { 159 | border: 0; 160 | padding: 5px; 161 | margin: 0 5px 0 0; 162 | border-radius: 5px; 163 | cursor: pointer; 164 | } 165 | 166 | .book_shelf > .book_list > .book_item > .action > .green { 167 | background-color: #2ecc71; 168 | color: white; 169 | } 170 | 171 | .book_shelf > .book_list > .book_item > .action > .yellow { 172 | background-color: #f1c40f; 173 | color: white; 174 | } 175 | 176 | .book_shelf > .book_list > .book_item > .action > .red { 177 | background-color: #e74c3c; 178 | color: white; 179 | } 180 | 181 | .error { 182 | border: 2px solid red; 183 | } 184 | 185 | small { 186 | color: red; 187 | } 188 | 189 | .error-display { 190 | display: none; 191 | } 192 | 193 | .dark-button { 194 | background-color: #2c3e50; 195 | color: white; 196 | border: 0; 197 | border-radius: 5px; 198 | display: block; 199 | width: 100%; 200 | padding: 8px; 201 | cursor: pointer; 202 | margin-top: 16px; 203 | } 204 | 205 | .light-button { 206 | background-color: #ecf0f1; 207 | color: #2c3e50; 208 | border: 0; 209 | border-radius: 5px; 210 | display: block; 211 | width: 100%; 212 | padding: 8px; 213 | cursor: pointer; 214 | margin-top: 16px; 215 | } 216 | 217 | .body-dark { 218 | background-color: #34495e; 219 | color: #ecf0f1; 220 | } 221 | 222 | .head_bar-dark { 223 | background-color: #2c3e50; 224 | } 225 | 226 | .color-dark { 227 | color: #ecf0f1 !important; 228 | } 229 | 230 | .border-dark { 231 | border: 1px solid #ecf0f1 !important; 232 | } 233 | --------------------------------------------------------------------------------