From f57683c937bc1c93252012c0ec9c71c1118dd394 Mon Sep 17 00:00:00 2001 From: Hamza Nasher-Alneam Date: Tue, 25 Jun 2024 14:08:17 -0400 Subject: [PATCH] Show activity history with collapse options --- development/changelog.md | 0 development/todo.md | 6 +- index.html | 30 ++-- scripts/activities.js | 312 +++++++++++++++++++++++++++++++++++++++ scripts/initAndSave.js | 33 +++++ scripts/main.js | 276 ++-------------------------------- scripts/stats.js | 58 ++++---- styles/styles.css | 85 ++++++----- styles/tailwind.css | 41 +++++ 9 files changed, 506 insertions(+), 335 deletions(-) delete mode 100644 development/changelog.md create mode 100644 scripts/activities.js diff --git a/development/changelog.md b/development/changelog.md deleted file mode 100644 index e69de29..0000000 diff --git a/development/todo.md b/development/todo.md index 755c7ba..35f00ae 100644 --- a/development/todo.md +++ b/development/todo.md @@ -37,4 +37,8 @@ For activity log, which you will use today to log your activity, work on the web - create easy way to add time later (set start finish times, length) -- export settings with export, export completed with export \ No newline at end of file +- export settings with export, export completed with export +- add a uuid for each activity (same name different sessions)? +- save open page +- creating new task should take to main page +- add back finished to activities \ No newline at end of file diff --git a/index.html b/index.html index 8da7685..e5f486a 100644 --- a/index.html +++ b/index.html @@ -9,20 +9,21 @@ + Activity Log @@ -127,6 +130,7 @@

Collapse Options

- + + diff --git a/scripts/activities.js b/scripts/activities.js new file mode 100644 index 0000000..4727b0a --- /dev/null +++ b/scripts/activities.js @@ -0,0 +1,312 @@ +// ========================================== +// Creating activities +// ========================================== + +let activityLoop; + +// When entering tasks, to prevent passing in empty string (could do in html) +function textentered() { + if (document.querySelector(".newActivity").value !== "") + document.querySelector(".newActivityBtn").disabled = false; + else if (document.querySelector(".newActivity").value == "") + document.querySelector(".newActivityBtn").disabled = true; +} + +// On enter in input +document.querySelector(".newActivity").addEventListener("keyup", (event) => { + if (event.key === "Enter" && document.querySelector(".newActivity").value !== "") newActivity(); +}); + +// When you press the run again button in history - does this still work? +function restartActivity(activityName) { + setActivity({ + name: activityName, + time: 0, + paused: false, + start: new Date() + }); +} + +function newActivity() { + // Get name + let activityName = document.querySelector(".newActivity").value; + document.querySelector(".newActivity").value = ""; + document.querySelector(".newActivityBtn").disabled = true; + + setActivity({ + name: activityName, + time: 0, + paused: false, + start: new Date() + }); +} + + +// ========================================== +// Active activity creation and logic +// ========================================== + +// Create a new activity +function setActivity(data, bypassOverrideCheck) { + if (isActiveTask && !bypassOverrideCheck) { + if (!okayToOverrideTask()) return; + finishActivity(); + } + + // Set activtiy data + isActiveTask = true; + activeTask = data; + + activityRunningElement.classList.add("hidden"); + activeTaskElement.classList.remove("hidden"); + + document.querySelector(".activity-name").textContent = activeTask.name; + let timeDisplay = document.querySelector(".activity-counter"); + + + // Reset in case paused task is being reset + if (activeTask.paused) pauseButton.innerHTML = "play_arrow"; + timeDisplay.textContent = formatTimeAmount(activeTask.time, "yMwdhms", 1); + + // Handle pause/unpause + pauseButton.onclick = () => { + if (activeTask.paused) { + activeTask.paused = false; + pauseButton.innerHTML = "pause"; + } else { + activeTask.paused = true; + pauseButton.innerHTML = "play_arrow"; + } + saveActive(); + }; + + finishButton.onclick = finishActivity; + cancelButton.onclick = cancelActivity; + + let lastTime = new Date(); + activityLoop = setInterval(() => { + let now = new Date(); + if (!activeTask.paused) { + activeTask.time += now - lastTime; + timeDisplay.textContent = formatTimeAmount(activeTask.time, "yMwdhms", 1); + saveActive(); + } + lastTime = now; + }, 100); + + // Send to main page, for if they were on history + displayPage("main"); +} + +function cancelActivity() { + isActiveTask = false; + activeTask = {}; + clearInterval(activityLoop); + activityRunningElement.classList.remove("hidden"); + activeTaskElement.classList.add("hidden"); + saveActive(); +} + +function finishActivity() { + delete activeTask.pause; + activeTask.finish = Date.now(); + activities.push(activeTask) + cancelActivity(); + saveActive(); + saveActivites(); + addCompletedActivity(activities[activities.length - 1]); +} + +function okayToOverrideTask() { + let isSure = confirm("You already have an activity running. Do you want to finish it and start a new one instead?"); + if (isSure) return true; + return false; +} + + +// ========================================== +// Put completed activties into history and stats +// ========================================== + +// be careful with this, because it is used to move items to stats and history +// we will need to run this when a activity is completed as well +// activity is the full item +function addCompletedActivity(activity) { + let activityClassName = hash(activity.name); + + // If there is another element and collapsing is on + if (document.querySelector(`._${activityClassName}`) && settings.collapse !== "none") { + let existingElement = document.querySelector(`._${activityClassName}`); + // Long collapse - list all tasks + if (settings.collapse == "long") { + let subElement = document.createElement("div"); + let timerElement = document.createElement("span"); + let dateElement = document.createElement("span"); + + timerElement.classList.add("time"); + + timerElement.innerHTML = formatTimeAmount(activity.time, "yMwdhms", 1) + "
"; + dateElement.innerHTML = `Started ${at(activity.start)}
+ Finished ${at(activity.finish)}

