-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PR to add JavaScript ToDo app #1
base: main
Are you sure you want to change the base?
Changes from 14 commits
d4d77c1
7311976
ff06a0a
a5717d7
055375d
7bfa22e
b859f19
8b398dd
9c3ae01
fe0e1ac
717d87e
b66060b
e48227f
fab7c46
5fb834c
016e0e0
019f746
0fa4d58
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
# ui-playground | ||
Playground repo for ui training | ||
|
||
Playground repo for ui training |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500&display=swap"); | ||
|
||
:root { | ||
--primary-color: #f25278; | ||
--secondary-color: rgb(69, 69, 236); | ||
--text-primary: #fff; | ||
--border-color: #bdbdbd; | ||
--disabled-color: rgba(189, 189, 235, 0.925); | ||
} | ||
* { | ||
box-sizing: border-box; | ||
margin: 0; | ||
padding: 0; | ||
font-family: "Open Sans", "Courier New", Courier, monospace; | ||
} | ||
|
||
body { | ||
min-height: calc(100vh - 1.5rem); | ||
width: 100%; | ||
background-color: var(--primary-color); | ||
} | ||
|
||
body li { | ||
list-style-type: none; | ||
} | ||
|
||
.header-text { | ||
width: 100%; | ||
text-align: center; | ||
margin: 1.5rem 0; | ||
color: var(--text-primary); | ||
} | ||
.container { | ||
margin: 0 auto; | ||
max-width: 35rem; | ||
} | ||
|
||
.input-container { | ||
margin: 1rem auto; | ||
display: flex; | ||
background-color: var(--text-primary); | ||
align-items: center; | ||
} | ||
.input-container > input { | ||
padding: 0.5rem 0.8rem; | ||
width: 100%; | ||
outline: none; | ||
font-size: 1.15rem; | ||
border: 0; | ||
} | ||
.input-container > button { | ||
padding-right: 1rem; | ||
background: transparent; | ||
border: 0; | ||
color: var(--secondary-color); | ||
font-weight: 600; | ||
font-size: 1.05rem; | ||
cursor: pointer; | ||
} | ||
|
||
.input-container button:disabled, | ||
.todo-container button:disabled { | ||
color: var(--disabled-color); | ||
cursor: initial; | ||
} | ||
|
||
.todo-container { | ||
background-color: var(--text-primary); | ||
margin: 1.5rem auto; | ||
} | ||
|
||
.todo-container button { | ||
min-width: 1.5rem; | ||
height: 1.5rem; | ||
margin-right: 8px; | ||
background-color: var(--primary-color); | ||
color: var(--text-primary); | ||
border: 0; | ||
outline: none; | ||
cursor: pointer; | ||
font-weight: 600; | ||
} | ||
|
||
.todo { | ||
display: flex; | ||
width: 100%; | ||
align-items: center; | ||
position: relative; | ||
padding: 1rem 0; | ||
border-bottom: 1px solid var(--border-color); | ||
} | ||
|
||
.todo.sub-todo-input { | ||
padding-top: 1rem; | ||
padding-left: 1.2rem; | ||
} | ||
|
||
button { | ||
padding: 0 10px; | ||
} | ||
.todo button:disabled { | ||
opacity: 0.8; | ||
color: var(--text-primary); | ||
cursor: initial; | ||
} | ||
.todo input[type="checkbox"] { | ||
margin-right: 8px; | ||
cursor: pointer; | ||
} | ||
.todo input[type="text"] { | ||
padding: 0.4rem; | ||
flex: 1; | ||
outline: none; | ||
} | ||
.todo p { | ||
font-size: 1.05rem; | ||
flex: 1; | ||
word-break: break-all; | ||
color: gray; | ||
margin-bottom: 4px; | ||
text-align: start; | ||
padding: 0 8px; | ||
} | ||
|
||
p.text-through { | ||
text-decoration: line-through; | ||
color: var(--primary-color); | ||
} | ||
|
||
.sub-todo { | ||
padding-left: 1.2rem; | ||
} | ||
|
||
.action-container { | ||
display: flex; | ||
justify-content: end; | ||
align-items: center; | ||
margin: 1rem 0 1rem auto; | ||
} | ||
|
||
/* Utility classes */ | ||
.d-none { | ||
display: none; | ||
} | ||
|
||
.d-block { | ||
display: block; | ||
} | ||
.padding-xs { | ||
padding: 1rem; | ||
} | ||
|
||
.action-container .action-btn { | ||
display: block; | ||
padding: 0 1rem; | ||
margin: 0; | ||
} | ||
.action-container .action-btn:first-child { | ||
margin-right: 8px; | ||
} | ||
.invisible { | ||
visibility: hidden; | ||
} | ||
.padding-bottom-0 { | ||
padding-bottom: 0; | ||
} | ||
|
||
.padding-top-0 { | ||
padding-top: 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<!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" /> | ||
<link rel="stylesheet" href="css/style.css" /> | ||
<link | ||
rel="stylesheet" | ||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.1/css/all.min.css" | ||
integrity="sha512-9my9Mb2+0YO+I4PUCSwUYO7sEK21Y0STBAiFEYoWtd2VzLEZZ4QARDrZ30hdM1GlioHJ8o8cWQiy8IAb1hy/Hg==" | ||
crossorigin="anonymous" | ||
referrerpolicy="no-referrer" | ||
/> | ||
<title>FlixTodos</title> | ||
</head> | ||
<body> | ||
<main> | ||
<h2 class="header-text">TO-DO LIST</h2> | ||
<div class="container input-container"> | ||
<input type="text" placeholder="New Task" /> | ||
<button type="button" disabled id="add-todo">ADD</button> | ||
</div> | ||
<div class="container todo-container d-none"> | ||
<div id="todo-wrapper"></div> | ||
<div class="action-container"> | ||
<button id="mark-complete" class="action-btn"> | ||
Mark All Complete | ||
</button> | ||
<button id="clear" class="action-btn">Delete All</button> | ||
</div> | ||
</div> | ||
<h3 class="header-text" id="no-todo-text">No Todos found</h3> | ||
</main> | ||
<script type="module" src="./js/todo.js"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export { default as createTodoBase } from "./todoBase.js" | ||
export { default as createTodoRoot } from "./todoRoot.js" | ||
export { default as createTodoInput } from "./todoInput.js" | ||
export { default as createTodoCheckbox } from "./todoCheckbox.js" | ||
export { default as createTodoButton } from "./todoButton.js" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import todos from "../constant.js" | ||
import render from "../todo.js" | ||
import { todoWrapper } from "../selectors.js" | ||
|
||
const createTodoBase = (todo, props = {}) => { | ||
const { draggable = false } = props | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should use semicolons after every statement |
||
|
||
const onTodoDragStart = (event) => { | ||
const dataId = event.currentTarget.getAttribute("data-id") | ||
event.dataTransfer.dropEffect = "move" | ||
event.dataTransfer.setData("data_id", dataId) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. two different variable with same name but different convention would be confusing - data-id and data_id |
||
} | ||
|
||
const onTodoDragOver = (event) => { | ||
event.preventDefault() | ||
} | ||
|
||
const onTodoDrop = (event) => { | ||
const currentId = event.currentTarget.getAttribute("data-id") | ||
const previousId = event.dataTransfer.getData("data_id") | ||
|
||
const currentTodoIdx = todos.findIndex( | ||
(todo) => todo.id === Number(currentId), | ||
) | ||
const previousTodoIdx = todos.findIndex( | ||
(todo) => todo.id === Number(previousId), | ||
) | ||
|
||
if (currentTodoIdx >= 0 && previousTodoIdx >= 0) { | ||
const temp = todos[currentTodoIdx] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can use destructing assignment here for swapping to avoid temp - Eg: [b,a] = [a,b] |
||
todos[currentTodoIdx] = todos[previousTodoIdx] | ||
todos[previousTodoIdx] = temp | ||
|
||
todoWrapper.innerHTML = "" | ||
render() | ||
} | ||
} | ||
|
||
const todoRootEl = document.createElement("li") | ||
todoRootEl.setAttribute("draggable", draggable) | ||
|
||
if (todo?.id) { | ||
todoRootEl.setAttribute("data-id", todo?.id) | ||
} | ||
|
||
if (draggable) { | ||
todoRootEl.addEventListener("dragstart", onTodoDragStart) | ||
todoRootEl.addEventListener("dragover", onTodoDragOver) | ||
todoRootEl.addEventListener("drop", onTodoDrop) | ||
} | ||
|
||
return todoRootEl | ||
} | ||
|
||
export default createTodoBase |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const createTodoButton = (props = {}) => { | ||
const { textContent = "", innerHTML = "" } = props | ||
|
||
const todoBtnEl = document.createElement("button") | ||
todoBtnEl.textContent = textContent | ||
|
||
if (innerHTML) { | ||
todoBtnEl.innerHTML = innerHTML | ||
} | ||
|
||
return todoBtnEl | ||
} | ||
|
||
export default createTodoButton |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const createTodoCheckbox = (isCompleted = false) => { | ||
const todoCheckEl = document.createElement("input") | ||
todoCheckEl.type = "checkbox" | ||
todoCheckEl.checked = isCompleted | ||
|
||
return todoCheckEl | ||
} | ||
|
||
export default createTodoCheckbox |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const createTodoInput = (props = {}) => { | ||
const { type = "text", value = "" } = props | ||
|
||
const inputEl = document.createElement("input") | ||
inputEl.type = type | ||
inputEl.value = value | ||
|
||
return inputEl | ||
} | ||
|
||
export default createTodoInput |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
const createTodoRoot = (hasChildTodos = false) => { | ||
function onTodoMouseOver() { | ||
this.childNodes.forEach((node) => { | ||
if (node.id === "sub-todo") { | ||
node.classList.remove("invisible") | ||
} | ||
}) | ||
} | ||
|
||
function onTodoMouseLeave() { | ||
this.childNodes.forEach((node) => { | ||
if (node.id === "sub-todo") { | ||
node.classList.add("invisible") | ||
} | ||
}) | ||
} | ||
|
||
const todoEl = document.createElement("div") | ||
todoEl.classList.add("todo") | ||
|
||
if (hasChildTodos) { | ||
todoEl.addEventListener("mouseover", onTodoMouseOver) | ||
todoEl.addEventListener("mouseleave", onTodoMouseLeave) | ||
} else { | ||
todoEl.classList.add("sub-todo") | ||
} | ||
|
||
return todoEl | ||
} | ||
|
||
export default createTodoRoot |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
const todos = [] | ||
|
||
export default todos |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
const mainEl = document.querySelector("main") | ||
const inputEl = document.querySelector("input") | ||
const cardContainer = document.querySelector(".todo-container") | ||
const todoWrapper = document.querySelector("#todo-wrapper") | ||
const addTodoBtn = document.querySelector(".input-container button") | ||
const noTodoText = document.querySelector("#no-todo-text") | ||
const markAllCompleteBtn = document.querySelector("#mark-complete") | ||
|
||
export { | ||
inputEl, | ||
cardContainer, | ||
todoWrapper, | ||
addTodoBtn, | ||
noTodoText, | ||
markAllCompleteBtn, | ||
mainEl, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should use semicolon after every statement. Applies to all the files.