]> git.amazingca.dev Git - autumn/todo/commitdiff
More of an inital commit
authorAmazingca <luzovich@cs.colostate.edu>
Fri, 1 May 2026 05:21:33 +0000 (23:21 -0600)
committerAmazingca <luzovich@cs.colostate.edu>
Fri, 1 May 2026 05:21:33 +0000 (23:21 -0600)
index.html
script.js
style.css

index 28e3f7ff99204a40f14b7d2a3b3498fd88a99864..aa00f695161c54f86d89bb0e3a72c5357602023c 100644 (file)
@@ -4,9 +4,49 @@
     <title>todo</title>
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <link rel="stylesheet" type="text/css" href="./style.css">
-    <script src="./script.js"></script>
+    <script src="./script.js" defer></script>
   </head>
   <body>
-    <h1>Hello, World!</h1>
+    <header>
+      <div>
+        <h3>todo</h3>
+        <nav>
+          <a href="./index.html">home</a>
+          <a href="./archived.html">archived</a>
+          <a href="./settings.html">settings</a>
+        </nav>
+      </div>
+      <hr>
+    </header>
+    <div id="main">
+      <div>
+        <button id="createTodo">
+          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+            <g fill="none" stroke="currentColor" stroke-dasharray="16" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
+              <path d="M5 12h14">
+                <animate fill="freeze" attributeName="stroke-dashoffset" dur="0.5s" values="16;0"/>
+              </path>
+              <path stroke-dashoffset="16" d="M12 5v14">
+                <animate fill="freeze" attributeName="stroke-dashoffset" begin="0.5s" dur="0.5s" to="0"/>
+              </path>
+            </g>
+          </svg>
+        </button>
+        <div id="todos"></div>
+        <button id="showCompleted">
+          <svg id="showCompleted_open" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+               <path fill="currentColor" d="m7 10l5 5l5-5z" />
+          </svg>
+          <svg id="showCompleted_close" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+               <path fill="currentColor" d="m7 15l5-5l5 5z" />
+          </svg>
+          <p id="showCompleted_text"><show>show</show><hide>hide</hide> completed</p>
+        </button>
+        <div>
+          <div id="todos-completed" class="hidden"></div>
+        </div>
+      </div>
+    </div>
+    <footer></footer>
   </body>
 </html>
