Skip to content

Instantly share code, notes, and snippets.

@abalter
Created August 12, 2024 21:56
Show Gist options
  • Save abalter/f488567a66948ec5a4a6b69bd5d3b5d9 to your computer and use it in GitHub Desktop.
Save abalter/f488567a66948ec5a4a6b69bd5d3b5d9 to your computer and use it in GitHub Desktop.
<!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