diff --git a/index.html b/index.html
index f7a0b2d..91d3d7c 100644
--- a/index.html
+++ b/index.html
@@ -20,8 +20,11 @@
+
Snotes Deck
-
+
@@ -39,12 +42,15 @@
+
+
-
-
-
diff --git a/libsnotes/src/lib.rs b/libsnotes/src/lib.rs
index 924f42c..3115288 100644
--- a/libsnotes/src/lib.rs
+++ b/libsnotes/src/lib.rs
@@ -10,7 +10,6 @@ pub struct Note {
tag: String,
}
-
pub fn init_db() -> Result<()> {
let home = home_dir().unwrap().join(".snotes.db");
let connection = Connection::open(home)?;
@@ -64,19 +63,21 @@ pub fn show_notes(all: bool, tag: &str) -> Result {
}
if !tag.is_empty() {
- query = format!("SELECT * FROM notes WHERE tag IS '{}'", tag);
+ query = format!("SELECT * FROM notes WHERE tag IS '{tag}'");
}
let mut prepare = connection.prepare(&query).unwrap();
- let notes = prepare.query_map([], |row| {
- Ok(Note {
- id: row.get(0)?,
- content: row.get(1)?,
- date: row.get(2)?,
- tag: row.get(3)?,
+ let notes = prepare
+ .query_map([], |row| {
+ Ok(Note {
+ id: row.get(0)?,
+ content: row.get(1)?,
+ date: row.get(2)?,
+ tag: row.get(3)?,
+ })
})
- }).unwrap();
+ .unwrap();
let mut json_array = Vec::new();
@@ -96,20 +97,32 @@ pub fn show_notes(all: bool, tag: &str) -> Result {
Ok(json_string)
}
-pub fn delete_latest_note() -> Result<()> {
+pub fn delete_latest_note() -> Result<(), String> {
let home = home_dir().unwrap().join(".snotes.db");
- let connection = Connection::open(home)?;
+ let connection = Connection::open(home).map_err(|e| format!("Database Error: {e}"))?;
let query = String::from("DELETE FROM NOTES WHERE nid = (SELECT MAX(nid) FROM notes)");
match connection.execute(&query, []) {
- Ok(v) => println!("DELETE OK {}", v),
- Err(e) => println!("DELETE ERR {}", e),
+ Ok(v) => {
+ println!("DELETE OK {}", v);
+ Ok(())
+ }
+ Err(e) => Err(format!("Delete Error: {e}")),
}
-
- Ok(())
}
+pub fn delete_specific_note(id: i32) -> Result<(), String> {
+ let home = home_dir().unwrap().join(".snotes.db");
+ let connection = Connection::open(home).map_err(|e| format!("Database Error: {e}"))?;
+
+ let query = "DELETE FROM notes WHERE nid = ?1";
+ match connection.execute(query, [id]) {
+ Ok(1) => Ok(()), // 1 row affected means the note was deleted successfully
+ Ok(_) => Err("No note with the provided ID found.".to_string()),
+ Err(e) => Err(format!("Delete Error: {e}")),
+ }
+}
#[cfg(test)]
mod tests {
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 17ea91a..71eb928 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -11,8 +11,8 @@ fn greet(name: &str) -> String {
#[tauri::command]
fn get_notes_list() -> String {
- let notes = show_notes(false, &String::new()).unwrap();
- format!("{}", notes)
+ let notes = show_notes(false, "").unwrap();
+ notes.to_string()
}
#[tauri::command]
@@ -23,9 +23,16 @@ fn create_note(content: &str, tag: &str) -> bool {
true
}
+#[tauri::command]
+fn delete_specific_note(id: u32) -> bool {
+ println!("reched Delete");
+
+ libsnotes::delete_specific_note(id.try_into().unwrap()).is_ok()
+}
+
fn main() {
tauri::Builder::default()
- .invoke_handler(tauri::generate_handler![greet, get_notes_list, create_note])
+ .invoke_handler(tauri::generate_handler![greet, get_notes_list, create_note, delete_specific_note])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 06bfe44..d19e06c 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -8,7 +8,7 @@
},
"package": {
"productName": "snotes-deck",
- "version": "0.0.1"
+ "version": "0.0.2"
},
"tauri": {
"allowlist": {
@@ -41,4 +41,4 @@
]
}
}
-}
+}
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
index e7928e4..e76bd58 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,13 +3,14 @@ import { Note } from "./model";
let notesMsgEl: HTMLElement | null;
-//let createMsgEl: HTMLElement | null;
let createNoteContentEl: HTMLTextAreaElement | null;
let createNoteTagEl: HTMLInputElement | null;
let noteSidebarContainerEl: HTMLDivElement | null;
+let noteArray: Note[] = []
+
// create
async function createNote() {
console.log("reached ssssjs")
@@ -25,13 +26,9 @@ async function createNote() {
// read
async function showNotes() {
if (notesMsgEl) {
- //const notesJson: string = await invoke("get_notes_list");
- //const formattedJson = JSON.stringify(JSON.parse(notesJson), null, 2); // Indentation of 2 spaces
- //notesMsgEl.textContent = formattedJson;
-
const array: Array = await retrieveNotes();
- const noteArray: Note[] = array.map((jsonObj) => ({
+ noteArray = array.map((jsonObj) => ({
id: jsonObj.id,
content: jsonObj.content,
date: jsonObj.date,
@@ -51,31 +48,6 @@ async function retrieveNotes(): Promise> {
return notesJson;
}
-
-// TODO: read better array of note elements with id iterable the whole thing
-
-// update
-// async function updateNote() {
-// if (true) {
-// await invoke("update_note", {
-// id: null,
-// content: null,
-// tag: null
-// });
-// }
-// }
-
-// delete
-// async function deleteNote() {
-// if (true) {
-// await invoke("delete_note", {
-// id: null
-// }
-// )
-// }
-// }
-
-
window.addEventListener("DOMContentLoaded", () => {
createNoteContentEl = document.querySelector("#create-input");
createNoteTagEl = document.querySelector("#create-tag");
@@ -91,8 +63,57 @@ window.addEventListener("DOMContentLoaded", () => {
e.preventDefault();
showNotes();
})
+
+ refreshContextMenuElements();
});
+/**
+ * We need to add new event listeners every time we refresh the note list
+ */
+function refreshContextMenuElements() {
+ const elements: NodeListOf = document.querySelectorAll(".rightclick-element")
+ const contextMenu = document.getElementById('contextMenu');
+
+ if (contextMenu) {
+ elements.forEach(element => {
+
+ element.addEventListener("contextmenu", (e: MouseEvent) => {
+ e.preventDefault();
+
+ // get the position with mouse and everything
+ const mouseX = e.clientX;
+ const mouseY = e.clientY;
+
+ // Calculate the position of the context menu relative to the mouse cursor
+ const menuWidth = contextMenu.offsetWidth;
+ const menuHeight = contextMenu.offsetHeight;
+ const viewportWidth = window.innerWidth;
+ const viewportHeight = window.innerHeight;
+
+ let posX = mouseX + menuWidth > viewportWidth ? mouseX - menuWidth : mouseX;
+ let posY = mouseY + menuHeight > viewportHeight ? mouseY - menuHeight : mouseY;
+
+
+ contextMenu.style.display = 'block'; // Show the custom context menu
+ contextMenu.style.left = `${posX}px`;
+ contextMenu.style.top = `${posY}px`;
+
+ const noteIdElement = element.querySelector('.sidebar-note-id');
+ if (noteIdElement) {
+ const noteIdStr = noteIdElement.textContent;
+ //console.log('Right-clicked note id:', noteId);
+ if (noteIdStr) {
+ const noteId: Number = parseInt(noteIdStr);
+ showNoteSidebarContextMenu(noteId);
+ }
+ } else {
+ console.error('.sidebar-note-id element not found within the note.');
+ }
+ });
+
+ })
+ }
+}
function fillNoteSidebar(noteArray: Note[]) {
@@ -106,6 +127,7 @@ function fillNoteSidebar(noteArray: Note[]) {
// Create HTML elements for each note
const noteEl: HTMLDivElement = document.createElement('div');
noteEl.classList.add('sidebar-note');
+ noteEl.classList.add('rightclick-element');
noteEl.addEventListener("click", () => handleSidebarNoteClick(note.id), false);
const idSpan: HTMLSpanElement = document.createElement('span');
@@ -131,11 +153,61 @@ function fillNoteSidebar(noteArray: Note[]) {
// Append noteEl to the container, if it still exists?
noteSidebarContainerEl ? noteSidebarContainerEl.appendChild(noteEl) : null;
});
+
+ refreshContextMenuElements();
}
}
function handleSidebarNoteClick(id: Number): any {
console.log("huh " + id);
+ if (createNoteContentEl && createNoteTagEl) {
+ // search for note
+ let n: Note = {
+ id: 0,
+ content: "undefined",
+ date: "undefined",
+ tag: "undefined"
+ };
+
+ noteArray.forEach(note => {
+ if (note.id === id) {
+ n = note;
+ }
+ });
+
+ if (n) {
+ createNoteContentEl.value = n.content as string;
+ createNoteTagEl.value = n.tag as string;
+ } else {
+ // don't destory currently editing note if this fails
+ console.error("Error fetching note");
+ }
+
+ }
+}
+
+function showNoteSidebarContextMenu(noteId: Number) {
+ const contextMenu = document.getElementById('contextMenu');
+ const deleteButton = document.getElementById('deleteButton');
+
+ if (contextMenu && deleteButton) {
+ deleteButton.addEventListener('click', async function () {
+ console.log('Deleting...');
+ await invoke("delete_specific_note", {
+ id: noteId
+ });
+ // hide after delete
+ contextMenu.style.display = 'none';
+ showNotes();
+ });
+
+ // hide when clicking outside of it
+ document.addEventListener('click', function (event) {
+ if (!contextMenu.contains(event.target as Node)) {
+ contextMenu.style.display = 'none';
+ }
+ });
+ }
}
diff --git a/src/styles.css b/src/styles.css
index adcbcf6..73a44b5 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -12,7 +12,7 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
-
+
}
#button-row {
@@ -90,11 +90,11 @@ button:active {
background-color: #e8e8e8;
}
-#create-tag{
+#create-tag {
margin: 0.5em;
}
-#create-input{
+#create-input {
margin: 0.5em;
height: 100%;
@@ -114,7 +114,8 @@ button:active {
#create-input:focus {
border-color: #cf66e9;
box-shadow: 0 0 5px rgba(102, 175, 233, 0.6);
- outline: none; /* Remove default focus outline */
+ outline: none;
+ /* Remove default focus outline */
}
input,
@@ -165,4 +166,30 @@ button {
margin-left: 10px;
padding: 2px 6px;
border-radius: 4px;
+}
+
+/* CONTEXT MENU */
+
+.context-menu {
+ position: relative;
+}
+
+.menu {
+ display: none;
+ position: absolute;
+ z-index: 999;
+ border: 1px solid #ccc;
+ padding: 5px;
+}
+
+.menu button {
+ display: block;
+ background-color: transparent;
+ border: none;
+ cursor: pointer;
+ padding: 5px;
+}
+
+.menu button:hover {
+ background-color: #770079;
}
\ No newline at end of file