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 */\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 */\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;