`; + + subElement.appendChild(timerElement); + subElement.appendChild(dateElement); + existingElement.appendChild(subElement); + } + // Short collapse - group task data together + else if (settings.collapse = "short" && document.querySelector(`._short_${activityClassName}`) == null) { + document.querySelector(`._${activityClassName}`).firstChild.nextSibling.remove(); + document.querySelector(`._${activityClassName}`).firstChild.nextSibling.remove(); + + let element = document.createElement("div"); + let averageTimeElement = document.createElement("p"); + let totalTimeElement = document.createElement("p"); + let activityCountElement = document.createElement("p"); + + element.classList.add(`._short_${activityClassName}`); + + // Average time + avgActivityTime(); + let index = labels.indexOf(activity.name); + averageTimeElement.innerHTML = `
+ avg_time +

Average time: ${formatTimeAmount(Math.round(10 * getArrayAverage(data[index])) / 10)}

+
`; + // Total time + totalTimeElement.innerHTML = `
+ timer +

Total time: ${formatTimeAmount(getArraySum(data[index]))}

+
`; + + // Activity count + activityCountElement.innerHTML = `
+ numbers +

Activites: ${data[index].length}

+
`; + + element.append(averageTimeElement); + element.append(totalTimeElement); + element.append(activityCountElement); + document.querySelector(`._${activityClassName}`).append(element); + } + + return; + } + + + + + // If first of this activity name + let element = document.createElement("div"); + let nameElement = document.createElement("h4"); + let timerElement = document.createElement("span"); + let dateElement = document.createElement("span"); + let controlsElement = document.createElement("div"); + let rerunButton = document.createElement("span"); + + element.classList.add(`_${activityClassName}`, "activity"); + nameElement.textContent = activity.name; + timerElement.innerHTML = formatTimeAmount(activity.time, "yMwdhms", 1) + "
"; + timerElement.classList.add("time"); + dateElement.innerHTML = `Started ${at(activity.start)}
+ Finished ${at(activity.finish)}

`; + controlsElement.classList.add("controls"); + rerunButton.classList.add("control-button"); + rerunButton.classList.add(`ar${activities.indexOf(activity)}`); + rerunButton.innerHTML = "replay"; + + rerunButton.onclick = () => restartActivity(activity.name); + + element.appendChild(nameElement); + element.appendChild(timerElement); + element.appendChild(dateElement); + controlsElement.appendChild(rerunButton); + element.appendChild(controlsElement); + document.querySelector(".history-items").append(element); + + document.querySelector(".are-activities-completed").classList.add("hidden"); + + + function at(time) { + return formatTime(new Date(time), "12") + " on " + formatDate(new Date(time), "quick"); + } + + // code above is basically everthing from the else statement below + + + // // Checks if multiple elements of same task, then collapses + + // if (document.querySelector(`._${noSpaces(activityName)}`) && settings.collapse !== "none") { + // if (settings.collapse == "long") { + // let newww = document.createElement("DIV"); + // newww.innerHTML = `${formatTime(timer)}
+ // Started ${new Date(activities[activity][4]["start"]).toLocaleString()}
+ // Finished ${new Date(activities[activity][4]["finish"]).toLocaleString()}

