Spaces:
Running
Running
Add 2 files
Browse files- index.html +307 -204
- prompts.txt +2 -1
index.html
CHANGED
|
@@ -6,45 +6,71 @@
|
|
| 6 |
<title>Nexus Notes - Modern Note Taking</title>
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
<style>
|
| 10 |
.markdown-content h1 {
|
| 11 |
-
@apply text-2xl font-bold my-4;
|
| 12 |
}
|
| 13 |
.markdown-content h2 {
|
| 14 |
-
@apply text-xl font-bold my-3;
|
| 15 |
}
|
| 16 |
.markdown-content p {
|
| 17 |
-
@apply my-2;
|
| 18 |
}
|
| 19 |
.markdown-content ul {
|
| 20 |
-
@apply list-disc pl-5 my-2;
|
| 21 |
}
|
| 22 |
.markdown-content ol {
|
| 23 |
-
@apply list-decimal pl-5 my-2;
|
| 24 |
}
|
| 25 |
.markdown-content pre {
|
| 26 |
-
@apply bg-gray-100 p-3 rounded my-2 overflow-x-auto;
|
| 27 |
}
|
| 28 |
.markdown-content code {
|
| 29 |
-
@apply bg-gray-100 px-1 rounded text-sm;
|
| 30 |
}
|
| 31 |
.markdown-content blockquote {
|
| 32 |
-
@apply border-l-4 border-
|
|
|
|
|
|
|
|
|
|
| 33 |
}
|
| 34 |
|
| 35 |
/* Custom scrollbar */
|
| 36 |
::-webkit-scrollbar {
|
| 37 |
-
width:
|
| 38 |
-
height:
|
| 39 |
}
|
| 40 |
::-webkit-scrollbar-track {
|
| 41 |
-
@apply bg-gray-
|
| 42 |
}
|
| 43 |
::-webkit-scrollbar-thumb {
|
| 44 |
-
@apply bg-gray-400 rounded;
|
| 45 |
}
|
| 46 |
::-webkit-scrollbar-thumb:hover {
|
| 47 |
-
@apply bg-gray-500;
|
| 48 |
}
|
| 49 |
|
| 50 |
/* Animation for note cards */
|
|
@@ -56,134 +82,178 @@
|
|
| 56 |
animation: fadeIn 0.3s ease-out forwards;
|
| 57 |
}
|
| 58 |
|
| 59 |
-
/*
|
| 60 |
-
.
|
| 61 |
-
|
| 62 |
-
width: 100%;
|
| 63 |
-
height: calc(100vh - 60px);
|
| 64 |
}
|
| 65 |
-
.
|
| 66 |
-
|
| 67 |
-
width: 25%;
|
| 68 |
-
min-width: 250px;
|
| 69 |
-
overflow-y: auto;
|
| 70 |
}
|
| 71 |
-
.
|
| 72 |
-
|
| 73 |
-
overflow-y: auto;
|
| 74 |
}
|
| 75 |
|
| 76 |
-
/*
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
.
|
| 82 |
-
|
| 83 |
-
height: auto;
|
| 84 |
-
max-height: 40vh;
|
| 85 |
-
border-right: none;
|
| 86 |
-
border-bottom: 1px solid #e5e7eb;
|
| 87 |
-
}
|
| 88 |
-
.split-pane-right {
|
| 89 |
-
height: 60vh;
|
| 90 |
}
|
| 91 |
}
|
| 92 |
</style>
|
| 93 |
</head>
|
| 94 |
-
<body class="bg-gray-50 text-gray-800
|
| 95 |
<div class="flex flex-col h-screen">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
<!-- Header -->
|
| 97 |
-
<header class="bg-
|
| 98 |
<div class="container mx-auto flex justify-between items-center">
|
| 99 |
<div class="flex items-center space-x-3">
|
| 100 |
<i class="fas fa-cube text-2xl"></i>
|
| 101 |
<h1 class="text-xl font-bold">Nexus Notes</h1>
|
| 102 |
</div>
|
| 103 |
<div class="flex items-center space-x-4">
|
| 104 |
-
<button id="darkModeToggle" class="p-2 rounded-full hover:bg-
|
| 105 |
-
<i class="fas fa-moon"></i>
|
|
|
|
| 106 |
</button>
|
| 107 |
-
<button id="newNoteBtn" class="bg-white text-
|
| 108 |
-
<i class="fas fa-plus mr-2"></i> New Note
|
| 109 |
</button>
|
| 110 |
</div>
|
| 111 |
</div>
|
| 112 |
</header>
|
| 113 |
|
| 114 |
<!-- Main Content -->
|
| 115 |
-
<div class="
|
| 116 |
-
<!-- Left Pane - Note List -->
|
| 117 |
-
<div class="
|
| 118 |
-
<div class="p-4
|
| 119 |
-
<div class="relative">
|
| 120 |
<input type="text" id="searchNotes" placeholder="Search notes..."
|
| 121 |
-
class="w-full p-2 pl-10 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-
|
| 122 |
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
|
| 123 |
</div>
|
| 124 |
-
<div class="flex justify-between items-center
|
| 125 |
-
<h2 class="font-semibold text-gray-700">My Notes</h2>
|
| 126 |
<div class="flex space-x-2">
|
| 127 |
-
<button id="sortDateBtn" class="p-1 text-
|
| 128 |
<i class="fas fa-calendar"></i>
|
| 129 |
</button>
|
| 130 |
-
<button id="sortAlphaBtn" class="p-1 text-gray-500 hover:text-
|
| 131 |
<i class="fas fa-sort-alpha-down"></i>
|
| 132 |
</button>
|
| 133 |
</div>
|
| 134 |
</div>
|
| 135 |
</div>
|
| 136 |
-
<div id="noteList" class="divide-y divide-gray-
|
| 137 |
<!-- Notes will be dynamically added here -->
|
| 138 |
-
<div class="p-4 text-center text-gray-500">
|
| 139 |
No notes yet. Create your first note!
|
| 140 |
</div>
|
| 141 |
</div>
|
| 142 |
</div>
|
| 143 |
|
| 144 |
<!-- Right Pane - Note Editor -->
|
| 145 |
-
<div class="
|
| 146 |
-
<div id="emptyState" class="h-full flex flex-col items-center justify-center text-gray-500">
|
| 147 |
<i class="fas fa-sticky-note text-5xl mb-4 opacity-30"></i>
|
| 148 |
<h2 class="text-xl font-medium mb-2">No Note Selected</h2>
|
| 149 |
-
<p class="mb-4">Select a note from the sidebar or create a new one</p>
|
| 150 |
-
<button id="emptyNewNoteBtn" class="bg-
|
| 151 |
<i class="fas fa-plus mr-2"></i> Create New Note
|
| 152 |
</button>
|
| 153 |
</div>
|
| 154 |
|
| 155 |
<div id="noteEditor" class="h-full hidden flex-col">
|
| 156 |
-
<div class="p-4 border-b border-gray-200 sticky top-0 bg-white z-10 flex justify-between items-center">
|
| 157 |
<input type="text" id="noteTitle" placeholder="Note title"
|
| 158 |
-
class="text-xl font-bold w-full focus:outline-none">
|
| 159 |
<div class="flex space-x-2">
|
| 160 |
-
<button id="saveNoteBtn" class="p-2 text-gray-500 hover:text-
|
| 161 |
<i class="fas fa-save"></i>
|
| 162 |
</button>
|
| 163 |
-
<button id="deleteNoteBtn" class="p-2 text-gray-500 hover:text-red-600 hover:bg-gray-100 rounded-full transition" title="Delete">
|
| 164 |
<i class="fas fa-trash"></i>
|
| 165 |
</button>
|
| 166 |
-
<button id="exportNoteBtn" class="p-2 text-gray-500 hover:text-
|
| 167 |
<i class="fas fa-file-export"></i>
|
| 168 |
</button>
|
| 169 |
</div>
|
| 170 |
</div>
|
| 171 |
|
| 172 |
-
<div class="flex border-b border-gray-200">
|
| 173 |
-
<button id="writeTab" class="px-4 py-2 font-medium border-b-2 border-
|
| 174 |
-
<button id="previewTab" class="px-4 py-2 font-medium text-gray-500 hover:text-gray-700">Preview</button>
|
| 175 |
-
</div>
|
| 176 |
-
|
| 177 |
-
<div id="writePane" class="flex-1 overflow-auto">
|
| 178 |
-
<textarea id="noteContent" class="w-full h-full p-4 focus:outline-none resize-none font-mono"
|
| 179 |
-
placeholder="Start writing your note here... Markdown is supported!"></textarea>
|
| 180 |
</div>
|
| 181 |
|
| 182 |
-
<div
|
| 183 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
</div>
|
| 185 |
|
| 186 |
-
<div class="p-2 border-t border-gray-200 bg-gray-50 text-sm text-gray-500 flex justify-between items-center">
|
| 187 |
<div id="wordCount">0 words</div>
|
| 188 |
<div id="lastSaved" class="text-xs">Not saved yet</div>
|
| 189 |
</div>
|
|
@@ -198,10 +268,15 @@
|
|
| 198 |
const darkModeToggle = document.getElementById('darkModeToggle');
|
| 199 |
const newNoteBtn = document.getElementById('newNoteBtn');
|
| 200 |
const emptyNewNoteBtn = document.getElementById('emptyNewNoteBtn');
|
|
|
|
| 201 |
const searchNotes = document.getElementById('searchNotes');
|
|
|
|
| 202 |
const sortDateBtn = document.getElementById('sortDateBtn');
|
| 203 |
const sortAlphaBtn = document.getElementById('sortAlphaBtn');
|
|
|
|
|
|
|
| 204 |
const noteList = document.getElementById('noteList');
|
|
|
|
| 205 |
const emptyState = document.getElementById('emptyState');
|
| 206 |
const noteEditor = document.getElementById('noteEditor');
|
| 207 |
const noteTitle = document.getElementById('noteTitle');
|
|
@@ -215,6 +290,10 @@
|
|
| 215 |
const previewPane = document.getElementById('previewPane');
|
| 216 |
const wordCount = document.getElementById('wordCount');
|
| 217 |
const lastSaved = document.getElementById('lastSaved');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
|
| 219 |
// State
|
| 220 |
let notes = JSON.parse(localStorage.getItem('nexus-notes')) || [];
|
|
@@ -224,51 +303,53 @@
|
|
| 224 |
|
| 225 |
// Initialize
|
| 226 |
if (darkMode) {
|
| 227 |
-
|
| 228 |
}
|
| 229 |
renderNoteList();
|
|
|
|
| 230 |
|
| 231 |
// Event Listeners
|
| 232 |
darkModeToggle.addEventListener('click', toggleDarkMode);
|
| 233 |
newNoteBtn.addEventListener('click', createNewNote);
|
| 234 |
emptyNewNoteBtn.addEventListener('click', createNewNote);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
searchNotes.addEventListener('input', filterNotes);
|
|
|
|
| 236 |
sortDateBtn.addEventListener('click', () => {
|
| 237 |
sortByDate = true;
|
| 238 |
renderNoteList();
|
| 239 |
-
|
| 240 |
-
sortDateBtn.classList.add('text-indigo-600');
|
| 241 |
-
sortAlphaBtn.classList.remove('text-indigo-600');
|
| 242 |
-
sortAlphaBtn.classList.add('text-gray-500');
|
| 243 |
});
|
| 244 |
sortAlphaBtn.addEventListener('click', () => {
|
| 245 |
sortByDate = false;
|
| 246 |
renderNoteList();
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
});
|
| 252 |
saveNoteBtn.addEventListener('click', saveCurrentNote);
|
| 253 |
deleteNoteBtn.addEventListener('click', deleteCurrentNote);
|
| 254 |
exportNoteBtn.addEventListener('click', exportCurrentNote);
|
| 255 |
writeTab.addEventListener('click', () => {
|
| 256 |
-
|
| 257 |
-
previewPane.classList.add('hidden');
|
| 258 |
-
writeTab.classList.add('border-indigo-600', 'text-indigo-600');
|
| 259 |
-
writeTab.classList.remove('text-gray-500');
|
| 260 |
-
previewTab.classList.remove('border-indigo-600', 'text-indigo-600');
|
| 261 |
-
previewTab.classList.add('text-gray-500');
|
| 262 |
});
|
| 263 |
previewTab.addEventListener('click', () => {
|
| 264 |
-
|
| 265 |
-
previewPane.classList.remove('hidden');
|
| 266 |
-
previewTab.classList.add('border-indigo-600', 'text-indigo-600');
|
| 267 |
-
previewTab.classList.remove('text-gray-500');
|
| 268 |
-
writeTab.classList.remove('border-indigo-600', 'text-indigo-600');
|
| 269 |
-
writeTab.classList.add('text-gray-500');
|
| 270 |
-
renderMarkdownPreview();
|
| 271 |
});
|
|
|
|
|
|
|
|
|
|
| 272 |
|
| 273 |
// Auto-save when typing
|
| 274 |
let saveTimeout;
|
|
@@ -288,46 +369,54 @@
|
|
| 288 |
darkMode = !darkMode;
|
| 289 |
localStorage.setItem('darkMode', darkMode);
|
| 290 |
if (darkMode) {
|
| 291 |
-
|
| 292 |
} else {
|
| 293 |
-
|
| 294 |
}
|
| 295 |
}
|
| 296 |
|
| 297 |
-
function
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
}
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
el.classList.add('bg-gray-700');
|
| 310 |
-
el.classList.remove('bg-gray-100');
|
| 311 |
-
});
|
| 312 |
-
darkModeToggle.innerHTML = '<i class="fas fa-sun"></i>';
|
| 313 |
}
|
| 314 |
|
| 315 |
-
function
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
}
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
}
|
| 332 |
|
| 333 |
function createNewNote() {
|
|
@@ -342,6 +431,7 @@
|
|
| 342 |
notes.unshift(newNote);
|
| 343 |
saveNotes();
|
| 344 |
renderNoteList();
|
|
|
|
| 345 |
openNote(newNote.id);
|
| 346 |
|
| 347 |
// Focus on title field
|
|
@@ -356,10 +446,42 @@
|
|
| 356 |
}
|
| 357 |
|
| 358 |
function renderNoteList() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 359 |
let filteredNotes = [...notes];
|
| 360 |
|
| 361 |
// Filter by search
|
| 362 |
-
const searchTerm = searchNotes.value.toLowerCase();
|
| 363 |
if (searchTerm) {
|
| 364 |
filteredNotes = filteredNotes.filter(note =>
|
| 365 |
note.title.toLowerCase().includes(searchTerm) ||
|
|
@@ -374,29 +496,26 @@
|
|
| 374 |
filteredNotes.sort((a, b) => a.title.localeCompare(b.title));
|
| 375 |
}
|
| 376 |
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
`;
|
| 384 |
-
return;
|
| 385 |
-
}
|
| 386 |
|
| 387 |
-
|
| 388 |
-
<div class="note-card cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 transition ${
|
| 389 |
-
data-id="${note.id}" onclick="
|
| 390 |
<div class="p-4">
|
| 391 |
-
<h3 class="font-medium truncate">${note.title || 'Untitled Note'}</h3>
|
| 392 |
-
<p class="text-sm text-gray-500 dark:text-gray-400 truncate mt-1">${note.content.substring(0, 100)}${note.content.length > 100 ? '...' : ''}</p>
|
| 393 |
-
<div class="flex justify-between items-center mt-2 text-xs text-gray-400 dark:text-gray-500">
|
| 394 |
<span>${formatDate(note.updatedAt)}</span>
|
| 395 |
<span>${countWords(note.content)} words</span>
|
| 396 |
</div>
|
| 397 |
</div>
|
| 398 |
</div>
|
| 399 |
-
`
|
| 400 |
}
|
| 401 |
|
| 402 |
function openNote(id) {
|
|
@@ -411,22 +530,27 @@
|
|
| 411 |
updateWordCount();
|
| 412 |
lastSaved.textContent = `Last saved: ${formatDate(note.updatedAt)}`;
|
| 413 |
|
| 414 |
-
// Highlight active note in
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 415 |
document.querySelectorAll('.note-card').forEach(card => {
|
| 416 |
-
if (card.dataset.id ===
|
| 417 |
-
card.classList.add('bg-
|
|
|
|
|
|
|
|
|
|
| 418 |
} else {
|
| 419 |
-
card.classList.remove('bg-
|
|
|
|
|
|
|
|
|
|
| 420 |
}
|
| 421 |
});
|
| 422 |
-
|
| 423 |
-
// Switch to write tab
|
| 424 |
-
writePane.classList.remove('hidden');
|
| 425 |
-
previewPane.classList.add('hidden');
|
| 426 |
-
writeTab.classList.add('border-indigo-600', 'text-indigo-600');
|
| 427 |
-
writeTab.classList.remove('text-gray-500');
|
| 428 |
-
previewTab.classList.remove('border-indigo-600', 'text-indigo-600');
|
| 429 |
-
previewTab.classList.add('text-gray-500');
|
| 430 |
}
|
| 431 |
|
| 432 |
function saveCurrentNote() {
|
|
@@ -444,6 +568,7 @@
|
|
| 444 |
|
| 445 |
saveNotes();
|
| 446 |
renderNoteList();
|
|
|
|
| 447 |
lastSaved.textContent = `Last saved: ${formatDate(new Date().toISOString())}`;
|
| 448 |
}
|
| 449 |
|
|
@@ -454,6 +579,7 @@
|
|
| 454 |
notes = notes.filter(note => note.id !== currentNoteId);
|
| 455 |
saveNotes();
|
| 456 |
renderNoteList();
|
|
|
|
| 457 |
|
| 458 |
// Reset editor
|
| 459 |
currentNoteId = null;
|
|
@@ -483,6 +609,10 @@
|
|
| 483 |
renderNoteList();
|
| 484 |
}
|
| 485 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 486 |
function updateWordCount() {
|
| 487 |
const text = noteContent.value;
|
| 488 |
wordCount.textContent = `${countWords(text)} words`;
|
|
@@ -507,47 +637,20 @@
|
|
| 507 |
return date.toLocaleDateString([], { year: 'numeric', month: 'short', day: 'numeric' });
|
| 508 |
}
|
| 509 |
|
| 510 |
-
function
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
let html = note.content
|
| 518 |
-
// Headers
|
| 519 |
-
.replace(/^# (.*$)/gm, '<h1>$1</h1>')
|
| 520 |
-
.replace(/^## (.*$)/gm, '<h2>$1</h2>')
|
| 521 |
-
.replace(/^### (.*$)/gm, '<h3>$1</h3>')
|
| 522 |
-
// Bold
|
| 523 |
-
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
| 524 |
-
// Italic
|
| 525 |
-
.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
| 526 |
-
// Links
|
| 527 |
-
.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" class="text-indigo-600 hover:underline">$1</a>')
|
| 528 |
-
// Lists
|
| 529 |
-
.replace(/^\s*\*\s(.*$)/gm, '<li>$1</li>')
|
| 530 |
-
.replace(/^\s*-\s(.*$)/gm, '<li>$1</li>')
|
| 531 |
-
// Code blocks
|
| 532 |
-
.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>')
|
| 533 |
-
// Inline code
|
| 534 |
-
.replace(/`(.*?)`/g, '<code>$1</code>')
|
| 535 |
-
// Blockquotes
|
| 536 |
-
.replace(/^>\s(.*$)/gm, '<blockquote>$1</blockquote>')
|
| 537 |
-
// Paragraphs
|
| 538 |
-
.replace(/^(?!<[a-z])(.*$)/gm, function(m) {
|
| 539 |
-
return m.trim() ? '<p>' + m + '</p>' : '';
|
| 540 |
-
});
|
| 541 |
-
|
| 542 |
-
// Handle line breaks
|
| 543 |
-
html = html.replace(/\n/g, '<br>');
|
| 544 |
-
|
| 545 |
-
previewPane.innerHTML = html;
|
| 546 |
}
|
| 547 |
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
|
|
|
|
|
|
| 553 |
</html>
|
|
|
|
| 6 |
<title>Nexus Notes - Modern Note Taking</title>
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
| 9 |
+
<script>
|
| 10 |
+
tailwind.config = {
|
| 11 |
+
darkMode: 'class',
|
| 12 |
+
theme: {
|
| 13 |
+
extend: {
|
| 14 |
+
colors: {
|
| 15 |
+
primary: {
|
| 16 |
+
50: '#f0f9ff',
|
| 17 |
+
100: '#e0f2fe',
|
| 18 |
+
200: '#bae6fd',
|
| 19 |
+
300: '#7dd3fc',
|
| 20 |
+
400: '#38bdf8',
|
| 21 |
+
500: '#0ea5e9',
|
| 22 |
+
600: '#0284c7',
|
| 23 |
+
700: '#0369a1',
|
| 24 |
+
800: '#075985',
|
| 25 |
+
900: '#0c4a6e',
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
</script>
|
| 32 |
<style>
|
| 33 |
.markdown-content h1 {
|
| 34 |
+
@apply text-2xl font-bold my-4 text-gray-900 dark:text-white;
|
| 35 |
}
|
| 36 |
.markdown-content h2 {
|
| 37 |
+
@apply text-xl font-bold my-3 text-gray-800 dark:text-gray-200;
|
| 38 |
}
|
| 39 |
.markdown-content p {
|
| 40 |
+
@apply my-2 text-gray-700 dark:text-gray-300;
|
| 41 |
}
|
| 42 |
.markdown-content ul {
|
| 43 |
+
@apply list-disc pl-5 my-2 text-gray-700 dark:text-gray-300;
|
| 44 |
}
|
| 45 |
.markdown-content ol {
|
| 46 |
+
@apply list-decimal pl-5 my-2 text-gray-700 dark:text-gray-300;
|
| 47 |
}
|
| 48 |
.markdown-content pre {
|
| 49 |
+
@apply bg-gray-100 dark:bg-gray-700 p-3 rounded my-2 overflow-x-auto text-gray-800 dark:text-gray-200;
|
| 50 |
}
|
| 51 |
.markdown-content code {
|
| 52 |
+
@apply bg-gray-100 dark:bg-gray-700 px-1 rounded text-sm text-gray-800 dark:text-gray-200;
|
| 53 |
}
|
| 54 |
.markdown-content blockquote {
|
| 55 |
+
@apply border-l-4 border-primary-500 pl-4 italic my-2 text-gray-600 dark:text-gray-400;
|
| 56 |
+
}
|
| 57 |
+
.markdown-content a {
|
| 58 |
+
@apply text-primary-600 dark:text-primary-400 hover:underline;
|
| 59 |
}
|
| 60 |
|
| 61 |
/* Custom scrollbar */
|
| 62 |
::-webkit-scrollbar {
|
| 63 |
+
width: 6px;
|
| 64 |
+
height: 6px;
|
| 65 |
}
|
| 66 |
::-webkit-scrollbar-track {
|
| 67 |
+
@apply bg-gray-200 dark:bg-gray-800;
|
| 68 |
}
|
| 69 |
::-webkit-scrollbar-thumb {
|
| 70 |
+
@apply bg-gray-400 dark:bg-gray-600 rounded;
|
| 71 |
}
|
| 72 |
::-webkit-scrollbar-thumb:hover {
|
| 73 |
+
@apply bg-gray-500 dark:bg-gray-500;
|
| 74 |
}
|
| 75 |
|
| 76 |
/* Animation for note cards */
|
|
|
|
| 82 |
animation: fadeIn 0.3s ease-out forwards;
|
| 83 |
}
|
| 84 |
|
| 85 |
+
/* Mobile menu transition */
|
| 86 |
+
.mobile-menu {
|
| 87 |
+
transition: transform 0.3s ease-in-out;
|
|
|
|
|
|
|
| 88 |
}
|
| 89 |
+
.mobile-menu.hidden {
|
| 90 |
+
transform: translateX(-100%);
|
|
|
|
|
|
|
|
|
|
| 91 |
}
|
| 92 |
+
.mobile-menu.shown {
|
| 93 |
+
transform: translateX(0);
|
|
|
|
| 94 |
}
|
| 95 |
|
| 96 |
+
/* Editor height */
|
| 97 |
+
.editor-container {
|
| 98 |
+
height: calc(100vh - 180px);
|
| 99 |
+
}
|
| 100 |
+
@media (min-width: 768px) {
|
| 101 |
+
.editor-container {
|
| 102 |
+
height: calc(100vh - 140px);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
}
|
| 104 |
}
|
| 105 |
</style>
|
| 106 |
</head>
|
| 107 |
+
<body class="bg-gray-50 text-gray-800 dark:bg-gray-900 dark:text-gray-100 transition-colors duration-200">
|
| 108 |
<div class="flex flex-col h-screen">
|
| 109 |
+
<!-- Mobile Menu Button -->
|
| 110 |
+
<div class="md:hidden fixed bottom-4 right-4 z-50">
|
| 111 |
+
<button id="mobileMenuButton" class="bg-primary-600 text-white p-4 rounded-full shadow-lg hover:bg-primary-700 transition">
|
| 112 |
+
<i class="fas fa-bars text-xl"></i>
|
| 113 |
+
</button>
|
| 114 |
+
</div>
|
| 115 |
+
|
| 116 |
+
<!-- Mobile Menu -->
|
| 117 |
+
<div id="mobileMenu" class="mobile-menu hidden md:hidden fixed inset-0 z-40 bg-gray-100 dark:bg-gray-800 w-64 pt-4 pb-20 px-4 overflow-y-auto">
|
| 118 |
+
<div class="flex items-center justify-between mb-6">
|
| 119 |
+
<div class="flex items-center space-x-3">
|
| 120 |
+
<i class="fas fa-cube text-2xl text-primary-600"></i>
|
| 121 |
+
<h1 class="text-xl font-bold">Nexus Notes</h1>
|
| 122 |
+
</div>
|
| 123 |
+
<button id="closeMobileMenu" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition">
|
| 124 |
+
<i class="fas fa-times"></i>
|
| 125 |
+
</button>
|
| 126 |
+
</div>
|
| 127 |
+
|
| 128 |
+
<div class="mb-6">
|
| 129 |
+
<button id="mobileNewNoteBtn" class="w-full bg-primary-600 text-white px-4 py-2 rounded-md font-medium hover:bg-primary-700 transition flex items-center justify-center">
|
| 130 |
+
<i class="fas fa-plus mr-2"></i> New Note
|
| 131 |
+
</button>
|
| 132 |
+
</div>
|
| 133 |
+
|
| 134 |
+
<div class="relative mb-6">
|
| 135 |
+
<input type="text" id="mobileSearchNotes" placeholder="Search notes..."
|
| 136 |
+
class="w-full p-2 pl-10 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 bg-white dark:bg-gray-700">
|
| 137 |
+
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
|
| 138 |
+
</div>
|
| 139 |
+
|
| 140 |
+
<div class="flex justify-between items-center mb-4">
|
| 141 |
+
<h2 class="font-semibold text-gray-700 dark:text-gray-300">My Notes</h2>
|
| 142 |
+
<div class="flex space-x-2">
|
| 143 |
+
<button id="mobileSortDateBtn" class="p-1 text-primary-600 dark:text-primary-400" title="Sort by date">
|
| 144 |
+
<i class="fas fa-calendar"></i>
|
| 145 |
+
</button>
|
| 146 |
+
<button id="mobileSortAlphaBtn" class="p-1 text-gray-500 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400" title="Sort alphabetically">
|
| 147 |
+
<i class="fas fa-sort-alpha-down"></i>
|
| 148 |
+
</button>
|
| 149 |
+
</div>
|
| 150 |
+
</div>
|
| 151 |
+
|
| 152 |
+
<div id="mobileNoteList" class="divide-y divide-gray-200 dark:divide-gray-700">
|
| 153 |
+
<!-- Notes will be dynamically added here -->
|
| 154 |
+
<div class="p-4 text-center text-gray-500 dark:text-gray-400">
|
| 155 |
+
No notes yet. Create your first note!
|
| 156 |
+
</div>
|
| 157 |
+
</div>
|
| 158 |
+
</div>
|
| 159 |
+
|
| 160 |
+
<!-- Overlay for mobile menu -->
|
| 161 |
+
<div id="mobileMenuOverlay" class="hidden fixed inset-0 z-30 bg-black bg-opacity-50"></div>
|
| 162 |
+
|
| 163 |
<!-- Header -->
|
| 164 |
+
<header class="bg-primary-600 text-white p-4 shadow-md">
|
| 165 |
<div class="container mx-auto flex justify-between items-center">
|
| 166 |
<div class="flex items-center space-x-3">
|
| 167 |
<i class="fas fa-cube text-2xl"></i>
|
| 168 |
<h1 class="text-xl font-bold">Nexus Notes</h1>
|
| 169 |
</div>
|
| 170 |
<div class="flex items-center space-x-4">
|
| 171 |
+
<button id="darkModeToggle" class="p-2 rounded-full hover:bg-primary-500 transition">
|
| 172 |
+
<i class="fas fa-moon dark:hidden"></i>
|
| 173 |
+
<i class="fas fa-sun hidden dark:block"></i>
|
| 174 |
</button>
|
| 175 |
+
<button id="newNoteBtn" class="bg-white text-primary-600 px-4 py-2 rounded-md font-medium hover:bg-primary-50 transition flex items-center">
|
| 176 |
+
<i class="fas fa-plus mr-2"></i> <span class="hidden md:inline">New Note</span>
|
| 177 |
</button>
|
| 178 |
</div>
|
| 179 |
</div>
|
| 180 |
</header>
|
| 181 |
|
| 182 |
<!-- Main Content -->
|
| 183 |
+
<div class="flex flex-1 overflow-hidden">
|
| 184 |
+
<!-- Left Pane - Note List (Desktop) -->
|
| 185 |
+
<div class="hidden md:flex md:w-1/3 lg:w-1/4 xl:w-1/5 bg-white dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 flex-col overflow-y-auto">
|
| 186 |
+
<div class="p-4 sticky top-0 bg-white dark:bg-gray-800 z-10">
|
| 187 |
+
<div class="relative mb-4">
|
| 188 |
<input type="text" id="searchNotes" placeholder="Search notes..."
|
| 189 |
+
class="w-full p-2 pl-10 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 bg-white dark:bg-gray-700">
|
| 190 |
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
|
| 191 |
</div>
|
| 192 |
+
<div class="flex justify-between items-center">
|
| 193 |
+
<h2 class="font-semibold text-gray-700 dark:text-gray-300">My Notes</h2>
|
| 194 |
<div class="flex space-x-2">
|
| 195 |
+
<button id="sortDateBtn" class="p-1 text-primary-600 dark:text-primary-400" title="Sort by date">
|
| 196 |
<i class="fas fa-calendar"></i>
|
| 197 |
</button>
|
| 198 |
+
<button id="sortAlphaBtn" class="p-1 text-gray-500 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400" title="Sort alphabetically">
|
| 199 |
<i class="fas fa-sort-alpha-down"></i>
|
| 200 |
</button>
|
| 201 |
</div>
|
| 202 |
</div>
|
| 203 |
</div>
|
| 204 |
+
<div id="noteList" class="divide-y divide-gray-200 dark:divide-gray-700 flex-1 overflow-y-auto">
|
| 205 |
<!-- Notes will be dynamically added here -->
|
| 206 |
+
<div class="p-4 text-center text-gray-500 dark:text-gray-400">
|
| 207 |
No notes yet. Create your first note!
|
| 208 |
</div>
|
| 209 |
</div>
|
| 210 |
</div>
|
| 211 |
|
| 212 |
<!-- Right Pane - Note Editor -->
|
| 213 |
+
<div class="flex-1 flex flex-col bg-white dark:bg-gray-800 overflow-hidden">
|
| 214 |
+
<div id="emptyState" class="h-full flex flex-col items-center justify-center text-gray-500 dark:text-gray-400 p-4">
|
| 215 |
<i class="fas fa-sticky-note text-5xl mb-4 opacity-30"></i>
|
| 216 |
<h2 class="text-xl font-medium mb-2">No Note Selected</h2>
|
| 217 |
+
<p class="mb-4 text-center">Select a note from the sidebar or create a new one</p>
|
| 218 |
+
<button id="emptyNewNoteBtn" class="bg-primary-600 text-white px-4 py-2 rounded-md font-medium hover:bg-primary-700 transition flex items-center">
|
| 219 |
<i class="fas fa-plus mr-2"></i> Create New Note
|
| 220 |
</button>
|
| 221 |
</div>
|
| 222 |
|
| 223 |
<div id="noteEditor" class="h-full hidden flex-col">
|
| 224 |
+
<div class="p-4 border-b border-gray-200 dark:border-gray-700 sticky top-0 bg-white dark:bg-gray-800 z-10 flex justify-between items-center">
|
| 225 |
<input type="text" id="noteTitle" placeholder="Note title"
|
| 226 |
+
class="text-xl font-bold w-full focus:outline-none bg-transparent">
|
| 227 |
<div class="flex space-x-2">
|
| 228 |
+
<button id="saveNoteBtn" class="p-2 text-gray-500 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition" title="Save">
|
| 229 |
<i class="fas fa-save"></i>
|
| 230 |
</button>
|
| 231 |
+
<button id="deleteNoteBtn" class="p-2 text-gray-500 dark:text-gray-400 hover:text-red-600 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition" title="Delete">
|
| 232 |
<i class="fas fa-trash"></i>
|
| 233 |
</button>
|
| 234 |
+
<button id="exportNoteBtn" class="p-2 text-gray-500 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition" title="Export">
|
| 235 |
<i class="fas fa-file-export"></i>
|
| 236 |
</button>
|
| 237 |
</div>
|
| 238 |
</div>
|
| 239 |
|
| 240 |
+
<div class="flex border-b border-gray-200 dark:border-gray-700">
|
| 241 |
+
<button id="writeTab" class="px-4 py-2 font-medium border-b-2 border-primary-600 text-primary-600 dark:text-primary-400">Write</button>
|
| 242 |
+
<button id="previewTab" class="px-4 py-2 font-medium text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">Preview</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 243 |
</div>
|
| 244 |
|
| 245 |
+
<div class="editor-container flex flex-col">
|
| 246 |
+
<div id="writePane" class="flex-1 overflow-auto">
|
| 247 |
+
<textarea id="noteContent" class="w-full h-full p-4 focus:outline-none resize-none font-mono bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200"
|
| 248 |
+
placeholder="Start writing your note here... Markdown is supported!"></textarea>
|
| 249 |
+
</div>
|
| 250 |
+
|
| 251 |
+
<div id="previewPane" class="flex-1 overflow-auto p-4 hidden markdown-content bg-white dark:bg-gray-800">
|
| 252 |
+
<!-- Markdown preview will be rendered here -->
|
| 253 |
+
</div>
|
| 254 |
</div>
|
| 255 |
|
| 256 |
+
<div class="p-2 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700 text-sm text-gray-500 dark:text-gray-400 flex justify-between items-center">
|
| 257 |
<div id="wordCount">0 words</div>
|
| 258 |
<div id="lastSaved" class="text-xs">Not saved yet</div>
|
| 259 |
</div>
|
|
|
|
| 268 |
const darkModeToggle = document.getElementById('darkModeToggle');
|
| 269 |
const newNoteBtn = document.getElementById('newNoteBtn');
|
| 270 |
const emptyNewNoteBtn = document.getElementById('emptyNewNoteBtn');
|
| 271 |
+
const mobileNewNoteBtn = document.getElementById('mobileNewNoteBtn');
|
| 272 |
const searchNotes = document.getElementById('searchNotes');
|
| 273 |
+
const mobileSearchNotes = document.getElementById('mobileSearchNotes');
|
| 274 |
const sortDateBtn = document.getElementById('sortDateBtn');
|
| 275 |
const sortAlphaBtn = document.getElementById('sortAlphaBtn');
|
| 276 |
+
const mobileSortDateBtn = document.getElementById('mobileSortDateBtn');
|
| 277 |
+
const mobileSortAlphaBtn = document.getElementById('mobileSortAlphaBtn');
|
| 278 |
const noteList = document.getElementById('noteList');
|
| 279 |
+
const mobileNoteList = document.getElementById('mobileNoteList');
|
| 280 |
const emptyState = document.getElementById('emptyState');
|
| 281 |
const noteEditor = document.getElementById('noteEditor');
|
| 282 |
const noteTitle = document.getElementById('noteTitle');
|
|
|
|
| 290 |
const previewPane = document.getElementById('previewPane');
|
| 291 |
const wordCount = document.getElementById('wordCount');
|
| 292 |
const lastSaved = document.getElementById('lastSaved');
|
| 293 |
+
const mobileMenuButton = document.getElementById('mobileMenuButton');
|
| 294 |
+
const mobileMenu = document.getElementById('mobileMenu');
|
| 295 |
+
const mobileMenuOverlay = document.getElementById('mobileMenuOverlay');
|
| 296 |
+
const closeMobileMenu = document.getElementById('closeMobileMenu');
|
| 297 |
|
| 298 |
// State
|
| 299 |
let notes = JSON.parse(localStorage.getItem('nexus-notes')) || [];
|
|
|
|
| 303 |
|
| 304 |
// Initialize
|
| 305 |
if (darkMode) {
|
| 306 |
+
document.documentElement.classList.add('dark');
|
| 307 |
}
|
| 308 |
renderNoteList();
|
| 309 |
+
renderMobileNoteList();
|
| 310 |
|
| 311 |
// Event Listeners
|
| 312 |
darkModeToggle.addEventListener('click', toggleDarkMode);
|
| 313 |
newNoteBtn.addEventListener('click', createNewNote);
|
| 314 |
emptyNewNoteBtn.addEventListener('click', createNewNote);
|
| 315 |
+
mobileNewNoteBtn.addEventListener('click', () => {
|
| 316 |
+
createNewNote();
|
| 317 |
+
hideMobileMenu();
|
| 318 |
+
});
|
| 319 |
searchNotes.addEventListener('input', filterNotes);
|
| 320 |
+
mobileSearchNotes.addEventListener('input', filterMobileNotes);
|
| 321 |
sortDateBtn.addEventListener('click', () => {
|
| 322 |
sortByDate = true;
|
| 323 |
renderNoteList();
|
| 324 |
+
updateSortButtons();
|
|
|
|
|
|
|
|
|
|
| 325 |
});
|
| 326 |
sortAlphaBtn.addEventListener('click', () => {
|
| 327 |
sortByDate = false;
|
| 328 |
renderNoteList();
|
| 329 |
+
updateSortButtons();
|
| 330 |
+
});
|
| 331 |
+
mobileSortDateBtn.addEventListener('click', () => {
|
| 332 |
+
sortByDate = true;
|
| 333 |
+
renderMobileNoteList();
|
| 334 |
+
updateMobileSortButtons();
|
| 335 |
+
});
|
| 336 |
+
mobileSortAlphaBtn.addEventListener('click', () => {
|
| 337 |
+
sortByDate = false;
|
| 338 |
+
renderMobileNoteList();
|
| 339 |
+
updateMobileSortButtons();
|
| 340 |
});
|
| 341 |
saveNoteBtn.addEventListener('click', saveCurrentNote);
|
| 342 |
deleteNoteBtn.addEventListener('click', deleteCurrentNote);
|
| 343 |
exportNoteBtn.addEventListener('click', exportCurrentNote);
|
| 344 |
writeTab.addEventListener('click', () => {
|
| 345 |
+
showWritePane();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
});
|
| 347 |
previewTab.addEventListener('click', () => {
|
| 348 |
+
showPreviewPane();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
});
|
| 350 |
+
mobileMenuButton.addEventListener('click', showMobileMenu);
|
| 351 |
+
mobileMenuOverlay.addEventListener('click', hideMobileMenu);
|
| 352 |
+
closeMobileMenu.addEventListener('click', hideMobileMenu);
|
| 353 |
|
| 354 |
// Auto-save when typing
|
| 355 |
let saveTimeout;
|
|
|
|
| 369 |
darkMode = !darkMode;
|
| 370 |
localStorage.setItem('darkMode', darkMode);
|
| 371 |
if (darkMode) {
|
| 372 |
+
document.documentElement.classList.add('dark');
|
| 373 |
} else {
|
| 374 |
+
document.documentElement.classList.remove('dark');
|
| 375 |
}
|
| 376 |
}
|
| 377 |
|
| 378 |
+
function updateSortButtons() {
|
| 379 |
+
if (sortByDate) {
|
| 380 |
+
sortDateBtn.classList.remove('text-gray-500', 'dark:text-gray-400');
|
| 381 |
+
sortDateBtn.classList.add('text-primary-600', 'dark:text-primary-400');
|
| 382 |
+
sortAlphaBtn.classList.remove('text-primary-600', 'dark:text-primary-400');
|
| 383 |
+
sortAlphaBtn.classList.add('text-gray-500', 'dark:text-gray-400');
|
| 384 |
+
} else {
|
| 385 |
+
sortAlphaBtn.classList.remove('text-gray-500', 'dark:text-gray-400');
|
| 386 |
+
sortAlphaBtn.classList.add('text-primary-600', 'dark:text-primary-400');
|
| 387 |
+
sortDateBtn.classList.remove('text-primary-600', 'dark:text-primary-400');
|
| 388 |
+
sortDateBtn.classList.add('text-gray-500', 'dark:text-gray-400');
|
| 389 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 390 |
}
|
| 391 |
|
| 392 |
+
function updateMobileSortButtons() {
|
| 393 |
+
if (sortByDate) {
|
| 394 |
+
mobileSortDateBtn.classList.remove('text-gray-500', 'dark:text-gray-400');
|
| 395 |
+
mobileSortDateBtn.classList.add('text-primary-600', 'dark:text-primary-400');
|
| 396 |
+
mobileSortAlphaBtn.classList.remove('text-primary-600', 'dark:text-primary-400');
|
| 397 |
+
mobileSortAlphaBtn.classList.add('text-gray-500', 'dark:text-gray-400');
|
| 398 |
+
} else {
|
| 399 |
+
mobileSortAlphaBtn.classList.remove('text-gray-500', 'dark:text-gray-400');
|
| 400 |
+
mobileSortAlphaBtn.classList.add('text-primary-600', 'dark:text-primary-400');
|
| 401 |
+
mobileSortDateBtn.classList.remove('text-primary-600', 'dark:text-primary-400');
|
| 402 |
+
mobileSortDateBtn.classList.add('text-gray-500', 'dark:text-gray-400');
|
| 403 |
+
}
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
function showMobileMenu() {
|
| 407 |
+
mobileMenu.classList.remove('hidden');
|
| 408 |
+
mobileMenuOverlay.classList.remove('hidden');
|
| 409 |
+
setTimeout(() => {
|
| 410 |
+
mobileMenu.classList.add('shown');
|
| 411 |
+
}, 10);
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
function hideMobileMenu() {
|
| 415 |
+
mobileMenu.classList.remove('shown');
|
| 416 |
+
setTimeout(() => {
|
| 417 |
+
mobileMenu.classList.add('hidden');
|
| 418 |
+
mobileMenuOverlay.classList.add('hidden');
|
| 419 |
+
}, 300);
|
| 420 |
}
|
| 421 |
|
| 422 |
function createNewNote() {
|
|
|
|
| 431 |
notes.unshift(newNote);
|
| 432 |
saveNotes();
|
| 433 |
renderNoteList();
|
| 434 |
+
renderMobileNoteList();
|
| 435 |
openNote(newNote.id);
|
| 436 |
|
| 437 |
// Focus on title field
|
|
|
|
| 446 |
}
|
| 447 |
|
| 448 |
function renderNoteList() {
|
| 449 |
+
let filteredNotes = getFilteredNotes();
|
| 450 |
+
|
| 451 |
+
// Render
|
| 452 |
+
if (filteredNotes.length === 0) {
|
| 453 |
+
noteList.innerHTML = `
|
| 454 |
+
<div class="p-4 text-center text-gray-500 dark:text-gray-400">
|
| 455 |
+
${searchNotes.value ? 'No notes found matching your search.' : 'No notes yet. Create your first note!'}
|
| 456 |
+
</div>
|
| 457 |
+
`;
|
| 458 |
+
return;
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
noteList.innerHTML = filteredNotes.map(note => createNoteCardHTML(note)).join('');
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
function renderMobileNoteList() {
|
| 465 |
+
let filteredNotes = getFilteredNotes(true);
|
| 466 |
+
|
| 467 |
+
// Render
|
| 468 |
+
if (filteredNotes.length === 0) {
|
| 469 |
+
mobileNoteList.innerHTML = `
|
| 470 |
+
<div class="p-4 text-center text-gray-500 dark:text-gray-400">
|
| 471 |
+
${mobileSearchNotes.value ? 'No notes found matching your search.' : 'No notes yet. Create your first note!'}
|
| 472 |
+
</div>
|
| 473 |
+
`;
|
| 474 |
+
return;
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
mobileNoteList.innerHTML = filteredNotes.map(note => createNoteCardHTML(note, true)).join('');
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
function getFilteredNotes(forMobile = false) {
|
| 481 |
let filteredNotes = [...notes];
|
| 482 |
|
| 483 |
// Filter by search
|
| 484 |
+
const searchTerm = forMobile ? mobileSearchNotes.value.toLowerCase() : searchNotes.value.toLowerCase();
|
| 485 |
if (searchTerm) {
|
| 486 |
filteredNotes = filteredNotes.filter(note =>
|
| 487 |
note.title.toLowerCase().includes(searchTerm) ||
|
|
|
|
| 496 |
filteredNotes.sort((a, b) => a.title.localeCompare(b.title));
|
| 497 |
}
|
| 498 |
|
| 499 |
+
return filteredNotes;
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
function createNoteCardHTML(note, forMobile = false) {
|
| 503 |
+
const isActive = currentNoteId === note.id;
|
| 504 |
+
const onClick = forMobile ? `openNote('${note.id}'); hideMobileMenu();` : `openNote('${note.id}')`;
|
|
|
|
|
|
|
|
|
|
| 505 |
|
| 506 |
+
return `
|
| 507 |
+
<div class="note-card cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 transition ${isActive ? 'bg-primary-50 dark:bg-gray-700' : ''}"
|
| 508 |
+
data-id="${note.id}" onclick="${onClick}">
|
| 509 |
<div class="p-4">
|
| 510 |
+
<h3 class="font-medium truncate ${isActive ? 'text-primary-600 dark:text-primary-400' : 'text-gray-800 dark:text-gray-200'}">${note.title || 'Untitled Note'}</h3>
|
| 511 |
+
<p class="text-sm ${isActive ? 'text-primary-500 dark:text-primary-300' : 'text-gray-500 dark:text-gray-400'} truncate mt-1">${note.content.substring(0, 100)}${note.content.length > 100 ? '...' : ''}</p>
|
| 512 |
+
<div class="flex justify-between items-center mt-2 text-xs ${isActive ? 'text-primary-400 dark:text-primary-300' : 'text-gray-400 dark:text-gray-500'}">
|
| 513 |
<span>${formatDate(note.updatedAt)}</span>
|
| 514 |
<span>${countWords(note.content)} words</span>
|
| 515 |
</div>
|
| 516 |
</div>
|
| 517 |
</div>
|
| 518 |
+
`;
|
| 519 |
}
|
| 520 |
|
| 521 |
function openNote(id) {
|
|
|
|
| 530 |
updateWordCount();
|
| 531 |
lastSaved.textContent = `Last saved: ${formatDate(note.updatedAt)}`;
|
| 532 |
|
| 533 |
+
// Highlight active note in lists
|
| 534 |
+
highlightActiveNote();
|
| 535 |
+
|
| 536 |
+
// Switch to write tab
|
| 537 |
+
showWritePane();
|
| 538 |
+
}
|
| 539 |
+
|
| 540 |
+
function highlightActiveNote() {
|
| 541 |
document.querySelectorAll('.note-card').forEach(card => {
|
| 542 |
+
if (card.dataset.id === currentNoteId) {
|
| 543 |
+
card.classList.add('bg-primary-50', 'dark:bg-gray-700');
|
| 544 |
+
card.querySelector('h3').classList.add('text-primary-600', 'dark:text-primary-400');
|
| 545 |
+
card.querySelector('p').classList.add('text-primary-500', 'dark:text-primary-300');
|
| 546 |
+
card.querySelector('div').classList.add('text-primary-400', 'dark:text-primary-300');
|
| 547 |
} else {
|
| 548 |
+
card.classList.remove('bg-primary-50', 'dark:bg-gray-700');
|
| 549 |
+
card.querySelector('h3').classList.remove('text-primary-600', 'dark:text-primary-400');
|
| 550 |
+
card.querySelector('p').classList.remove('text-primary-500', 'dark:text-primary-300');
|
| 551 |
+
card.querySelector('div').classList.remove('text-primary-400', 'dark:text-primary-300');
|
| 552 |
}
|
| 553 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 554 |
}
|
| 555 |
|
| 556 |
function saveCurrentNote() {
|
|
|
|
| 568 |
|
| 569 |
saveNotes();
|
| 570 |
renderNoteList();
|
| 571 |
+
renderMobileNoteList();
|
| 572 |
lastSaved.textContent = `Last saved: ${formatDate(new Date().toISOString())}`;
|
| 573 |
}
|
| 574 |
|
|
|
|
| 579 |
notes = notes.filter(note => note.id !== currentNoteId);
|
| 580 |
saveNotes();
|
| 581 |
renderNoteList();
|
| 582 |
+
renderMobileNoteList();
|
| 583 |
|
| 584 |
// Reset editor
|
| 585 |
currentNoteId = null;
|
|
|
|
| 609 |
renderNoteList();
|
| 610 |
}
|
| 611 |
|
| 612 |
+
function filterMobileNotes() {
|
| 613 |
+
renderMobileNoteList();
|
| 614 |
+
}
|
| 615 |
+
|
| 616 |
function updateWordCount() {
|
| 617 |
const text = noteContent.value;
|
| 618 |
wordCount.textContent = `${countWords(text)} words`;
|
|
|
|
| 637 |
return date.toLocaleDateString([], { year: 'numeric', month: 'short', day: 'numeric' });
|
| 638 |
}
|
| 639 |
|
| 640 |
+
function showWritePane() {
|
| 641 |
+
writePane.classList.remove('hidden');
|
| 642 |
+
previewPane.classList.add('hidden');
|
| 643 |
+
writeTab.classList.add('border-primary-600', 'text-primary-600', 'dark:text-primary-400');
|
| 644 |
+
writeTab.classList.remove('text-gray-500', 'dark:text-gray-400');
|
| 645 |
+
previewTab.classList.remove('border-primary-600', 'text-primary-600', 'dark:text-primary-400');
|
| 646 |
+
previewTab.classList.add('text-gray-500', 'dark:text-gray-400');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 647 |
}
|
| 648 |
|
| 649 |
+
function showPreviewPane() {
|
| 650 |
+
writePane.classList.add('hidden');
|
| 651 |
+
previewPane.classList.remove('hidden');
|
| 652 |
+
previewTab.classList.add('border-primary-600', 'text-primary-600', 'dark:text-primary-400');
|
| 653 |
+
previewTab.classList.remove('text-gray-500', 'dark:text-gray-400');
|
| 654 |
+
writeTab.classList.remove('border-primary-600', 'text-primary-600', 'dark:text-primary-400');
|
| 655 |
+
writeTab.classList.add('text-gray-500', 'dark:text-gray-
|
| 656 |
</html>
|
prompts.txt
CHANGED
|
@@ -1 +1,2 @@
|
|
| 1 |
-
Bana Obsidian Note benzeri modern ve ayrıca gelişmiş, responsive tasarıma sahip olan bir uygulama oluştur. Başta hiçbir not vb. bulunmasın ve biz kaydedelim. Eklediğin tüm özellikler yapmacık olmasın ve hepsi çalışsın.
|
|
|
|
|
|
| 1 |
+
Bana Obsidian Note benzeri modern ve ayrıca gelişmiş, responsive tasarıma sahip olan bir uygulama oluştur. Başta hiçbir not vb. bulunmasın ve biz kaydedelim. Eklediğin tüm özellikler yapmacık olmasın ve hepsi çalışsın.
|
| 2 |
+
Uygulama mobile tam olarak uyumlu değil ve çok kötü bir görünümü var. Örnek olarak temayı değiştirme, notlarım kısmı ve uygulama içi renk uyumsuzluğu bunlardan sadece birkaçı. Bunları düzeltmeni ve daha iyi bir yapı haline getirmeni rica ediyorum.
|