diff options
Diffstat (limited to 'assets')
-rw-r--r-- | assets/css/app.css | 540 | ||||
-rw-r--r-- | assets/js/board.js | 197 |
2 files changed, 737 insertions, 0 deletions
diff --git a/assets/css/app.css b/assets/css/app.css new file mode 100644 index 00000000..2e3e6987 --- /dev/null +++ b/assets/css/app.css @@ -0,0 +1,540 @@ +/* reset */ +figure, +li, +ul, +ol, +table, +tr, +td, +th, +p, +blockquote, +body { + margin: 0; + padding: 0; + font-size: 100%; +} + +/* layout */ +body { + max-width: 1500px; + margin-left: 10px; + margin-right: 10px; + color: #333; + font-family: HelveticaNeue, "Helvetica Neue", Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +/* links */ +a { + color: #3366CC; + border: 1px solid rgba(255, 255, 255, 0); +} + +a:focus { + outline: 0; + color: red; + text-decoration: none; + border: 1px dotted #aaa; +} + +a:hover { + color: #333; + text-decoration: none; +} + +/* titles */ +h1, h2, h3 { + font-weight: normal; + color: #333; +} + +h2 { + font-size: 1.6em; +} + +h3 { + margin-top: 10px; + font-size: 1.2em; +} + +/* tables */ +table { + width: 100%; + border-collapse: collapse; + border-spacing: 0; +} + +table caption { + font-weight: bold; + font-size: 1.0em; + text-align: left; + padding-bottom: 0.5em; + padding-top: 0.5em; +} + +th, +td { + border: 1px solid #ccc; + padding-top: 0.5em; + padding-bottom: 0.5em; + padding-left: 5px; +} + +th { + text-align: left; + background: #f0f0f0; +} + +tr:nth-child(odd) td { + background: #fcfcfc; +} + +td li { + margin-left: 20px; +} + +/* forms */ +form { + padding-top: 5px; + padding-bottom: 5px; + padding-left: 15px; + margin-bottom: 20px; + border-left: 2px dotted #ddd; +} + +label { + cursor: pointer; + display: block; + margin-top: 10px; +} + +input[type="checkbox"] { + border: 1px solid #ccc; +} + +input[type="date"], +input[type="email"], +input[type="tel"], +input[type="password"], +input[type="text"] { + border: 1px solid #ccc; + padding: 3px; + line-height: 15px; + width: 400px; + font-size: 99%; + margin-top: 5px; + -webkit-appearance: none; + appearance: none; +} + +input[type="date"]:focus, +input[type="email"]:focus, +input[type="tel"]:focus, +input[type="password"]:focus, +input[type="text"]:focus, +textarea:focus { + color: #000; + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + box-shadow: 0 0 8px rgba(82, 168, 236, 0.6); +} + +textarea { + border: 1px solid #ccc; + padding: 3px; + width: 400px; + height: 200px; + font-size: 99%; +} + +select { +} + +::-webkit-input-placeholder { + color: #bbb; + padding-top: 2px; +} + +::-ms-input-placeholder { + color: #bbb; + padding-top: 2px; +} + +::-moz-placeholder { + color: #bbb; + padding-top: 2px; +} + +.form-actions { + margin-top: 20px; +} + +input.form-error, +textarea.form-error { + border: 2px solid #b94a48; +} + +.form-errors { + color: #b94a48; + list-style-type: none; +} + +.form-help { + font-size: 0.9em; + color: brown; + margin-bottom: 15px; +} + +.form-inline { + padding: 0; + margin: 0; + border: none; +} + +.form-inline label { + display: inline; +} + +.form-inline input, +.form-inline select { + margin: 0; + margin-right: 15px; +} + +/* alerts */ +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + color: #c09853; + background-color: #fcf8e3; + border: 1px solid #fbeed5; + border-radius: 4px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-normal { + color: #333; + background-color: #f0f0f0; + border-color: #ddd; +} + +/* labels */ +a.label { + text-decoration: none; +} + +a.label:hover, +a.label:focus { + text-decoration: underline; +} + +.label { + font-size: 0.9em; + border-radius: 5px 5px 5px 5px; + border: 1px solid #000; + border-color: rgba(0, 0, 0, 0.3); + background: #fff; + color: #000; + color: rgba(0, 0, 0, 0.8); + display: inline-block; + padding: 2px 5px; + vertical-align: top; + overflow: hidden; + text-overflow: ellipsis; +} + +.label-yellow { + background-color: #ffee92; +} + +.label-red { + background-color: #eea2a0; +} + +.label-green { + background-color: #b3e494; +} + +.label-blue { + background-color: #d5eeff; +} + +.label-purple { + background-color: #dca9de; +} + +/* buttons */ +.btn { + -webkit-appearance: none; + appearance: none; + display: inline-block; + color: #333; + border: 1px solid #ccc; + background: #efefef; + padding: 5px; + padding-left: 15px; + padding-right: 15px; + font-size: 0.9em; + cursor: pointer; + border-radius: 2px; +} + +.btn-small { + padding: 2px; + padding-left: 5px; + padding-right: 5px; +} + +a.btn { + text-decoration: none; + font-weight: bold; +} + +.btn-red { + border-color: #b0281a;; + background: #d14836; + color: #fff; +} + +a.btn-red:hover, +.btn-red:hover, +.btn-red:focus { + color: #fff; + background: #c53727; +} + +.btn-blue { + border-color: #3079ed; + background: #4d90fe; + color: #fff; +} + +.btn-blue:hover, +.btn-blue:focus { + border-color: #2f5bb7; + background: #357ae8; +} + +/* header */ +header { + margin-bottom: 25px; + margin-top: 10px; +} + +header ul { + text-align: right; + font-size: 90%; +} + +header li { + display: inline; + padding-left: 30px; +} + +header a { + color: #777; + text-decoration: none; +} + +nav .active a { + color: #333; + font-weight: bold; +} + +.logo { + color: #DF5353; + letter-spacing: 1px; + float: left; +} + +.page-section { + margin-top: 30px; +} + +.page-section, +.page-header { + margin-bottom: 25px; +} + +.page-section h2, +.page-header h2 { + margin: 0; + padding: 0; + font-size: 140%; + border-bottom: 1px dotted red; +} + +.page-header ul { + text-align: left; + margin-top: 5px; +} + +.page-header li { + display: inline; + padding-left: 10px; + padding-right: 10px; + border-left: 1px dotted #ccc; +} + +.page-header li:first-child { + border: none; + padding-left: 0; +} + +/* boards */ +#board th a { + text-decoration: none; + font-size: 150%; +} + +#board td { + vertical-align: top; +} + +.task-title { + margin-top: 10px; + font-size: 110%; +} + +.task-user { + font-size: 80%; +} + +.task-nobody { + font-style: italic; +} + +.task { + border: 1px solid #000; + padding: 5px; + font-size: 95%; +} + +td.over { + background-color: #f0f0f0; +} + +td div.over { + border: 2px dashed #000; +} + +.draggable-item { + margin-right: 5px; + margin-bottom: 10px; +} + +[draggable] { + user-select: none; +} + +[draggable=true]:hover { + box-shadow: 0 0 3px #333; +} + +div.task a { + color: #000; + text-decoration: none; + font-weight: bold; +} + +div.task a:focus, +div.task a:hover { + text-decoration: underline; +} + +article.task li { + margin-left: 20px; + list-style-type: square; +} + +.task-blue { + background-color: rgb(219, 235, 255); + border-color: rgb(168, 207, 255); +} + +.task-purple { + background-color: rgb(223, 176, 255); + border-color: rgb(205, 133, 254); +} + +.task-grey { + background-color: rgb(238, 238, 238); + border-color: rgb(204, 204, 204); +} + +.task-red { + background-color: rgb(255, 187, 187); + border-color: rgb(255, 151, 151); +} + +.task-green { + background-color: rgb(189, 244, 203); + border-color: rgb(74, 227, 113); +} + +.task-yellow { + background-color: rgb(245, 247, 196); + border-color: rgb(223, 227, 45); +} + +.task-orange { + background-color: rgb(255, 215, 179); + border-color: rgb(255, 172, 98); +} + +#description { + border-left: 5px solid #000; + background: #f0f0f0; + padding-left: 10px; + padding-top: 10px; + padding-bottom: 10px; +} + +#description li { + margin-left: 25px; +} + +/* config page */ +.settings { + border-radius: 4px; + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + border: 1px solid #ddd; + color: #333; + background-color: #f0f0f0; +} + +.settings li { + list-style-type: square; + margin-left: 20px; + margin-bottom: 3px; +} + +/* confirmation box */ +.confirm { + max-width: 700px; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 15px; + border-left: 2px dotted #ddd; +} diff --git a/assets/js/board.js b/assets/js/board.js new file mode 100644 index 00000000..a9bd35d1 --- /dev/null +++ b/assets/js/board.js @@ -0,0 +1,197 @@ +(function () { + + function handleItemDragStart(e) + { + this.style.opacity = '0.4'; + + dragSrcItem = this; + dragSrcColumn = this.parentNode; + + e.dataTransfer.effectAllowed = 'copy'; + e.dataTransfer.setData('text/plain', this.innerHTML); + } + + function handleItemDragEnd(e) + { + // Restore styles + removeOver(); + this.style.opacity = '1.0'; + + dragSrcColumn = null; + dragSrcItem = null; + } + + function handleItemDragOver(e) + { + if (e.preventDefault) e.preventDefault(); + + e.dataTransfer.dropEffect = 'copy'; + + return false; + } + + function handleItemDragEnter(e) + { + if (dragSrcItem != this) { + removeOver(); + this.classList.add('over'); + } + } + + function handleItemDrop(e) + { + if (e.preventDefault) e.preventDefault(); + if (e.stopPropagation) e.stopPropagation(); + + // Drop the element if the item is not the same + if (dragSrcItem != this) { + + var position = getItemPosition(this); + var item = createItem(e.dataTransfer.getData('text/plain')); + + if (countColumnItems(this.parentNode) == position) { + this.parentNode.appendChild(item); + } + else { + this.parentNode.insertBefore(item, this); + } + + dragSrcItem.parentNode.removeChild(dragSrcItem); + + saveBoard(); + } + + dragSrcColumn = null; + dragSrcItem = null; + + return false; + } + + + function handleColumnDragOver(e) + { + if (e.preventDefault) e.preventDefault(); + + e.dataTransfer.dropEffect = 'copy'; + + return false; + } + + function handleColumnDragEnter(e) + { + if (dragSrcColumn != this) { + removeOver(); + this.classList.add('over'); + } + } + + function handleColumnDrop(e) + { + if (e.preventDefault) e.preventDefault(); + if (e.stopPropagation) e.stopPropagation(); + + // Drop the element if the column is not the same + if (dragSrcColumn != this) { + + var item = createItem(e.dataTransfer.getData('text/plain')); + this.appendChild(item); + dragSrcColumn.removeChild(dragSrcItem); + + saveBoard(); + } + + return false; + } + + function saveBoard() + { + var data = []; + var projectId = document.getElementById("board").getAttribute("data-project-id"); + var cols = document.querySelectorAll('.column'); + + [].forEach.call(cols, function(col) { + + [].forEach.call(col.children, function(item) { + + data.push({ + "task_id": item.firstElementChild.getAttribute("data-task-id"), + "position": getItemPosition(item), + "column_id": col.getAttribute("data-column-id") + }) + }); + }); + + var xhr = new XMLHttpRequest(); + xhr.open("POST", "?controller=board&action=save&project_id=" + projectId, true); + xhr.send(JSON.stringify(data)); + } + + function getItemPosition(element) + { + var i = 0; + + while ((element = element.previousSibling) != null) { + + if (element.nodeName == "DIV" && element.className == "draggable-item") { + i++; + } + } + + return i + 1; + } + + function countColumnItems(element) + { + return element.children.length; + } + + function createItem(html) + { + var item = document.createElement("div"); + item.className = "draggable-item"; + item.draggable = true; + item.innerHTML = html; + item.ondragstart = handleItemDragStart; + item.ondragend = handleItemDragEnd; + item.ondragenter = handleItemDragEnter; + item.ondragover = handleItemDragOver; + item.ondrop = handleItemDrop; + + return item; + } + + function removeOver() + { + // Remove column over + [].forEach.call(document.querySelectorAll('.column'), function (col) { + col.classList.remove('over'); + }); + + // Remove item over + [].forEach.call(document.querySelectorAll('.draggable-item'), function (item) { + item.classList.remove('over'); + }); + } + + var dragSrcItem = null; + var dragSrcColumn = null; + + var items = document.querySelectorAll('.draggable-item'); + + [].forEach.call(items, function(item) { + item.addEventListener('dragstart', handleItemDragStart, false); + item.addEventListener('dragend', handleItemDragEnd, false); + item.addEventListener('dragenter', handleItemDragEnter, false); + item.addEventListener('dragover', handleItemDragOver, false); + item.addEventListener('drop', handleItemDrop, false); + }); + + var cols = document.querySelectorAll('.column'); + + [].forEach.call(cols, function(col) { + col.addEventListener('dragenter', handleColumnDragEnter, false); + col.addEventListener('dragover', handleColumnDragOver, false); + col.addEventListener('drop', handleColumnDrop, false); + }); + +}());
\ No newline at end of file |