`; + // document.querySelector(`._${noSpaces(activityName)}`).append(newww); + // } else if (settings.collapse == "short") { + // // If there isn't another summary + // if (document.querySelector(`._short_${noSpaces(activityName)}`) == null) { + // // Remove time for first activity + // document.querySelector(`._${noSpaces(activityName)}`).firstChild.nextSibling.remove(); + // // Parent container + // let element = document.createElement("DIV"); + // element.classList.add(`_short_${noSpaces(activityName)}`); + // // To get the labels and data + // avgActivityTime(); + // // Average time + // let taskAvg = document.createElement("P"); + // const average = (array) => array.reduce((a, b) => a + b) / array.length; + // // Find index of label, then find corresponding in data + // let thisIndex = labels.indexOf(activityName); + // taskAvg.innerHTML = `
avg_time

Average time: ${formatTime( + // Math.round(10 * average(data[thisIndex])) / 10 + // )}

`; + // // Total time + // let taskTotal = document.createElement("P"); + // const totalTime = (array) => array.reduce((part, a) => part + a, 0); + // taskTotal.innerHTML = `
timer

Total time: ${formatTime( + // totalTime(data[thisIndex]) + // )}

`; + // // Amount of activites + // let activityAmounts = document.createElement("P"); + // activityAmounts.innerHTML = `
numbers

Activites: ${data[thisIndex].length}

`; + // // Append items to block + // element.append(taskAvg); + // element.append(taskTotal); + // element.append(activityAmounts); + // document.querySelector(`._${noSpaces(activityName)}`).append(element); + // } + // } + // } + + + // else { + // document.querySelector(".history").append(element); + // element.classList.add(`_${noSpaces(activityName)}`); + + // // Remove old controls + // // Add new controls + // // Start again button + // let elRestart = document.createElement("SPAN"); + // elRestart.classList.add("continueActivity"); + // elRestart.classList.add(`ar${activities.indexOf(activity)}`); + // elRestart.innerHTML = + // "replay"; + // elRestart.onclick = () => restartActivity(activityName); + // controls.appendChild(elRestart); + + // // Set time if from save + // timeDisplay.textContent = formatTime(timer); + + // // Display start and end times + // timeDisplay.innerHTML = `${timeDisplay.textContent}
+ // Started ${new Date(activities[activity][4]["start"]).toLocaleString()}
+ // Finished ${new Date(activities[activity][4]["finish"]).toLocaleString()}

`; + // } +} + +function hash(string) { + return Math.abs(string.split('').reduce((hash, char) => { + return char.charCodeAt(0) + (hash << 6) + (hash << 16) - hash; + }, 0)); +} diff --git a/scripts/initAndSave.js b/scripts/initAndSave.js index 0b9a4ab..ebbee90 100644 --- a/scripts/initAndSave.js +++ b/scripts/initAndSave.js @@ -16,11 +16,44 @@ let labels = []; let data = []; function reinit() { + for (let i = 0; i < activities.length; i++) { + addCompletedActivity(activities[i]); + } // Select the right radio button // if (settings.collapse) document.querySelector(`#${settings.collapse}`).checked = true; } +// Get elements for activity management +let activeTaskElement = document.querySelector(".active-activity"); +let activityRunningElement = document.querySelector(".activityProgressing"); +let controlButtons = document.querySelector(".controls"); +let pauseButton = document.querySelector(".control-pause"); +let finishButton = document.querySelector(".control-finish"); +let cancelButton = document.querySelector(".control-cancel"); + + + + +// Save +function saveActive() { + localStorage.setItem("activityLogActiveSave", JSON.stringify({ + isActiveTask: isActiveTask, + activeTask: activeTask + })); +} + +function saveActivites() { + localStorage.setItem("activityLogSave", JSON.stringify(activities)); +} + +function saveSettings() { + localStorage.setItem( "activityLogSettingsSave", JSON.stringify(settings)); +} + + + +// Settings function clearSave() { if (confirm("Are you sure you want to delete your save?")) { activities = []; diff --git a/scripts/main.js b/scripts/main.js index 3e19f66..9067001 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -4,15 +4,7 @@ // Init and save // ========================================== -// Get elements for activity management -let activeTaskElement = document.querySelector(".active-activity"); -let activityRunningElement = document.querySelector(".activityProgressing"); -let controlButtons = document.querySelector(".controls"); -let pauseButton = document.querySelector(".control-pause"); -let finishButton = document.querySelector(".control-finish"); -let cancelButton = document.querySelector(".control-cancel"); -let activityLoop; - +// Check if there is a local save, if so read it if (localStorage.getItem("activityLogSave")) { activeSaveData = JSON.parse(localStorage.getItem("activityLogActiveSave")); activeTask = activeSaveData.activeTask; @@ -27,283 +19,41 @@ if (localStorage.getItem("activityLogSave")) { settings = settingsInit; } -function saveActive() { - localStorage.setItem("activityLogActiveSave", JSON.stringify({ - isActiveTask: isActiveTask, - activeTask: activeTask - })); -} - -function saveActivites() { - localStorage.setItem("activityLogSave", JSON.stringify(activities)); -} - -function saveSettings() { - localStorage.setItem( "activityLogSettingsSave", JSON.stringify(settings)); -} - // Collapse settings function saveCollapseSettings() { let collapseoption = document.querySelector("input[name='collapsesettings']:checked").value; settings.collapse = collapseoption; -} - -// ========================================== -// Creating activities -// ========================================== - -// When entering tasks, to prevent passing in empty string (could do in html) -function textentered() { - if (document.querySelector(".newActivity").value !== "") - document.querySelector(".newActivityBtn").disabled = false; - else if (document.querySelector(".newActivity").value == "") - document.querySelector(".newActivityBtn").disabled = true; -} - -// On enter in input -document.querySelector(".newActivity").addEventListener("keyup", (event) => { - if (event.key === "Enter" && document.querySelector(".newActivity").value !== "") newActivity(); -}); - -// For from save -function restartActivity(activity) { - document.querySelector(".newActivity").value = activity; - setActivity(); -} - -function newActivity() { - // Get name - let activityName = document.querySelector(".newActivity").value; - document.querySelector(".newActivity").value = ""; - document.querySelector(".newActivityBtn").disabled = true; - - setActivity({ - name: activityName, - time: 0, - paused: false, - start: new Date() - }); -} - -// Create a new activity -function setActivity(data, bypassOverrideCheck) { - if (isActiveTask && !bypassOverrideCheck) { - if (!okayToOverrideTask()) return; - finishActivity(); - } - - // Set activtiy data - isActiveTask = true; - activeTask = data; - - activityRunningElement.classList.add("hidden"); - activeTaskElement.classList.remove("hidden"); - - document.querySelector(".activity-name").textContent = activeTask.name; - let timeDisplay = document.querySelector(".activity-counter"); - - - // Reset in case paused task is being reset - if (activeTask.paused) pauseButton.innerHTML = "play_arrow"; - timeDisplay.textContent = getFormattedTime(); - - // Handle pause/unpause - pauseButton.onclick = () => { - if (activeTask.paused) { - activeTask.paused = false; - pauseButton.innerHTML = "pause"; - } else { - activeTask.paused = true; - pauseButton.innerHTML = "play_arrow"; - } - saveActive(); - }; - - finishButton.onclick = finishActivity; - cancelButton.onclick = cancelActivity; - - let lastTime = new Date(); - activityLoop = setInterval(() => { - let now = new Date(); - if (!activeTask.paused) { - activeTask.time += now - lastTime; - timeDisplay.textContent = getFormattedTime(); - saveActive(); - } - lastTime = now; - }, 100); - - - function cancelActivity() { - isActiveTask = false; - activeTask = {}; - clearInterval(activityLoop); - activityRunningElement.classList.remove("hidden"); - activeTaskElement.classList.add("hidden"); - saveActive(); - } - - function finishActivity() { - delete activeTask.pause; - activities.push(activeTask) - cancelActivity(); - saveActive(); - saveActivites(); - } - - - // be careful with this, because it is used to move items to stats and history - function oldfinishActivity() { - // Pause timer - clearInterval(timerRun); - - // copy element - let newActivity = element; - element.remove(); - document.querySelector(".activitiesCompleted").textContent = ""; - // Checks if multiple elements of same task, then collapses - if (document.querySelector(`._${noSpaces(activityName)}`) && settings.collapse !== "none") { - if (settings.collapse == "long") { - let newww = document.createElement("DIV"); - newww.innerHTML = `${formatTime(timer)}
- Started ${new Date(activities[activity][4]["start"]).toLocaleString()}
- Finished ${new Date(activities[activity][4]["finish"]).toLocaleString()}

`; - document.querySelector(`._${noSpaces(activityName)}`).append(newww); - } else if (settings.collapse == "short") { - // If there isn't another summary - if (document.querySelector(`._short_${noSpaces(activityName)}`) == null) { - // Remove time for first activity - document.querySelector(`._${noSpaces(activityName)}`).firstChild.nextSibling.remove(); - // Parent container - let element = document.createElement("DIV"); - element.classList.add(`_short_${noSpaces(activityName)}`); - // To get the labels and data - avgActivityTime(); - // Average time - let taskAvg = document.createElement("P"); - const average = (array) => array.reduce((a, b) => a + b) / array.length; - // Find index of label, then find corresponding in data - let thisIndex = labels.indexOf(activityName); - taskAvg.innerHTML = `
avg_time

Average time: ${formatTime( - Math.round(10 * average(data[thisIndex])) / 10 - )}

`; - // Total time - let taskTotal = document.createElement("P"); - const totalTime = (array) => array.reduce((part, a) => part + a, 0); - taskTotal.innerHTML = `
timer

Total time: ${formatTime( - totalTime(data[thisIndex]) - )}

`; - // Amount of activites - let activityAmounts = document.createElement("P"); - activityAmounts.innerHTML = `
numbers

Activites: ${data[thisIndex].length}

`; - // Append items to block - element.append(taskAvg); - element.append(taskTotal); - element.append(activityAmounts); - document.querySelector(`._${noSpaces(activityName)}`).append(element); - } - } - } else { - document.querySelector(".completedActivities").append(newActivity); - newActivity.classList.add(`_${noSpaces(activityName)}`); - - // Remove old controls - // Add new controls - // Start again button - let elRestart = document.createElement("SPAN"); - elRestart.classList.add("continueActivity"); - elRestart.classList.add(`ar${activities.indexOf(activity)}`); - elRestart.innerHTML = - "replay"; - elRestart.onclick = () => restartActivity(activityName); - controls.appendChild(elRestart); - - // Set time if from save - timeDisplay.textContent = formatTime(timer); - - // Display start and end times - timeDisplay.innerHTML = `${timeDisplay.textContent}
- Started ${new Date(activities[activity][4]["start"]).toLocaleString()}
- Finished ${new Date(activities[activity][4]["finish"]).toLocaleString()}

`; - } - // Add identifier - // Set state as complete - activities[activity][2] = "complete"; - // Check if no tasks running - if (!document.querySelector(".activitiesProgressing").firstChild) document.querySelector(".activityProgressing").textContent = "No tasks in progress"; - } -} - -function okayToOverrideTask() { - let isSure = confirm("You already have an activity running. Do you want to finish it and start a new one instead?"); - if (isSure) return true; - return false; -} - -function getFormattedTime() { - let totalSeconds = activeTask.time / 1000; - let minutes = Math.floor(totalSeconds / 60); - let seconds = totalSeconds % 60; - seconds = Math.round(seconds * 10) / 10; - - if (minutes > 0) return minutes + " minute" + (minutes !== 1 ? "s" : "") + " " + Math.round(seconds) + " seconds"; - return seconds.toFixed(1) + " seconds"; + saveSettings(); } - // ========================================== // Suggestions // ========================================== -generateSuggestions(); +// generateSuggestions(); // ========================================== // Stats // ========================================== -updateChartValues(); +// updateChartValues(); -setInterval(() => { - updateChartValues(); - chart.data.labels = labels; - chart.data.datasets[0].data = data; - chart.update(); -}, 2000); +// setInterval(() => { +// updateChartValues(); +// chart.data.labels = labels; +// chart.data.datasets[0].data = data; +// chart.update(); +// }, 2000); -// Avg activity time -avgActivityTime(); -setInterval(avgActivityTime, 2000); +// // Avg activity time +// avgActivityTime(); +// setInterval(avgActivityTime, 2000); // ========================================== // Other Functions // ========================================== -function formatTime(timeInSeconds) { - let seconds = Math.round(10 * (timeInSeconds += 0.1)) / 10; - let minutes = Math.floor(seconds / 60); - let hours = Math.floor(minutes / 60); - seconds = Math.round(10 * (seconds -= minutes * 60)) / 10; - minutes = Math.round(10 * (minutes -= hours * 60)) / 10; - if (hours > 0) - return `${hours} hour${hours != 1 ? "s" : ""} and ${minutes} minute${ - minutes != 1 ? "s" : "" - }`; - else if (minutes > 0) - return `${minutes} minute${ - minutes != 1 ? "s" : "" - } and ${seconds} second${seconds != 1 ? "s" : ""}`; - else if (seconds == 1) return seconds + " second"; - else return `${seconds} second${seconds != 1 ? "s" : ""}`; -} - let randomColor = "#" + Math.floor(Math.random() * 2 ** 24).toString(16).padStart(6, 0); - -function noSpaces(txt) { - // Note that if any of these replacment words are used in the actual activity name, it might cause problems, like considering them the same - // Suopport these ! # $ & ' ( ) * + , / : ; = ? @ [ ] - // A valid name should start with an underscore (_), a hyphen (-) or a letter (a-z) which is followed by any numbers, hyphens, underscores, letters. A name should be at least two characters long. Cannot start with a digit, two hyphens or a hyphen followed by a number. - return encodeURI(txt.replace(/\s/g, "").replaceAll("!", "nonono").replaceAll("?", "nononono")).replaceAll("%", "WHYCSS").replaceAll(":", "uunununu").replaceAll("(", "oeunen"); -} diff --git a/scripts/stats.js b/scripts/stats.js index 7c78bd9..f4d58cf 100644 --- a/scripts/stats.js +++ b/scripts/stats.js @@ -11,7 +11,7 @@ let chart = new Chart(ctx, { labels: labels, datasets: [{ label: "seconds", - data: data + data: sumNestedArrays(data) }] } }); @@ -19,14 +19,14 @@ let chart = new Chart(ctx, { function updateChartValues() { labels = []; data = []; - activities.forEach((el, i) => { - if (el[2] == "complete") { - if (labels.findIndex((name) => name == el[0]) != -1) { - data[labels.findIndex((name) => name == el[0])] += el[1]; - } else { - labels.push(el[0]); - data.push(el[1]); - } + + activities.forEach((activity, i) => { + let activityDataIndex = labels.findIndex((name) => name == activity.name); + if (activityDataIndex != -1) { + data[activityDataIndex].push(activity.time); + } else { + labels.push(activity.name); + data.push([activity.time]); } }); } @@ -34,33 +34,41 @@ function updateChartValues() { // Avg activity time function avgActivityTime() { document.querySelector(".avgtime").innerHTML = ""; - labels = []; - data = []; - activities.forEach((el, i) => { - if (el[2] == "complete") { - if (labels.findIndex((name) => name == el[0]) != -1) { - data[labels.findIndex((name) => name == el[0])].push(el[1]); - } else { - labels.push(el[0]); - data.push([el[1]]); - } - } - }); + updateChartValues(); + for (i in labels) { let element = document.createElement("DIV"); element.classList.add("avgtimeblock"); let taskName = document.createElement("P"); taskName.textContent = labels[i]; let taskAvg = document.createElement("P"); - const average = (array) => array.reduce((a, b) => a + b) / array.length; + + taskAvg.textContent = - "Average time: " + formatTime(Math.round(10 * average(data[i])) / 10); + "Average time: " + formatTimeAmount(Math.round(10 * getArrayAverage(data[i])) / 10); let taskTotal = document.createElement("P"); - const totalTime = (array) => array.reduce((part, a) => part + a, 0); - taskTotal.textContent = "Total time: " + formatTime(totalTime(data[i])); + + taskTotal.textContent = "Total time: " + formatTimeAmount(getArraySum(data[i])); element.append(taskName); element.append(taskAvg); element.append(taskTotal); document.querySelector(".avgtime").append(element); } + +} + +function getArrayAverage(array) { + let sum = 0; + for (let i = 0; i < array.length; i++) { + sum += array[i]; + } + return sum / array.length; +} + +function sumNestedArrays(array) { + return array.map(arr => arr.reduce((acc, val) => acc + val, 0)); +} + +function getArraySum(array) { + return array.reduce((part, a) => part + a, 0); } \ No newline at end of file diff --git a/styles/styles.css b/styles/styles.css index 1ba878a..0d7df59 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -78,9 +78,9 @@ legend { } input { - padding: 0.3em 0.6em; + padding: 0.5rem 0.6em; border: solid 0.1em #666; - border-radius: 0.2em; + border-radius: var(--container-border-radius); transition: 0.15s; } @@ -90,24 +90,27 @@ input:focus { box-shadow: 0 0 0 0.2em #ddd; } + button { - padding: 0.3em 0.6em; - margin: 0.2em 0.3em; - font-size: 95%; - background-color: #eee; - border: none; - border-radius: 0.2em; - box-shadow: 0 0.08em 0.2em #ccc; - transition: 0.15s; + margin: 0.17em 0.2em; + padding: 0.3em 0.7em; + background-color: transparent; + color: #222; + border-radius: var(--container-border-radius); + font-family: sans-serif; + font-weight: 600; + border: solid 0.2rem #222; + transition: 0.2s; } button:hover { - box-shadow: 0 0.1em 0.3em #bbb; + color: #fff; + border: solid 0.2em transparent; + background-color: #222; } button:active { - background-color: #f5f5f5; - box-shadow: 0 0.08em 0.3em #ddd; + transform: scale(1.05); } button:focus { @@ -116,16 +119,18 @@ button:focus { } button:disabled { - background-color: #ddd; - box-shadow: 0 0.08em 0.2em #aaa; + background-color: #ccc; + border-color: #ccc; + color: #444; + box-shadow: none; } /* Specific Styles */ .activity { position: relative; - padding: 0.4em 0.7em; - margin: 0.2em 0; - box-shadow: 0 0.1em 0.5em #ddd; + margin: .4rem .6rem; + padding: 1rem 1.6rem; + box-shadow: 0 0.1em 0.3em #ddd; border-radius: var(--container-border-radius); } @@ -194,22 +199,8 @@ button:disabled { position: absolute; top: 0; right: 0; - margin: 0.17em 0.2em; - padding: 0.3em 0.7em; - background-color: transparent; - color: #222; - border-radius: var(--container-border-radius); - font-family: sans-serif; - font-weight: 600; - border: solid 0.19em #222; - transition: 0.2s; } -.settingsblock button:hover { - color: #fff; - border: solid 0.19em transparent; - background-color: #222; -} .settingHeaderTxt { font-size: 1.25em; @@ -281,6 +272,9 @@ hr { .page-inner { grid-template-columns: 100%; } + .history-items { + grid-template-columns: 100%; + } } /* So it won't hurt your eyes ;) */ @@ -297,4 +291,29 @@ hr { .redo-activty-icon:hover { transform: scale(1.2); -} \ No newline at end of file +} + +.history .controls { + position: absolute; + top: 0; + right: 0; + background-color: none; + padding: 0; + margin: .6rem .4rem; +} + +.history .control-button { + height: 1rem; + width: 1rem; + padding: 0.6rem; + font-size: 0.6rem; +} + +.history h4 { + font-weight: 600; + font-size: 1.2em; +} + +.history .time { + color: #444; +} diff --git a/styles/tailwind.css b/styles/tailwind.css index 51f9dcb..c675d97 100644 --- a/styles/tailwind.css +++ b/styles/tailwind.css @@ -570,14 +570,50 @@ video { display: grid; } +.inline-grid { + display: inline-grid; +} + .hidden { display: none; } +.h-20 { + height: 5rem; +} + +.h-40 { + height: 10rem; +} + +.w-full { + width: 100%; +} + .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.gap-2 { + gap: 0.5rem; +} + +.gap-3 { + gap: 0.75rem; +} + +.gap-\[1\.5rem\] { + gap: 1.5rem; +} + +.gap-4 { + gap: 1rem; +} + +.gap-5 { + gap: 1.25rem; +} + .bg-gray-100 { --tw-bg-opacity: 1; background-color: rgb(243 244 246 / var(--tw-bg-opacity)); @@ -588,6 +624,11 @@ video { background-color: rgb(229 231 235 / var(--tw-bg-opacity)); } +.bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); +} + .text-center { text-align: center; }