Files
kennethreitzandClaude Fable 5 15b469726a Tokenize family tree and Strong's index pages; clearer current-nav state
- base.html: the sidebar's current item is now a deep-green filled pill
  with cream text (accent-fill/on-accent) instead of a faint tinted box
- family_tree.html: all hardcoded grays/whites/greens mapped to shared
  tokens; gender spines use the muted genre inks; messianic-line cards
  get a gold-soft wash; gilt pill badge; removed 24 dark-mode rules
- strongs_index.html: homepage-style search bar with green SEARCH,
  gilt Hebrew/Greek chips replacing brown/royal-blue fills, bronze
  Strong's numbers, elevated result/browse cards, unified small-caps
  section headings; removed dark-mode rules
- family_tree_interactive.html: tokenized controls/buttons/nodes, gold
  selection for the messianic line, warm inputs; removed 13 dark rules

Dark mode on all three pages now derives entirely from the tokens.
All 976 tests pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 23:33:24 -04:00

432 lines
12 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Strong's Concordance - KJV Study{% endblock %}
{% block description %}Search Strong's Exhaustive Concordance. Look up Hebrew and Greek word definitions, etymology, and KJV usage.{% endblock %}
{% block head %}
<style>
.search-form {
max-width: 600px;
margin: 2rem 0;
}
.search-input-group {
display: flex;
gap: 0;
border: 1px solid var(--border-color-darker);
border-radius: 8px;
overflow: hidden;
background: var(--bg-elevated);
box-shadow: var(--shadow-soft);
transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
.search-input-group:focus-within {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-soft), var(--shadow-soft);
}
.search-input {
flex: 1;
min-width: 0;
padding: 0.8rem 1rem;
font-size: 1.05rem;
font-family: inherit;
border: none;
background: transparent;
color: var(--text-color);
}
.search-input::placeholder {
color: var(--text-tertiary);
font-style: italic;
}
.search-input:focus {
outline: none;
}
.search-btn {
padding: 0.75rem 1.5rem;
font-size: 0.82rem;
font-family: inherit;
text-transform: uppercase;
letter-spacing: 0.14em;
background: var(--accent-fill);
color: var(--on-accent);
border: none;
cursor: pointer;
font-weight: 600;
transition: background 0.2s ease;
}
.search-btn:hover {
background: var(--accent-fill-hover);
}
.results-count {
color: var(--text-secondary);
margin-bottom: 1rem;
}
.results-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 0.75rem;
}
.result-item {
display: block;
padding: 1rem;
background: var(--bg-elevated);
border: 1px solid var(--border-color-dark);
border-radius: 6px;
text-decoration: none;
color: inherit;
transition: border-color 0.2s, box-shadow 0.2s;
cursor: pointer;
}
.result-item:hover {
border-color: var(--accent);
box-shadow: var(--shadow-soft);
}
.result-header {
display: flex;
align-items: baseline;
gap: 0.75rem;
margin-bottom: 0.5rem;
}
.result-strongs {
font-size: 0.85rem;
letter-spacing: 0.08em;
color: var(--bronze);
font-weight: 600;
}
.result-word {
font-size: 1.4rem;
}
.result-word.hebrew {
direction: rtl;
font-family: "SBL Hebrew", "Ezra SIL", "Times New Roman", serif;
}
.result-word.greek {
font-family: "SBL Greek", "Gentium Plus", "Times New Roman", serif;
}
.result-lang {
font-size: 0.75rem;
padding: 0.15rem 0.4rem;
border-radius: 3px;
text-transform: uppercase;
letter-spacing: 0.03em;
font-weight: 600;
}
.result-lang.hebrew,
.result-lang.greek {
background: var(--gold-soft);
border: 1px solid var(--border-color-dark);
color: var(--bronze);
border-radius: 999px;
}
.result-definition {
color: var(--text-color);
margin-bottom: 0.25rem;
}
.result-kjv {
font-size: 0.9rem;
color: var(--text-secondary);
}
.quick-lookup {
margin-top: 2rem;
padding-top: 2rem;
border-top: 1px solid var(--border-color);
}
.quick-lookup h3,
.browse-section h3 {
position: relative;
font-size: 0.85rem;
font-weight: 600;
font-style: normal;
text-transform: uppercase;
letter-spacing: 0.18em;
color: var(--text-secondary) !important;
margin: 0 0 1rem;
padding-bottom: 0.6rem;
border-bottom: 1px solid var(--border-color);
}
.quick-lookup h3::after,
.browse-section h3::after {
content: '';
position: absolute;
left: 0;
bottom: -1px;
width: 2.75rem;
height: 1px;
background: var(--gold);
}
.quick-links {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.quick-link {
padding: 0.35rem 0.7rem;
font-size: 0.85rem;
background: var(--bg-elevated);
border: 1px solid var(--border-color-dark);
border-radius: 6px;
text-decoration: none;
color: var(--text-color);
transition: all 0.15s;
}
.quick-link:hover {
border-color: var(--accent);
color: var(--accent-strong);
background: var(--accent-softer);
}
/* Browse language cards */
.browse-section {
margin: 2rem 0;
}
.browse-section h3 {
font-size: 1rem;
margin-bottom: 1rem;
}
.browse-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.browse-card {
background: var(--bg-elevated);
border: 1px solid var(--border-color-dark);
border-radius: 8px;
padding: 1.5rem;
text-decoration: none;
color: var(--text-color);
transition: all 0.2s;
}
.browse-card:hover {
border-color: var(--accent);
transform: translateY(-2px);
box-shadow: var(--shadow-soft);
}
.browse-card .lang-title {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 0.25rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.browse-card .lang-badge {
font-size: 0.65rem;
padding: 0.2rem 0.5rem;
border-radius: 3px;
text-transform: uppercase;
letter-spacing: 0.03em;
font-weight: 600;
}
.browse-card .lang-badge.hebrew,
.browse-card .lang-badge.greek {
background: var(--gold-soft);
border: 1px solid var(--border-color-dark);
color: var(--bronze);
border-radius: 999px;
}
.browse-card .lang-count {
font-size: 0.9rem;
color: var(--text-secondary);
margin-bottom: 0.5rem;
}
.browse-card .lang-sample {
font-size: 1.5rem;
color: var(--text-secondary);
}
.browse-card .lang-sample.hebrew {
direction: rtl;
font-family: "SBL Hebrew", "Ezra SIL", "Times New Roman", serif;
}
.browse-card .lang-sample.greek {
font-family: "SBL Greek", "Gentium Plus", "Times New Roman", serif;
}
</style>
{% endblock %}
{% block content %}
<h1>Strong's Concordance</h1>
<p class="subtitle">Hebrew & Greek Word Definitions</p>
<form class="search-form" action="/strongs" method="get">
<div class="search-input-group">
<input type="text" name="q" class="search-input" placeholder="Search by number (G26, H430) or definition (love, grace)" value="{{ query }}" {% if not query %}autofocus{% endif %}>
<button type="submit" class="search-btn">Search</button>
</div>
</form>
{% if query %}
<p class="results-count">{{ results|length }} result{% if results|length != 1 %}s{% endif %} for "{{ query }}"</p>
{% if results %}
<div class="results-list">
{% for result in results %}
<a href="/strongs/{{ result.strongs }}" class="result-item">
<div class="result-header">
<span class="result-strongs">{{ result.strongs }}</span>
<span class="result-word {% if result.language == 'Hebrew' %}hebrew{% else %}greek{% endif %}">{{ result.word }}</span>
<span class="result-lang {% if result.language == 'Hebrew' %}hebrew{% else %}greek{% endif %}">{{ result.language }}</span>
</div>
<p class="result-definition">{{ result.definition }}</p>
{% if result.kjv_usage %}
<p class="result-kjv"><strong>KJV:</strong> {{ result.kjv_usage }}</p>
{% endif %}
</a>
{% endfor %}
</div>
{% else %}
<p>No results found for "{{ query }}".</p>
{% endif %}
{% else %}
<div class="browse-section">
<h3>Browse All Entries</h3>
<div class="browse-cards">
<a href="/strongs/hebrew" class="browse-card">
<div class="lang-title">
Hebrew
<span class="lang-badge hebrew">OT</span>
</div>
<div class="lang-count">8,674 entries (H1–H8674)</div>
<div class="lang-sample hebrew">אָב אֱלֹהִים שָׁלוֹם</div>
</a>
<a href="/strongs/greek" class="browse-card">
<div class="lang-title">
Greek
<span class="lang-badge greek">NT</span>
</div>
<div class="lang-count">5,523 entries (G1–G5624)</div>
<div class="lang-sample greek">ἀγάπη πίστις χάρις</div>
</a>
</div>
</div>
<div class="quick-lookup">
<h3>Quick Lookup - Common Words</h3>
<div class="quick-links">
<a href="/strongs/G26" class="quick-link">G26 - agape (love)</a>
<a href="/strongs/G4102" class="quick-link">G4102 - pistis (faith)</a>
<a href="/strongs/G5485" class="quick-link">G5485 - charis (grace)</a>
<a href="/strongs/G3056" class="quick-link">G3056 - logos (word)</a>
<a href="/strongs/G2316" class="quick-link">G2316 - theos (God)</a>
<a href="/strongs/G5547" class="quick-link">G5547 - Christos (Christ)</a>
<a href="/strongs/H430" class="quick-link">H430 - Elohim (God)</a>
<a href="/strongs/H3068" class="quick-link">H3068 - YHWH (LORD)</a>
<a href="/strongs/H7965" class="quick-link">H7965 - shalom (peace)</a>
<a href="/strongs/H2617" class="quick-link">H2617 - chesed (mercy)</a>
</div>
</div>
{% endif %}
<script>
(function() {
// For search results page
const resultItems = Array.from(document.querySelectorAll('.result-item'));
// For browse page - cards and quick links
const browseCards = Array.from(document.querySelectorAll('.browse-card'));
const quickLinks = Array.from(document.querySelectorAll('.quick-link'));
const allItems = resultItems.length > 0 ? resultItems : browseCards.concat(quickLinks);
if (allItems.length === 0) return;
let selectedIndex = -1;
function selectItem(index) {
if (selectedIndex >= 0 && selectedIndex < allItems.length) {
allItems[selectedIndex].style.outline = '';
allItems[selectedIndex].style.outlineOffset = '';
allItems[selectedIndex].classList.remove('selected');
}
selectedIndex = Math.max(0, Math.min(index, allItems.length - 1));
allItems[selectedIndex].style.outline = '2px solid var(--accent)';
allItems[selectedIndex].style.outlineOffset = '2px';
allItems[selectedIndex].classList.add('selected');
allItems[selectedIndex].scrollIntoView({ behavior: 'auto', block: 'center' });
}
document.addEventListener('keydown', function(e) {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
if (KJVNav.sidebarActive) return;
if (e.key === 'ArrowDown' || e.key === 'j') {
e.preventDefault();
if (KJVNav.isSelectionOffScreen(allItems, selectedIndex)) {
selectItem(KJVNav.findFirstVisibleIndex(allItems));
} else {
selectItem(selectedIndex < 0 ? 0 : selectedIndex + 1);
}
} else if (e.key === 'ArrowUp' || e.key === 'k') {
e.preventDefault();
if (KJVNav.isSelectionOffScreen(allItems, selectedIndex)) {
selectItem(KJVNav.findFirstVisibleIndex(allItems));
} else if (selectedIndex <= 0) {
selectItem(0);
} else {
selectItem(selectedIndex - 1);
}
} else if (e.key === 'ArrowLeft' || e.key === 'h') {
e.preventDefault();
history.back();
} else if (e.key === 'Enter' && selectedIndex >= 0) {
e.preventDefault();
// All items are now anchors
if (allItems[selectedIndex].href) {
window.location.href = allItems[selectedIndex].href;
}
} else if (e.key === 'Escape') {
e.preventDefault();
if (selectedIndex >= 0 && selectedIndex < allItems.length) {
allItems[selectedIndex].style.outline = '';
allItems[selectedIndex].style.outlineOffset = '';
allItems[selectedIndex].classList.remove('selected');
}
selectedIndex = -1;
}
});
})();
</script>
{% endblock %}