]> git.amazingca.dev Git - autumn/todo/commitdiff
Finish up management logic, add importing
authorAmazingca <luzovich@cs.colostate.edu>
Fri, 1 May 2026 07:23:01 +0000 (01:23 -0600)
committerAmazingca <luzovich@cs.colostate.edu>
Fri, 1 May 2026 07:23:01 +0000 (01:23 -0600)
archived.html [new file with mode: 0644]
archived.js [new file with mode: 0644]
index.html
index.js [moved from script.js with 89% similarity]
settings.html [new file with mode: 0644]
settings.js [new file with mode: 0644]
style.css

diff --git a/archived.html b/archived.html
new file mode 100644 (file)
index 0000000..c3e951d
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <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="./archived.js" defer></script>
+  </head>
+  <body>
+    <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>
+        <div id="archived"></div>
+      </div>
+    </div>
+    <footer></footer>
+  </body>
+</html>
diff --git a/archived.js b/archived.js
new file mode 100644 (file)
index 0000000..1a9814d
--- /dev/null
@@ -0,0 +1,107 @@
+var todos = {
+  uncompleted: [],
+  completed: []
+};
+var archived = [];
+var theme = {
+  colorScheme: "default",
+  css: ""
+};
+
+if (localStorage.getItem("todos")) {
+
+  todos = JSON.parse(localStorage.getItem("todos"));
+}
+
+if (localStorage.getItem("archived")) {
+
+  archived = JSON.parse(localStorage.getItem("archived"));
+}
+
+if (localStorage.getItem("theme")) {
+
+  theme = JSON.parse(localStorage.getItem("theme"));
+}
+
+const backupData = () => {
+
+  localStorage.setItem("todos", JSON.stringify(todos));
+  localStorage.setItem("archived", JSON.stringify(archived));
+  localStorage.setItem("theme", JSON.stringify(theme));
+}
+
+const archivedElement = document.getElementById("archived");
+
+const todoElement = (item, index) => {
+
+  return `
+    <todo id="todo-archived-${index}">
+      <div class="data">
+        <textarea id="todo-archived-${index}-description">${item.description}</textarea>
+        <div>
+          <p id="todo-archived-${index}-restore">restore</p>
+          <p id="todo-archived-${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 < archived.length; i++) {
+
+    let index = i; // fixes scoping issue - what a disaster
+
+    document.getElementById(`todo-archived-${i}-description`).addEventListener("input", (event) => {
+
+      event.target.style.height = "0";
+      event.target.style.height = event.target.scrollHeight + "px";
+
+      archived[index].description = event.target.value;
+
+      backupData();
+    });
+
+    document.getElementById(`todo-archived-${i}-restore`).addEventListener("click", (event) => {
+
+      todos.uncompleted = [
+        archived[index]
+      ].concat(todos.uncompleted);
+      archived.splice(index, 1);
+
+      hydrateTodos();
+      backupData();
+    });
+
+    document.getElementById(`todo-archived-${i}-delete`).addEventListener("click", (event) => {
+
+      archived.splice(index, 1);
+
+      hydrateTodos();
+      backupData();
+    });
+  }
+}
+
+const hydrateTodos = () => {
+
+  archivedElement.innerHTML = archived
+    .map((x, index) => todoElement(x, index))
+    .join("");
+
+  applyListeners();
+};
+
+hydrateTodos();
index aa00f695161c54f86d89bb0e3a72c5357602023c..4aa4a8f7ecdcf685979c33f6c8400c06bda1e29f 100644 (file)
@@ -4,7 +4,7 @@
     <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" defer></script>
+    <script src="./index.js" defer></script>
   </head>
   <body>
     <header>
similarity index 89%
rename from script.js
rename to index.js
index f8df07e617d3631eda050b9f6023328098deedce..7ca7fa90ea36618af4a83cf8ca4c92b9b68299d3 100644 (file)
--- a/script.js
+++ b/index.js
@@ -3,6 +3,10 @@ var todos = {
   completed: []
 };
 var archived = [];
+var theme = {
+  colorScheme: "default",
+  css: ""
+};
 
 if (localStorage.getItem("todos")) {
 
@@ -14,7 +18,32 @@ if (localStorage.getItem("archived")) {
   archived = JSON.parse(localStorage.getItem("archived"));
 }
 
-// TODO: URL sharing data override here...
+if (localStorage.getItem("theme")) {
+
+  theme = JSON.parse(localStorage.getItem("theme"));
+}
+
+const backupData = () => {
+
+  localStorage.setItem("todos", JSON.stringify(todos));
+  localStorage.setItem("archived", JSON.stringify(archived));
+  localStorage.setItem("theme", JSON.stringify(theme));
+}
+
+if (window.location.hash.length > 0) {
+
+  try {
+
+    ({todos, archived, theme} = JSON.parse(atob(window.location.hash.substring(1)))); // using parenthesis around this is required because we're doing object literal destructuring without a declaration
+
+    backupData();
+  } catch (e) {
+
+    console.error(e);
+
+    window.alert("The import URL provided was not valid!");
+  }
+}
 
 document.getElementById("createTodo").addEventListener("click", () => {
 
@@ -25,6 +54,7 @@ document.getElementById("createTodo").addEventListener("click", () => {
   ].concat(todos.uncompleted);
 
   hydrateUncompleted();
+  applyListeners();
   backupData();
 });
 
@@ -34,12 +64,6 @@ document.getElementById("showCompleted").addEventListener("click", () => {
   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");
 
diff --git a/settings.html b/settings.html
new file mode 100644 (file)
index 0000000..1403db1
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <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="./settings.js" defer></script>
+  </head>
+  <body>
+    <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="exportData">
+          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+               <path fill="currentColor" d="M6 22q-.825 0-1.412-.587T4 20V10q0-.825.588-1.412T6 8h2q.425 0 .713.288T9 9t-.288.713T8 10H6v10h12V10h-2q-.425 0-.712-.288T15 9t.288-.712T16 8h2q.825 0 1.413.588T20 10v10q0 .825-.587 1.413T18 22zm5.288-6.288Q11 15.425 11 15V4.825l-.9.9q-.3.3-.7.288T8.7 5.7q-.275-.3-.287-.7t.287-.7l2.6-2.6q.15-.15.325-.212T12 1.425t.375.063t.325.212l2.6 2.6q.275.275.275.688T15.3 5.7q-.3.3-.712.3t-.713-.3L13 4.825V15q0 .425-.288.713T12 16t-.712-.288" />
+          </svg>
+          <p id="exportData_text">export as link</p>
+        </button>
+        <h3>theming</h3>
+        <h3>override css</h3>
+        <textarea id="override_css"></textarea>
+      </div>
+    </div>
+    <footer></footer>
+  </body>
+</html>
diff --git a/settings.js b/settings.js
new file mode 100644 (file)
index 0000000..43e958d
--- /dev/null
@@ -0,0 +1,70 @@
+var todos = {
+  uncompleted: [],
+  completed: []
+};
+var archived = [];
+var theme = {
+  colorScheme: "default",
+  css: ""
+};
+
+if (localStorage.getItem("todos")) {
+
+  todos = JSON.parse(localStorage.getItem("todos"));
+}
+
+if (localStorage.getItem("archived")) {
+
+  archived = JSON.parse(localStorage.getItem("archived"));
+}
+
+if (localStorage.getItem("theme")) {
+
+  theme = JSON.parse(localStorage.getItem("theme"));
+}
+
+const exportDataText = document.getElementById("exportData_text");
+
+document.getElementById("exportData").addEventListener("click", async (event) => {
+
+  const dataExport = {
+    todos: todos,
+    archived: archived,
+    theme: theme
+  };
+
+  const exportURL = window.location.href.replace("settings.html", "") + "index.html#" + btoa(JSON.stringify(dataExport));
+
+  if (!window.navigator.userAgent.includes("Mozilla")) {
+    
+    try {
+    
+      await navigator.share({
+        title: "todo data export",
+        url: exportURL
+      });
+      
+      exportDataText.innerHTML = "shared!";
+      setTimeout(() => {
+        exportDataText.innerHTML = "export as link";
+      }, 2000);
+    } catch (e) {
+    
+      console.error(e);
+    }
+  } else {
+
+    navigator.clipboard.writeText(exportURL);
+
+    exportDataText.innerHTML = "link copied!";
+    setTimeout(() => {
+      exportDataText.innerHTML = "export as link";
+    }, 2000);
+  }
+});
+
+const override_css = document.getElementById("override_css");
+
+const update = () => {
+  
+}
index 1cfc15a1cefc5096581c761bb91cabbff1e85cc4..04ccb708bfab26a2394b547d657c12a6fe3b2104 100644 (file)
--- a/style.css
+++ b/style.css
@@ -16,7 +16,6 @@ body {
 
 h3 {
   margin: 0;
-  user-select: none;
 }
 
 header {
@@ -44,7 +43,7 @@ nav {
   display: flex;
   width: 100%;
   justify-content: center;
-  & > div, #todos, #todos-completed {
+  & > div, #todos, #todos-completed, #archived {
     width: 400px;
     display: flex;
     flex-direction: column;
@@ -80,7 +79,7 @@ todo {
       justify-content: right;
       gap: 0.5rem;
       & > p {
-        user-select: none;
+        /* user-select: none; */
         font-size: 0.9rem;
         margin: 0;
         cursor: pointer;
@@ -104,8 +103,11 @@ button {
   cursor: pointer;
 }
 
+#override_css {
+  resize: vertical;
+}
+
 a, a:visited, a:active {
-  user-select: none;
   color: var(--text-primary);
   background-color: var(--background-secondary);
   text-decoration: none;