Created
August 12, 2024 21:56
-
-
Save abalter/f488567a66948ec5a4a6b69bd5d3b5d9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Notes Application</title> | |
<style> | |
.note { | |
display: none; | |
margin: 20px 0; | |
padding: 10px; | |
border: 1px solid #ccc; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Notes Application</h1> | |
<!-- Search Form --> | |
<form id="search-form"> | |
<label for="search">Search:</label> | |
<input type="text" id="search" name="search" placeholder="Search notes..."> | |
<button type="submit">Search</button> | |
<button type="button" id="clear-button">Clear</button> | |
</form> | |
<!-- New Note Button --> | |
<button id="new-note-button">New Note</button> | |
<!-- Notes Container --> | |
<div id="notes-container"> | |
<!-- Existing Notes can be placed here --> | |
<div class="note" data-id="travel-notes" data-tags="travel, Europe" data-title="Travel notes" data-relates-to="" data-depends-on="" data-content="We went to Italy and France." data-created="2024-08-12T21:10:20.832Z" data-modified="2024-08-12T21:10:47.157Z" style="display: none;"></div> | |
<div class="note" data-id="garden-ideas" data-tags="household, garden" data-title="Garden ideas" data-relates-to="" data-depends-on="Seeds" data-content="Plant lettuce." data-created="2024-08-12T21:10:06.591Z" data-modified="2024-08-12T21:31:20.150Z" style="display: none;"></div> | |
<div class="note" data-id="supplies-needed" data-tags="household, furniture" data-title="Supplies needed" data-relates-to="Furniture needed" data-depends-on="" data-created="2024-08-12T21:09:19.737Z" data-modified="2024-08-12T21:09:57.272Z" style="display: none;" data-content="Get shims for bookcase. Get sliders for chair."></div> | |
<div class="note" data-id="furniture-needed" data-tags="household, furniture" data-title="Furniture needed" data-relates-to="" data-depends-on="Supplies needed" data-created="2024-08-12T21:08:45.796Z" data-modified="2024-08-12T21:10:05.021Z" style="display: none;" data-content="Bookcase for the living room. Chair for the dining room."></div> | |
</div> | |
<!-- Note Template --> | |
<template id="note-template"> | |
<form class="note-form"> | |
<label for="title">Title:</label> | |
<input type="text" name="title" class="note-title" required> | |
<label for="content">Content:</label> | |
<textarea name="content" class="note-content" rows="4"></textarea> | |
<label for="tags">Tags:</label> | |
<input type="text" name="tags" class="note-tags" list="tags-datalist"> | |
<label for="relates-to">Relates To:</label> | |
<input type="text" name="relates-to" class="note-relates-to" list="titles-datalist"> | |
<label for="depends-on">Depends On:</label> | |
<input type="text" name="depends-on" class="note-depends-on" list="titles-datalist"> | |
<button type="button" class="save-note-button">Save</button> | |
</form> | |
</template> | |
<datalist id="tags-datalist"></datalist> | |
<datalist id="titles-datalist"></datalist> | |
<script> | |
const notesContainer = document.getElementById('notes-container'); | |
const noteTemplate = document.getElementById('note-template').content; | |
const newNoteButton = document.getElementById('new-note-button'); | |
const searchForm = document.getElementById('search-form'); | |
const searchInput = document.getElementById('search'); | |
const clearButton = document.getElementById('clear-button'); | |
let tagsList = []; | |
let titlesList = []; | |
function updateAutocomplete() { | |
const tagsDatalist = document.getElementById('tags-datalist'); | |
tagsDatalist.innerHTML = ''; | |
tagsList.forEach(tag => { | |
const option = document.createElement('option'); | |
option.value = tag; | |
tagsDatalist.appendChild(option); | |
}); | |
const titlesDatalist = document.getElementById('titles-datalist'); | |
titlesDatalist.innerHTML = ''; | |
titlesList.forEach(title => { | |
const option = document.createElement('option'); | |
option.value = title; | |
titlesDatalist.appendChild(option); | |
}); | |
} | |
function updateLists() { | |
tagsList = [...new Set([...document.querySelectorAll('.note')].flatMap(note => note.dataset.tags.split(',').map(tag => tag.trim())))]; | |
titlesList = [...document.querySelectorAll('.note')].map(note => note.dataset.title); | |
updateAutocomplete(); | |
} | |
function loadExistingNotes() { | |
const notes = document.querySelectorAll('.note'); | |
notes.forEach(note => { | |
note.style.display = 'none'; // Ensure notes are hidden initially | |
}); | |
} | |
function populateForm(note, data = {}) { | |
const form = noteTemplate.cloneNode(true).querySelector('.note-form'); | |
const titleInput = form.querySelector('.note-title'); | |
const contentInput = form.querySelector('.note-content'); | |
const tagsInput = form.querySelector('.note-tags'); | |
const relatesToInput = form.querySelector('.note-relates-to'); | |
const dependsOnInput = form.querySelector('.note-depends-on'); | |
titleInput.value = data.title || ''; | |
contentInput.value = data.content || ''; | |
tagsInput.value = data.tags || ''; | |
relatesToInput.value = data.relatesTo || ''; | |
dependsOnInput.value = data.dependsOn || ''; | |
form.querySelector('.save-note-button').addEventListener('click', () => saveNote(note, form)); | |
note.innerHTML = ''; // Clear the note before inserting the form | |
note.appendChild(form); | |
note.style.display = 'block'; | |
} | |
function createNoteElement() { | |
const note = document.createElement('div'); | |
note.classList.add('note'); | |
notesContainer.insertBefore(note, notesContainer.firstChild); | |
populateForm(note); // Populate with empty form for new notes | |
updateLists(); | |
} | |
function saveNote(note, form) { | |
const title = form.querySelector('.note-title').value.trim(); | |
const content = form.querySelector('.note-content').value.trim(); | |
const tags = form.querySelector('.note-tags').value.trim(); | |
const relatesTo = form.querySelector('.note-relates-to').value.trim(); | |
const dependsOn = form.querySelector('.note-depends-on').value.trim(); | |
if (titlesList.includes(title) && note.dataset.id !== title.toLowerCase().replace(/\s/g, '-')) { | |
alert('Title must be unique!'); | |
return; | |
} | |
if (relatesTo && !titlesList.includes(relatesTo)) { | |
alert(`Relates_To must match an existing title. '${relatesTo}' does not exist.`); | |
return; | |
} | |
if (dependsOn && !titlesList.includes(dependsOn)) { | |
alert(`Depends_On must match an existing title. '${dependsOn}' does not exist.`); | |
return; | |
} | |
note.dataset.id = title.toLowerCase().replace(/\s/g, '-'); | |
note.dataset.title = title; | |
note.dataset.tags = tags; | |
note.dataset.relatesTo = relatesTo; | |
note.dataset.dependsOn = dependsOn; | |
note.dataset.modified = new Date().toISOString(); | |
note.dataset.content = content; // Store the content in the data-content attribute | |
// Re-populate the form with updated data | |
populateForm(note, { title, content, tags, relatesTo, dependsOn }); | |
updateLists(); | |
} | |
newNoteButton.addEventListener('click', createNoteElement); | |
clearButton.addEventListener('click', () => { | |
const notes = document.querySelectorAll('.note'); | |
notes.forEach(note => note.style.display = 'none'); | |
}); | |
searchForm.addEventListener('submit', (event) => { | |
event.preventDefault(); | |
const searchTerm = searchInput.value.toLowerCase(); | |
const notes = document.querySelectorAll('.note'); | |
notes.forEach(note => { | |
const tags = note.dataset.tags.toLowerCase(); | |
const title = note.dataset.title.toLowerCase(); | |
const relatesTo = note.dataset.relatesTo.toLowerCase(); | |
const dependsOn = note.dataset.dependsOn.toLowerCase(); | |
const content = note.dataset.content.toLowerCase(); | |
if (tags.includes(searchTerm) || title.includes(searchTerm) || relatesTo.includes(searchTerm) || dependsOn.includes(searchTerm) || content.includes(searchTerm)) { | |
populateForm(note, { | |
id: note.dataset.id, | |
title: note.dataset.title, | |
tags: note.dataset.tags, | |
relatesTo: note.dataset.relatesTo, | |
dependsOn: note.dataset.dependsOn, | |
content: note.dataset.content // Use the data-content attribute for content | |
}); | |
} else { | |
note.style.display = 'none'; | |
} | |
}); | |
}); | |
updateLists(); | |
loadExistingNotes(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment