mirror of
https://github.com/thejakubruzicka/MNotes.git
synced 2025-07-10 22:44:05 +02:00
Update script.js
This commit is contained in:
parent
88b0432891
commit
5bc9c9bdb1
1 changed files with 120 additions and 55 deletions
175
script.js
175
script.js
|
@ -7,15 +7,52 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const noteTitleInput = document.getElementById('noteTitleInput');
|
const noteTitleInput = document.getElementById('noteTitleInput');
|
||||||
const noteContentInput = document.getElementById('noteContentInput');
|
const noteContentInput = document.getElementById('noteContentInput');
|
||||||
|
|
||||||
|
const themeToggleBtn = document.getElementById('themeToggleBtn');
|
||||||
|
const body = document.body;
|
||||||
|
|
||||||
let notes = [];
|
let notes = [];
|
||||||
let currentEditingId = null;
|
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 ---
|
// --- Data Persistence ---
|
||||||
function loadNotes() {
|
function loadNotes() {
|
||||||
const storedNotes = localStorage.getItem('material-notes');
|
const storedNotes = localStorage.getItem('material-notes');
|
||||||
if (storedNotes) {
|
notes = storedNotes ? JSON.parse(storedNotes) : [];
|
||||||
notes = JSON.parse(storedNotes);
|
|
||||||
}
|
|
||||||
renderNotes();
|
renderNotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,36 +64,39 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
function renderNotes() {
|
function renderNotes() {
|
||||||
notesList.innerHTML = ''; // Clear existing notes
|
notesList.innerHTML = ''; // Clear existing notes
|
||||||
if (notes.length === 0) {
|
if (notes.length === 0) {
|
||||||
notesList.innerHTML = `<p style="text-align:center; color: var(--md-sys-color-outline);">No notes yet. Click the + button to add one!</p>`;
|
const p = document.createElement('p');
|
||||||
|
p.textContent = "No notes yet. Click the + button to add one!";
|
||||||
|
notesList.appendChild(p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notes.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified)); // Sort by most recently modified
|
||||||
|
|
||||||
notes.forEach(note => {
|
notes.forEach(note => {
|
||||||
const noteCard = document.createElement('div');
|
const noteCard = document.createElement('div');
|
||||||
noteCard.className = 'note-card';
|
noteCard.className = 'note-card';
|
||||||
// Add md-elevation for a card-like appearance
|
|
||||||
const elevation = document.createElement('md-elevation');
|
|
||||||
noteCard.appendChild(elevation);
|
|
||||||
|
|
||||||
|
const elevation = document.createElement('md-elevation'); // Add MWC elevation
|
||||||
|
noteCard.appendChild(elevation);
|
||||||
|
|
||||||
const title = document.createElement('h3');
|
const title = document.createElement('h3');
|
||||||
title.textContent = note.title;
|
title.textContent = note.title;
|
||||||
|
|
||||||
const content = document.createElement('p');
|
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');
|
const actions = document.createElement('div');
|
||||||
actions.className = 'note-card-actions';
|
actions.className = 'note-card-actions';
|
||||||
|
|
||||||
const editButton = document.createElement('md-icon-button');
|
const editButton = document.createElement('md-icon-button');
|
||||||
editButton.innerHTML = `<md-icon>edit</md-icon>`;
|
editButton.innerHTML = `<md-icon>edit</md-icon>`;
|
||||||
editButton.ariaLabel = 'Edit Note';
|
editButton.ariaLabel = `Edit note: ${note.title}`;
|
||||||
editButton.addEventListener('click', () => openNoteDialog(note));
|
editButton.addEventListener('click', (e) => { e.stopPropagation(); openNoteDialog(note); });
|
||||||
|
|
||||||
const deleteButton = document.createElement('md-icon-button');
|
const deleteButton = document.createElement('md-icon-button');
|
||||||
deleteButton.innerHTML = `<md-icon>delete</md-icon>`;
|
deleteButton.innerHTML = `<md-icon>delete</md-icon>`;
|
||||||
deleteButton.ariaLabel = 'Delete Note';
|
deleteButton.ariaLabel = `Delete note: ${note.title}`;
|
||||||
deleteButton.addEventListener('click', () => deleteNote(note.id));
|
deleteButton.addEventListener('click', (e) => { e.stopPropagation(); deleteNote(note.id); });
|
||||||
|
|
||||||
actions.appendChild(editButton);
|
actions.appendChild(editButton);
|
||||||
actions.appendChild(deleteButton);
|
actions.appendChild(deleteButton);
|
||||||
|
@ -70,54 +110,89 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
// --- Note Operations ---
|
// --- Note Operations ---
|
||||||
function openNoteDialog(note = null) {
|
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) {
|
if (note) {
|
||||||
currentEditingId = note.id;
|
currentEditingId = note.id;
|
||||||
noteIdInput.value = note.id;
|
|
||||||
noteTitleInput.value = note.title;
|
noteTitleInput.value = note.title;
|
||||||
noteContentInput.value = note.content;
|
noteContentInput.value = note.content; // Full content for editing
|
||||||
noteDialog.querySelector('[slot="headline"]').textContent = 'Edit Note';
|
noteDialog.querySelector('[slot="headline"]').textContent = 'Edit Note';
|
||||||
} else {
|
} else {
|
||||||
currentEditingId = null;
|
currentEditingId = null;
|
||||||
noteIdInput.value = '';
|
|
||||||
noteDialog.querySelector('[slot="headline"]').textContent = 'Add New Note';
|
noteDialog.querySelector('[slot="headline"]').textContent = 'Add New Note';
|
||||||
}
|
}
|
||||||
noteDialog.show();
|
noteDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFormSubmit() {
|
function handleDialogClose(event) {
|
||||||
const title = noteTitleInput.value.trim();
|
// event.detail.action contains the `value` of the button that closed it
|
||||||
const content = noteContentInput.value.trim();
|
if (event.detail.action === 'save') {
|
||||||
|
const title = noteTitleInput.value.trim();
|
||||||
|
const content = noteContentInput.value.trim();
|
||||||
|
|
||||||
if (!title || !content) {
|
let isValid = true;
|
||||||
// Basic validation, could be more robust
|
if (!title) {
|
||||||
alert('Title and content cannot be empty.');
|
noteTitleInput.error = true;
|
||||||
return;
|
noteTitleInput.errorText = "Title cannot be empty.";
|
||||||
}
|
isValid = false;
|
||||||
|
} else {
|
||||||
if (currentEditingId) {
|
noteTitleInput.error = false;
|
||||||
// Editing existing note
|
noteTitleInput.errorText = "";
|
||||||
const noteIndex = notes.findIndex(n => n.id === currentEditingId);
|
}
|
||||||
if (noteIndex > -1) {
|
if (!content) {
|
||||||
notes[noteIndex].title = title;
|
noteContentInput.error = true;
|
||||||
notes[noteIndex].content = content;
|
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();
|
if (!isValid) {
|
||||||
renderNotes();
|
// To prevent dialog from closing on invalid native form submission,
|
||||||
// noteDialog.close(); // Handled by form method="dialog" and button value
|
// 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) {
|
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?')) {
|
if (confirm('Are you sure you want to delete this note?')) {
|
||||||
notes = notes.filter(note => note.id !== id);
|
notes = notes.filter(note => note.id !== id);
|
||||||
saveNotes();
|
saveNotes();
|
||||||
|
@ -127,19 +202,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
// --- Event Listeners ---
|
// --- Event Listeners ---
|
||||||
addNoteFab.addEventListener('click', () => openNoteDialog());
|
addNoteFab.addEventListener('click', () => openNoteDialog());
|
||||||
|
noteDialog.addEventListener('closed', handleDialogClose);
|
||||||
// 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();
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- Initial Load ---
|
// --- Initial Load ---
|
||||||
|
loadInitialTheme();
|
||||||
loadNotes();
|
loadNotes();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue