diff --git a/index.html b/index.html index e3bb799..f9c05e3 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ Kanban - + diff --git a/index.js b/index.js index 1b448a4..a953976 100644 --- a/index.js +++ b/index.js @@ -46,7 +46,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexpo \*************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { -eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.setupListDragZone = exports.setupDraggables = void 0;\nconst layout_1 = __webpack_require__(/*! ./layout */ \"./src/layout.js\");\nfunction setupDraggables(api) {\n const dragables = document.querySelectorAll('.task');\n const droppables = document.querySelectorAll('.swim-list');\n dragables.forEach((task) => (0, layout_1.addDragListeners)(task));\n droppables.forEach((zone) => setupListDragZone(api, zone));\n}\nexports.setupDraggables = setupDraggables;\nfunction setupListDragZone(api, zone) {\n zone.addEventListener('dragover', (e) => {\n e.preventDefault();\n const bottomTask = insertAboveTask(zone, e.clientY);\n const currentTask = document.querySelector('.is-dragging');\n const taskItem = api.getTaskFromID(currentTask.id);\n taskItem.setListID(zone.id);\n if (!bottomTask) {\n zone.appendChild(currentTask);\n }\n else {\n zone.insertBefore(currentTask, bottomTask);\n }\n });\n}\nexports.setupListDragZone = setupListDragZone;\nfunction insertAboveTask(zone, mouseY) {\n // Grab all tasks that aren't currently being dragged\n const els = zone.querySelectorAll('.task:not(.is-dragging)');\n let closestTask = null;\n let closestOffset = Number.NEGATIVE_INFINITY;\n els.forEach((task) => {\n const { top } = task.getBoundingClientRect();\n const offset = mouseY - top;\n if (offset < 0 && offset > closestOffset) {\n closestOffset = offset;\n closestTask = task;\n }\n });\n return closestTask;\n}\n\n\n//# sourceURL=webpack://kanban-board/./src/dragging.js?"); +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.setupListDragZone = exports.setupDraggables = void 0;\nconst layout_1 = __webpack_require__(/*! ./layout */ \"./src/layout.js\");\nfunction setupDraggables(api) {\n const dragables = document.querySelectorAll('.task');\n const droppables = document.querySelectorAll('.list-content');\n dragables.forEach((task) => (0, layout_1.addDragListeners)(task));\n droppables.forEach((zone) => setupListDragZone(api, zone));\n}\nexports.setupDraggables = setupDraggables;\nfunction setupListDragZone(api, zone) {\n zone.addEventListener('dragover', (e) => {\n e.preventDefault();\n const bottomTask = insertAboveTask(zone, e.clientY);\n const currentTask = document.querySelector('.is-dragging');\n const taskItem = api.getTaskFromID(currentTask.id);\n taskItem.setListID(zone.getAttribute('value'));\n if (!bottomTask) {\n zone.appendChild(currentTask);\n }\n else {\n zone.insertBefore(currentTask, bottomTask);\n }\n });\n}\nexports.setupListDragZone = setupListDragZone;\nfunction insertAboveTask(zone, mouseY) {\n // Grab all tasks that aren't currently being dragged\n const els = zone.querySelectorAll('.task:not(.is-dragging)');\n let closestTask = null;\n let closestOffset = Number.NEGATIVE_INFINITY;\n els.forEach((task) => {\n const { top } = task.getBoundingClientRect();\n const offset = mouseY - top;\n if (offset < 0 && offset > closestOffset) {\n closestOffset = offset;\n closestTask = task;\n }\n });\n return closestTask;\n}\n\n\n//# sourceURL=webpack://kanban-board/./src/dragging.js?"); /***/ }), @@ -56,7 +56,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexpo \**********************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { -eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst api_1 = __webpack_require__(/*! ./api */ \"./src/api.js\");\nconst dragging_1 = __webpack_require__(/*! ./dragging */ \"./src/dragging.js\");\nconst layout_1 = __webpack_require__(/*! ./layout */ \"./src/layout.js\");\n// 30 seconds\nconst serialiseInterval = 10 * 1000;\nfunction main() {\n const api = new api_1.API();\n api.tryLoadFromLocalStorage();\n setInterval(() => api.serializeToLocalStorage(), serialiseInterval);\n (0, layout_1.setupAddTask)(api);\n (0, layout_1.setupListAddButton)(api);\n (0, dragging_1.setupDraggables)(api);\n (0, layout_1.setupErrorModalLayout)();\n (0, layout_1.setupModalLayout)();\n}\nwindow.addEventListener('load', main);\n\n\n//# sourceURL=webpack://kanban-board/./src/index.js?"); +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst api_1 = __webpack_require__(/*! ./api */ \"./src/api.js\");\nconst dragging_1 = __webpack_require__(/*! ./dragging */ \"./src/dragging.js\");\nconst layout_1 = __webpack_require__(/*! ./layout */ \"./src/layout.js\");\n// 30 seconds\nconst serialiseInterval = 30 * 1000;\nfunction main() {\n const api = new api_1.API();\n api.tryLoadFromLocalStorage();\n setInterval(() => api.serializeToLocalStorage(), serialiseInterval);\n (0, layout_1.setupAddTask)(api);\n (0, layout_1.setupListAddButton)(api);\n (0, dragging_1.setupDraggables)(api);\n (0, layout_1.setupErrorModalLayout)();\n (0, layout_1.setupModalLayout)();\n}\nwindow.addEventListener('load', main);\n\n\n//# sourceURL=webpack://kanban-board/./src/index.js?"); /***/ }), @@ -66,7 +66,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\ncons \***********************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { -eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.generateElementsForLoadedData = exports.setupNewTaskModalFields = exports.setupAddTask = exports.showErrorModal = exports.addDragListeners = exports.setupModalLayout = exports.setupErrorModalLayout = exports.setupListAddButton = void 0;\nconst api_1 = __webpack_require__(/*! ./api */ \"./src/api.js\");\nconst dragging_1 = __webpack_require__(/*! ./dragging */ \"./src/dragging.js\");\nconst task_1 = __webpack_require__(/*! ./task */ \"./src/task.js\");\nfunction setupListAddButton(api) {\n const btn = document.querySelector('#list-add-btn');\n btn.onclick = () => {\n const listDiv = document.querySelector('#task-lists');\n const listEl = createDefaultList(api);\n if (!listEl) {\n showErrorModal('Cannot create default list, as one already exists.');\n return;\n }\n listDiv.insertBefore(listEl, listDiv.children[listDiv.children.length - 1]);\n };\n}\nexports.setupListAddButton = setupListAddButton;\nfunction setupErrorModalLayout() {\n const modal = document.querySelector('#error-modal');\n const close = document.querySelector('#error-modal-close');\n close.onclick = function (e) {\n e.preventDefault();\n modal.style.display = 'none';\n };\n}\nexports.setupErrorModalLayout = setupErrorModalLayout;\nfunction setupModalLayout() {\n // Get the modal\n const modal = document.querySelector('#modal');\n const modalHeader = document.querySelector('#modal-header');\n // Get the element that closes the modal\n const span = document.querySelector('#close');\n const colorSelected = document.querySelector('#color-selected');\n const firstStyle = colorSelected.options[0].style;\n colorSelected.value = firstStyle.backgroundColor;\n colorSelected.style.background = firstStyle.backgroundColor;\n // When the user clicks on (x), close the modal\n span.onclick = function () {\n modal.style.display = 'none';\n };\n colorSelected.onchange = function () {\n let color = colorSelected.options[colorSelected.selectedIndex].style.backgroundColor;\n colorSelected.style.backgroundColor = color;\n modalHeader.style.backgroundColor = color;\n };\n}\nexports.setupModalLayout = setupModalLayout;\nfunction addDragListeners(el) {\n el.addEventListener('dragstart', () => {\n el.classList.add('is-dragging');\n });\n el.addEventListener('dragend', () => {\n el.classList.remove('is-dragging');\n });\n}\nexports.addDragListeners = addDragListeners;\nfunction showErrorModal(message) {\n const errorModal = document.querySelector('#error-modal');\n const modalText = document.querySelector('#error-modal-text');\n modalText.innerText = message;\n errorModal.style.display = 'block';\n}\nexports.showErrorModal = showErrorModal;\nfunction setupAddTask(api) {\n const form = document.querySelector('#add-task-btn');\n form.onclick = (e) => {\n e.preventDefault();\n const lists = document.querySelectorAll('.swim-list');\n if (lists.length === 0) {\n showErrorModal('No lists available to add a task.');\n return;\n }\n const modal = document.querySelector('#modal');\n modal.style.display = 'block';\n setupNewTaskModalFields(api);\n };\n}\nexports.setupAddTask = setupAddTask;\nfunction setupNewTaskModalFields(api) {\n const modal = document.querySelector('#modal');\n const modalHeader = document.querySelector('#modal-header');\n const createdOn = document.querySelector('#created-on');\n const taskTitle = document.querySelector('#task-title');\n const taskDesc = document.querySelector('#task-desc');\n const saveBtn = document.querySelector('#modal-save-btn');\n const tagKind = document.querySelector('#kind-option');\n tagKind.value = 'prg';\n const dueDate = document.querySelector('#due-date');\n dueDate.valueAsDate = null;\n const colorSelected = document.querySelector('#color-selected');\n const firstStyle = colorSelected.options[0].style;\n colorSelected.value = firstStyle.backgroundColor;\n colorSelected.style.background = firstStyle.backgroundColor;\n modalHeader.style.backgroundColor = colorSelected.value;\n const taskTitleText = `Task Title #${api.CurrentTaskIndex + 1}`;\n taskTitle.value = taskTitleText;\n taskDesc.value = '';\n const date = new Date();\n modal.style.display = 'block';\n createdOn.innerText = `Created on ${date.toDateString()}`;\n saveBtn.onclick = () => {\n if (taskTitle.value === taskTitleText) {\n showErrorModal('Invalid title name.');\n return;\n }\n // Add to todo list\n const list = document.querySelectorAll('.swim-list')[0];\n const taskEl = createTaskItemElement(api, taskTitle.value, api.CurrentTaskIndex);\n list.appendChild(taskEl);\n const tagKind = document.querySelector('#kind-option');\n const dueDate = document.querySelector('#due-date');\n const colorSelected = document.querySelector('#color-selected');\n api.addNewTask(date, list.id, taskTitle.value, (0, task_1.tagStrToKind)(tagKind.value), dueDate.valueAsDate, colorSelected.style.background, taskDesc.value);\n // Hide modal\n modal.style.display = 'none';\n };\n}\nexports.setupNewTaskModalFields = setupNewTaskModalFields;\nfunction generateElementsForLoadedData(api) {\n const listDiv = document.querySelector('#task-lists');\n // Generate all list elements\n api.TaskLists.forEach((list) => {\n const listEl = createListWithName(api, list.Identifier);\n listDiv.insertBefore(listEl, listDiv.children[listDiv.children.length - 1]);\n });\n // Generate all task elements\n api.Tasks.forEach((task) => {\n const list = document.querySelector(`#${task.ListID}`);\n list.appendChild(createTaskItemElement(api, task.Title, task.ID));\n });\n}\nexports.generateElementsForLoadedData = generateElementsForLoadedData;\nfunction populateTaskModalFields(api, taskID) {\n const task = api.getTaskFromID(taskID);\n const modal = document.querySelector('#modal');\n const modalHeader = document.querySelector('#modal-header');\n const createdOn = document.querySelector('#created-on');\n const taskTitle = document.querySelector('#task-title');\n const saveBtn = document.querySelector('#modal-save-btn');\n const taskDesc = document.querySelector('#task-desc');\n const tagKind = document.querySelector('#kind-option');\n const dueDate = document.querySelector('#due-date-option');\n const colorSelected = document.querySelector('#color-selected');\n const taskTitleText = task.Title;\n taskTitle.value = taskTitleText;\n taskDesc.value = task.Description;\n createdOn.innerText = `Created on ${task.CreatedAt.toDateString()}`;\n tagKind.value = (0, task_1.tagKindToStr)(task.Tag);\n dueDate.valueAsDate = task.DueDate;\n modalHeader.style.background = task.Color;\n colorSelected.value = task.Color;\n colorSelected.style.background = task.Color;\n saveBtn.onclick = () => {\n task.applyFields(taskTitle.value, (0, task_1.tagStrToKind)(tagKind.value), dueDate.valueAsDate, colorSelected.style.background, taskDesc.value);\n // Hide modal\n modal.style.display = 'none';\n };\n // Show modal\n modal.style.display = 'block';\n}\nfunction createTaskItemElement(api, taskTitle, index) {\n /**\n *
\n

Get Groceries

\n \n
\n */\n const taskID = `task-id-${index}`;\n const newTask = document.createElement('div');\n newTask.className = 'task';\n newTask.id = taskID;\n newTask.setAttribute('draggable', 'true');\n const taskTitleEl = document.createElement('p');\n newTask.appendChild(taskTitleEl);\n taskTitleEl.className = 'task-title';\n taskTitleEl.innerText = taskTitle;\n const innerBtn = document.createElement('button');\n newTask.appendChild(innerBtn);\n innerBtn.className = 'task-edit';\n innerBtn.innerText = '...';\n innerBtn.onclick = () => populateTaskModalFields(api, taskID);\n addDragListeners(newTask);\n return newTask;\n}\nfunction createDefaultList(api) {\n if (!api.tryAddNewList()) {\n return null;\n }\n return createListWithName(api, 'New List');\n}\nfunction createListWithName(api, title) {\n /**\n *
\n TODO\n
\n */\n const el = document.createElement('div');\n el.className = 'swim-list';\n el.id = (0, api_1.listNameToID)(title);\n const header = document.createElement('div');\n el.appendChild(header);\n header.className = 'list-heading-inner-text';\n const headerTitle = document.createElement('input');\n header.appendChild(headerTitle);\n headerTitle.className = 'list-heading-input';\n headerTitle.type = 'text';\n headerTitle.value = title;\n headerTitle.defaultValue = title;\n headerTitle.onchange = (e) => listHeaderChange(el, headerTitle, e, api);\n const deleteSpan = document.createElement('span');\n header.appendChild(deleteSpan);\n deleteSpan.className = 'list-delete-span';\n deleteSpan.innerText = '\\u{00D7}';\n deleteSpan.onclick = (e) => {\n e.preventDefault();\n if (el.children.length > 1) {\n showErrorModal('Cannot delete list that contains tasks.');\n return;\n }\n api.deleteTaskList(el.id);\n const listDiv = document.querySelector('#task-lists');\n listDiv.removeChild(el);\n };\n (0, dragging_1.setupListDragZone)(api, el);\n return el;\n}\nfunction listHeaderChange(el, self, e, api) {\n e.preventDefault();\n const newID = (0, api_1.listNameToID)(self.value);\n if (el.id === newID) {\n return;\n }\n if (api.taskListContains(self.value)) {\n showErrorModal(`Task list with name '${self.value}' already exists.`);\n self.value = self.defaultValue;\n return;\n }\n api.renameTaskList(self.defaultValue, self.value);\n self.defaultValue = self.value;\n el.id = newID;\n}\n\n\n//# sourceURL=webpack://kanban-board/./src/layout.js?"); +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.generateElementsForLoadedData = exports.setupNewTaskModalFields = exports.setupAddTask = exports.showErrorModal = exports.addDragListeners = exports.setupModalLayout = exports.setupErrorModalLayout = exports.setupListAddButton = void 0;\nconst api_1 = __webpack_require__(/*! ./api */ \"./src/api.js\");\nconst dragging_1 = __webpack_require__(/*! ./dragging */ \"./src/dragging.js\");\nconst task_1 = __webpack_require__(/*! ./task */ \"./src/task.js\");\nfunction setupListAddButton(api) {\n const btn = document.querySelector('#list-add-btn');\n btn.onclick = () => {\n const listDiv = document.querySelector('#task-lists');\n const listEl = createDefaultList(api);\n if (!listEl) {\n showErrorModal('Cannot create default list, as one already exists.');\n return;\n }\n listDiv.insertBefore(listEl, listDiv.children[listDiv.children.length - 1]);\n };\n}\nexports.setupListAddButton = setupListAddButton;\nfunction setupErrorModalLayout() {\n const modal = document.querySelector('#error-modal');\n const close = document.querySelector('#error-modal-close');\n close.onclick = function (e) {\n e.preventDefault();\n modal.style.display = 'none';\n };\n}\nexports.setupErrorModalLayout = setupErrorModalLayout;\nfunction setupModalLayout() {\n // Get the modal\n const modal = document.querySelector('#modal');\n const modalHeader = document.querySelector('#modal-header');\n // Get the element that closes the modal\n const span = document.querySelector('#close');\n const colorSelected = document.querySelector('#color-selected');\n const firstStyle = colorSelected.options[0].style;\n colorSelected.value = firstStyle.backgroundColor;\n colorSelected.style.background = firstStyle.backgroundColor;\n // When the user clicks on (x), close the modal\n span.onclick = function () {\n modal.style.display = 'none';\n };\n colorSelected.onchange = function () {\n let color = colorSelected.options[colorSelected.selectedIndex].style.backgroundColor;\n colorSelected.style.backgroundColor = color;\n modalHeader.style.backgroundColor = color;\n };\n}\nexports.setupModalLayout = setupModalLayout;\nfunction addDragListeners(el) {\n el.addEventListener('dragstart', () => {\n el.classList.add('is-dragging');\n });\n el.addEventListener('dragend', () => {\n el.classList.remove('is-dragging');\n });\n}\nexports.addDragListeners = addDragListeners;\nfunction showErrorModal(message) {\n const errorModal = document.querySelector('#error-modal');\n const modalText = document.querySelector('#error-modal-text');\n modalText.innerText = message;\n errorModal.style.display = 'block';\n}\nexports.showErrorModal = showErrorModal;\nfunction setupAddTask(api) {\n const form = document.querySelector('#add-task-btn');\n form.onclick = (e) => {\n e.preventDefault();\n const lists = document.querySelectorAll('.swim-list');\n if (lists.length === 0) {\n showErrorModal('No lists available to add a task.');\n return;\n }\n const modal = document.querySelector('#modal');\n modal.style.display = 'block';\n setupNewTaskModalFields(api);\n };\n}\nexports.setupAddTask = setupAddTask;\nfunction setupNewTaskModalFields(api) {\n const modal = document.querySelector('#modal');\n const modalHeader = document.querySelector('#modal-header');\n const createdOn = document.querySelector('#created-on');\n const taskTitle = document.querySelector('#task-title');\n const taskDesc = document.querySelector('#task-desc');\n const saveBtn = document.querySelector('#modal-save-btn');\n const tagKind = document.querySelector('#kind-option');\n tagKind.value = 'prg';\n const dueDate = document.querySelector('#due-date');\n dueDate.valueAsDate = null;\n const colorSelected = document.querySelector('#color-selected');\n const firstStyle = colorSelected.options[0].style;\n colorSelected.value = firstStyle.backgroundColor;\n colorSelected.style.background = firstStyle.backgroundColor;\n modalHeader.style.backgroundColor = colorSelected.value;\n const taskTitleText = `Task Title #${api.CurrentTaskIndex + 1}`;\n taskTitle.value = taskTitleText;\n taskDesc.value = '';\n const date = new Date();\n modal.style.display = 'block';\n createdOn.innerText = `Created on ${date.toDateString()}`;\n saveBtn.onclick = () => {\n if (taskTitle.value === taskTitleText) {\n showErrorModal('Invalid title name.');\n return;\n }\n // Add to todo list\n const firstList = document.querySelectorAll('.swim-list')[0];\n const listContent = firstList.querySelector('.list-content');\n const taskEl = createTaskItemElement(api, taskTitle.value, api.CurrentTaskIndex);\n listContent.appendChild(taskEl);\n const tagKind = document.querySelector('#kind-option');\n const dueDate = document.querySelector('#due-date');\n const colorSelected = document.querySelector('#color-selected');\n api.addNewTask(date, firstList.id, taskTitle.value, (0, task_1.tagStrToKind)(tagKind.value), dueDate.valueAsDate, colorSelected.style.background, taskDesc.value);\n // Hide modal\n modal.style.display = 'none';\n };\n}\nexports.setupNewTaskModalFields = setupNewTaskModalFields;\nfunction generateElementsForLoadedData(api) {\n const listDiv = document.querySelector('#task-lists');\n // Generate all list elements\n api.TaskLists.forEach((list) => {\n const listEl = createListWithName(api, list.Identifier);\n listDiv.insertBefore(listEl, listDiv.children[listDiv.children.length - 1]);\n });\n // Generate all task elements\n api.Tasks.forEach((task) => {\n console.log(task);\n console.log(`Loading '${task.ListID}'`);\n const list = document.querySelector(`#${task.ListID}`);\n const content = list.querySelector('.list-content');\n content.appendChild(createTaskItemElement(api, task.Title, task.ID));\n });\n}\nexports.generateElementsForLoadedData = generateElementsForLoadedData;\nfunction populateTaskModalFields(api, taskID) {\n const task = api.getTaskFromID(taskID);\n const modal = document.querySelector('#modal');\n const modalHeader = document.querySelector('#modal-header');\n const createdOn = document.querySelector('#created-on');\n const taskTitle = document.querySelector('#task-title');\n const saveBtn = document.querySelector('#modal-save-btn');\n const taskDesc = document.querySelector('#task-desc');\n const tagKind = document.querySelector('#kind-option');\n const dueDate = document.querySelector('#due-date-option');\n const colorSelected = document.querySelector('#color-selected');\n const taskTitleText = task.Title;\n taskTitle.value = taskTitleText;\n taskDesc.value = task.Description;\n createdOn.innerText = `Created on ${task.CreatedAt.toDateString()}`;\n tagKind.value = (0, task_1.tagKindToStr)(task.Tag);\n dueDate.valueAsDate = task.DueDate;\n modalHeader.style.background = task.Color;\n colorSelected.value = task.Color;\n colorSelected.style.background = task.Color;\n saveBtn.onclick = () => {\n task.applyFields(taskTitle.value, (0, task_1.tagStrToKind)(tagKind.value), dueDate.valueAsDate, colorSelected.style.background, taskDesc.value);\n // Hide modal\n modal.style.display = 'none';\n };\n // Show modal\n modal.style.display = 'block';\n}\nfunction createTaskItemElement(api, taskTitle, index) {\n /**\n *
\n

Get Groceries

\n \n
\n */\n const taskID = `task-id-${index}`;\n const newTask = document.createElement('div');\n newTask.className = 'task';\n newTask.id = taskID;\n newTask.setAttribute('draggable', 'true');\n const taskTitleEl = document.createElement('p');\n newTask.appendChild(taskTitleEl);\n taskTitleEl.className = 'task-title';\n taskTitleEl.innerText = taskTitle;\n const innerBtn = document.createElement('button');\n newTask.appendChild(innerBtn);\n innerBtn.className = 'task-edit';\n innerBtn.innerText = '...';\n innerBtn.onclick = () => populateTaskModalFields(api, taskID);\n addDragListeners(newTask);\n return newTask;\n}\nfunction createDefaultList(api) {\n if (!api.tryAddNewList()) {\n return null;\n }\n return createListWithName(api, 'New List');\n}\nfunction createListWithName(api, title) {\n /**\n *
\n TODO\n
\n */\n const listID = (0, api_1.listNameToID)(title);\n const el = document.createElement('div');\n el.className = 'swim-list';\n el.id = listID;\n const header = document.createElement('div');\n el.appendChild(header);\n header.className = 'list-heading-inner-text';\n const headerTitle = document.createElement('input');\n header.appendChild(headerTitle);\n headerTitle.className = 'list-heading-input';\n headerTitle.type = 'text';\n headerTitle.value = title;\n headerTitle.defaultValue = title;\n headerTitle.onchange = (e) => listHeaderChange(el, headerTitle, e, api);\n const deleteSpan = document.createElement('span');\n header.appendChild(deleteSpan);\n deleteSpan.className = 'list-delete-span';\n deleteSpan.innerText = '\\u{00D7}';\n deleteSpan.onclick = (e) => {\n e.preventDefault();\n if (el.children.length > 1) {\n showErrorModal('Cannot delete list that contains tasks.');\n return;\n }\n api.deleteTaskList(listID);\n const listDiv = document.querySelector('#task-lists');\n listDiv.removeChild(el);\n };\n const listContentZone = document.createElement('div');\n el.appendChild(listContentZone);\n listContentZone.setAttribute('value', listID);\n listContentZone.className = 'list-content';\n (0, dragging_1.setupListDragZone)(api, listContentZone);\n return el;\n}\nfunction listHeaderChange(el, self, e, api) {\n e.preventDefault();\n const newID = (0, api_1.listNameToID)(self.value);\n if (el.id === newID) {\n return;\n }\n if (api.taskListContains(self.value)) {\n showErrorModal(`Task list with name '${self.value}' already exists.`);\n self.value = self.defaultValue;\n return;\n }\n const content = el.querySelector('.list-content');\n content.setAttribute('value', newID);\n api.renameTaskList(self.defaultValue, self.value);\n self.defaultValue = self.value;\n el.id = newID;\n}\n\n\n//# sourceURL=webpack://kanban-board/./src/layout.js?"); /***/ }), diff --git a/style.css b/style.css index fadc719..b65be6c 100644 --- a/style.css +++ b/style.css @@ -16,7 +16,7 @@ .board { width: 100%; height: 100vh; - overflow: scroll; + overflow: hidden; background-image: url(https://images.unsplash.com/photo-1696332331308-8a064129a487?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1740&q=80); background-position: center; @@ -52,8 +52,7 @@ padding: 24px 32px; - overflow: scroll; - height: 100%; + overflow: hidden; } .list-heading-text { @@ -115,11 +114,18 @@ padding: 12px; border-radius: 4px; width: 225px; - min-height: 120px; + min-height: 100px; + max-height: 80vh; flex-shrink: 0; } +.list-content { + min-height: 48px; + height: 100%; + overflow-y: scroll; +} + #list-add-btn { border: none; border-radius: 4px; @@ -128,15 +134,17 @@ } #list-add-btn:hover { - box-shadow: 0px 5px 15px inset rgba(0, 0, 0, 0.15); + box-shadow: 0px 5px 15px inset rgba(0, 0, 0, 0.05); + cursor: pointer; } .task { display: flex; background: white; - box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15); + box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.1); padding: 12px; + margin: 0 4px 10px 4px; border-radius: 4px; cursor: move; @@ -154,7 +162,6 @@ .task .task-edit { border: none; - padding: 4px; margin: 0 8px; background: transparent; } @@ -162,12 +169,14 @@ .task .task-edit:hover { background-color: rgb(241, 241, 241); border: 1px solid rgb(241, 241, 241); - border-radius: 14px; + border-radius: 16px; + + cursor: pointer; } .is-dragging { scale: 1.05; - box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.25); + box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15); background: rgb(50, 50, 50); color: white; } diff --git a/ts-src/dragging.ts b/ts-src/dragging.ts index 4fd4f14..cfb09c8 100644 --- a/ts-src/dragging.ts +++ b/ts-src/dragging.ts @@ -3,7 +3,7 @@ import { addDragListeners } from './layout'; export function setupDraggables(api: API) { const dragables = document.querySelectorAll('.task') as NodeListOf; - const droppables = document.querySelectorAll('.swim-list') as NodeListOf; + const droppables = document.querySelectorAll('.list-content') as NodeListOf; dragables.forEach((task) => addDragListeners(task)); droppables.forEach((zone) => setupListDragZone(api, zone)); @@ -17,7 +17,7 @@ export function setupListDragZone(api: API, zone: HTMLElement) { const currentTask = document.querySelector('.is-dragging') as HTMLElement; const taskItem = api.getTaskFromID(currentTask.id); - taskItem.setListID(zone.id); + taskItem.setListID(zone.getAttribute('value')!); if (!bottomTask) { zone.appendChild(currentTask); diff --git a/ts-src/layout.ts b/ts-src/layout.ts index 62a4faa..f1bc4e0 100644 --- a/ts-src/layout.ts +++ b/ts-src/layout.ts @@ -122,9 +122,11 @@ export function setupNewTaskModalFields(api: API) { } // Add to todo list - const list = (document.querySelectorAll('.swim-list') as NodeListOf)[0]; + const firstList = (document.querySelectorAll('.swim-list') as NodeListOf)[0]; + const listContent = firstList.querySelector('.list-content') as HTMLDivElement; + const taskEl = createTaskItemElement(api, taskTitle.value, api.CurrentTaskIndex); - list.appendChild(taskEl); + listContent.appendChild(taskEl); const tagKind = document.querySelector('#kind-option') as HTMLSelectElement; const dueDate = document.querySelector('#due-date') as HTMLInputElement; @@ -132,7 +134,7 @@ export function setupNewTaskModalFields(api: API) { api.addNewTask( date, - list.id, + firstList.id, taskTitle.value, tagStrToKind(tagKind.value), dueDate.valueAsDate, @@ -156,8 +158,12 @@ export function generateElementsForLoadedData(api: API) { // Generate all task elements api.Tasks.forEach((task) => { + console.log(task); + + console.log(`Loading '${task.ListID}'`); const list = document.querySelector(`#${task.ListID}`) as HTMLDivElement; - list.appendChild(createTaskItemElement(api, task.Title, task.ID)); + const content = list.querySelector('.list-content') as HTMLDivElement; + content.appendChild(createTaskItemElement(api, task.Title, task.ID)); }); } @@ -248,9 +254,11 @@ function createListWithName(api: API, title: string): HTMLElement { TODO */ + const listID = listNameToID(title); + const el = document.createElement('div') as HTMLDivElement; el.className = 'swim-list'; - el.id = listNameToID(title); + el.id = listID; const header = document.createElement('div') as HTMLDivElement; el.appendChild(header); @@ -279,13 +287,19 @@ function createListWithName(api: API, title: string): HTMLElement { return; } - api.deleteTaskList(el.id); + api.deleteTaskList(listID); const listDiv = document.querySelector('#task-lists') as HTMLDivElement; listDiv.removeChild(el); }; - setupListDragZone(api, el); + const listContentZone = document.createElement('div') as HTMLDivElement; + el.appendChild(listContentZone); + + listContentZone.setAttribute('value', listID); + listContentZone.className = 'list-content'; + + setupListDragZone(api, listContentZone); return el; } @@ -304,6 +318,9 @@ function listHeaderChange(el: HTMLElement, self: HTMLInputElement, e: Event, api return; } + const content = el.querySelector('.list-content') as HTMLElement; + content.setAttribute('value', newID); + api.renameTaskList(self.defaultValue, self.value); self.defaultValue = self.value; el.id = newID;