index 3135ddbdfed7afa8848ff91a24db4edfb78dfc46..f8df07e617d3631eda050b9f6023328098deedce 100644 (file)
--- a/script.js
+++ b/script.js
@@ -1 +1,189 @@
-window.alert("Welcome!");
+var todos = {
+  uncompleted: [],
+  completed: []
+};
+var archived = [];
+
+if (localStorage.getItem("todos")) {
+
+  todos = JSON.parse(localStorage.getItem("todos"));
+}
+
+if (localStorage.getItem("archived")) {
+
+  archived = JSON.parse(localStorage.getItem("archived"));
+}
+
+// TODO: URL sharing data override here...
+
+document.getElementById("createTodo").addEventListener("click", () => {
+
+  todos.uncompleted = [
+    {
+      description: ""
+    }
+  ].concat(todos.uncompleted);
+
+  hydrateUncompleted();
+  backupData();
+});
+
+document.getElementById("showCompleted").addEventListener("click", () => {
+
+  document.getElementById("todos-completed").classList.toggle("hidden");
+  resizeTextHeights();
+});
+
+const backupData = () => {
+
+  localStorage.setItem("todos", JSON.stringify(todos));
+  localStorage.setItem("archived", JSON.stringify(archived));
+}
+
+const todosElement = document.getElementById("todos");
+const completedElement = document.getElementById("todos-completed");
+
+const todoElement = (item, index, isCompleted) => {
+
+  let completedText = (isCompleted) ? "completed" : "uncompleted";
+
+  return `
+    <todo id="todo-${completedText}-${index}">
+      <div id="todo-${completedText}-${index}-completion" class="completion">
+        ${(isCompleted) ? '<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'24\' height=\'24\' viewBox=\'0 0 24 24\'><path fill=\'currentColor\' d=\'m10.6 13.8l-2.15-2.15q-.275-.275-.7-.275t-.7.275t-.275.7t.275.7L9.9 15.9q.3.3.7.3t.7-.3l5.65-5.65q.275-.275.275-.7t-.275-.7t-.7-.275t-.7.275zM12 22q-2.075 0-3.9-.788t-3.175-2.137T2.788 15.9T2 12t.788-3.9t2.137-3.175T8.1 2.788T12 2t3.9.788t3.175 2.137T21.213 8.1T22 12t-.788 3.9t-2.137 3.175t-3.175 2.138T12 22\' /></svg>' : '<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'24\' height=\'24\' viewBox=\'0 0 24 24\'><path fill=\'currentColor\' d=\'M12 20a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2\' /></svg>'}
+      </div>
+      <div class="data">
+        <textarea id="todo-${completedText}-${index}-description">${item.description}</textarea>
+        <div>
+          <p id="todo-${completedText}-${index}-archive">archive</p>
+          <p id="todo-${completedText}-${index}-delete">delete</p>
+        </div>
+      </div>
+    </todo>
+  `;
+}
+
+const resizeTextHeights = () => {
+
+  for (const element of document.querySelectorAll("todo textarea")) {
+
+    element.style.height = "0";
+    element.style.height = element.scrollHeight + "px";
+  }
+}
+
+const applyListeners = () => {
+
+  resizeTextHeights();
+
+  for (var i = 0; i < todos.uncompleted.length; i++) {
+
+    let index = i; // fixes scoping issue - what a disaster
+
+    document.getElementById(`todo-uncompleted-${i}-description`).addEventListener("input", (event) => {
+
+      event.target.style.height = "0";
+      event.target.style.height = event.target.scrollHeight + "px";
+
+      todos.uncompleted[index].description = event.target.value;
+
+      backupData();
+    });
+
+    document.getElementById(`todo-uncompleted-${i}-completion`).addEventListener("click", (event) => {
+
+      todos.completed = [
+        todos.uncompleted[index]
+      ].concat(todos.completed);
+      todos.uncompleted.splice(index, 1);
+      
+      hydrateTodos();
+      backupData();
+    });
+
+    document.getElementById(`todo-uncompleted-${i}-archive`).addEventListener("click", (event) => {
+
+      archived = [
+        todos.uncompleted[index]
+      ].concat(archived);
+      todos.uncompleted.splice(index, 1);
+
+      hydrateTodos();
+      backupData();
+    });
+
+    document.getElementById(`todo-uncompleted-${i}-delete`).addEventListener("click", (event) => {
+
+      todos.uncompleted.splice(index, 1);
+
+      hydrateTodos();
+      backupData();
+    });
+  }
+  
+  for (var i = 0; i < todos.completed.length; i++) {
+
+    let index = i; // fixes scoping issue - what a disaster
+
+    document.getElementById(`todo-completed-${i}-description`).addEventListener("input", (event) => {
+
+      todos.completed[index].description = event.target.value;
+
+      backupData();
+    });
+
+    document.getElementById(`todo-completed-${i}-completion`).addEventListener("click", (event) => {
+
+      todos.uncompleted = [
+        todos.completed[index]
+      ].concat(todos.uncompleted);
+      todos.completed.splice(index, 1);
+      
+      hydrateTodos();
+      backupData();
+    });
+    
+    document.getElementById(`todo-completed-${i}-archive`).addEventListener("click", (event) => {
+
+      archived = [
+        todos.completed[index]
+      ].concat(archived);
+      todos.completed.splice(index, 1);
+
+      hydrateTodos();
+      backupData();
+    });
+
+    document.getElementById(`todo-completed-${i}-delete`).addEventListener("click", (event) => {
+
+      todos.completed.splice(index, 1);
+
+      hydrateTodos();
+      backupData();
+    });
+  }
+}
+
+const hydrateUncompleted = () => {
+
+  todosElement.innerHTML = todos.uncompleted
+    .map((x, index) => todoElement(x, index, false))
+    .join("");
+}
+
+const hydrateCompleted = () => {
+
+  completedElement.innerHTML = todos.completed
+    .map((x, index) => todoElement(x, index, true))
+    .join("");
+}
+
+const hydrateTodos = () => {
+
+  hydrateUncompleted();
+  hydrateCompleted();
+
+  applyListeners();
+};
+
+hydrateTodos();
index 5b9ab9b949eba8e033ee2251dae981a499caebf6..1cfc15a1cefc5096581c761bb91cabbff1e85cc4 100644 (file)
--- a/style.css
+++ b/style.css
@@ -1,3 +1,127 @@
+:root {
+  --text-primary: #000;
+  --background-primary: #fff;
+  --background-secondary: #eee;
+  --background-tertiary: #ccc;
+}
+
 body {
-  background-color: gray;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  color: var(--text-primary);
+  background-color: var(--background-primary);
+  font-family: Arial;
+}
+
+h3 {
+  margin: 0;
+  user-select: none;
+}
+
+header {
+  width: 100%;
+  max-width: 750px;
+  & > div {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    align-items: center;
+    gap: 0.5rem;
+  }
+  & > hr {
+    border: 1px solid var(--text-primary);
+  }
+}
+
+nav {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 0.25rem;
+}
+
+#main {
+  display: flex;
+  width: 100%;
+  justify-content: center;
+  & > div, #todos, #todos-completed {
+    width: 400px;
+    display: flex;
+    flex-direction: column;
+    gap: 0.25rem;
+  }
+}
+
+todo {
+  background-color: var(--background-secondary);
+  border-radius: 0.5rem;
+  display: flex;
+  /* align-items: center; */
+  padding: 0.5rem;
+  gap: 0.5rem;
+  & .completion {
+    cursor: pointer;
+  }
+  & .data {
+    flex-grow: 0.97;
+    & textarea {
+      width: 100%;
+      resize: none;
+      border: unset;
+      border-radius: 0.25rem;
+      &:focus-visible {
+        outline: unset;
+      }
+    }
+    & > div {
+      margin-top: 0.25rem;
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: right;
+      gap: 0.5rem;
+      & > p {
+        user-select: none;
+        font-size: 0.9rem;
+        margin: 0;
+        cursor: pointer;
+        &:hover {
+          text-decoration: underline;
+        }
+      }
+    }
+  }
+}
+
+button {
+  background-color: var(--background-secondary);
+  border: unset;
+  border-radius: 0.5rem;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 1rem;
+  cursor: pointer;
+}
+
+a, a:visited, a:active {
+  user-select: none;
+  color: var(--text-primary);
+  background-color: var(--background-secondary);
+  text-decoration: none;
+  padding: 0.25rem;
+  border-radius: 0.5rem;
+}
+
+button:active, a:hover {
+  background-color: var(--background-tertiary);
+}
+
+.hidden,
+div:has(> #todos-completed.hidden),
+#main div:has(#todos-completed.hidden) #showCompleted_close,
+#main div:not(:has(#todos-completed.hidden)) #showCompleted_open,
+#main div:has(#todos-completed.hidden) hide,
+#main div:not(:has(#todos-completed.hidden)) show {
+  display: none;
 }