Frontend Features and refactor

This commit is contained in:
2026-10-19 15:10:59 -07:00
parent 7a0dbe19ea
commit 317f5bf746
28 changed files with 3915 additions and 530 deletions
+97
View File
@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Saved - KJV API</title>
<link rel="stylesheet" href="/styles/page.css?v=__V__">
<style>
.item { background-color: var(--color-bg-secondary); border: 1px solid var(--color-border);
border-left: 3px solid var(--color-accent-primary); border-radius: var(--border-radius-sm);
padding: var(--space-sm) var(--space-md); margin-bottom: var(--space-sm); }
.item .ref { font-weight: 700; }
.item .text { font-family: var(--font-scripture); margin: 0.25rem 0 0.5rem; color: var(--color-text-primary); }
.item p { margin: 0.25rem 0; }
.item button { min-height: 36px; padding: 0.2rem 0.9rem; font-size: 0.85rem;
background-color: var(--color-bg-tertiary); color: var(--color-text-primary); border: 1px solid var(--color-border); }
.empty { color: var(--color-text-muted); }
.note { font-size: 0.9rem; color: var(--color-text-muted); }
</style>
</head>
<body>
<header>
<a href="/">Home</a> <a href="/find">Quick Search</a> <a href="/plan">Reading Plan</a>
<a href="/random?view=rich">Random Verse</a> <a href="/votd?view=rich">Verse of the Day</a>
</header>
<h2>Saved</h2>
<p class="note">Saved in this browser only. Clearing site data or using another device starts fresh.</p>
<h3>Favorite verses</h3>
<div id="fav"></div>
<h3>Definitions</h3>
<div id="defs"></div>
<h3>Cross references</h3>
<div id="xrefs"></div>
<script>
var KEYS = { fav: 'kjv.favorites', defs: 'kjv.definitions', xrefs: 'kjv.crossrefs' };
function load(key) {
try { var v = JSON.parse(localStorage.getItem(key)); return Array.isArray(v) ? v : []; }
catch (e) { return []; }
}
function el(tag, cls, text) {
var n = document.createElement(tag);
if (cls) n.className = cls;
if (text !== undefined) n.textContent = text;
return n;
}
function findUrl(ref) { return '/find?kw=' + encodeURIComponent(ref) + '&view=rich'; }
function render(key, targetId, emptyText, build) {
var target = document.getElementById(targetId);
target.textContent = '';
var list = load(key);
if (!list.length) { target.appendChild(el('p', 'empty', emptyText)); return; }
list.forEach(function (item, i) {
var box = el('div', 'item');
build(box, item);
var remove = el('button', '', 'Remove');
remove.type = 'button';
remove.addEventListener('click', function () {
var current = load(key);
current.splice(i, 1);
try { localStorage.setItem(key, JSON.stringify(current)); } catch (e) {}
render(key, targetId, emptyText, build);
});
box.appendChild(remove);
target.appendChild(box);
});
}
function refLink(ref) {
var a = el('a', 'ref', ref);
a.href = findUrl(ref);
return a;
}
function draw() {
render(KEYS.fav, 'fav', 'No favorites yet. Tap a verse and choose Favorite.', function (box, f) {
box.appendChild(refLink(f.ref));
box.appendChild(el('div', 'text', f.text));
});
render(KEYS.defs, 'defs', 'No saved definitions. Tap a verse, choose Define words, and save one.', function (box, d) {
box.appendChild(el('strong', '', d.word));
if (d.ref) { box.appendChild(document.createTextNode(' from ')); box.appendChild(refLink(d.ref)); }
(d.defs || []).forEach(function (t) { box.appendChild(el('p', '', t)); });
});
render(KEYS.xrefs, 'xrefs', 'No saved cross references. Tap a verse, choose Cross references, and save one.', function (box, x) {
box.appendChild(refLink(x.ref));
box.appendChild(el('span', 'note', ' (cross reference of ' + x.from + ')'));
box.appendChild(el('div', 'text', x.text));
});
}
draw();
</script>
</body>
</html>