|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>ScribbleSync - Digital Notepad</title> |
|
|
<link rel="icon" type="image/x-icon" href="/static/favicon.ico"> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<script src="https://unpkg.com/feather-icons"></script> |
|
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> |
|
|
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script> |
|
|
<style> |
|
|
.note-card { |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.note-card:hover { |
|
|
transform: translateY(-5px); |
|
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
|
|
} |
|
|
#vanta-bg { |
|
|
position: fixed; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
z-index: -1; |
|
|
opacity: 0.1; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50"> |
|
|
<div id="vanta-bg"></div> |
|
|
|
|
|
|
|
|
<nav class="bg-white shadow-sm fixed w-full z-10"> |
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
|
|
<div class="flex justify-between h-16"> |
|
|
<div class="flex"> |
|
|
<div class="flex-shrink-0 flex items-center"> |
|
|
<i data-feather="edit-3" class="text-indigo-600 h-6 w-6"></i> |
|
|
<span class="ml-2 text-xl font-bold text-indigo-600">ScribbleSync</span> |
|
|
</div> |
|
|
<div class="hidden sm:ml-6 sm:flex sm:space-x-8"> |
|
|
<a href="index.html" class="border-indigo-500 text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"> |
|
|
Notes |
|
|
</a> |
|
|
<a href="history.html" class="border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"> |
|
|
History |
|
|
</a> |
|
|
</div> |
|
|
</div> |
|
|
<div class="hidden sm:ml-6 sm:flex sm:items-center"> |
|
|
<button id="new-note-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-md text-sm font-medium flex items-center"> |
|
|
<i data-feather="plus" class="mr-1 h-4 w-4"></i> New Note |
|
|
</button> |
|
|
</div> |
|
|
<div class="-mr-2 flex items-center sm:hidden"> |
|
|
<button type="button" id="mobile-menu-button" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"> |
|
|
<i data-feather="menu"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="mobile-menu" class="sm:hidden hidden"> |
|
|
<div class="pt-2 pb-3 space-y-1"> |
|
|
<a href="index.html" class="bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium"> |
|
|
Notes |
|
|
</a> |
|
|
<a href="history.html" class="border-transparent text-gray-500 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium"> |
|
|
History |
|
|
</a> |
|
|
<button id="mobile-new-note-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-md text-sm font-medium flex items-center ml-3 mt-2 mb-2"> |
|
|
<i data-feather="plus" class="mr-1 h-4 w-4"></i> New Note |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</nav> |
|
|
|
|
|
|
|
|
<main class="pt-20 pb-10 px-4 sm:px-6 lg:px-8"> |
|
|
<div class="max-w-7xl mx-auto"> |
|
|
<div class="mb-8"> |
|
|
<h1 class="text-3xl font-bold text-gray-900">Your Notes</h1> |
|
|
<p class="mt-2 text-sm text-gray-500">Create, edit and organize your thoughts</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="notes-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="empty-state" class="text-center py-16 hidden"> |
|
|
<i data-feather="edit" class="mx-auto h-12 w-12 text-gray-400"></i> |
|
|
<h3 class="mt-2 text-lg font-medium text-gray-900">No notes</h3> |
|
|
<p class="mt-1 text-sm text-gray-500">Get started by creating a new note.</p> |
|
|
<div class="mt-6"> |
|
|
<button id="empty-new-note-btn" class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> |
|
|
<i data-feather="plus" class="-ml-1 mr-2 h-5 w-5"></i> New Note |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</main> |
|
|
|
|
|
|
|
|
<div id="note-modal" class="fixed z-50 inset-0 overflow-y-auto hidden" aria-labelledby="modal-title" role="dialog" aria-modal="true"> |
|
|
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |
|
|
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div> |
|
|
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span> |
|
|
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"> |
|
|
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |
|
|
<div class="sm:flex sm:items-start"> |
|
|
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left w-full"> |
|
|
<h3 class="text-lg leading-6 font-medium text-gray-900 mb-4" id="modal-title"> |
|
|
<span id="modal-title-text">New Note</span> |
|
|
</h3> |
|
|
<div class="mt-2"> |
|
|
<input type="text" id="note-title" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md mb-4 p-2" placeholder="Note title"> |
|
|
<textarea id="note-content" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 h-64" placeholder="Write your note here..."></textarea> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |
|
|
<button type="button" id="save-note-btn" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:ml-3 sm:w-auto sm:text-sm"> |
|
|
Save |
|
|
</button> |
|
|
<button type="button" id="cancel-note-btn" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> |
|
|
Cancel |
|
|
</button> |
|
|
<button type="button" id="delete-note-btn" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-red-600 text-white font-medium hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm hidden"> |
|
|
Delete |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
VANTA.NET({ |
|
|
el: "#vanta-bg", |
|
|
color: 0x6366f1, |
|
|
backgroundColor: 0xf9fafb, |
|
|
points: 10, |
|
|
maxDistance: 20, |
|
|
spacing: 15 |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
feather.replace(); |
|
|
|
|
|
|
|
|
const mobileMenuButton = document.getElementById('mobile-menu-button'); |
|
|
const mobileMenu = document.getElementById('mobile-menu'); |
|
|
|
|
|
mobileMenuButton.addEventListener('click', function() { |
|
|
if (mobileMenu.classList.contains('hidden')) { |
|
|
mobileMenu.classList.remove('hidden'); |
|
|
} else { |
|
|
mobileMenu.classList.add('hidden'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
let notes = JSON.parse(localStorage.getItem('notes')) || []; |
|
|
let currentNoteId = null; |
|
|
|
|
|
|
|
|
const notesContainer = document.getElementById('notes-container'); |
|
|
const emptyState = document.getElementById('empty-state'); |
|
|
const noteModal = document.getElementById('note-modal'); |
|
|
const noteTitle = document.getElementById('note-title'); |
|
|
const noteContent = document.getElementById('note-content'); |
|
|
const saveNoteBtn = document.getElementById('save-note-btn'); |
|
|
const cancelNoteBtn = document.getElementById('cancel-note-btn'); |
|
|
const deleteNoteBtn = document.getElementById('delete-note-btn'); |
|
|
const modalTitle = document.getElementById('modal-title-text'); |
|
|
|
|
|
|
|
|
const newNoteBtn = document.getElementById('new-note-btn'); |
|
|
const mobileNewNoteBtn = document.getElementById('mobile-new-note-btn'); |
|
|
const emptyNewNoteBtn = document.getElementById('empty-new-note-btn'); |
|
|
|
|
|
|
|
|
[newNoteBtn, mobileNewNoteBtn, emptyNewNoteBtn].forEach(btn => { |
|
|
btn.addEventListener('click', () => { |
|
|
openNewNoteModal(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
cancelNoteBtn.addEventListener('click', closeNoteModal); |
|
|
|
|
|
|
|
|
saveNoteBtn.addEventListener('click', saveNote); |
|
|
|
|
|
|
|
|
deleteNoteBtn.addEventListener('click', deleteNote); |
|
|
|
|
|
|
|
|
renderNotes(); |
|
|
|
|
|
|
|
|
function openNewNoteModal() { |
|
|
currentNoteId = null; |
|
|
noteTitle.value = ''; |
|
|
noteContent.value = ''; |
|
|
modalTitle.textContent = 'New Note'; |
|
|
deleteNoteBtn.classList.add('hidden'); |
|
|
noteModal.classList.remove('hidden'); |
|
|
noteTitle.focus(); |
|
|
} |
|
|
|
|
|
function openEditNoteModal(id) { |
|
|
const note = notes.find(note => note.id === id); |
|
|
if (note) { |
|
|
currentNoteId = id; |
|
|
noteTitle.value = note.title; |
|
|
noteContent.value = note.content; |
|
|
modalTitle.textContent = 'Edit Note'; |
|
|
deleteNoteBtn.classList.remove('hidden'); |
|
|
noteModal.classList.remove('hidden'); |
|
|
noteTitle.focus(); |
|
|
} |
|
|
} |
|
|
|
|
|
function closeNoteModal() { |
|
|
noteModal.classList.add('hidden'); |
|
|
} |
|
|
|
|
|
function saveNote() { |
|
|
const title = noteTitle.value.trim(); |
|
|
const content = noteContent.value.trim(); |
|
|
|
|
|
if (!title) { |
|
|
alert('Please enter a title for your note'); |
|
|
return; |
|
|
} |
|
|
|
|
|
const now = new Date(); |
|
|
const timestamp = now.toISOString(); |
|
|
|
|
|
if (currentNoteId) { |
|
|
|
|
|
const noteIndex = notes.findIndex(note => note.id === currentNoteId); |
|
|
if (noteIndex !== -1) { |
|
|
notes[noteIndex] = { |
|
|
...notes[noteIndex], |
|
|
title, |
|
|
content, |
|
|
updatedAt: timestamp |
|
|
}; |
|
|
} |
|
|
} else { |
|
|
|
|
|
const newNote = { |
|
|
id: Date.now().toString(), |
|
|
title, |
|
|
content, |
|
|
createdAt: timestamp, |
|
|
updatedAt: timestamp |
|
|
}; |
|
|
notes.unshift(newNote); |
|
|
} |
|
|
|
|
|
saveToLocalStorage(); |
|
|
renderNotes(); |
|
|
closeNoteModal(); |
|
|
} |
|
|
function deleteNote() { |
|
|
if (confirm('Are you sure you want to delete this note?')) { |
|
|
const noteIndex = notes.findIndex(note => note.id === currentNoteId); |
|
|
if (noteIndex !== -1) { |
|
|
const deletedNote = notes[noteIndex]; |
|
|
|
|
|
|
|
|
const trash = JSON.parse(localStorage.getItem('trash')) || []; |
|
|
trash.push({ |
|
|
...deletedNote, |
|
|
deletedAt: new Date().toISOString() |
|
|
}); |
|
|
localStorage.setItem('trash', JSON.stringify(trash)); |
|
|
|
|
|
|
|
|
notes.splice(noteIndex, 1); |
|
|
saveToLocalStorage(); |
|
|
renderNotes(); |
|
|
closeNoteModal(); |
|
|
} |
|
|
} |
|
|
} |
|
|
function saveToLocalStorage() { |
|
|
localStorage.setItem('notes', JSON.stringify(notes)); |
|
|
} |
|
|
|
|
|
function renderNotes() { |
|
|
notesContainer.innerHTML = ''; |
|
|
|
|
|
if (notes.length === 0) { |
|
|
emptyState.classList.remove('hidden'); |
|
|
return; |
|
|
} |
|
|
|
|
|
emptyState.classList.add('hidden'); |
|
|
|
|
|
notes.forEach(note => { |
|
|
const noteDate = new Date(note.updatedAt); |
|
|
const formattedDate = noteDate.toLocaleDateString('en-US', { |
|
|
year: 'numeric', |
|
|
month: 'short', |
|
|
day: 'numeric', |
|
|
hour: '2-digit', |
|
|
minute: '2-digit' |
|
|
}); |
|
|
|
|
|
const truncatedContent = note.content.length > 150 |
|
|
? note.content.substring(0, 150) + '...' |
|
|
: note.content; |
|
|
|
|
|
const noteCard = document.createElement('div'); |
|
|
noteCard.className = 'bg-white overflow-hidden shadow rounded-lg note-card cursor-pointer'; |
|
|
noteCard.innerHTML = ` |
|
|
<div class="px-4 py-5 sm:p-6" onclick="openEditNoteModal('${note.id}')"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<h3 class="text-lg leading-6 font-medium text-gray-900">${note.title}</h3> |
|
|
<span class="text-xs text-gray-500">${formattedDate}</span> |
|
|
</div> |
|
|
<div class="mt-2 text-sm text-gray-600"> |
|
|
<p>${truncatedContent}</p> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
notesContainer.appendChild(noteCard); |
|
|
}); |
|
|
|
|
|
feather.replace(); |
|
|
} |
|
|
|
|
|
|
|
|
window.openEditNoteModal = openEditNoteModal; |
|
|
}); |
|
|
</script> |
|
|
</body> |
|
|
</html> |
|
|
|