Quick-notes / static /app.js
Sameer Singh
initial commit
d044ca3
Raw
History Blame Contribute Delete
4.48 kB
const noteInput = document.getElementById("note-input");
const charCount = document.getElementById("char-count");
const saveBtn = document.getElementById("save-btn");
const searchInput = document.getElementById("search-input");
const notesList = document.getElementById("notes-list");
const emptyState = document.getElementById("empty-state");
const noteTemplate = document.getElementById("note-template");
const themeToggle = document.getElementById("theme-toggle");
let notes = [];
let editingNoteId = null;
const THEME_KEY = "quick-notes-theme";
function formatDate(dateString) {
const date = new Date(dateString.replace(" ", "T"));
if (Number.isNaN(date.getTime())) {
return dateString;
}
return date.toLocaleString();
}
function updateCounter() {
charCount.textContent = `${noteInput.value.length} characters`;
}
function applySavedTheme() {
const saved = localStorage.getItem(THEME_KEY);
if (saved === "dark") {
document.body.classList.add("dark");
}
}
function toggleTheme() {
document.body.classList.toggle("dark");
const active = document.body.classList.contains("dark") ? "dark" : "light";
localStorage.setItem(THEME_KEY, active);
}
async function fetchNotes() {
const response = await fetch("/notes");
if (!response.ok) {
throw new Error("Failed to fetch notes");
}
notes = await response.json();
renderNotes();
}
async function saveNote() {
const content = noteInput.value.trim();
if (!content) {
alert("Please write a note before saving.");
return;
}
const method = editingNoteId ? "PUT" : "POST";
const endpoint = editingNoteId ? `/notes/${editingNoteId}` : "/notes";
const response = await fetch(endpoint, {
method,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ content }),
});
if (!response.ok) {
alert("Could not save note.");
return;
}
editingNoteId = null;
noteInput.value = "";
updateCounter();
saveBtn.textContent = "Save Note";
await fetchNotes();
}
async function deleteNote(noteId) {
const confirmed = confirm("Delete this note?");
if (!confirmed) {
return;
}
const response = await fetch(`/notes/${noteId}`, { method: "DELETE" });
if (!response.ok) {
alert("Could not delete note.");
return;
}
if (editingNoteId === noteId) {
editingNoteId = null;
noteInput.value = "";
saveBtn.textContent = "Save Note";
updateCounter();
}
await fetchNotes();
}
async function copyNote(content) {
try {
await navigator.clipboard.writeText(content);
alert("Note copied.");
} catch (error) {
alert("Clipboard copy failed.");
}
}
function beginEdit(note) {
editingNoteId = note.id;
noteInput.value = note.content;
saveBtn.textContent = "Update Note";
updateCounter();
noteInput.focus();
}
function renderNotes() {
const query = searchInput.value.trim().toLowerCase();
const filteredNotes = notes.filter((note) =>
note.content.toLowerCase().includes(query)
);
notesList.innerHTML = "";
if (filteredNotes.length === 0) {
emptyState.style.display = "block";
emptyState.textContent = query
? "No notes matched your search."
: "No notes yet. Save your first one.";
return;
}
emptyState.style.display = "none";
filteredNotes.forEach((note, index) => {
const fragment = noteTemplate.content.cloneNode(true);
const noteItem = fragment.querySelector(".note-item");
noteItem.style.animationDelay = `${index * 45}ms`;
fragment.querySelector(".note-content").textContent = note.content;
fragment.querySelector(".note-created").textContent = `Created: ${formatDate(note.created_at)}`;
fragment.querySelector(".note-updated").textContent = `Updated: ${formatDate(note.updated_at)}`;
fragment.querySelector(".edit-btn").addEventListener("click", () => beginEdit(note));
fragment.querySelector(".delete-btn").addEventListener("click", () => deleteNote(note.id));
fragment.querySelector(".copy-btn").addEventListener("click", () => copyNote(note.content));
notesList.appendChild(fragment);
});
}
noteInput.addEventListener("input", updateCounter);
saveBtn.addEventListener("click", saveNote);
searchInput.addEventListener("input", renderNotes);
themeToggle.addEventListener("click", toggleTheme);
applySavedTheme();
updateCounter();
fetchNotes().catch(() => {
emptyState.style.display = "block";
emptyState.textContent = "Could not load notes. Refresh to retry.";
});