From 5bc9c9bdb18dfa928ae34b9b571804ec721f98b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20R=C5=AF=C5=BEi=C4=8Dka?=
<97810333+thejakubruzicka@users.noreply.github.com>
Date: Tue, 20 May 2025 20:07:34 +0200
Subject: [PATCH] Update script.js
---
script.js | 175 +++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 120 insertions(+), 55 deletions(-)
diff --git a/script.js b/script.js
index 836f82e..921cd7b 100644
--- a/script.js
+++ b/script.js
@@ -7,15 +7,52 @@ document.addEventListener('DOMContentLoaded', () => {
const noteTitleInput = document.getElementById('noteTitleInput');
const noteContentInput = document.getElementById('noteContentInput');
+ const themeToggleBtn = document.getElementById('themeToggleBtn');
+ const body = document.body;
+
let notes = [];
let currentEditingId = null;
+ // --- Theming ---
+ function applyTheme(theme) { // theme is 'light' or 'dark'
+ body.classList.remove('light-theme', 'dark-theme');
+ body.classList.add(theme + '-theme'); // e.g., 'dark-theme'
+ localStorage.setItem('mnotes-theme', theme);
+
+ const icon = themeToggleBtn.querySelector('md-icon');
+ if (theme === 'dark') {
+ icon.textContent = 'light_mode';
+ themeToggleBtn.ariaLabel = "Activate light theme";
+ } else {
+ icon.textContent = 'dark_mode';
+ themeToggleBtn.ariaLabel = "Activate dark theme";
+ }
+ }
+
+ function toggleTheme() {
+ const currentTheme = localStorage.getItem('mnotes-theme') || (body.classList.contains('dark-theme') ? 'dark' : 'light');
+ applyTheme(currentTheme === 'light' ? 'dark' : 'light');
+ }
+
+ function loadInitialTheme() {
+ const savedTheme = localStorage.getItem('mnotes-theme');
+ if (savedTheme) {
+ applyTheme(savedTheme);
+ } else {
+ // Prefer system theme if no preference saved
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ applyTheme('dark');
+ } else {
+ applyTheme('light'); // Default to light
+ }
+ }
+ }
+ themeToggleBtn.addEventListener('click', toggleTheme);
+
// --- Data Persistence ---
function loadNotes() {
const storedNotes = localStorage.getItem('material-notes');
- if (storedNotes) {
- notes = JSON.parse(storedNotes);
- }
+ notes = storedNotes ? JSON.parse(storedNotes) : [];
renderNotes();
}
@@ -27,36 +64,39 @@ document.addEventListener('DOMContentLoaded', () => {
function renderNotes() {
notesList.innerHTML = ''; // Clear existing notes
if (notes.length === 0) {
- notesList.innerHTML = `
No notes yet. Click the + button to add one!
`;
+ const p = document.createElement('p');
+ p.textContent = "No notes yet. Click the + button to add one!";
+ notesList.appendChild(p);
return;
}
+ notes.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified)); // Sort by most recently modified
+
notes.forEach(note => {
const noteCard = document.createElement('div');
noteCard.className = 'note-card';
- // Add md-elevation for a card-like appearance
- const elevation = document.createElement('md-elevation');
+
+ const elevation = document.createElement('md-elevation'); // Add MWC elevation
noteCard.appendChild(elevation);
-
const title = document.createElement('h3');
title.textContent = note.title;
const content = document.createElement('p');
- content.textContent = note.content.substring(0, 150) + (note.content.length > 150 ? '...' : ''); // Preview
+ content.textContent = note.content.substring(0, 150) + (note.content.length > 150 ? '...' : '');
const actions = document.createElement('div');
actions.className = 'note-card-actions';
const editButton = document.createElement('md-icon-button');
editButton.innerHTML = `edit`;
- editButton.ariaLabel = 'Edit Note';
- editButton.addEventListener('click', () => openNoteDialog(note));
+ editButton.ariaLabel = `Edit note: ${note.title}`;
+ editButton.addEventListener('click', (e) => { e.stopPropagation(); openNoteDialog(note); });
const deleteButton = document.createElement('md-icon-button');
deleteButton.innerHTML = `delete`;
- deleteButton.ariaLabel = 'Delete Note';
- deleteButton.addEventListener('click', () => deleteNote(note.id));
+ deleteButton.ariaLabel = `Delete note: ${note.title}`;
+ deleteButton.addEventListener('click', (e) => { e.stopPropagation(); deleteNote(note.id); });
actions.appendChild(editButton);
actions.appendChild(deleteButton);
@@ -70,54 +110,89 @@ document.addEventListener('DOMContentLoaded', () => {
// --- Note Operations ---
function openNoteDialog(note = null) {
- noteForm.reset(); // Clear form
+ noteForm.reset(); // Clear form fields
+ // Reset MWC text field states (e.g. error messages)
+ noteTitleInput.errorText = "";
+ noteTitleInput.error = false;
+ noteContentInput.errorText = "";
+ noteContentInput.error = false;
+
if (note) {
currentEditingId = note.id;
- noteIdInput.value = note.id;
noteTitleInput.value = note.title;
- noteContentInput.value = note.content;
+ noteContentInput.value = note.content; // Full content for editing
noteDialog.querySelector('[slot="headline"]').textContent = 'Edit Note';
} else {
currentEditingId = null;
- noteIdInput.value = '';
noteDialog.querySelector('[slot="headline"]').textContent = 'Add New Note';
}
noteDialog.show();
}
- function handleFormSubmit() {
- const title = noteTitleInput.value.trim();
- const content = noteContentInput.value.trim();
+ function handleDialogClose(event) {
+ // event.detail.action contains the `value` of the button that closed it
+ if (event.detail.action === 'save') {
+ const title = noteTitleInput.value.trim();
+ const content = noteContentInput.value.trim();
- if (!title || !content) {
- // Basic validation, could be more robust
- alert('Title and content cannot be empty.');
- return;
- }
-
- if (currentEditingId) {
- // Editing existing note
- const noteIndex = notes.findIndex(n => n.id === currentEditingId);
- if (noteIndex > -1) {
- notes[noteIndex].title = title;
- notes[noteIndex].content = content;
+ let isValid = true;
+ if (!title) {
+ noteTitleInput.error = true;
+ noteTitleInput.errorText = "Title cannot be empty.";
+ isValid = false;
+ } else {
+ noteTitleInput.error = false;
+ noteTitleInput.errorText = "";
+ }
+ if (!content) {
+ noteContentInput.error = true;
+ noteContentInput.errorText = "Content cannot be empty.";
+ isValid = false;
+ } else {
+ noteContentInput.error = false;
+ noteContentInput.errorText = "";
}
- } else {
- // Creating new note
- const newNote = {
- id: Date.now().toString(), // Simple unique ID
- title,
- content
- };
- notes.push(newNote);
- }
- saveNotes();
- renderNotes();
- // noteDialog.close(); // Handled by form method="dialog" and button value
+ if (!isValid) {
+ // To prevent dialog from closing on invalid native form submission,
+ // we'd need to handle the 'submit' event on the form, preventDefault,
+ // then manually close if valid.
+ // Since `method="dialog"` auto-closes, we re-show if invalid.
+ // This is a common pattern if not using full form.requestSubmit().
+ noteDialog.show(); // Re-open dialog if validation fails after it auto-closed.
+ return;
+ }
+
+ const now = new Date().toISOString();
+ if (currentEditingId) {
+ const noteIndex = notes.findIndex(n => n.id === currentEditingId);
+ if (noteIndex > -1) {
+ notes[noteIndex].title = title;
+ notes[noteIndex].content = content;
+ notes[noteIndex].lastModified = now;
+ }
+ } else {
+ notes.push({
+ id: Date.now().toString(),
+ title,
+ content,
+ createdAt: now,
+ lastModified: now
+ });
+ }
+ saveNotes();
+ renderNotes();
+ }
+ // Reset for next time dialog opens
+ currentEditingId = null;
+ noteForm.reset(); // Ensure form is clean
+ noteTitleInput.error = false; noteTitleInput.errorText = "";
+ noteContentInput.error = false; noteContentInput.errorText = "";
}
function deleteNote(id) {
+ // Consider using an md-dialog for confirmation for better UX
+ // For simplicity, using confirm() for now
if (confirm('Are you sure you want to delete this note?')) {
notes = notes.filter(note => note.id !== id);
saveNotes();
@@ -127,19 +202,9 @@ document.addEventListener('DOMContentLoaded', () => {
// --- Event Listeners ---
addNoteFab.addEventListener('click', () => openNoteDialog());
-
- // The dialog component handles its own close on button clicks if `form.method="dialog"`
- // and buttons have `value="cancel"` or `form="formId"`.
- // We listen for the 'closed' event to react to the "save" action.
- noteDialog.addEventListener('closed', (event) => {
- if (event.detail.action === 'save') {
- handleFormSubmit();
- }
- // Reset for next time
- currentEditingId = null;
- noteForm.reset();
- });
+ noteDialog.addEventListener('closed', handleDialogClose);
// --- Initial Load ---
+ loadInitialTheme();
loadNotes();
});