Advertisement
haxcow

Bookshelf Web App

Aug 12th, 2022
1,047
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5.   <meta charset="UTF-8">
  6.   <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7.   <meta name="viewport" content="width=device-width, initial-scale=1.0">
  8.   <title>Bookshelf Web App</title>
  9.  
  10.   <style>
  11.         @import url('https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:wght@300;500;700&display=swap');
  12.  
  13.         :root {
  14.           --nav: rgb(139, 191, 159);
  15.           --body: rgb(133, 126, 123);
  16.           --container: rgb(245, 224, 183);
  17.           --button: rgb(203, 195, 195);
  18.           --buttonHover: rgb(89,52,79);
  19.         }
  20.  
  21.         * {
  22.           padding: 0;
  23.           margin: 0;
  24.           font-family: 'Fira Sans Condensed', sans-serif;
  25.           box-sizing: border-box;
  26.         }
  27.  
  28.         body {
  29.           height: 100vh;
  30.           width: 100vw;
  31.         }
  32.  
  33.         /* NAVBAR */
  34.  
  35.         header {
  36.           display: flex;
  37.           flex-direction: row;
  38.           align-items: center;
  39.           background-color: var(--nav);
  40.           padding: 10px 10%;
  41.         }
  42.  
  43.         header > img {
  44.           width: 30px;
  45.         }
  46.  
  47.         .space {
  48.           padding: 0 5px;
  49.         }
  50.  
  51.         .search-bar {
  52.           height: 20px;
  53.         }
  54.  
  55.         .search-bar[type='text'] {
  56.           font-size: 1rem;
  57.           font-weight: 500;
  58.         }
  59.  
  60.         /* CONTENT */
  61.  
  62.         .container {
  63.           padding: 0 10%;
  64.           width: auto;
  65.           height: 570px;
  66.         }
  67.  
  68.         .bg-img {
  69.           background-image: url(assets/alfons-morales-YLSwjSy7stw-unsplash.jpg);
  70.           background-position: center;
  71.           background-size: cover;
  72.           height: 635px;
  73.         }
  74.  
  75.         .center {
  76.           display: flex;
  77.           justify-content: center;
  78.           align-items: center;
  79.         }
  80.  
  81.         .wrapper {
  82.           background-color: var(--container);
  83.           height: auto;
  84.           width: 430px;
  85.           padding: 0 5%;
  86.         }
  87.  
  88.         .wrapper > p {
  89.           text-align: center;
  90.           padding: 10px 0;
  91.           font-size: 2rem;
  92.         }
  93.  
  94.         .form label {
  95.           float: left;
  96.           width: 40%;
  97.         }
  98.  
  99.         .form input {
  100.           float: right;
  101.           width: 60%;
  102.         }
  103.  
  104.         .form-grup {
  105.           display: flex;
  106.           flex-direction: row;
  107.           padding: 2% 0;
  108.           font-size: 1.5rem;
  109.           padding: 10px 0;
  110.         }
  111.  
  112.         .btn-center {
  113.           display: flex;
  114.           justify-content: center;
  115.         }
  116.  
  117.         .btn-submit {
  118.           font-size: 1rem;
  119.           background-color: var(--button);
  120.           border: 1px solid var(--button);
  121.           padding: 1%;
  122.         }
  123.  
  124.         .btn-submit:hover {
  125.           background-color: var(--buttonHover);
  126.         }
  127.  
  128.         input[type=text], input[type=number] {
  129.           background: white;
  130.           border: 1px solid white;
  131.           border-radius: 5px;
  132.           font-size: 1.5rem;
  133.         }
  134.  
  135.         input:focus {
  136.           outline: none;
  137.         }
  138.  
  139.         .wrapper-list {
  140.           background-color: var(--container);
  141.           margin: 16px;
  142.           padding: 10px;
  143.           border-radius: 5px;
  144.         }
  145.  
  146.         .item {
  147.           background-color: white;
  148.           padding: 10px;
  149.           border-radius: 5px;
  150.           margin: 10px;
  151.           display: flex;
  152.           align-items: center;
  153.           /* justify-content: space-between; */
  154.         }
  155.  
  156.         .item > .inner h2 {
  157.           margin-bottom: unset;
  158.         }
  159.  
  160.         .item > .inner p {
  161.           font-size: 1rem;
  162.         }
  163.  
  164.         .undo-button {
  165.           width: 60px;
  166.           height: 60px;
  167.           background-image: url(assets/bx-refresh.svg);
  168.           background-size: contain;
  169.           margin-left: auto;
  170.           cursor: pointer;
  171.           border: none;
  172.         }
  173.  
  174.         .check-button {
  175.           width: 60px;
  176.           height: 60px;
  177.           background: url(assets/box-check.svg);
  178.           background-size: contain;
  179.           margin-left: auto;
  180.           cursor: pointer;
  181.           border: none;
  182.         }
  183.  
  184.         .check-button:hover {
  185.           background: url(assets/box-check-solid.svg);
  186.           background-size: contain;
  187.         }
  188.  
  189.         .trash-button {
  190.           width: 60px;
  191.           height: 60px;
  192.           background: url(assets/trash.svg);
  193.           background-size: contain;
  194.           cursor: pointer;
  195.           border: none;
  196.         }
  197.  
  198.         .trash-button:hover {
  199.           background: url(assets/trash-solid.svg);
  200.           background-size: contain;
  201.         }
  202.  
  203.         /* Desktop */
  204.  
  205.         @media screen and (min-width: 1025px) {
  206.           .wrapper {
  207.             width: 650px;
  208.           }
  209.         }
  210.   </style>
  211. </head>
  212.  
  213. <body>
  214.   <header>
  215.     <img src="assets/open-book.png" alt="icon">
  216.     <div class="space"></div>
  217.     <p>Bookshelf</p>
  218.     <div class="space"></div>
  219.     <form action="#">
  220.       <input type="text" placeholder="Cari buku" id="search-bar" class="search-bar">
  221.       <button type="submit"></button>
  222.     </form>
  223.   </header>
  224.  
  225.   <main>
  226.     <div class="container bg-img center">
  227.       <div class="wrapper">
  228.         <p>Daftar Buku</p>
  229.         <form action="#" class="form" id="form">
  230.           <div class="form-grup">
  231.             <label for="judul">Judul</label>
  232.             <input type="text" name="judul" id="judul">
  233.           </div>
  234.           <div class="form-grup">
  235.             <label for="penulis">Penulis</label>
  236.             <input type="text" name="penulis" id="penulis">
  237.           </div>
  238.           <div class="form-grup">
  239.             <label for="tahun">Tahun</label>
  240.             <input type="number" name="tahun" id="tahun">
  241.           </div>
  242.           <div class="form-grup btn-center">
  243.             <button type="submit" class="btn-submit">Belum Selesai</button>
  244.             <div class="space"></div>
  245.             <button type="submit" class="btn-submit">Sudah Selesai</button>
  246.           </div>
  247.         </form>
  248.       </div>
  249.     </div>
  250.     <div class="container">
  251.       <div class="wrapper-list">
  252.         <h2>Belum Selesai</h2>
  253.         <div class=" list-item" id="books"></div>
  254.       </div>
  255.       <div class="wrapper-list">
  256.         <h2>Sudah Selesai</h2>
  257.         <div class="list-item" id="done-books"></div>
  258.       </div>
  259.     </div>
  260.   </main>
  261.  
  262.   <script type="text/javascript">
  263.     const books = [];
  264.  
  265.     const RENDER_EVENT = "render-book";
  266.  
  267.     // #2
  268.     function addBook() {
  269.         const title = document.getElementById("judul").value;
  270.         const author = document.getElementById("penulis").value;
  271.         const timestamp = document.getElementById("tahun").value;
  272.  
  273.         const generatedID = generateId();
  274.  
  275.         const bookObject = generateBookObject(
  276.             generatedID,
  277.             title,
  278.             author,
  279.             timestamp,
  280.             false
  281.         );
  282.  
  283.         books.push(bookObject);
  284.  
  285.         document.dispatchEvent(new Event(RENDER_EVENT));
  286.     }
  287.  
  288.     // #3
  289.     function generateId() {
  290.         return +new Date();
  291.     }
  292.  
  293.     // #4
  294.     function generateBookObject(id, title, author, timestamp, isCompleted) {
  295.         return {
  296.             id,
  297.             title,
  298.             author,
  299.             timestamp,
  300.             isCompleted,
  301.         };
  302.     }
  303.  
  304.     // #5
  305.     function makeBook(bookObject) {
  306.         const textTitle = document.createElement("h2");
  307.         textTitle.innerText = bookObject.title;
  308.  
  309.         const textAuthor = document.createElement("p");
  310.         textAuthor.innerText = bookObject.author;
  311.  
  312.         const textTimestamp = document.createElement("p");
  313.         textTimestamp.innerText = bookObject.timestamp;
  314.  
  315.         const textContainer = document.createElement("div");
  316.         textContainer.classList.add("inner");
  317.         textContainer.append(textTitle, textAuthor, textTimestamp);
  318.  
  319.         const container = document.createElement("div");
  320.         container.classList.add("item");
  321.         container.append(textContainer);
  322.         container.setAttribute("id", `book-${bookObject.id}`);
  323.  
  324.         if (bookObject.isCompleted) {
  325.             const undoButton = document.createElement("button");
  326.             undoButton.classList.add("undo-button");
  327.  
  328.             undoButton.addEventListener("click", function () {
  329.                 undoTaskFromCompleted(bookObject.id);
  330.             });
  331.  
  332.             const trashButton = document.createElement("button");
  333.             trashButton.classList.add("trash-button");
  334.  
  335.             trashButton.addEventListener("click", function () {
  336.                 removeTaskFromCompleted(bookObject.id);
  337.             });
  338.  
  339.             container.append(undoButton, trashButton);
  340.         } else {
  341.             const checkButton = document.createElement("button");
  342.             checkButton.classList.add("check-button");
  343.  
  344.             checkButton.addEventListener("click", function () {
  345.                 addTaskToCompleted(bookObject.id);
  346.             });
  347.  
  348.             container.append(checkButton);
  349.         }
  350.  
  351.         return container;
  352.     }
  353.  
  354.     // #6
  355.     function addTaskToCompleted(bookId) {
  356.         const bookTarget = findBook(bookId);
  357.  
  358.         if (bookTarget == null) return;
  359.  
  360.         bookTarget.isCompleted = true;
  361.         document.dispatchEvent(new Event(RENDER_EVENT));
  362.     }
  363.  
  364.     // #7
  365.     function findBook(bookId) {
  366.         for (const bookItem of books) {
  367.             if (bookItem.id === bookId) {
  368.                 return bookItem;
  369.             }
  370.         }
  371.  
  372.         return null;
  373.     }
  374.  
  375.     // #8
  376.     function removeTaskFromCompleted(bookId) {
  377.         const bookTarget = findBookIndex(bookId);
  378.  
  379.         if (bookTarget === -1) return;
  380.  
  381.         books.splice(bookTarget, 1);
  382.         document.dispatchEvent(new Event(RENDER_EVENT));
  383.     }
  384.  
  385.     // #9
  386.     function undoTaskFromCompleted(bookId) {
  387.         const bookTarget = findBook(bookId);
  388.  
  389.         if (bookTarget == null) return;
  390.  
  391.         bookTarget.isCompleted = false;
  392.         document.dispatchEvent(new Event(RENDER_EVENT));
  393.     }
  394.  
  395.     // #10
  396.     function findBookIndex(bookId) {
  397.         for (const index in books) {
  398.             if (books[index].id === bookId) {
  399.                 return index;
  400.             }
  401.         }
  402.  
  403.         return -1;
  404.     }
  405.  
  406.     // #1
  407.     document.addEventListener("DOMContentLoaded", function () {
  408.         const submitForm = document.getElementById("form");
  409.         submitForm.addEventListener("submit", function (event) {
  410.             event.preventDefault();
  411.             addBook();
  412.         });
  413.     });
  414.  
  415.     // Memastikan fungsi berjalan
  416.     document.addEventListener(RENDER_EVENT, function () {
  417.         // console.log(books);
  418.         const uncompletedBookList = document.getElementById("books");
  419.         uncompletedBookList.innerHTML = "";
  420.  
  421.         const completedBookList = document.getElementById("done-books");
  422.         completedBookList.innerHTML = "";
  423.  
  424.         for (const bookItem of books) {
  425.             const bookElement = makeBook(bookItem);
  426.             if (!bookItem.isCompleted) {
  427.                 uncompletedBookList.append(bookElement);
  428.             } else {
  429.                 completedBookList.append(bookElement);
  430.             }
  431.         }
  432.     });
  433.  
  434.   </script>
  435. </body>
  436.  
  437. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement