| document.addEventListener('DOMContentLoaded', () => { |
| |
| let notes = JSON.parse(localStorage.getItem('notes')) || []; |
| let currentNoteId = null; |
|
|
| |
| const notesGrid = document.getElementById('notes-grid'); |
| const newNoteBtn = document.getElementById('new-note-btn'); |
| const editorModal = document.getElementById('editor-modal'); |
| const noteTitle = document.getElementById('note-title'); |
| const editorContent = document.getElementById('editor-content'); |
| const saveNoteBtn = document.getElementById('save-note'); |
| const closeEditorBtn = document.getElementById('close-editor'); |
| const toolbarButtons = document.querySelectorAll('#editor-toolbar button'); |
|
|
| |
| function renderNotes() { |
| notesGrid.innerHTML = ''; |
| notes.forEach(note => { |
| const preview = note.blocks.find(block => block.type === 'paragraph')?.content || 'No content'; |
| |
| const noteElement = document.createElement('div'); |
| noteElement.className = 'bg-white dark:bg-secondary-700 rounded-lg shadow-md overflow-hidden hover:shadow-lg transition cursor-pointer'; |
| noteElement.innerHTML = ` |
| <div class="p-4"> |
| <h3 class="font-bold text-lg mb-2 text-secondary-900 dark:text-white">${note.title || 'Untitled Note'}</h3> |
| <p class="text-secondary-600 dark:text-secondary-300 line-clamp-3">${preview}</p> |
| </div> |
| <div class="px-4 py-2 bg-secondary-50 dark:bg-secondary-800 text-secondary-500 dark:text-secondary-400 text-sm flex justify-between items-center"> |
| <span>${new Date(note.updatedAt).toLocaleDateString()}</span> |
| <button class="text-red-500 hover:text-red-700 delete-note" data-id="${note.id}"> |
| <i data-feather="trash-2"></i> |
| </button> |
| </div> |
| `; |
| |
| noteElement.addEventListener('click', () => openEditor(note.id)); |
| notesGrid.appendChild(noteElement); |
| }); |
| |
| |
| document.querySelectorAll('.delete-note').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| e.stopPropagation(); |
| deleteNote(btn.dataset.id); |
| }); |
| }); |
| |
| feather.replace(); |
| } |
|
|
| |
| function createNewNote() { |
| const newNote = { |
| id: Date.now().toString(), |
| title: '', |
| blocks: [{ type: 'paragraph', content: '' }], |
| createdAt: new Date(), |
| updatedAt: new Date() |
| }; |
| |
| notes.unshift(newNote); |
| saveNotes(); |
| openEditor(newNote.id); |
| } |
|
|
| |
| function openEditor(noteId) { |
| const note = notes.find(n => n.id === noteId); |
| if (!note) return; |
| |
| currentNoteId = noteId; |
| noteTitle.value = note.title; |
| editorContent.innerHTML = ''; |
| |
| note.blocks.forEach(block => { |
| const blockElement = createBlockElement(block); |
| editorContent.appendChild(blockElement); |
| }); |
| |
| editorModal.classList.remove('hidden'); |
| document.body.style.overflow = 'hidden'; |
| } |
|
|
| |
| function closeEditor() { |
| editorModal.classList.add('hidden'); |
| document.body.style.overflow = ''; |
| currentNoteId = null; |
| } |
|
|
| |
| function saveNote() { |
| if (!currentNoteId) return; |
| |
| const noteIndex = notes.findIndex(n => n.id === currentNoteId); |
| if (noteIndex === -1) return; |
| |
| const title = noteTitle.value.trim(); |
| const blocks = []; |
| |
| |
| editorContent.querySelectorAll('[data-block]').forEach(blockEl => { |
| const type = blockEl.dataset.block; |
| let content = ''; |
| |
| if (type === 'image') { |
| content = blockEl.querySelector('img')?.src || ''; |
| } else { |
| content = blockEl.textContent; |
| } |
| |
| blocks.push({ type, content }); |
| }); |
| |
| notes[noteIndex] = { |
| ...notes[noteIndex], |
| title, |
| blocks, |
| updatedAt: new Date() |
| }; |
| |
| saveNotes(); |
| renderNotes(); |
| } |
|
|
| |
| function deleteNote(noteId) { |
| if (confirm('Are you sure you want to delete this note?')) { |
| notes = notes.filter(note => note.id !== noteId); |
| saveNotes(); |
| renderNotes(); |
| } |
| } |
|
|
| |
| function saveNotes() { |
| localStorage.setItem('notes', JSON.stringify(notes)); |
| } |
|
|
| |
| function createBlockElement(block) { |
| const blockElement = document.createElement('div'); |
| blockElement.dataset.block = block.type; |
| blockElement.className = `block-${block.type} mb-4`; |
| blockElement.contentEditable = true; |
| |
| switch (block.type) { |
| case 'heading': |
| blockElement.innerHTML = `<h2>${block.content || 'Heading'}</h2>`; |
| break; |
| case 'list': |
| blockElement.innerHTML = `<ul><li>${block.content || 'List item'}</li></ul>`; |
| break; |
| case 'image': |
| blockElement.innerHTML = `<img src="${block.content || 'https://via.placeholder.com/600x400'}" alt="Image" class="rounded-lg w-full">`; |
| break; |
| case 'quote': |
| blockElement.innerHTML = `<blockquote>${block.content || 'Quote'}</blockquote>`; |
| break; |
| case 'code': |
| blockElement.innerHTML = `<pre><code>${block.content || 'Code'}</code></pre>`; |
| break; |
| default: |
| blockElement.textContent = block.content || ''; |
| } |
| |
| return blockElement; |
| } |
|
|
| |
| function addBlock(type) { |
| const block = { type, content: '' }; |
| const blockElement = createBlockElement(block); |
| |
| |
| editorContent.appendChild(blockElement); |
| |
| |
| blockElement.focus(); |
| } |
|
|
| |
| newNoteBtn.addEventListener('click', createNewNote); |
| saveNoteBtn.addEventListener('click', saveNote); |
| closeEditorBtn.addEventListener('click', closeEditor); |
| |
| toolbarButtons.forEach(btn => { |
| btn.addEventListener('click', () => addBlock(btn.dataset.type)); |
| }); |
|
|
| |
| editorModal.addEventListener('click', (e) => { |
| if (e.target === editorModal) { |
| closeEditor(); |
| } |
| }); |
|
|
| |
| renderNotes(); |
| }); |