static-pages/books/index.html
Naomi Carrigan 00dc40ba47
Some checks failed
Code Analysis / SonarQube (push) Failing after 50s
feat: add books too
2025-03-24 20:07:24 -07:00

117 lines
4.3 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>Naomi's Book Library</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="An interactive explorer for the books Naomi reads." />
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
</head>
<body>
<main>
<h1>Naomi's Book Library</h1>
<section>
<p>An interactive explorer for the books Naomi reads.</p>
<p id="count">Loading library...</p>
</section>
<div style="display: none;">
<span>Search Authors: </span>
<input type="text" id="author" />
</div>
<div style="display: none;">
<span>Search Titles: </span>
<input type="text" id="title" />
</div>
<div style="display: none;">
<button type="button" id="clear">Clear Filters</button>
</div>
<table id="books">
</table>
</main>
</body>
<script>
const authorQuery = document.getElementById('author');
const titleQuery = document.getElementById('title');
const resetButton = document.getElementById('clear');
const bookTable = document.getElementById('books');
const filterBooks = (author, title) => {
let result = [...bookList];
if(author) {
result = result.filter(book => book.author.toLowerCase().includes(author.toLowerCase()));
}
if(title) {
result = result.filter(book => book.title.toLowerCase().includes(title.toLowerCase()));
}
resetButton.parentElement.style.display = author || title ? "block" : "none";
document.getElementById('count').innerText = author || title ? `Filtered to ${result.length} books from ${bookList.length}.` : `Naomi currently has ${bookList.length} books.`;
updateTable(result);
}
const loadBooks = (books) => {
bookList.push(...books);
authorQuery.value = "";
titleQuery.value = "";
authorQuery.parentElement.style.display = "block";
titleQuery.parentElement.style.display = "block";
document.getElementById('count').innerText = `Naomi currently has ${books.length} books.`;
updateTable(books);
}
const updateTable = (books) => {
books = books.sort((a, b) => a.title.localeCompare(b.title));
bookTable.innerHTML = "";
const header = document.createElement('tr');
const authorHeader = document.createElement('th');
authorHeader.innerText = "Author";
const titleHeader = document.createElement('th');
titleHeader.innerText = "Title";
header.appendChild(titleHeader);
header.appendChild(authorHeader);
bookTable.appendChild(header);
books.forEach(book => {
const row = document.createElement('tr');
const author = document.createElement('td');
author.innerText = book.author;
const title = document.createElement('td');
title.innerText = book.title;
row.appendChild(title);
row.appendChild(author);
bookTable.appendChild(row);
});
}
const bookList = [];
fetch("./books.json").then(res => res.json()).then(data => loadBooks(data))
authorQuery?.addEventListener("input", (e) => filterBooks(e.target.value, titleQuery.value));
titleQuery?.addEventListener("input", (e) => filterBooks(authorQuery.value, e.target.value));
resetButton?.addEventListener("click", () => {
authorQuery.value = "";
titleQuery.value = "";
filterBooks("", "");
});
</script>
<style>
table {
width: 100%;
border-collapse: collapse;
}
tr:nth-of-type(even) {
background-color: #db7093dd;
color: #ffefef;
}
input {
background:var(--foreground);
color:var(--background);
border:1px solid white;
border-radius:10px;
padding:.25rem
}
button {
background:var(--foreground);
color:var(--background);
border:1px solid white;
border-radius:10px;
padding:.25rem;
cursor:url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
}
</style>
</html>