본문 바로가기

프론트엔드/자바스크립트

프로젝트 - to do

반응형

To do 리스트 관리 애플리케이션

 

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <script src="https://kit.fontawesome.com/833be080c6.js" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="./main.css">
  <script type="module" defer src="./index.js"></script>
</head>

<body>
  <h1>To Do</h1>

  <!-- container -->
  <div class="container">
    
    <!-- To do -->
    <div class="card">
      <h2 style="background-color: rgb(124, 204, 177);">to do</h2>
      <div class="list-box" id="1">
      </div>
      <button class="btn-add">
        <i class="fas-fa-plus"></i>add item
      </button>
    </div>
    
    <!-- in progress -->
    <div class="card">
      <h2 style="background-color: rgb(228, 191, 135);">In Progress</h2>
      <div class="list-box" id="2">
      </div>
      <button class="btn-add">
        <i class="fas-fa-plus"></i>add item
      </button>
    </div>
    
    <!-- completed -->
    <div class="card">
      <h2 style="background-color: rgb(220, 78, 78);">Completed</h2>
      <div class="list-box" id="3">
      </div>
      <button class="btn-add">
        <i class="fas-fa-plus"></i>add item
      </button>
    </div>
    
    <!-- on hold -->
    <div class="card">
      <h2 style="background-color: rgb(177, 214, 103);">on hold</h2>
      <div class="list-box" id="4">
      </div>
      <button class="btn-add">
        <i class="fas-fa-plus"></i>add item
      </button>
    </div>
  </div>

</body>

</html>

 

main.css

@import url('https://fonts.googleapis.com/css?family=Poppins&display=swap');

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  display: flex;
  flex-direction: column;
  text-transform: capitalize;
  font-family: 'Poppins';
  background: linear-gradient(
    90deg,
    rgb(240, 244, 207) 50%,
    rgb(245, 236, 207) 90%
  );
}

/* title style */
h1 {
  text-align: center;
  margin: 20px;
  text-transform: uppercase;
}

/* container style */
.container {
  display: flex;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* card style */
.card {
  height: 500px;
  width: 300px;
  display: flex;
  justify-content: space-between;
  flex-direction: column;
  flex-shrink: 0;
  background-color: rgba(0, 0, 0, 0.3);
  border-radius: 5px;
  box-shadow: 2px 2px 1px 0 rgba(0, 0, 0, 0.4);
}

/* card title style */
h2 {
  text-align: center;
  padding: 15px;
  margin: 10px;
  border-radius: 5px;
  box-shadow: 2px 2px 1px 0 rgba(0, 0, 0, 0.4);
}

/* list box style */
.list-box {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: scroll;
}

::-webkit-scrollbar {
  display: none;
}

input {
  height: 40px;
  margin: 10px;
  border-radius: 5px;
  padding: 0 10px;
  font-size: 1.3rem;
  flex-shrink: 0;
  box-shadow: 2px 2px 1px 0 rgba(0, 0, 0, 0.4);
}

/* button style */
button {
  height: 40px;
  margin: 10px;
  padding: 10px;
  border-radius: 5px;
  box-shadow: 2px 2px 1px 0 rgba(0, 0, 0, 0.4);
  border: none;
  background-color: rgb(152, 231, 152);
  cursor: pointer;
  transition: 0.3s ease;
  text-transform: uppercase;
  font-size: 1.2rem;
}

button:hover {
  background-color: #fff;
  cursor: pointer;
}

button:active {
  transform: scale(0.98);
}

 

index.js

import { createId } from './id.creator.js'

// variables
const inputsEl = document.querySelectorAll('input')
const boxesEl = document.querySelectorAll('.list-box')
const btnAddsEl = document.querySelectorAll('.btn-add')
const listBoxesEl = document.querySelectorAll('.list-box')

let lists = []
let flag = false

// storage
if (localStorage.getItem('list')) {
  lists = JSON.parse(localStorage.getItem('list'))
  addNewList(lists)
}

// event handlers
inputsEl.forEach((input) => {
  input.addEventListener('dragstart', (e) => {    
    e.dataTransfer.setData('list', e.target.id)
  })
})

boxesEl.forEach((box) => {
  box.addEventListener('dragover', (e) => {
    e.preventDefault()
  })
})

boxesEl.forEach((box) => {
  box.addEventListener('drop', (e) => {
    let data = e.dataTransfer.getData('list')
    box.appendChild(document.getElementById(data))
    console.log(e.target.id)
    console.log(data)
    updateContainerId(data, e.target.id)
  })
})

addNewList()

// functions
function addNewList(lists) {  
  if (typeof lists !== 'undefined') {
    lists.forEach((list) => {
      const newList = document.createElement('input')
      newList.draggable = true
      newList.readOnly = true
      newList.id = list.id
      newList.value = list.text
      newList.addEventListener('dragstart', (e) => {
        e.dataTransfer.setData('list', e.target.id)
      })

      newList.addEventListener('click', (e) => {
        newList.readOnly = false
      })

      newList.addEventListener('input', (e) => {
        flag = true
        newList.value = e.target.value
      })

      window.addEventListener('click', (e) => {
        e.target === newList
          ? updateStatue(newList, false)
          : updateStatue(newList, true, list.containerId)
      })
      listBoxesEl[list.containerId - 1].appendChild(newList)
    })
  }
  
  btnAddsEl.forEach((btnAdd) => {
    btnAdd.addEventListener('click', () => {
      const newList = document.createElement('input')
      newList.draggable = true
      newList.readOnly = true
      newList.id = createId()
      newList.addEventListener('dragstart', (e) => {
        e.dataTransfer.setData('list', e.target.id)
      })

      newList.addEventListener('click', (e) => {
        newList.readOnly = false
      })

      newList.addEventListener('input', (e) => {
        flag = true
        newList.value = e.target.value
      })
      window.addEventListener('click', (e) => {
        e.target === newList
          ? updateStatue(newList, false)
          : updateStatue(newList, true, btnAdd.previousElementSibling.id)
      })
      btnAdd.previousElementSibling.appendChild(newList)
    })
  })
}

function updateStatue(newList, isReadOnly, containerId) {
  newList.readOnly = isReadOnly
  if (flag && isReadOnly) {
    lists.push({
      id: newList.id,
      text: newList.value,
      containerId: containerId,
    })
    updateList()
    flag = false
  }
}

function updateContainerId(id, containerId) {
  lists = lists.map((list) =>
    list.id === id ? { ...list, containerId: containerId } : list
  )
  updateList()
}

function updateList() {
  localStorage.setItem('list', JSON.stringify(lists))
}

 

id.creator.js

let idList = []

if (localStorage.getItem('idList')) {
  idList = JSON.parse(localStorage.getItem('idList'))
}

function createId() {
  const id = Math.floor(Math.random() * 100000)
  console.log(id)
  if (idList.includes(id)) return
  idList.push(id)
  localStorage.setItem('idList', JSON.stringify(idList))
  return id
}

export {createId}

 

데모

 

Document

 

jin-co-jcg.vercel.app

 

728x90
반응형