From 44c902c1635aa99c09b19a39230be42273092add Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Sun, 1 Jun 2025 02:44:55 -0400 Subject: [PATCH 01/12] (BROKEN) shift things around --- js/_main_.js | 25 +++ js/formatBar.js | 2 +- js/notes.js | 550 ++++++++++++++++++++++++------------------------ js/settings.js | 10 +- js/sidepanel.js | 16 -- js/tags.js | 4 +- sidepanel.html | 10 +- 7 files changed, 314 insertions(+), 303 deletions(-) create mode 100644 js/_main_.js delete mode 100644 js/sidepanel.js diff --git a/js/_main_.js b/js/_main_.js new file mode 100644 index 0000000..13bd237 --- /dev/null +++ b/js/_main_.js @@ -0,0 +1,25 @@ +(async _ => { + // notes are stored as an object + // key: Date.now() + // value: {content: string, tags: string[], title: string} + // this lets us sort the notes by date, and delete by some ID + let notes = {}; + + await loadSettings(); + await loadNotes(); + //insertTag(); + //formatBar.append(createFormatBar()); + + add.addEventListener("click", _ => { addNote(""); }); + document.addEventListener("DOMContentLoaded", _ => { reloadNoteHTML(); loadFolders(); }); + document.addEventListener("visibilitychange", _ => { saveNotesOrder(); saveFolders(); }); + + // context menu --> add new note + chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + const content = request.content; + + // make that new message if it's non-empty + if (content) addNote(content); + }); +})() + diff --git a/js/formatBar.js b/js/formatBar.js index 96638a9..46c8176 100644 --- a/js/formatBar.js +++ b/js/formatBar.js @@ -2,7 +2,7 @@ * Generates "bottom bar" below note boxes to hold text formating buttons * @returns {object} bottomBar */ -function createFormatBar() { +export default function createFormatBar() { const bottomBar = document.createElement("div"); bottomBar.className = "bottom-bar"; diff --git a/js/notes.js b/js/notes.js index 0cf42da..ce8f5cd 100644 --- a/js/notes.js +++ b/js/notes.js @@ -1,303 +1,303 @@ const infoInput = document.getElementById("info"); const titleInput = document.getElementById("title"); -// notes are stored as an object -// key: Date.now() -// value: {content: string, tags: string[], title: string} -// this lets us sort the notes by date, and delete by some ID -let notes = {}; - -// a bunch of helper functions in case we need them later -// tbh we don't really need them but it's nicer to type -function loadNotes() { - const notesText = localStorage.getItem("notesData") || "{}"; - notes = JSON.parse(notesText); -} -function saveNotes() { - localStorage.setItem("notesData", JSON.stringify(notes)); -} -function reloadNoteHTML() { - // delete all the current notes - const currentNotes = Array.from(document.getElementsByClassName("note")); - for (let i = 0; i < currentNotes.length; i++) { - currentNotes[i].remove(); - } - - // add them all back from notes[] - Object.entries(notes).reverse().forEach(([id, {title, content, tags}]) => { - addNoteHTML(title, content, tags, id); - }); -} -function deleteNote(id) { - delete notes[id]; - saveNotes(); -} -function deleteAllNotes() { - notes = {}; - reloadNoteHTML(); - saveNotes(); - reloadFolders(); -} +export default Notes = { + // a bunch of helper functions in case we need them later + // tbh we don't really need them but it's nicer to type + async loadNotes() { + console.log("bleghhhh"); + const { notesData } = await chrome.storage.local.get("notesData"); + notes = notesData; + }, + + async saveNotes() { + console.log("should be saved") + chrome.storage.local.set({notesData: notes}); + }, + + reloadNoteHTML() { + // delete all the current notes + const currentNotes = Array.from(document.getElementsByClassName("note")); + for (let i = 0; i < currentNotes.length; i++) { + currentNotes[i].remove(); + } -/** - * this function only creates the note in the notes[] array, then calls addNoteHTML - * @param {string} text - textual/body content of note - * @param {object} insertAfter - the note that precedes the new note you're trying to add - */ - -function addNote(text, insertAfter) { - const title = titleInput.value || ""; - const content = text === "" ? infoInput.value : text; - infoInput.value = ""; // empty out the textbox - titleInput.value = ""; - - // stop if no text is provided - if (title === "" && content === "") return; - - const id = Date.now(); - const tags = []; - - notes[id] = { title, content, tags }; - - //Move new note to top - const notesArray = Object.entries(notes); - if (notesArray.length > 0) { - newNote = notesArray.pop() - notesArray.unshift(newNote); - - const sortedNotes = {}; - notesArray.forEach(([id, note]) => { - sortedNotes[id] = note; + // add them all back from notes[] + Object.entries(notes).reverse().forEach(([id, {title, content, tags}]) => { + addNoteHTML(title, content, tags, id); }); - notes = sortedNotes; - } + }, + async deleteNote(id) { + delete notes[id]; + await saveNotes(); + }, + async deleteAllNotes() { + notes = {}; + reloadNoteHTML(); + await saveNotes(); + reloadFolders(); + }, + + /** + * this function only creates the note in the notes[] array, then calls addNoteHTML + * @param {string} text - textual/body content of note + * @param {object} insertAfter - the note that precedes the new note you're trying to add + */ + + async addNote(text, insertAfter) { + const title = titleInput.value || ""; + const content = text === "" ? infoInput.value : text; + infoInput.value = ""; // empty out the textbox + titleInput.value = ""; + + // stop if no text is provided + if (title === "" && content === "") return; + + const id = Date.now(); + const tags = []; + + notes[id] = { title, content, tags }; + + //Move new note to top + const notesArray = Object.entries(notes); + if (notesArray.length > 0) { + newNote = notesArray.pop() + notesArray.unshift(newNote); - saveNotes(); - reloadNoteHTML(); - console.log(tags); -} - -/** - * Generates the actual HTML element in the DOM - * don't call directly unless you're reloading - * @param {string} title - title of a note - * @param {string} text - textual/body content of a note - * @param {string[]} tags - list containing all tags of a given note - * parameter id = id - * @param {object} insertAfter - the note that precedes the new note you're trying to add - */ -function addNoteHTML(title, text, tags, id, insertAfter = null) { - if (!id) { - console.log("no ID provided!!!"); - } - // create note elements, then add event listeners - const note = document.createElement("div"); - note.className = "note"; - note.id = id; - note.draggable = true; - - const deleteButton = document.createElement("button"); - deleteButton.className = "del"; - deleteButton.textContent = "X"; - deleteButton.style.display = "none"; - deleteButton.addEventListener("click", function (event) { - event.stopPropagation(); - deleteNote(id); - note.remove(); - customMenu.style.display = "none"; - - // remove overlay - let ove = document.getElementsByClassName("overlay"); - if (ove.length !== 0) document.body.removeChild(ove[0]); - }); - note.appendChild(deleteButton); - - addDraggingEvents(note); - addContextMenuToNote(note); - - note.addEventListener("mouseover", function () { - deleteButton.style.display = "block"; - }); - - note.addEventListener("mouseout", function () { - deleteButton.style.display = "none"; - }); - - note.addEventListener("click", function (event) { - // if the user clicks on a link inside the note, don't change into edit mode - if (event.target.nodeName === "A") return; - - if (!this.classList.contains("overlay-created")) { - const overlay = document.createElement("div"); - overlay.className = "overlay"; - document.body.appendChild(overlay); - - // show only noteContent - const noteTitle = note.getElementsByClassName("note-title")[0]; - const noteContent = note.getElementsByClassName("note-content")[0]; - const noteDisplay = note.getElementsByClassName("note-display")[0]; - noteContent.classList.remove("displayNone"); - noteDisplay.classList.add("displayNone"); - - // Disable dragging if note in focused mode - note.draggable = false; - overlay.addEventListener("click", function () { - // remove overlay - document.body.removeChild(overlay); - note.classList.remove("overlay-created"); - note.style.zIndex = null; - note.draggable = true; - - // update noteDisplay, persist to notes - notes[note.id].title = noteTitle.innerText; - notes[note.id].content = noteContent.value; - //TODO: persist tags as well - noteDisplay.innerHTML = DOMPurify.sanitize(marked.parse(noteContent.value)); - - // only show noteDisplay - noteContent.classList.add("displayNone"); - noteDisplay.classList.remove("displayNone"); + const sortedNotes = {}; + notesArray.forEach(([id, note]) => { + sortedNotes[id] = note; }); - - this.classList.add("overlay-created"); - this.style.zIndex = "999"; + notes = sortedNotes; + } + + await saveNotes(); + reloadNoteHTML(); + console.log(tags); + }, + + /** + * Generates the actual HTML element in the DOM + * don't call directly unless you're reloading + * @param {string} title - title of a note + * @param {string} text - textual/body content of a note + * @param {string[]} tags - list containing all tags of a given note + * parameter id = id + * @param {object} insertAfter - the note that precedes the new note you're trying to add + */ + addNoteHTML(title, text, tags, id, insertAfter = null) { + if (!id) { + console.log("no ID provided!!!"); } - }); - - const noteTitle = document.createElement("div"); - noteTitle.contentEditable = "plaintext-only"; - noteTitle.className = "note-title title"; - noteTitle.innerText = title; - const noteContent = document.createElement("textarea"); - noteContent.className = "note-content displayNone body"; - noteContent.value = text; - const noteDisplay = document.createElement("div"); - noteDisplay.className = "note-display body"; - noteDisplay.innerHTML = DOMPurify.sanitize(marked.parse(text)); - - note.appendChild(noteTitle); - note.appendChild(noteContent); - note.appendChild(noteDisplay); - - const tagBar = document.createElement("div"); - tagBar.className = "tag-bar"; - - if(tags) { - tags.forEach((tag) => { - const tagElement = document.createElement("div"); - tagElement.className = "note-tag"; - tagElement.textContent = tag; - - tagBar.appendChild(tagElement); + // create note elements, then add event listeners + const note = document.createElement("div"); + note.className = "note"; + note.id = id; + note.draggable = true; + + const deleteButton = document.createElement("button"); + deleteButton.className = "del"; + deleteButton.textContent = "X"; + deleteButton.style.display = "none"; + deleteButton.addEventListener("click", function (event) { + event.stopPropagation(); + deleteNote(id); + note.remove(); + customMenu.style.display = "none"; + + // remove overlay + let ove = document.getElementsByClassName("overlay"); + if (ove.length !== 0) document.body.removeChild(ove[0]); }); - } + note.appendChild(deleteButton); - note.appendChild(tagBar); - - const bottomBar = createFormatBar(); - - const timeText = document.createElement("div"); - timeText.className = "time-text"; - timeText.style = "justify-content: right"; - const noteCreatedTime = new Date(+id); - timeText.textContent = `${noteCreatedTime.toLocaleString([], { - timeStyle: "short", - dateStyle: "short" - })}`; - const bottomDiv = document.createElement("div"); - bottomDiv.className = "bottomDiv"; - bottomDiv.appendChild(bottomBar); - bottomDiv.appendChild(timeText); - note.appendChild(bottomDiv); - - if (insertAfter && insertAfter.nextElementSibling) { - container.insertBefore(note, insertAfter.nextElementSibling); - } else { - container.prepend(note); - } -} + addDraggingEvents(note); + addContextMenuToNote(note); -function saveNotesOrder() { - const newNotesOrder = {}; - const noteElements = Array.from(container.getElementsByClassName("note")); + note.addEventListener("mouseover", function () { + deleteButton.style.display = "block"; + }); - noteElements.forEach(noteElement => { - const id = noteElement.id; - newNotesOrder[id] = notes[id]; - }); + note.addEventListener("mouseout", function () { + deleteButton.style.display = "none"; + }); - notes = newNotesOrder; - saveNotes(); -} + note.addEventListener("click", function (event) { + // if the user clicks on a link inside the note, don't change into edit mode + if (event.target.nodeName === "A") return; + + if (!this.classList.contains("overlay-created")) { + const overlay = document.createElement("div"); + overlay.className = "overlay"; + document.body.appendChild(overlay); + + // show only noteContent + const noteTitle = note.getElementsByClassName("note-title")[0]; + const noteContent = note.getElementsByClassName("note-content")[0]; + const noteDisplay = note.getElementsByClassName("note-display")[0]; + noteContent.classList.remove("displayNone"); + noteDisplay.classList.add("displayNone"); + + // Disable dragging if note in focused mode + note.draggable = false; + overlay.addEventListener("click", function () { + // remove overlay + document.body.removeChild(overlay); + note.classList.remove("overlay-created"); + note.style.zIndex = null; + note.draggable = true; + + // update noteDisplay, persist to notes + notes[note.id].title = noteTitle.innerText; + notes[note.id].content = noteContent.value; + //TODO: persist tags as well + noteDisplay.innerHTML = DOMPurify.sanitize(marked.parse(noteContent.value)); + + // only show noteDisplay + noteContent.classList.add("displayNone"); + noteDisplay.classList.remove("displayNone"); + }); -infoInput.addEventListener("keydown", evt => { - if (evt.ctrlKey && evt.key === "Enter") { - evt.preventDefault(); - addNote(""); // that was easy - } -}); + this.classList.add("overlay-created"); + this.style.zIndex = "999"; + } + }); -function addContextMenuToNote(note) { - console.log(note); - note.addEventListener("contextmenu", function(event) { - event.preventDefault(); + const noteTitle = document.createElement("div"); + noteTitle.contentEditable = "plaintext-only"; + noteTitle.className = "note-title title"; + noteTitle.innerText = title; + const noteContent = document.createElement("textarea"); + noteContent.className = "note-content displayNone body"; + noteContent.value = text; + const noteDisplay = document.createElement("div"); + noteDisplay.className = "note-display body"; + noteDisplay.innerHTML = DOMPurify.sanitize(marked.parse(text)); + + note.appendChild(noteTitle); + note.appendChild(noteContent); + note.appendChild(noteDisplay); + + const tagBar = document.createElement("div"); + tagBar.className = "tag-bar"; + + if(tags) { + tags.forEach((tag) => { + const tagElement = document.createElement("div"); + tagElement.className = "note-tag"; + tagElement.textContent = tag; + + tagBar.appendChild(tagElement); + }); + } - customMenu.style.display = "block"; - customMenu.style.left = `${event.clientX}px`; - customMenu.style.top = `${event.clientY}px`; + note.appendChild(tagBar); + + const bottomBar = createFormatBar(); + + const timeText = document.createElement("div"); + timeText.className = "time-text"; + timeText.style = "justify-content: right"; + const noteCreatedTime = new Date(+id); + timeText.textContent = `${noteCreatedTime.toLocaleString([], { + timeStyle: "short", + dateStyle: "short" + })}`; + const bottomDiv = document.createElement("div"); + bottomDiv.className = "bottomDiv"; + bottomDiv.appendChild(bottomBar); + bottomDiv.appendChild(timeText); + note.appendChild(bottomDiv); + + if (insertAfter && insertAfter.nextElementSibling) { + container.insertBefore(note, insertAfter.nextElementSibling); + } else { + container.prepend(note); + } + }, - document.getElementById("rem").addEventListener("click", function() { - let tagBar = note.querySelector('.tag-bar'); - while (tagBar.firstChild) { - tagBar.removeChild(tagBar.firstChild); - } - notes[note.id].tags = []; - saveNotes(); + async saveNotesOrder() { + const newNotesOrder = {}; + const noteElements = Array.from(container.getElementsByClassName("note")); - customMenu.style.display = "none"; + noteElements.forEach(noteElement => { + const id = noteElement.id; + newNotesOrder[id] = notes[id]; }); - document.getElementById("rem").addEventListener("mouseover", function() { - tagMenu.style.display = "none"; - }); - - document.getElementById("addtofolder").addEventListener("mouseover", function(event) { - const tagInputs = document.querySelectorAll('.tag-input'); - - tagMenu.innerHTML = ''; - - tagInputs.forEach(input => { - const menuItem = document.createElement('div'); - menuItem.className = "menu-item"; - menuItem.textContent = input.textContent; - - menuItem.addEventListener("click", () => { - let tagBar = note.querySelector('.tag-bar'); - const tagElement = document.createElement("div"); - tagElement.className = "note-tag"; - tagElement.textContent = menuItem.textContent; - - while (tagBar.firstChild) { - tagBar.removeChild(tagBar.firstChild); - } - tagBar.appendChild(tagElement); - - notes[note.id].tags = []; - notes[note.id].tags.push(menuItem.textContent); - saveNotes(); - }); + notes = newNotesOrder; + await saveNotes(); + }, + + async addContextMenuToNote(note) { + console.log(note); + note.addEventListener("contextmenu", function(event) { + event.preventDefault(); + + customMenu.style.display = "block"; + customMenu.style.left = `${event.clientX}px`; + customMenu.style.top = `${event.clientY}px`; - tagMenu.appendChild(menuItem); + document.getElementById("rem").addEventListener("click", function() { + let tagBar = note.querySelector('.tag-bar'); + while (tagBar.firstChild) { + tagBar.removeChild(tagBar.firstChild); + } + notes[note.id].tags = []; + await saveNotes(); + + customMenu.style.display = "none"; + }); + + document.getElementById("rem").addEventListener("mouseover", function() { + tagMenu.style.display = "none"; + }); + + document.getElementById("addtofolder").addEventListener("mouseover", function(event) { + const tagInputs = document.querySelectorAll('.tag-input'); + + tagMenu.innerHTML = ''; + + tagInputs.forEach(input => { + const menuItem = document.createElement('div'); + menuItem.className = "menu-item"; + menuItem.textContent = input.textContent; + + menuItem.addEventListener("click", () => { + let tagBar = note.querySelector('.tag-bar'); + const tagElement = document.createElement("div"); + tagElement.className = "note-tag"; + tagElement.textContent = menuItem.textContent; + + while (tagBar.firstChild) { + tagBar.removeChild(tagBar.firstChild); + } + tagBar.appendChild(tagElement); + + notes[note.id].tags = []; + notes[note.id].tags.push(menuItem.textContent); + await saveNotes(); + }); + + tagMenu.appendChild(menuItem); + }); + + const customMenuRect = customMenu.getBoundingClientRect(); + tagMenu.style.left = `${customMenuRect.right + 10}px`; + tagMenu.style.top = `${customMenuRect.top}px`; + tagMenu.style.display = "block"; }); - - const customMenuRect = customMenu.getBoundingClientRect(); - tagMenu.style.left = `${customMenuRect.right + 10}px`; - tagMenu.style.top = `${customMenuRect.top}px`; - tagMenu.style.display = "block"; }); - }); + } } +infoInput.addEventListener("keydown", evt => { + if (evt.ctrlKey && evt.key === "Enter") { + evt.preventDefault(); + addNote(""); // that was easy + } +}); + const customMenu = document.createElement("div"); customMenu.className = "custom-context-menu"; diff --git a/js/settings.js b/js/settings.js index 85bf964..373406f 100644 --- a/js/settings.js +++ b/js/settings.js @@ -6,7 +6,7 @@ const defaultSettings = { Object.assign(settings, defaultSettings); -function loadSettings() { +async function loadSettings() { const settingsObject = JSON.parse(localStorage.getItem("settings")) || {}; const keys = Object.keys(settingsObject); console.log("keys!!", keys); @@ -76,7 +76,7 @@ function saveSettings() { } } -function sortNotesByTag() { +async function sortNotesByTag() { const notesArray = Object.entries(notes); notesArray.sort(([, noteA], [, noteB]) => { @@ -112,10 +112,10 @@ function sortNotesByTag() { notes = sortedNotes; reloadNoteHTML(); - saveNotes(); + await saveNotes(); } -function sortNotesByDate() { +async function sortNotesByDate() { const notesArray = Object.entries(notes); notesArray.sort(([idA], [idB]) => idA - idB); @@ -126,7 +126,7 @@ function sortNotesByDate() { notes = sortedNotes; reloadNoteHTML(); - saveNotes(); + await saveNotes(); } // Get references to elements diff --git a/js/sidepanel.js b/js/sidepanel.js deleted file mode 100644 index 8183f4b..0000000 --- a/js/sidepanel.js +++ /dev/null @@ -1,16 +0,0 @@ -loadSettings(); -loadNotes(); -//insertTag(); -//formatBar.append(createFormatBar()); - -add.addEventListener("click", _ => { addNote(""); }); -document.addEventListener("DOMContentLoaded", _ => { reloadNoteHTML(); loadFolders(); }); -document.addEventListener("visibilitychange", _ => { saveNotesOrder(); saveFolders(); }); - -// context menu --> add new note -chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { - const content = request.content; - - // make that new message if it's non-empty - if (content) addNote(content); -}); diff --git a/js/tags.js b/js/tags.js index 33f7cc1..9f5f9a5 100644 --- a/js/tags.js +++ b/js/tags.js @@ -57,7 +57,7 @@ function updateVisible() { }); } -function insertTag(folderName) { +async function insertTag(folderName) { if (tagContainer.querySelector('.new-tag')) { return; } @@ -250,7 +250,7 @@ function insertTag(folderName) { notes[draggedNoteId].tags = []; notes[draggedNoteId].tags.push(tagText); - saveNotes(); + await saveNotes(); } } diff --git a/sidepanel.html b/sidepanel.html index a0122c9..1f515a8 100644 --- a/sidepanel.html +++ b/sidepanel.html @@ -122,15 +122,17 @@ - - + + + + + - - + From 6c187b3bbae565441cde2cfe8f0369b4c9bb7bfc Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Sun, 1 Jun 2025 06:06:45 -0400 Subject: [PATCH 02/12] thinking about how to restructure data --- background.js | 60 ++++++++++++++++++++++++++++++++++++++++++++----- js/notes.js | 5 +++-- newjs/_main_.js | 3 +++ sidepanel.html | 8 +++---- 4 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 newjs/_main_.js diff --git a/background.js b/background.js index d573fa7..5d2f2ed 100644 --- a/background.js +++ b/background.js @@ -1,12 +1,36 @@ -// add context menu on select -function setupContextMenu(){ +// our service worker loses all state every 30s, so we're treating chrome.storage.local as the single source of truth +// to persist data, make changes to storage +const appData = { + notes: [], + folders: [] +} +const initAppData = chrome.storage.local.get().then((items) => { + Object.assign(appData, items); +}); + + +async function saveStorage() { + return chrome.storage.local.set(appData); +} + + + +chrome.runtime.onInstalled.addListener(async () => { + // setup chrome context menus chrome.contextMenus.create({ id: "addnote", title: "Add to Harbor", contexts: ["selection"] }) -} -chrome.runtime.onInstalled.addListener(() => { setupContextMenu() }) + + // initialize storage + try { + await initAppData; + } catch (e) { + // no error handling ? + } + chrome.storage.local.set(appData); +}); // handle context menu click chrome.contextMenus.onClicked.addListener((info, tab) => { @@ -22,4 +46,30 @@ chrome.contextMenus.onClicked.addListener((info, tab) => { // open panel onclick chrome.sidePanel .setPanelBehavior({ openPanelOnActionClick: true }) - .catch((error) => console.error(error)) \ No newline at end of file + .catch((error) => console.error(error)) + +/** Usage: + * chrome.runtime.sendMessage({command: "getData"}) + * chrome.runtime.sendMessage({command: "addNote", title: "test", content: "hello world"}) + **/ +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message === null) return; + const command = message.command; + + switch (command) { + case "getData": { + sendResponse(appData); + break; + } + + case "addNote": { + const {title, content, folder} = message; + } + + + default: { + sendResponse("I DONT KNOW WHAT YOU WANT ME TO DO"); + break; + } + } +}); \ No newline at end of file diff --git a/js/notes.js b/js/notes.js index ce8f5cd..5c58bb1 100644 --- a/js/notes.js +++ b/js/notes.js @@ -2,12 +2,13 @@ const infoInput = document.getElementById("info"); const titleInput = document.getElementById("title"); export default Notes = { + data: {}, + // a bunch of helper functions in case we need them later // tbh we don't really need them but it's nicer to type async loadNotes() { - console.log("bleghhhh"); const { notesData } = await chrome.storage.local.get("notesData"); - notes = notesData; + data = notesData; }, async saveNotes() { diff --git a/newjs/_main_.js b/newjs/_main_.js new file mode 100644 index 0000000..b8d4016 --- /dev/null +++ b/newjs/_main_.js @@ -0,0 +1,3 @@ +chrome.runtime.sendMessage('getNotes', (response) => { + console.log('received user data', response); +}); \ No newline at end of file diff --git a/sidepanel.html b/sidepanel.html index 1f515a8..abde172 100644 --- a/sidepanel.html +++ b/sidepanel.html @@ -123,16 +123,16 @@ - - - + + + From 38864812aacc7b8309a8a2d85b9f1f3e7a23b175 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Sun, 1 Jun 2025 22:14:27 -0400 Subject: [PATCH 03/12] some more message passing --- background.js | 65 +++++++++++++++++++++++++++++++++++-------------- newjs/_main_.js | 31 ++++++++++++++++++++--- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/background.js b/background.js index 5d2f2ed..b19f7f7 100644 --- a/background.js +++ b/background.js @@ -1,9 +1,27 @@ -// our service worker loses all state every 30s, so we're treating chrome.storage.local as the single source of truth -// to persist data, make changes to storage +/** Helpful type definitions + * @typedef {Object} Note + * @property {string} title - Title of the note + * @property {string} content - Content of the note + * @property {Date} createdDate - The date the note was created + * @property {number} folderID - unique ID of the folder + * + * @typedef {Object} Folder + * @property {string} folderName + * @property {number} folderID + * + * @typedef AppData + * @property {Note[]} notes + * @property {number[]} folders + */ + +/** @type AppData - Stores the app's state */ const appData = { notes: [], folders: [] } + +// Our service worker loses all state every 30s, so we're treating chrome.storage.local as the single source of truth +// To persist data, make changes to storage const initAppData = chrome.storage.local.get().then((items) => { Object.assign(appData, items); }); @@ -13,6 +31,10 @@ async function saveStorage() { return chrome.storage.local.set(appData); } +async function PaulRevere() { + chrome.runtime.sendMessage("updateNotes"); +} + chrome.runtime.onInstalled.addListener(async () => { @@ -24,36 +46,39 @@ chrome.runtime.onInstalled.addListener(async () => { }) // initialize storage - try { - await initAppData; - } catch (e) { - // no error handling ? - } + await initAppData chrome.storage.local.set(appData); }); // handle context menu click chrome.contextMenus.onClicked.addListener((info, tab) => { - console.log(info, tab); if (info.menuItemId === "addnote") { - console.log(`Adding the note "${info.selectionText}"`); - - // we don't need a response, don't bother waiting for one - chrome.runtime.sendMessage({content: info.selectionText}); + chrome.runtime.sendMessage({ + command: "addNote", + data: { /** @type Note */ + title: "", + content: info.selectionText, + createdDate: Date.now(), + folderID: -1 + } + }); } -}) +}); // open panel onclick chrome.sidePanel .setPanelBehavior({ openPanelOnActionClick: true }) .catch((error) => console.error(error)) -/** Usage: +/** Usage * chrome.runtime.sendMessage({command: "getData"}) - * chrome.runtime.sendMessage({command: "addNote", title: "test", content: "hello world"}) + * chrome.runtime.sendMessage({command: "addNote", data: {title: "test", content: "hello world"}}) **/ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - if (message === null) return; + if (message === null || message.command === null) { + sendResponse("CHECK YOU FORMATTED THE COMMAND PROPERLY"); + return; + }; const command = message.command; switch (command) { @@ -63,10 +88,14 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { } case "addNote": { - const {title, content, folder} = message; + /** @type Note */ + const noteData = message.data; + const {title, content, createdDate, folderID} = noteData; + appData.notes.push({title, content, createdDate, folderID}); + chrome.runtime.message("addNoteUI") + saveStorage(); } - default: { sendResponse("I DONT KNOW WHAT YOU WANT ME TO DO"); break; diff --git a/newjs/_main_.js b/newjs/_main_.js index b8d4016..ecde043 100644 --- a/newjs/_main_.js +++ b/newjs/_main_.js @@ -1,3 +1,28 @@ -chrome.runtime.sendMessage('getNotes', (response) => { - console.log('received user data', response); -}); \ No newline at end of file +chrome.runtime.sendMessage({command: "getNotes"}, (response) => { + console.log(response); +}); + + + + +(async _ => { + + + // await loadSettings(); + // await loadNotes(); + //insertTag(); + //formatBar.append(createFormatBar()); + + add.addEventListener("click", _ => { addNote(""); }); + document.addEventListener("DOMContentLoaded", _ => { reloadNoteHTML(); loadFolders(); }); + document.addEventListener("visibilitychange", _ => { saveNotesOrder(); saveFolders(); }); + + // context menu --> add new note + chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + const content = request.content; + + // make that new message if it's non-empty + if (content) addNote(content); + }); +})() + From 0c1f3d677009a75713403fcb5a057a19eb5e9bf0 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Tue, 3 Jun 2025 01:12:35 -0400 Subject: [PATCH 04/12] addNote and deleteNote events --- background.js | 68 ++++++++-- newjs/_main_.js | 332 ++++++++++++++++++++++++++++++++++++++++++++++++ newjs/notes.js | 0 3 files changed, 389 insertions(+), 11 deletions(-) create mode 100644 newjs/notes.js diff --git a/background.js b/background.js index b19f7f7..2d7645f 100644 --- a/background.js +++ b/background.js @@ -1,5 +1,6 @@ /** Helpful type definitions * @typedef {Object} Note + * @property {string|number} noteID - Unique ID identifying the note * @property {string} title - Title of the note * @property {string} content - Content of the note * @property {Date} createdDate - The date the note was created @@ -32,7 +33,7 @@ async function saveStorage() { } async function PaulRevere() { - chrome.runtime.sendMessage("updateNotes"); + chrome.runtime.sendMessage({command: "UpdateUI"}); } @@ -74,26 +75,71 @@ chrome.sidePanel * chrome.runtime.sendMessage({command: "getData"}) * chrome.runtime.sendMessage({command: "addNote", data: {title: "test", content: "hello world"}}) **/ -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - if (message === null || message.command === null) { - sendResponse("CHECK YOU FORMATTED THE COMMAND PROPERLY"); - return; - }; +chrome.runtime.onMessage.addListener(processCommand); + +/** + * The core event loop for the extension + * @param {{command: string, data?: Object}} message + * @param {chrome.runtime.MessageSender} sender + * @param {(response?: any) => void} sendResponse + */ +function processCommand(message, sender, sendResponse) { + if (message === null || message.command === null) return; const command = message.command; + const data = message.data; switch (command) { case "getData": { sendResponse(appData); break; } + case "getNotes": { + sendResponse(appData.notes); + break; + } + case "getStructure": { + sendResponse(appData.folders); + break; + } case "addNote": { /** @type Note */ - const noteData = message.data; - const {title, content, createdDate, folderID} = noteData; - appData.notes.push({title, content, createdDate, folderID}); - chrome.runtime.message("addNoteUI") + const noteData = data; + // you can replace the noteID with whatever you want, as long as it's a unique string/number + let noteObject = { + noteID: (Math.random()+"").slice(2) + (Math.random()+"").slice(2), + title: noteData.title, + content: noteData.content, + createdDate: noteData.createdDate, + folderID: noteData.folderID || -1 + } + + appData.notes.push(noteObject); + chrome.runtime.sendMessage({command: "addNoteUI", data: noteObject}); + saveStorage(); + break; + } + + case "deleteNote": { + const noteID = data.id; + + let deletedNoteIndex = appData.notes.find(note => note.noteID === noteID); + if (deletedNoteIndex !== -1) { + let noteObject = appData.notes.splice(deletedNoteIndex, 1)[0]; + chrome.runtime.sendMessage({command: "deleteNoteUI", data: noteObject}); + saveStorage(); + } else { + console.error(`Trying to delete note ${noteID}, which can't be found`); + } + + break; + } + + case "deleteAllNotes": { + appData.notes = []; + chrome.runtime.sendMessage({command: "deleteAllNotesUI"}); saveStorage(); + break; } default: { @@ -101,4 +147,4 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { break; } } -}); \ No newline at end of file +} \ No newline at end of file diff --git a/newjs/_main_.js b/newjs/_main_.js index ecde043..8c096f9 100644 --- a/newjs/_main_.js +++ b/newjs/_main_.js @@ -26,3 +26,335 @@ chrome.runtime.sendMessage({command: "getNotes"}, (response) => { }); })() + + + + +const infoInput = document.getElementById("info"); +const titleInput = document.getElementById("title"); + + + +function reloadNoteHTML() { + // delete all the current notes + const currentNotes = Array.from(document.getElementsByClassName("note")); + for (let i = 0; i < currentNotes.length; i++) { + currentNotes[i].remove(); + } + + // add them all back from notes[] + Object.entries(notes).reverse().forEach(([id, {title, content, tags}]) => { + addNoteHTML(title, content, tags, id); + }); +} + +function deleteNote(id) { + chrome.runtime.sendMessage({command: "deleteNote", data: {noteID: id}}); +} + +function deleteAllNotes() { + notes = {}; + reloadNoteHTML(); + await saveNotes(); + reloadFolders(); +}, + +/** + * this function only creates the note in the notes[] array, then calls addNoteHTML + * @param {string} text - textual/body content of note + * @param {object} insertAfter - the note that precedes the new note you're trying to add + */ + +function addNote(text, insertAfter) { + const title = titleInput.value || ""; + const content = text === "" ? infoInput.value : text; + infoInput.value = ""; // empty out the textbox + titleInput.value = ""; + + // stop if no text is provided + if (title === "" && content === "") return; + + const id = Date.now(); + const tags = []; + + notes[id] = { title, content, tags }; + + //Move new note to top + const notesArray = Object.entries(notes); + if (notesArray.length > 0) { + newNote = notesArray.pop() + notesArray.unshift(newNote); + + const sortedNotes = {}; + notesArray.forEach(([id, note]) => { + sortedNotes[id] = note; + }); + notes = sortedNotes; + } + + await saveNotes(); + reloadNoteHTML(); + console.log(tags); +}, + +/** + * Generates the actual HTML element in the DOM + * don't call directly unless you're reloading + * @param {string} title - title of a note + * @param {string} text - textual/body content of a note + * @param {string[]} tags - list containing all tags of a given note + * @param {string} id + * @param {object} insertAfter - the note that precedes the new note you're trying to add + */ +addNoteHTML(title, text, tags, id, insertAfter = null) { + if (!id) { + console.log("no ID provided!!!"); + } + // create note elements, then add event listeners + const note = document.createElement("div"); + note.className = "note"; + note.id = id; + note.draggable = true; + + const deleteButton = document.createElement("button"); + deleteButton.className = "del"; + deleteButton.textContent = "X"; + deleteButton.style.display = "none"; + deleteButton.addEventListener("click", function (event) { + event.stopPropagation(); + deleteNote(id); + note.remove(); + customMenu.style.display = "none"; + + // remove overlay + let ove = document.getElementsByClassName("overlay"); + if (ove.length !== 0) document.body.removeChild(ove[0]); + }); + note.appendChild(deleteButton); + + addDraggingEvents(note); + addContextMenuToNote(note); + + note.addEventListener("mouseover", function () { + deleteButton.style.display = "block"; + }); + + note.addEventListener("mouseout", function () { + deleteButton.style.display = "none"; + }); + + note.addEventListener("click", function (event) { + // if the user clicks on a link inside the note, don't change into edit mode + if (event.target.nodeName === "A") return; + + if (!this.classList.contains("overlay-created")) { + const overlay = document.createElement("div"); + overlay.className = "overlay"; + document.body.appendChild(overlay); + + // show only noteContent + const noteTitle = note.getElementsByClassName("note-title")[0]; + const noteContent = note.getElementsByClassName("note-content")[0]; + const noteDisplay = note.getElementsByClassName("note-display")[0]; + noteContent.classList.remove("displayNone"); + noteDisplay.classList.add("displayNone"); + + // Disable dragging if note in focused mode + note.draggable = false; + overlay.addEventListener("click", function () { + // remove overlay + document.body.removeChild(overlay); + note.classList.remove("overlay-created"); + note.style.zIndex = null; + note.draggable = true; + + // update noteDisplay, persist to notes + notes[note.id].title = noteTitle.innerText; + notes[note.id].content = noteContent.value; + //TODO: persist tags as well + noteDisplay.innerHTML = DOMPurify.sanitize(marked.parse(noteContent.value)); + + // only show noteDisplay + noteContent.classList.add("displayNone"); + noteDisplay.classList.remove("displayNone"); + }); + + this.classList.add("overlay-created"); + this.style.zIndex = "999"; + } + }); + + const noteTitle = document.createElement("div"); + noteTitle.contentEditable = "plaintext-only"; + noteTitle.className = "note-title title"; + noteTitle.innerText = title; + const noteContent = document.createElement("textarea"); + noteContent.className = "note-content displayNone body"; + noteContent.value = text; + const noteDisplay = document.createElement("div"); + noteDisplay.className = "note-display body"; + noteDisplay.innerHTML = DOMPurify.sanitize(marked.parse(text)); + + note.appendChild(noteTitle); + note.appendChild(noteContent); + note.appendChild(noteDisplay); + + const tagBar = document.createElement("div"); + tagBar.className = "tag-bar"; + + if(tags) { + tags.forEach((tag) => { + const tagElement = document.createElement("div"); + tagElement.className = "note-tag"; + tagElement.textContent = tag; + + tagBar.appendChild(tagElement); + }); + } + + note.appendChild(tagBar); + + const bottomBar = createFormatBar(); + + const timeText = document.createElement("div"); + timeText.className = "time-text"; + timeText.style = "justify-content: right"; + const noteCreatedTime = new Date(+id); + timeText.textContent = `${noteCreatedTime.toLocaleString([], { + timeStyle: "short", + dateStyle: "short" + })}`; + const bottomDiv = document.createElement("div"); + bottomDiv.className = "bottomDiv"; + bottomDiv.appendChild(bottomBar); + bottomDiv.appendChild(timeText); + note.appendChild(bottomDiv); + + if (insertAfter && insertAfter.nextElementSibling) { + container.insertBefore(note, insertAfter.nextElementSibling); + } else { + container.prepend(note); + } +}, + +async saveNotesOrder() { + const newNotesOrder = {}; + const noteElements = Array.from(container.getElementsByClassName("note")); + + noteElements.forEach(noteElement => { + const id = noteElement.id; + newNotesOrder[id] = notes[id]; + }); + + notes = newNotesOrder; + await saveNotes(); +}, + +async addContextMenuToNote(note) { + console.log(note); + note.addEventListener("contextmenu", function(event) { + event.preventDefault(); + + customMenu.style.display = "block"; + customMenu.style.left = `${event.clientX}px`; + customMenu.style.top = `${event.clientY}px`; + + document.getElementById("rem").addEventListener("click", function() { + let tagBar = note.querySelector('.tag-bar'); + while (tagBar.firstChild) { + tagBar.removeChild(tagBar.firstChild); + } + notes[note.id].tags = []; + await saveNotes(); + + customMenu.style.display = "none"; + }); + + document.getElementById("rem").addEventListener("mouseover", function() { + tagMenu.style.display = "none"; + }); + + document.getElementById("addtofolder").addEventListener("mouseover", function(event) { + const tagInputs = document.querySelectorAll('.tag-input'); + + tagMenu.innerHTML = ''; + + tagInputs.forEach(input => { + const menuItem = document.createElement('div'); + menuItem.className = "menu-item"; + menuItem.textContent = input.textContent; + + menuItem.addEventListener("click", () => { + let tagBar = note.querySelector('.tag-bar'); + const tagElement = document.createElement("div"); + tagElement.className = "note-tag"; + tagElement.textContent = menuItem.textContent; + + while (tagBar.firstChild) { + tagBar.removeChild(tagBar.firstChild); + } + tagBar.appendChild(tagElement); + + notes[note.id].tags = []; + notes[note.id].tags.push(menuItem.textContent); + await saveNotes(); + }); + + tagMenu.appendChild(menuItem); + }); + + const customMenuRect = customMenu.getBoundingClientRect(); + tagMenu.style.left = `${customMenuRect.right + 10}px`; + tagMenu.style.top = `${customMenuRect.top}px`; + tagMenu.style.display = "block"; + }); + }); +} + + + + + + + + + + + + + +infoInput.addEventListener("keydown", evt => { + if (evt.ctrlKey && evt.key === "Enter") { + evt.preventDefault(); + addNote(""); // that was easy + } +}); + +const customMenu = document.createElement("div"); +customMenu.className = "custom-context-menu"; + +customMenu.innerHTML = ` + + +`; + +document.body.appendChild(customMenu); + +const tagMenu = document.createElement('div'); +tagMenu.className = "custom-context-menu"; +tagMenu.style.display = "none"; + +tagMenu.addEventListener("mouseleave", () => { + tagMenu.style.display = "none"; +}); + +document.body.appendChild(tagMenu); + +document.addEventListener("click", function () { + customMenu.style.display = "none"; + tagMenu.style.display = "none"; +}); + +document.addEventListener("contextmenu", () => { + tagMenu.style.display = "none"; +}); \ No newline at end of file diff --git a/newjs/notes.js b/newjs/notes.js new file mode 100644 index 0000000..e69de29 From a96327dc63eec44e6cf2ea21c8d7e904da648152 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Fri, 6 Jun 2025 01:58:57 -0400 Subject: [PATCH 05/12] context menu addNotes now works --- background.js | 2 +- js/notes.js | 4 +- newjs/_main_.js | 133 +++++++++++++++++++++--------------------------- 3 files changed, 62 insertions(+), 77 deletions(-) diff --git a/background.js b/background.js index 2d7645f..64ae17f 100644 --- a/background.js +++ b/background.js @@ -54,7 +54,7 @@ chrome.runtime.onInstalled.addListener(async () => { // handle context menu click chrome.contextMenus.onClicked.addListener((info, tab) => { if (info.menuItemId === "addnote") { - chrome.runtime.sendMessage({ + processCommand({ command: "addNote", data: { /** @type Note */ title: "", diff --git a/js/notes.js b/js/notes.js index 5c58bb1..23c02b5 100644 --- a/js/notes.js +++ b/js/notes.js @@ -239,7 +239,7 @@ export default Notes = { customMenu.style.left = `${event.clientX}px`; customMenu.style.top = `${event.clientY}px`; - document.getElementById("rem").addEventListener("click", function() { + document.getElementById("rem").addEventListener("click", async () => { let tagBar = note.querySelector('.tag-bar'); while (tagBar.firstChild) { tagBar.removeChild(tagBar.firstChild); @@ -264,7 +264,7 @@ export default Notes = { menuItem.className = "menu-item"; menuItem.textContent = input.textContent; - menuItem.addEventListener("click", () => { + menuItem.addEventListener("click", async () => { let tagBar = note.querySelector('.tag-bar'); const tagElement = document.createElement("div"); tagElement.className = "note-tag"; diff --git a/newjs/_main_.js b/newjs/_main_.js index 8c096f9..da451a7 100644 --- a/newjs/_main_.js +++ b/newjs/_main_.js @@ -1,31 +1,21 @@ -chrome.runtime.sendMessage({command: "getNotes"}, (response) => { - console.log(response); -}); +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + console.log(request); + const { command, data } = request; -(async _ => { - - - // await loadSettings(); - // await loadNotes(); - //insertTag(); - //formatBar.append(createFormatBar()); + if (command === "addNoteUI") { + let noteObject = data; + addNoteHTML(noteObject) + } +}); - add.addEventListener("click", _ => { addNote(""); }); - document.addEventListener("DOMContentLoaded", _ => { reloadNoteHTML(); loadFolders(); }); - document.addEventListener("visibilitychange", _ => { saveNotesOrder(); saveFolders(); }); - // context menu --> add new note - chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { - const content = request.content; - // make that new message if it's non-empty - if (content) addNote(content); - }); -})() +document.addEventListener("DOMContentLoaded", _ => { reloadNoteHTML(); }); +document.addEventListener("visibilitychange", _ => { reloadNoteHTML(); }); @@ -34,17 +24,19 @@ const infoInput = document.getElementById("info"); const titleInput = document.getElementById("title"); - +// call on DOM reload and page init function reloadNoteHTML() { - // delete all the current notes - const currentNotes = Array.from(document.getElementsByClassName("note")); - for (let i = 0; i < currentNotes.length; i++) { - currentNotes[i].remove(); - } + chrome.runtime.sendMessage({command: "getNotes"}, (notes) => { + // delete all the current notes + const currentNotes = Array.from(document.getElementsByClassName("note")); + for (let i = 0; i < currentNotes.length; i++) { + currentNotes[i].remove(); + } - // add them all back from notes[] - Object.entries(notes).reverse().forEach(([id, {title, content, tags}]) => { - addNoteHTML(title, content, tags, id); + // add them all back from notes[] + notes.forEach(noteObject => { + addNoteHTML(noteObject); + }); }); } @@ -53,19 +45,16 @@ function deleteNote(id) { } function deleteAllNotes() { - notes = {}; - reloadNoteHTML(); - await saveNotes(); - reloadFolders(); -}, + chrome.runtime.sendMessage({command: "deleteAllNotes"}); +} /** * this function only creates the note in the notes[] array, then calls addNoteHTML - * @param {string} text - textual/body content of note + * @param {Note} note - The note object * @param {object} insertAfter - the note that precedes the new note you're trying to add */ -function addNote(text, insertAfter) { +async function addNote(noteObject, insertAfter) { const title = titleInput.value || ""; const content = text === "" ? infoInput.value : text; infoInput.value = ""; // empty out the textbox @@ -95,35 +84,32 @@ function addNote(text, insertAfter) { await saveNotes(); reloadNoteHTML(); console.log(tags); -}, +} /** * Generates the actual HTML element in the DOM * don't call directly unless you're reloading - * @param {string} title - title of a note - * @param {string} text - textual/body content of a note - * @param {string[]} tags - list containing all tags of a given note - * @param {string} id + * @param {Note} noteObject - The note we're trying to add * @param {object} insertAfter - the note that precedes the new note you're trying to add */ -addNoteHTML(title, text, tags, id, insertAfter = null) { - if (!id) { - console.log("no ID provided!!!"); - } +function addNoteHTML(noteObject, insertAfter) { + let { noteID, title, content, createdDate, folderID } = noteObject; + + if (!noteID) console.log("no ID provided!!!"); + // create note elements, then add event listeners const note = document.createElement("div"); note.className = "note"; - note.id = id; + note.id = noteID; note.draggable = true; const deleteButton = document.createElement("button"); deleteButton.className = "del"; deleteButton.textContent = "X"; deleteButton.style.display = "none"; - deleteButton.addEventListener("click", function (event) { - event.stopPropagation(); + deleteButton.addEventListener("click", evt => { + evt.stopPropagation(); deleteNote(id); - note.remove(); customMenu.style.display = "none"; // remove overlay @@ -132,8 +118,8 @@ addNoteHTML(title, text, tags, id, insertAfter = null) { }); note.appendChild(deleteButton); - addDraggingEvents(note); - addContextMenuToNote(note); + // addDraggingEvents(note); + // addContextMenuToNote(note); note.addEventListener("mouseover", function () { deleteButton.style.display = "block"; @@ -190,43 +176,43 @@ addNoteHTML(title, text, tags, id, insertAfter = null) { noteTitle.innerText = title; const noteContent = document.createElement("textarea"); noteContent.className = "note-content displayNone body"; - noteContent.value = text; + noteContent.value = content; const noteDisplay = document.createElement("div"); noteDisplay.className = "note-display body"; - noteDisplay.innerHTML = DOMPurify.sanitize(marked.parse(text)); + noteDisplay.innerHTML = DOMPurify.sanitize(marked.parse(content)); note.appendChild(noteTitle); note.appendChild(noteContent); note.appendChild(noteDisplay); - const tagBar = document.createElement("div"); - tagBar.className = "tag-bar"; + // const tagBar = document.createElement("div"); + // tagBar.className = "tag-bar"; - if(tags) { - tags.forEach((tag) => { - const tagElement = document.createElement("div"); - tagElement.className = "note-tag"; - tagElement.textContent = tag; + // if(tags) { + // tags.forEach((tag) => { + // const tagElement = document.createElement("div"); + // tagElement.className = "note-tag"; + // tagElement.textContent = tag; - tagBar.appendChild(tagElement); - }); - } + // tagBar.appendChild(tagElement); + // }); + // } - note.appendChild(tagBar); + // note.appendChild(tagBar); - const bottomBar = createFormatBar(); + // const bottomBar = createFormatBar(); const timeText = document.createElement("div"); timeText.className = "time-text"; timeText.style = "justify-content: right"; - const noteCreatedTime = new Date(+id); + const noteCreatedTime = new Date(+createdDate); timeText.textContent = `${noteCreatedTime.toLocaleString([], { timeStyle: "short", dateStyle: "short" })}`; const bottomDiv = document.createElement("div"); bottomDiv.className = "bottomDiv"; - bottomDiv.appendChild(bottomBar); + // bottomDiv.appendChild(bottomBar); bottomDiv.appendChild(timeText); note.appendChild(bottomDiv); @@ -235,9 +221,9 @@ addNoteHTML(title, text, tags, id, insertAfter = null) { } else { container.prepend(note); } -}, +} -async saveNotesOrder() { +async function saveNotesOrder() { const newNotesOrder = {}; const noteElements = Array.from(container.getElementsByClassName("note")); @@ -248,10 +234,9 @@ async saveNotesOrder() { notes = newNotesOrder; await saveNotes(); -}, +} -async addContextMenuToNote(note) { - console.log(note); +async function addContextMenuToNote(note) { note.addEventListener("contextmenu", function(event) { event.preventDefault(); @@ -259,7 +244,7 @@ async addContextMenuToNote(note) { customMenu.style.left = `${event.clientX}px`; customMenu.style.top = `${event.clientY}px`; - document.getElementById("rem").addEventListener("click", function() { + document.getElementById("rem").addEventListener("click", async () => { let tagBar = note.querySelector('.tag-bar'); while (tagBar.firstChild) { tagBar.removeChild(tagBar.firstChild); @@ -284,7 +269,7 @@ async addContextMenuToNote(note) { menuItem.className = "menu-item"; menuItem.textContent = input.textContent; - menuItem.addEventListener("click", () => { + menuItem.addEventListener("click", async () => { let tagBar = note.querySelector('.tag-bar'); const tagElement = document.createElement("div"); tagElement.className = "note-tag"; From 0ab3ff0fb98c0cb66e792e602ff842530820a0b7 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Fri, 6 Jun 2025 02:23:14 -0400 Subject: [PATCH 06/12] addNotes and deleting notes works now --- background.js | 21 +++++++++++++-------- newjs/_main_.js | 46 ++++++++++++++++------------------------------ 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/background.js b/background.js index 64ae17f..01120b6 100644 --- a/background.js +++ b/background.js @@ -103,15 +103,19 @@ function processCommand(message, sender, sendResponse) { } case "addNote": { - /** @type Note */ - const noteData = data; + const { title, content, createdDate, folderID } = data; // you can replace the noteID with whatever you want, as long as it's a unique string/number let noteObject = { noteID: (Math.random()+"").slice(2) + (Math.random()+"").slice(2), - title: noteData.title, - content: noteData.content, - createdDate: noteData.createdDate, - folderID: noteData.folderID || -1 + title: title || "", + content: content || "", + createdDate: createdDate || Date.now(), + folderID: folderID || -1 + } + + if (noteObject.title === "" && noteObject.content === "") { + console.error("WARNING, TRYING TO ADD EMPTY NOTE!", noteObject); + return; } appData.notes.push(noteObject); @@ -121,9 +125,10 @@ function processCommand(message, sender, sendResponse) { } case "deleteNote": { - const noteID = data.id; + const noteID = data.noteID; - let deletedNoteIndex = appData.notes.find(note => note.noteID === noteID); + let deletedNoteIndex = appData.notes.findIndex(note => note.noteID === noteID); + console.log(`deleting note index ${deletedNoteIndex}`); if (deletedNoteIndex !== -1) { let noteObject = appData.notes.splice(deletedNoteIndex, 1)[0]; chrome.runtime.sendMessage({command: "deleteNoteUI", data: noteObject}); diff --git a/newjs/_main_.js b/newjs/_main_.js index da451a7..93ae0ca 100644 --- a/newjs/_main_.js +++ b/newjs/_main_.js @@ -8,12 +8,16 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (command === "addNoteUI") { let noteObject = data; addNoteHTML(noteObject) + } else if (command === "deleteNoteUI") { + reloadNoteHTML(); } }); - +add.addEventListener("click", _ => { + addNote(); +}); document.addEventListener("DOMContentLoaded", _ => { reloadNoteHTML(); }); document.addEventListener("visibilitychange", _ => { reloadNoteHTML(); }); @@ -48,42 +52,23 @@ function deleteAllNotes() { chrome.runtime.sendMessage({command: "deleteAllNotes"}); } -/** - * this function only creates the note in the notes[] array, then calls addNoteHTML - * @param {Note} note - The note object - * @param {object} insertAfter - the note that precedes the new note you're trying to add - */ - -async function addNote(noteObject, insertAfter) { +async function addNote() { const title = titleInput.value || ""; - const content = text === "" ? infoInput.value : text; + const content = infoInput.value || ""; infoInput.value = ""; // empty out the textbox titleInput.value = ""; // stop if no text is provided if (title === "" && content === "") return; - const id = Date.now(); - const tags = []; - - notes[id] = { title, content, tags }; - - //Move new note to top - const notesArray = Object.entries(notes); - if (notesArray.length > 0) { - newNote = notesArray.pop() - notesArray.unshift(newNote); + /** @type {Note} */ + const noteObject = { + title, + content, + folderID: -1 + } - const sortedNotes = {}; - notesArray.forEach(([id, note]) => { - sortedNotes[id] = note; - }); - notes = sortedNotes; - } - - await saveNotes(); - reloadNoteHTML(); - console.log(tags); + chrome.runtime.sendMessage({command: "addNote", data: noteObject}); } /** @@ -109,7 +94,8 @@ function addNoteHTML(noteObject, insertAfter) { deleteButton.style.display = "none"; deleteButton.addEventListener("click", evt => { evt.stopPropagation(); - deleteNote(id); + console.log(`deleting note ${noteID}`) + deleteNote(noteID); customMenu.style.display = "none"; // remove overlay From 54067eaa6bbc4c287c0f544c04afe2a5847f13e1 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Tue, 17 Jun 2025 20:15:59 -0400 Subject: [PATCH 07/12] add deleting notes --- background.js | 2 +- newjs/_main_.js | 47 +++++++++++++++++++++-------------------------- newjs/events.js | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 newjs/events.js diff --git a/background.js b/background.js index 01120b6..5670f5d 100644 --- a/background.js +++ b/background.js @@ -32,7 +32,7 @@ async function saveStorage() { return chrome.storage.local.set(appData); } -async function PaulRevere() { +function PaulRevere() { chrome.runtime.sendMessage({command: "UpdateUI"}); } diff --git a/newjs/_main_.js b/newjs/_main_.js index 93ae0ca..3f0df5d 100644 --- a/newjs/_main_.js +++ b/newjs/_main_.js @@ -5,7 +5,9 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { const { command, data } = request; - if (command === "addNoteUI") { + if (command === "UpdateUI") { + reloadNoteHTML(); + } else if (command === "addNoteUI") { let noteObject = data; addNoteHTML(noteObject) } else if (command === "deleteNoteUI") { @@ -28,31 +30,14 @@ const infoInput = document.getElementById("info"); const titleInput = document.getElementById("title"); -// call on DOM reload and page init -function reloadNoteHTML() { - chrome.runtime.sendMessage({command: "getNotes"}, (notes) => { - // delete all the current notes - const currentNotes = Array.from(document.getElementsByClassName("note")); - for (let i = 0; i < currentNotes.length; i++) { - currentNotes[i].remove(); - } - - // add them all back from notes[] - notes.forEach(noteObject => { - addNoteHTML(noteObject); - }); - }); -} - function deleteNote(id) { chrome.runtime.sendMessage({command: "deleteNote", data: {noteID: id}}); } - function deleteAllNotes() { chrome.runtime.sendMessage({command: "deleteAllNotes"}); } -async function addNote() { +function addNote() { const title = titleInput.value || ""; const content = infoInput.value || ""; infoInput.value = ""; // empty out the textbox @@ -61,16 +46,26 @@ async function addNote() { // stop if no text is provided if (title === "" && content === "") return; - /** @type {Note} */ - const noteObject = { - title, - content, - folderID: -1 - } - + const noteObject = { title, content, folderID: -1 } chrome.runtime.sendMessage({command: "addNote", data: noteObject}); } +// call on DOM reload and page init +function reloadNoteHTML() { + chrome.runtime.sendMessage({command: "getNotes"}, (notes) => { + // delete all the current notes + const currentNotes = Array.from(document.getElementsByClassName("note")); + for (let i = 0; i < currentNotes.length; i++) { + currentNotes[i].remove(); + } + + // add them all back from notes[] + notes.forEach(noteObject => { + addNoteHTML(noteObject); + }); + }); +} + /** * Generates the actual HTML element in the DOM * don't call directly unless you're reloading diff --git a/newjs/events.js b/newjs/events.js new file mode 100644 index 0000000..28ca363 --- /dev/null +++ b/newjs/events.js @@ -0,0 +1,21 @@ +const events = { + get: { + getData: "", + getNotes: "", + getStructure: "" + }, + + update: { + addNote: "", + updateNote: "", + deleteNote: "", + deleteAllNotes: "" + }, + + ui: { + addNoteUI: "", + deleteNoteUI: "", + deleteAllNotesUI: "", + UpdateUI: "" + } +} \ No newline at end of file From 214df388727c551187136cbcec17105734eeef80 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Tue, 17 Jun 2025 23:29:49 -0400 Subject: [PATCH 08/12] experiment with splitting into multiple pages --- manifest.json | 2 +- newjs/notes.js | 0 pages/main.html | 131 +++++++++++++++++++++++++ pages/settings.html | 94 ++++++++++++++++++ sidepanel.html => pages/sidepanel.html | 9 +- style.css => pages/style.css | 0 6 files changed, 231 insertions(+), 5 deletions(-) delete mode 100644 newjs/notes.js create mode 100644 pages/main.html create mode 100644 pages/settings.html rename sidepanel.html => pages/sidepanel.html (96%) rename style.css => pages/style.css (100%) diff --git a/manifest.json b/manifest.json index f53f856..e502f1a 100644 --- a/manifest.json +++ b/manifest.json @@ -7,7 +7,7 @@ "service_worker": "background.js" }, "side_panel":{ - "default_path": "sidepanel.html" + "default_path": "./pages/main.html" }, "permissions": [ "sidePanel", diff --git a/newjs/notes.js b/newjs/notes.js deleted file mode 100644 index e69de29..0000000 diff --git a/pages/main.html b/pages/main.html new file mode 100644 index 0000000..705246a --- /dev/null +++ b/pages/main.html @@ -0,0 +1,131 @@ + + + + + + + + + + + teaaaaaaaaaaaaast + +
+ + + + + + + +
+ +
+
+ + +
+
+ + +
+ +
+
+ + +
+
+
+ + +
+ + +
+ + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + diff --git a/pages/settings.html b/pages/settings.html new file mode 100644 index 0000000..1812af2 --- /dev/null +++ b/pages/settings.html @@ -0,0 +1,94 @@ + + + + + + + + + + + +
+ + + +
+ + +
+ + +
+ + test + + + + + + + + + + + + + + + + + diff --git a/sidepanel.html b/pages/sidepanel.html similarity index 96% rename from sidepanel.html rename to pages/sidepanel.html index abde172..07e9e6a 100644 --- a/sidepanel.html +++ b/pages/sidepanel.html @@ -1,8 +1,9 @@ + - - - + + + @@ -123,7 +124,7 @@ - + -
- - -
- - - -
- - -
- - -
- - - - - - - - - - - - - - - - - + + + + + + + + + +

Note Harbor (Settings)

+ + + + + + + +

+
+
+ +
+
+
+ +
+

+ + +
+ + + +
+
+ +

+ +
+ + + From 720b13325fb607e8a91646e07461880225d4ccb7 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Thu, 19 Jun 2025 03:21:14 -0400 Subject: [PATCH 10/12] refactor theme selector, cleaning CSS --- background.js | 36 +-- newjs/_settings_.js | 108 ++++++++ newjs/themes.js | 130 ++++++++++ pages/main.css | 151 +++++++++-- pages/main.html | 76 ++++-- pages/main2.css | 619 ++++++++++++++++++++++++++++++++++++++++++++ pages/settings.html | 42 +-- pages/style.css | 36 +-- pages/theme.css | 108 ++++++++ 9 files changed, 1203 insertions(+), 103 deletions(-) create mode 100644 newjs/_settings_.js create mode 100644 newjs/themes.js create mode 100644 pages/main2.css create mode 100644 pages/theme.css diff --git a/background.js b/background.js index 5670f5d..c859dad 100644 --- a/background.js +++ b/background.js @@ -13,30 +13,23 @@ * @typedef AppData * @property {Note[]} notes * @property {number[]} folders + * @property {{theme: number}} settings */ /** @type AppData - Stores the app's state */ const appData = { notes: [], - folders: [] -} - -// Our service worker loses all state every 30s, so we're treating chrome.storage.local as the single source of truth -// To persist data, make changes to storage -const initAppData = chrome.storage.local.get().then((items) => { - Object.assign(appData, items); -}); - - -async function saveStorage() { - return chrome.storage.local.set(appData); + folders: [], + settings: { + theme: "light" + } } -function PaulRevere() { - chrome.runtime.sendMessage({command: "UpdateUI"}); -} +// appData.settings.theme +const saveStorage = async () => chrome.storage.local.set(appData); +const getStorage = async () => chrome.storage.local.get(appData); chrome.runtime.onInstalled.addListener(async () => { // setup chrome context menus @@ -47,7 +40,8 @@ chrome.runtime.onInstalled.addListener(async () => { }) // initialize storage - await initAppData + const initAppData = await getStorage(); + Object.assign(appData, initAppData); chrome.storage.local.set(appData); }); @@ -101,6 +95,16 @@ function processCommand(message, sender, sendResponse) { sendResponse(appData.folders); break; } + case "getTheme": { + sendResponse(appData.settings.theme); + break; + } + + case "setTheme": { + appData.settings.theme = data.theme; + chrome.runtime.sendMessage({command: "setThemeUI", data: {theme: data.theme}}); + break; + } case "addNote": { const { title, content, createdDate, folderID } = data; diff --git a/newjs/_settings_.js b/newjs/_settings_.js new file mode 100644 index 0000000..7f3fb7c --- /dev/null +++ b/newjs/_settings_.js @@ -0,0 +1,108 @@ +// Get references to elements +const settingsMenu = document.getElementById("settingsMenu"); +const sortMenu = document.getElementById("sortMenu"); + +// Comfirm menu items +const deleteConfirmModal = document.getElementById("deleteConfirmModal"); +const confirmDeleteNotes = document.getElementById("confirmDeleteNotes"); +const cancelDeleteNotes = document.getElementById("cancelDeleteNotes"); + +const resetConfirmModal = document.getElementById("resetConfirmModal"); +const confirmResetNotes = document.getElementById("confirmResetNotes"); +const cancelResetNotes = document.getElementById("cancelResetNotes"); + +// Download notes +const downloadButton = document.getElementById("downloadButton"); + +//delete confirm stuff +const delall = document.getElementById("delall"); +delall.addEventListener("click", () => { + deleteConfirmModal.showModal(); +}); + +confirmDeleteNotes.addEventListener("click", () => { + deleteAllNotes(); + deleteConfirmModal.close(); +}); + +cancelDeleteNotes.addEventListener("click", () => { + deleteConfirmModal.close(); +}); + +deleteConfirmModal.addEventListener("click", function(event) { + const modalContent = document.getElementById("delall"); + if (!modalContent.contains(event.target)) { + deleteConfirmModal.close(); + } +}); + +//reset confirm stuff +const resetSettings = document.getElementById("resetSettings"); +resetSettings.addEventListener("click", () => { + resetConfirmModal.showModal(); +}); + +confirmResetNotes.addEventListener("click", function() { + Object.assign(settings, defaultSettings); + saveSettings(); + loadSettings(); + resetConfirmModal.close(); +}); + +cancelResetNotes.addEventListener("click", () => { + resetConfirmModal.close(); +}); + +resetConfirmModal.addEventListener("click", function(event) { + const modalContent = document.getElementById("resetSettings"); + if (!modalContent.contains(event.target)) { + resetConfirmModal.close(); + } +}); + +chrome.runtime.sendMessage({command: "getTheme"}, theme => { + themeDropdown.value = theme; + themeDropdown.addEventListener("change", evt => { + const selectedTheme = evt.target.value; + console.log(`${selectedTheme} theme selected`); + chrome.runtime.sendMessage({command: "setTheme", data: {theme: selectedTheme}}); + }); +}); + +downloadButton.addEventListener("click", () => { + const folders = JSON.parse(localStorage.getItem("folders") || "[]"); + const data = { + folders: folders, + notes: notes + }; + const blob = new Blob([JSON.stringify(data, null, 2)], { + type: "application/json" + }); + + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = "notes.json"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); +}); + +/* +sortDropdown.addEventListener("change", _ => { + settings.sortChoice = sortDropdown.value; + saveSettings(); +}); + +sortButton.addEventListener("click", function(event) { + event.stopPropagation(); + if (settings.sortChoice === "date") { + sortNotesByDate(); + } else if (settings.sortChoice === "tag") { + sortNotesByTag(); + } else { + console.log("UNIMPLEMENTED SORT FEATURE"); + } +}); +*/ diff --git a/newjs/themes.js b/newjs/themes.js new file mode 100644 index 0000000..b00a008 --- /dev/null +++ b/newjs/themes.js @@ -0,0 +1,130 @@ +const unimplementedColor = "#F00BA7"; +const themes = { + legacy: { + text: "#000000", + placeholder: "#747474", + background: "#97BCC7", + foreground: "#F2F1EF", + codeblocks: "#CFCFCF", + hover: "#135473", + click: "#053D57", + border: "#053D57", + button: "#006884", + buttonText: "#F2F1EF", + format: "#D9D9D9", + formatText: "#000000", + formatHover: "#C4C4C4", + formatClick: "#B0B0B0", + submenuHover: "#D9D9D9", + submenuClick: "#C4C4C4" + }, + light: { + text: "#000000", + placeholder: "#A0A0A0", + background: "#FFFFFF", + foreground: "#FFFFFF", + codeblocks: "#E0E0E0", + hover: "#DFDFDF", + click: "#C7C7C7", + border: "#C8C8C8", + button: "#EDEDED", + buttonText: "#000000", + format: "#EDEDED", + formatText: "#000000", + formatHover: "#D9D9D9", + formatClick: "#C4C4C4", + submenuHover: "#DFDFDF", + submenuClick: "#CCCCCC" + }, + dark: { + text: "#E6E6E6", + placeholder: "#A0A0A0", + background: "#181818", + foreground: "#2A2A2A", + codeblocks: "#3A3A3A", + hover: "#444444", + click: "#333333", + border: "#383838", + button: "#505050", + buttonText: "#E0E0E0", + format: "#505050", + formatText: "#E0E0E0", + formatHover: "#464646", + formatClick: "#3C3C3C", + submenuHover: "#404040", + submenuClick: "#363636" + }, + matcha: { + text: "#5A4632", + placeholder: "#84715B", + background: "#EDE3C9", + foreground: "#FFF8E5", + codeblocks: "#DAC3A3", + hover: "#8A9A5B", + click: "#7A8B4B", + border: "#A98467", + button: "#A0B762", + buttonText: "#FFF8E5", + format: "#A0B762", + formatText: "#FFF8E5", + formatHover: "#8FA456", + formatClick: "#7F934D", + submenuHover: "#EDE3C9", + submenuClick: "#D6CBAF" + }, + nebula: { + text: "#e2dbf0", + placeholder: "#A693B0", + background: "#121022", + foreground: "#282143", + codeblocks: "#4A3B6A", + hover: "#66001d", + click: "#4d0016", + border: "#5B4B8A", + button: "#99002b", + buttonText: "#DDD1E3", + format: "#99002b", + formatText: "#DDD1E3", + formatHover: "#870026", + formatClick: "#7A001F", + submenuHover: "#5B4B8A", + submenuClick: "#4F4178" + } +} + +// initialize to correct theme on load +chrome.runtime.sendMessage({command: "getTheme"}, theme => loadTheme(theme)); + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + console.log(request); + const { command, data } = request; + + if (command === "setThemeUI") { + console.log(`Loading theme ${data.theme}`); + loadTheme(data.theme); + } +}); + +function loadTheme(themeName) { + const des = document.body.style; + let selectedTheme = themes[themeName]; + des.setProperty("--theme-text", selectedTheme.text || unimplementedColor) + des.setProperty("--theme-placeholder", selectedTheme.placeholder || unimplementedColor); + des.setProperty("--theme-background", selectedTheme.background || unimplementedColor); + des.setProperty("--theme-foreground", selectedTheme.foreground || unimplementedColor); + des.setProperty("--theme-codeblocks", selectedTheme.codeblocks || unimplementedColor); + des.setProperty("--theme-hover", selectedTheme.hover || unimplementedColor); + des.setProperty("--theme-click", selectedTheme.click || unimplementedColor); + des.setProperty("--theme-border", selectedTheme.border || unimplementedColor); + des.setProperty("--theme-button", selectedTheme.button || unimplementedColor); + des.setProperty("--theme-buttonText", selectedTheme.buttonText || unimplementedColor); + des.setProperty("--theme-format", selectedTheme.format || unimplementedColor); + des.setProperty("--theme-formatText", selectedTheme.formatText || unimplementedColor); + des.setProperty("--theme-formatHover", selectedTheme.formatHover || unimplementedColor); + des.setProperty("--theme-formatClick", selectedTheme.formatClick || unimplementedColor); + des.setProperty("--theme-submenuHover", selectedTheme.submenuHover || unimplementedColor); + des.setProperty("--theme-submenuClick", selectedTheme.submenuClick || unimplementedColor); +} + + + diff --git a/pages/main.css b/pages/main.css index c86f196..e7d9413 100644 --- a/pages/main.css +++ b/pages/main.css @@ -1,16 +1,11 @@ -*, *::before, *::after { - box-sizing: border-box; +#draftArea { + background-color: green; } -body { - background-color: skyblue; - -} - -.draftArea { - padding: 10px; - background-color: aliceblue; - display: flex; +.cuteBorder { + border: 2px solid; + border-color: var(--theme-border); + border-radius: 10px; } #info, #noteEditor_info { @@ -33,15 +28,57 @@ body { #container { display: flex; padding: 10px; - background-color: limegreen; gap: 10px; flex-wrap: wrap; } +.del { + position: absolute; + top: -7px; + right: -7px; + border-radius: 50%; + border: 0px; + display: none; + text-align: center; + width: 25px; + height: 25px; + background-color: var(--theme-button); + color: var(--theme-buttonText); + background-color: var(--theme-button); + color: var(--theme-buttonText); + box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.3); +} + +.del:hover { + background-color: var(--theme-hover); +} + +.del:active { + background-color: var(--theme-click); +} + .note { - background-color: pink; - min-width: 300px; - flex-grow: 1; + width: 100%; + padding: 5px; + background-color: var(--theme-foreground); + position: relative; + border-radius: 10px; + height: 100%; + outline: 2px solid var(--theme-border); + box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.3); + color: var(--theme-text); + transition: transform .2s ease-in-out; +} + +.note:hover { + transform: scale(1.01); +} + +.note-title { + padding: 5px; + border-radius: 10px 10px 0px 0px; + color: var(--theme-text); + /* background-color: #e1e1e1 */ } #noteEditor { @@ -57,14 +94,96 @@ body { dodgerblue, green ); - opacity: 0.75; + opacity: 0.5; +} + +.settingsButton { + font-size: 40px } +input { + border-radius: 10px; +} +.flex { + display: flex; +} +.row { + display: flex; + flex-direction: row; + gap: 10px; +} + +.column { + display: flex; + flex-direction: column; + gap: 10px; +} .none { display: none !important; +} + + + + + +.overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + z-index: 2; + /* Make sure it's on top */ +} + +.topInput { + min-width: 100px; + border-radius: 5px; + padding: 5px; + background-color: var(--theme-foreground); + color: var(--theme-text); +} +.topInput::placeholder { + color: var(--theme-placeholder); +} + +.time-text { + color: var(--theme-text); + text-align: end; + width: 100%; + margin-right: 10px; +} + + + +#search { + flex: 1; + border-radius: 10px; + height: 34px; + border: 2px solid; + border-color: var(--theme-border); + /*box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3);*/ +} + +#search:hover { + background-color: var(--theme-submenuHover); +} + +#search:active { + background-color: var(--theme-submenuClick); +} + +#search:focus { + border: 2px solid var(--theme-border); + outline: 0px; +} + +#search::-webkit-calendar-picker-indicator { + display: none !important; } \ No newline at end of file diff --git a/pages/main.html b/pages/main.html index 347579b..9034647 100644 --- a/pages/main.html +++ b/pages/main.html @@ -2,6 +2,8 @@ + + @@ -9,36 +11,64 @@ -

Note Harbor (Settings)

- - - - - - - -

-
-
- -
-
-
- +
+ + + + + + +
+ +
+ +
+ +
-

- - -
-
- -

+ + +
+
+ +
+ + +
+
+ + +
+
+
+ + +
+ + +
+ + + +
+ + +
+ + +
+ diff --git a/pages/main2.css b/pages/main2.css new file mode 100644 index 0000000..44a61b0 --- /dev/null +++ b/pages/main2.css @@ -0,0 +1,619 @@ +.title { + font-size: 17px; + font-weight: bold; + color: black; +} + +.body { + font-size: 15px; +} + + + +.icon { + width: 24px; + height: 24px; + + /* Set up the PNG as a mask */ + -webkit-mask-image: url('chrome-extension://__MSG_@@extension_id__/img/close.png'); + mask-image: url('chrome-extension://__MSG_@@extension_id__/img/close.png'); + + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + + -webkit-mask-size: cover; + mask-size: cover; + + background-color: var(--theme-text); /* Color changes with theme */ +} + + + +nav { + background-color: orange; +} + + + +.topContainerSearch { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-bottom: 10px; +} + +.topContainer { + display: flex; + flex-direction: row; + align-items: flex-start; + justify-content: space-between; + gap: 10px; + margin-bottom: 10px; + position: relative; + position: relative; +} + +#container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + align-items: center; + position: relative; + width: 100%; + gap: 10px; + padding-top: 12px; +} + +#dAdd { + margin-top: 10px; + padding: 10px; + border: none; + border-radius: 5px; + margin-left: auto; + margin-right: auto; + width: fit-content; + display: none; +} + + + +.note-title:focus { + outline: none; + color: var(--theme-text) +} + +.note.dragging { + opacity: 0.5; + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2); +} + +.note-content { + height: auto; + max-height: 500px; + height: auto; + width: 100%; + background-color: var(--theme-foreground); + border: none; + padding: 5px; + overflow-x: scroll; + overflow-y: scroll; + white-space: pre-wrap; + color: var(--theme-text); +} + +.note-content:focus { + outline: none; + color: var(--theme-text); +} + +.note-content:link { + color: var(--button-text); + color: var(--button-text); +} + +.note-display { + height: auto; + max-height: 100px; + height: auto; + max-height: 100px; + max-width: 100%; + background-color: var(--theme-foreground); + color: var(--theme-text); + border: none; + padding: 5px; + overflow-x: scroll; + overflow-y: clip; + white-space: pre-wrap; +} + +.deleteButton { + color: var(--theme-buttonText) +} + + + + + + + +.inputContainer { + display: flex; + flex: 1; + flex-direction: column; + border-radius: 10px; + border: 2px solid; + border-color: var(--theme-border); + background-color: var(--theme-foreground); + color: var(--theme-text); + height: 150px; + height: 150px; + transition: transform .2s ease-in-out; +} + +.inputContainer:hover { + transform: scale(1.01); +} + +.bottomDiv { + display: flex; + align-items: center; +} + +.time-text { + font-size: 13px; +} +.bottom-bar { + margin: 5px; + padding: 5px; + background-color: var(--theme-format); + border-radius: 5px; + height: 10px; + width: 55px; + display: flex; + justify-content: center; + align-items: center; +} + +.bottom-bar button { + background-color: var(--theme-format); + color: var(--theme-formatText); + border: 0px; +} + +.bottom-bar button:hover { + background-color: var(--theme-formatHover); + color: var(--theme-formatText); + border: 0px; +} + +.bottom-bar button:active { + background-color: var(--theme-formatClick); + color: var(--theme-formatText); + border: 0px; +} + +#title { + font-weight: bold; + border-radius: 5px 5px 0px 0px; + margin: 5px 5px 0px 5px; + border: none; +} +#title:focus { + outline: none; +} + +#info { + border-radius: 0px 0px 10px 10px; + border: 0px; + color: var(--theme-text); + min-height: 74px; + resize: none; +} +#info:focus { + outline: none; +} + +.topButton { + border-radius: 10px; + background-color: var(--theme-button); + color: var(--theme-buttonText); + background-color: var(--theme-button); + color: var(--theme-buttonText); + border: 0px; +} + +.topButton:hover { + background-color: var(--theme-hover); + cursor: pointer; +} + +.topButton:active { + background-color: var(--theme-click); +} + +#openSettings { + height: 34px; +} + +.closeButton { + background-color: var(--theme-button); + color: var(--theme-buttonText); + background-color: var(--theme-button); + color: var(--theme-buttonText); + border: none; + width: 30px; + height: 30px; + border-radius: 20px; +} + +.closeButton:hover { + cursor: pointer; + background-color: var(--theme-hover); +} + +.closeButton:active { + background-color: var(--theme-click); +} + +#add { + height: 30px; + width: 75px; + z-index: 1; + position: absolute; + right: 10px; + bottom: 10px; + background-color: var(--theme-button); + color: var(--theme-buttonText); +} + +#add:hover { +background-color: var(--theme-hover); +} + +#add:active { + background-color: var(--theme-click) +} + +#erase { + height: 30px; + width: 65px; + z-index: 1; + position: absolute; + right: 95px; + bottom: 10px; +} + +.shadow { + box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.3); +} + +#tagRow { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 4px; +} + +#folderRow { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 4px; +} + +#addTagButton { + width: 30px; + height: 30px; + font-size: 20px; + align-items: center; +} + +#tagDropdown { + width: 50px; + height: 30px; + align-items: center; +} + +#downloadButton { + width: 40px; + text-align: center; +} + +/* Wrapper for new tag */ +.new-tag { + background-color: var(--theme-button); + color: var(--theme-placeholder); + padding: 2px 8px; + border-radius: 10px; + align-items: center; + display: flex; + font-size: 12px; +} + +.new-tag:focus { + border: none; +} + +.new-tag:hover { + background-color: var(--theme-hover); +} + +.new-tag:active { + background-color: var(--theme-click); +} + +.tag { + height: 30px; + background-color: var(--theme-button); + color: var(--theme-buttonText); + padding: 0px 8px; + border-radius: 10px; + align-items: center; + position: relative; + display: flex; + align-items: center; + font-size: 12px; +} + +.tag:hover { + background-color: var(--theme-hover); + cursor: pointer; +} +.tag:active { + background-color: var(--theme-click); +} + +.tag:focus { + border: none; + background-color: var(--theme-hover); + color: var(--theme-buttonText); + cursor: text; +} + +.tag-input { + background-color: transparent; + color: var(--theme-buttonText); + border: none; + outline: none; + padding: 0; + margin: 0; + flex-grow: 1; + margin-right: 7px; +} + +.tag-input:empty:before { + content: "Add Folder Name..."; + background-color: transparent; + color: var(--theme-placeholder); +} + +.del-tag { + border: none; + border-radius: 50%; + width: 17px; + height: 17px; + cursor: pointer; + font-size: 12px; + display: flex; + user-select: none; + background-color: transparent; + color: var(--theme-buttonText); + align-items: center; +} + +.tag-bar { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding-left: 5px; + gap: 5px; +} + + +.bottom-bar { + display: flex; + padding-left: 5px; +} + +.note-tag { + background-color: var(--theme-button); + color: var(--theme-buttonText); + height: 20px; + padding: 0px 8px; + border-radius: 5px; + align-items: center; + position: relative; + display: flex; + align-items: center; + font-size: 12px; +} + +.custom-context-menu { + position: absolute; + display: none; + z-index: 1; + background-color: #ffffff; + color: #000000; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 4px; + padding: 4px 0; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); + font-family: Arial, sans-serif; + font-size: 12px; +} + +.custom-context-menu .menu-item { + padding: 8px 16px; + cursor: pointer; + line-height: 1.5; + border-radius: 2px; +} + +.custom-context-menu .menu-item:hover { + background-color: #f5f5f5; +} + +/* Hide menus by default */ +.settings-menu { + position: absolute; + background: var(--theme-foreground); + border: 2px solid var(--theme-border); + border-radius: 8px; + padding: 5px; + width: 150px; + display: none; + box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2); + z-index: 1; +} + +/* Style for dropdown items */ +.menu-item { + padding: 8px; + color: var(--theme-text); + font-family: Arial, sans-serif; + font-size: 16px; + cursor: pointer; + border-radius: 5px; +} + +/* Hover effect for dropdown */ +.menu-item:hover { + background: var(--theme-submenuHover); +} + +/* Click effect for dropdown */ +.menu-item:active { + background: var(--theme-submenuClick); +} + +.settings-modal { + width: 70%; + min-width: 300px; + border-radius: 10px; + border: 2px solid var(--theme-border); + background-color: var(--theme-foreground); +} + +.confirmModal { + width: 50%; + min-width: 200px; +} + +#settingsTitle { + font-size: 20px; + color: var(--theme-text); +} + +.settingsHeader { + font-size: 17px; + font-weight: bold; + color: var(--theme-text); + margin-bottom: 3px; +} + +.settingsText { + font-size: 14px; + color: var(--theme-text); + margin-bottom: 3px; + display: flex; + width: 85%; +} + + + +#themeDropdown { + width: 140px; + height: 35px; + border-radius: 10px; + margin-top: 5px; + background-color: var(--theme-submenuHover); + border: none; + color: var(--theme-text); + padding-left: 5px; + outline: none; +} + +.settingsTop { + display: flex; + justify-content: space-between; +} + +.settingsDiv { + margin-top: 10px; +} + +.dropdown { + position: relative; + width: 30px; + height: 30px; + align-items: center; + font-family: Arial, sans-serif; + font-size: 12px; +} + +.dropdown-content { + display: flex; + justify-content: center; + width: 100%; + padding-top: 4px; + align-items: center; +} + +#dropdown-arrow { + font-size: 12px; + align-items: center; + margin-top: 4px; +} + +.dropdown-menu { + position: absolute; + top: 100%; + min-width: max-content; + background: var(--theme-foreground); + border-radius: 10px; + z-index: 1; + border: 2px solid var(--theme-border); + padding: 5px; + font-family: Arial, sans-serif; + font-size: 12px; +} + +.dropdown-item { + padding: 10px; + cursor: pointer; + color: var(--theme-text); + border-radius: 6px; +} + +.dropdown-item:hover { + background: var(--theme-submenuHover); +} + +.dropdown-item:active { + background: var(--theme-submenuClick); +} + +.hidden { + display: none; +} + +#errorMessage { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + background-color: var(--theme-format); + color: var(--theme-formatText); + /*background-color: #323232; + color: white; */ + padding: 10px 20px; + border-radius: 5px; + display: none; + z-index: 9999; + font-family: sans-serif; + box-shadow: 0 2px 8px rgba(0,0,0,0.3); +} \ No newline at end of file diff --git a/pages/settings.html b/pages/settings.html index 1812af2..205f6e1 100644 --- a/pages/settings.html +++ b/pages/settings.html @@ -2,30 +2,15 @@ - - - -
- - - -
- - -
- - -
- - test - + @@ -75,20 +67,10 @@
- - - + - + + diff --git a/pages/style.css b/pages/style.css index 7c213e4..99264ba 100644 --- a/pages/style.css +++ b/pages/style.css @@ -1,22 +1,22 @@ :root { - --theme-text: #000000; - --theme-placeholder: #747474; /* for use in placeholder text */ - --theme-background: #97BCC7; - --theme-foreground: #F2F1EF; - --theme-codeblocks: #CFCFCF; - --theme-hover: #135473; - --theme-click: #053D57; - --theme-border: #053D57; - --theme-button: #006884; /* for use in certain buttons */ - --theme-buttonText: #F2F1EF; - --theme-button: #006884; /* for use in certain buttons */ - --theme-buttonText: #F2F1EF; - --theme-format: #D9D9D9; - --theme-formatText: #000000; - --theme-formatHover: #C4C4C4; - --theme-formatClick: #B0B0B0; - --theme-submenuHover: #D9D9D9; - --theme-submenuClick: #C4C4C4; + --theme-text: inherit; + --theme-placeholder: inherit; /* for use in placeholder text */ + --theme-background: inherit; + --theme-foreground: inherit; + --theme-codeblocks: inherit; + --theme-hover: inherit; + --theme-click: inherit; + --theme-border: inherit; + --theme-button: inherit; /* for use in certain buttons */ + --theme-buttonText: inherit; + --theme-button: inherit; /* for use in certain buttons */ + --theme-buttonText: inherit; + --theme-format: inherit; + --theme-formatText: inherit; + --theme-formatHover: inherit; + --theme-formatClick: inherit; + --theme-submenuHover: inherit; + --theme-submenuClick: inherit; } a:link { diff --git a/pages/theme.css b/pages/theme.css new file mode 100644 index 0000000..237993c --- /dev/null +++ b/pages/theme.css @@ -0,0 +1,108 @@ +:root { + --theme-text: #000000; + --theme-placeholder: #747474; /* for use in placeholder text */ + --theme-background: #97BCC7; + --theme-foreground: #F2F1EF; + --theme-codeblocks: #CFCFCF; + --theme-hover: #135473; + --theme-click: #053D57; + --theme-border: #053D57; + --theme-button: #006884; /* for use in certain buttons */ + --theme-buttonText: #F2F1EF; + --theme-button: #006884; /* for use in certain buttons */ + --theme-buttonText: #F2F1EF; + --theme-format: #D9D9D9; + --theme-formatText: #000000; + --theme-formatHover: #C4C4C4; + --theme-formatClick: #B0B0B0; + --theme-submenuHover: #D9D9D9; + --theme-submenuClick: #C4C4C4; +} + +a:link { + color: var(--theme-button-text); + color: var(--theme-button-text); +} + +a:hover { + color: var(--theme-hover); +} + +a:active { + color: var(--theme-click); +} + +body { + background-color: var(--theme-background); + overflow: hidden; + margin: 10px; + overflow-y: scroll; + overflow-x: hidden; + font-family: Arial, Helvetica, sans-serif; +} + +textarea, input, button, select { + font-family: inherit; +} + +label { + font-size: medium; +} + +h1, h2, h3, h4, h5, h6, p { + margin: 0; + margin: 0; + overflow-wrap: break-word; +} + +/* Codeblocks */ +pre { + background-color: var(--theme-codeblocks); + margin: 0px; + padding: 5px; + border: solid 1px var(--theme-border); +} + +/* width */ +::-webkit-scrollbar { + width: 2px; + height: 2%; + color: 006884; +} + +/* Track */ +::-webkit-scrollbar-track { + background: #f1f1f1; +} + +/* Handle */ +::-webkit-scrollbar-thumb { + background: #888; +} + +/* Handle on hover */ +::-webkit-scrollbar-thumb:hover { + background: #555; +} + +::backdrop { + background: gray; + opacity: 0.50; +} + + + + + + + + + + + +.flex { + display: flex +} +.displayNone { + display: none; +} \ No newline at end of file From e272cae086a435a22c9a3de25617a7ba2c34bb00 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Thu, 19 Jun 2025 23:15:58 -0400 Subject: [PATCH 11/12] fix themes on main page --- background.js | 1 + newjs/_settings_.js | 20 +------------------- newjs/themes.js | 1 - pages/main.html | 3 ++- 4 files changed, 4 insertions(+), 21 deletions(-) diff --git a/background.js b/background.js index c859dad..678f1e4 100644 --- a/background.js +++ b/background.js @@ -103,6 +103,7 @@ function processCommand(message, sender, sendResponse) { case "setTheme": { appData.settings.theme = data.theme; chrome.runtime.sendMessage({command: "setThemeUI", data: {theme: data.theme}}); + saveStorage(); break; } diff --git a/newjs/_settings_.js b/newjs/_settings_.js index 7f3fb7c..cb9dc90 100644 --- a/newjs/_settings_.js +++ b/newjs/_settings_.js @@ -87,22 +87,4 @@ downloadButton.addEventListener("click", () => { a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); -}); - -/* -sortDropdown.addEventListener("change", _ => { - settings.sortChoice = sortDropdown.value; - saveSettings(); -}); - -sortButton.addEventListener("click", function(event) { - event.stopPropagation(); - if (settings.sortChoice === "date") { - sortNotesByDate(); - } else if (settings.sortChoice === "tag") { - sortNotesByTag(); - } else { - console.log("UNIMPLEMENTED SORT FEATURE"); - } -}); -*/ +}); \ No newline at end of file diff --git a/newjs/themes.js b/newjs/themes.js index b00a008..5a52d32 100644 --- a/newjs/themes.js +++ b/newjs/themes.js @@ -96,7 +96,6 @@ const themes = { chrome.runtime.sendMessage({command: "getTheme"}, theme => loadTheme(theme)); chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { - console.log(request); const { command, data } = request; if (command === "setThemeUI") { diff --git a/pages/main.html b/pages/main.html index 9034647..4113ad1 100644 --- a/pages/main.html +++ b/pages/main.html @@ -70,6 +70,7 @@ - + + From 231fffa97a10b7dd46362011014fb84519a1a8a6 Mon Sep 17 00:00:00 2001 From: Nat Wang Date: Fri, 20 Jun 2025 00:40:38 -0400 Subject: [PATCH 12/12] more cleanup, closer to mockup --- newjs/_main_.js | 1 + newjs/themes.js | 4 +- pages/main.css | 205 +++++++++++++++++++++++++++--------------------- pages/main.html | 19 ++--- pages/theme.css | 109 +++++++++++++------------ 5 files changed, 188 insertions(+), 150 deletions(-) diff --git a/newjs/_main_.js b/newjs/_main_.js index 532bc07..4f51e1c 100644 --- a/newjs/_main_.js +++ b/newjs/_main_.js @@ -23,6 +23,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { add.addEventListener("click", _ => addNote()); +settingsButton.addEventListener("click", _ => { window.location.href = "settings.html" }); document.addEventListener("DOMContentLoaded", _ => reloadNoteHTML()); document.addEventListener("visibilitychange", _ => reloadNoteHTML()); diff --git a/newjs/themes.js b/newjs/themes.js index 5a52d32..9c0a9d6 100644 --- a/newjs/themes.js +++ b/newjs/themes.js @@ -27,8 +27,8 @@ const themes = { hover: "#DFDFDF", click: "#C7C7C7", border: "#C8C8C8", - button: "#EDEDED", - buttonText: "#000000", + button: "#006884", + buttonText: "#F2F1EF", format: "#EDEDED", formatText: "#000000", formatHover: "#D9D9D9", diff --git a/pages/main.css b/pages/main.css index e7d9413..5fadec1 100644 --- a/pages/main.css +++ b/pages/main.css @@ -1,5 +1,27 @@ -#draftArea { - background-color: green; +*, *::before, *::after { + box-sizing: border-box; +} + +#draftArea, #noteEditor[open] { + display: flex; + flex-wrap: wrap; + justify-content: end; + gap: 5px; + padding: 5px; + background-color: var(--theme-foreground); + justify-content: end; +} + +#noteEditor { + border-color: black; +} + +.title { + font-weight: bold; +} + +.body { + border-radius: 0px; } .cuteBorder { @@ -8,10 +30,8 @@ border-radius: 10px; } -#info, #noteEditor_info { - background-color: white; +.body { min-height: 50px; - border: 1px black solid; } [contenteditable="plaintext-only"] { @@ -27,82 +47,69 @@ #container { display: flex; - padding: 10px; gap: 10px; + margin-top: 10px; flex-wrap: wrap; } .del { - position: absolute; - top: -7px; - right: -7px; - border-radius: 50%; - border: 0px; - display: none; - text-align: center; - width: 25px; - height: 25px; - background-color: var(--theme-button); - color: var(--theme-buttonText); - background-color: var(--theme-button); - color: var(--theme-buttonText); - box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.3); + position: absolute; + top: -7px; + right: -7px; + border-radius: 50%; + border: 0px; + display: none; + text-align: center; + width: 25px; + height: 25px; + background-color: var(--theme-button); + color: var(--theme-buttonText); + background-color: var(--theme-button); + color: var(--theme-buttonText); + box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.3); } .del:hover { - background-color: var(--theme-hover); + background-color: var(--theme-hover); } .del:active { - background-color: var(--theme-click); + background-color: var(--theme-click); } .note { - width: 100%; - padding: 5px; - background-color: var(--theme-foreground); - position: relative; - border-radius: 10px; - height: 100%; - outline: 2px solid var(--theme-border); - box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.3); - color: var(--theme-text); - transition: transform .2s ease-in-out; + width: 100%; + padding: 10px; + background-color: var(--theme-foreground); + position: relative; + border-radius: 10px; + height: 100%; + outline: 2px solid var(--theme-border); + box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.3); + color: var(--theme-text); + transition: transform .2s ease-in-out; } .note:hover { - transform: scale(1.01); + transform: scale(1.01); } .note-title { - padding: 5px; - border-radius: 10px 10px 0px 0px; - color: var(--theme-text); - /* background-color: #e1e1e1 */ -} - -#noteEditor { - background-color: purple; -} - - -::backdrop { - background-image: linear-gradient( - 45deg, - magenta, - rebeccapurple, - dodgerblue, - green - ); - opacity: 0.5; -} - -.settingsButton { - font-size: 40px -} - -input { + border-radius: 10px 10px 0px 0px; + color: var(--theme-text); + margin-bottom: 5px; + font-weight: bold; + overflow-x: hidden; +} + +#settingsButton { + text-align: center; + vertical-align: middle; + width: 34px; + height: 34px; + font-size: 20px; border-radius: 10px; + border: none; } .flex { @@ -113,6 +120,8 @@ input { display: flex; flex-direction: row; gap: 10px; + margin-bottom: 10px; + align-items: center; } .column { @@ -127,63 +136,81 @@ input { display: none !important; } +.topButton { + border-radius: 5px; + border: none; + padding: 4px; +} +#add { + background-color: var(--theme-button); + color: var(--theme-buttonText); +} + +#erase { + background-color: var(--theme-format); + color: var(--theme-formatText); +} .overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.5); - z-index: 2; - /* Make sure it's on top */ + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + z-index: 2; + /* Make sure it's on top */ } .topInput { - min-width: 100px; - border-radius: 5px; - padding: 5px; - background-color: var(--theme-foreground); - color: var(--theme-text); + min-width: 100px; + padding: 5px; + width: 100%; + background-color: var(--theme-foreground); + color: var(--theme-text); + border: none; } .topInput::placeholder { - color: var(--theme-placeholder); + color: var(--theme-placeholder); +} +.topInput:focus { + border: 1px solid red; } .time-text { - color: var(--theme-text); - text-align: end; - width: 100%; - margin-right: 10px; + color: var(--theme-text); + text-align: end; + width: 100%; + margin-right: 10px; } #search { - flex: 1; - border-radius: 10px; - height: 34px; - border: 2px solid; - border-color: var(--theme-border); - /*box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3);*/ + flex: 1; + border-radius: 10px; + height: 34px; + border: 2px solid; + border-color: var(--theme-border); + /*box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3);*/ } #search:hover { - background-color: var(--theme-submenuHover); + background-color: var(--theme-submenuHover); } #search:active { - background-color: var(--theme-submenuClick); + background-color: var(--theme-submenuClick); } #search:focus { - border: 2px solid var(--theme-border); - outline: 0px; + border: 2px solid var(--theme-border); + outline: 0px; } #search::-webkit-calendar-picker-indicator { - display: none !important; + display: none !important; } \ No newline at end of file diff --git a/pages/main.html b/pages/main.html index 4113ad1..b721689 100644 --- a/pages/main.html +++ b/pages/main.html @@ -2,9 +2,7 @@ - - @@ -12,26 +10,29 @@
+ - +
+
- +
- - + +
- +
- - + + +
diff --git a/pages/theme.css b/pages/theme.css index 237993c..1598114 100644 --- a/pages/theme.css +++ b/pages/theme.css @@ -1,108 +1,117 @@ :root { - --theme-text: #000000; - --theme-placeholder: #747474; /* for use in placeholder text */ - --theme-background: #97BCC7; - --theme-foreground: #F2F1EF; - --theme-codeblocks: #CFCFCF; - --theme-hover: #135473; - --theme-click: #053D57; - --theme-border: #053D57; - --theme-button: #006884; /* for use in certain buttons */ - --theme-buttonText: #F2F1EF; - --theme-button: #006884; /* for use in certain buttons */ - --theme-buttonText: #F2F1EF; - --theme-format: #D9D9D9; - --theme-formatText: #000000; - --theme-formatHover: #C4C4C4; - --theme-formatClick: #B0B0B0; - --theme-submenuHover: #D9D9D9; - --theme-submenuClick: #C4C4C4; + --theme-text: #000000; + --theme-placeholder: #747474; /* for use in placeholder text */ + --theme-background: #97BCC7; + --theme-foreground: #F2F1EF; + --theme-codeblocks: #CFCFCF; + --theme-hover: #135473; + --theme-click: #053D57; + --theme-border: #053D57; + --theme-button: #006884; /* for use in certain buttons */ + --theme-buttonText: #F2F1EF; + --theme-format: #D9D9D9; + --theme-formatText: #000000; + --theme-formatHover: #C4C4C4; + --theme-formatClick: #B0B0B0; + --theme-submenuHover: #D9D9D9; + --theme-submenuClick: #C4C4C4; } a:link { - color: var(--theme-button-text); - color: var(--theme-button-text); + color: var(--theme-button-text); + color: var(--theme-button-text); } a:hover { - color: var(--theme-hover); + color: var(--theme-hover); } a:active { - color: var(--theme-click); + color: var(--theme-click); } body { - background-color: var(--theme-background); - overflow: hidden; - margin: 10px; - overflow-y: scroll; - overflow-x: hidden; - font-family: Arial, Helvetica, sans-serif; + background-color: var(--theme-background); + overflow: hidden; + margin: 10px; + overflow-y: scroll; + overflow-x: hidden; + font-family: Arial, Helvetica, sans-serif; } textarea, input, button, select { - font-family: inherit; + font-family: inherit; } label { - font-size: medium; + font-size: medium; } h1, h2, h3, h4, h5, h6, p { - margin: 0; - margin: 0; - overflow-wrap: break-word; + margin: 0; + margin: 0; + overflow-wrap: break-word; } /* Codeblocks */ pre { - background-color: var(--theme-codeblocks); - margin: 0px; - padding: 5px; - border: solid 1px var(--theme-border); + background-color: var(--theme-codeblocks); + margin: 0px; + padding: 5px; + border: solid 1px var(--theme-border); } /* width */ ::-webkit-scrollbar { - width: 2px; - height: 2%; - color: 006884; + width: 2px; + height: 2%; + color: 006884; } /* Track */ ::-webkit-scrollbar-track { - background: #f1f1f1; + background: #f1f1f1; } /* Handle */ ::-webkit-scrollbar-thumb { - background: #888; + background: #888; } /* Handle on hover */ ::-webkit-scrollbar-thumb:hover { - background: #555; + background: #555; } ::backdrop { - background: gray; - opacity: 0.50; + background: gray; + opacity: 0.50; } +.primaryButton { + background-color: var(--theme-button); + color: var(--theme-buttonText); + padding: 10px; +} +.secondaryButton { + background-color: var(--theme-format); + color: var(--theme-formatText); + padding: 10px; +} - - - +.settingsIcon { + background-color: var(--theme-button); + color: var(--theme-buttonText); +} .flex { - display: flex + display: flex } .displayNone { - display: none; + display: none; } \ No newline at end of file