diff --git a/kjvstudy_org/templates/family_tree.html b/kjvstudy_org/templates/family_tree.html
index 24cd30e..f03d42a 100644
--- a/kjvstudy_org/templates/family_tree.html
+++ b/kjvstudy_org/templates/family_tree.html
@@ -197,6 +197,208 @@
display: none;
}
+ .comprehensive-person-view {
+ background: var(--card-background);
+ border-radius: 12px;
+ padding: 2rem;
+ border: 1px solid var(--border-color);
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
+ margin-top: 2rem;
+ display: block;
+ }
+
+ .person-header {
+ display: flex;
+ align-items: center;
+ gap: 1.5rem;
+ margin-bottom: 2rem;
+ padding-bottom: 1.5rem;
+ border-bottom: 2px solid var(--border-color);
+ }
+
+ .person-avatar {
+ width: 100px;
+ height: 100px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 2.5rem;
+ color: white;
+ flex-shrink: 0;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+ border: 3px solid rgba(255, 255, 255, 0.2);
+ }
+
+ .person-avatar.male {
+ background: linear-gradient(135deg, #74b9ff, #0984e3);
+ }
+
+ .person-avatar.female {
+ background: linear-gradient(135deg, #fd79a8, #e84393);
+ }
+
+ .person-basic-info h1 {
+ font-size: 2.2rem;
+ margin: 0 0 0.5rem 0;
+ color: var(--text-color);
+ font-family: 'Crimson Text', serif;
+ }
+
+ .person-basic-info .person-title {
+ font-size: 1.1rem;
+ color: var(--text-muted);
+ margin-bottom: 0.5rem;
+ font-style: italic;
+ }
+
+ .person-basic-info .person-lifespan {
+ font-size: 1rem;
+ color: var(--primary-color);
+ font-weight: 600;
+ }
+
+ .data-sections {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+ }
+
+ .data-section {
+ background: var(--background-color);
+ border-radius: 8px;
+ padding: 1.5rem;
+ border: 1px solid var(--border-color);
+ }
+
+ .data-section h3 {
+ font-size: 1.3rem;
+ margin: 0 0 1rem 0;
+ color: var(--primary-color);
+ font-family: 'Crimson Text', serif;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding-bottom: 0.5rem;
+ border-bottom: 2px solid var(--border-color);
+ }
+
+ .gedcom-field {
+ margin-bottom: 1rem;
+ padding-bottom: 0.75rem;
+ border-bottom: 1px solid var(--border-color);
+ }
+
+ .gedcom-field:last-child {
+ border-bottom: none;
+ margin-bottom: 0;
+ }
+
+ .field-label {
+ font-weight: 600;
+ color: var(--text-color);
+ font-size: 0.9rem;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ margin-bottom: 0.25rem;
+ }
+
+ .field-value {
+ color: var(--text-muted);
+ line-height: 1.5;
+ }
+
+ .scripture-references {
+ grid-column: 1 / -1;
+ }
+
+ .verse-reference-item {
+ background: var(--card-background);
+ border: 1px solid var(--border-color);
+ border-radius: 6px;
+ padding: 1rem;
+ margin-bottom: 1rem;
+ border-left: 4px solid var(--primary-color);
+ }
+
+ .verse-ref {
+ font-weight: 600;
+ color: var(--primary-color);
+ margin-bottom: 0.5rem;
+ }
+
+ .verse-ref a {
+ color: var(--primary-color);
+ text-decoration: none;
+ }
+
+ .verse-ref a:hover {
+ text-decoration: underline;
+ }
+
+ .verse-text {
+ font-family: 'Crimson Text', serif;
+ font-style: italic;
+ line-height: 1.6;
+ color: var(--text-color);
+ }
+
+ .family-connections {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 1rem;
+ margin-top: 1rem;
+ }
+
+ .connection-card {
+ background: var(--card-background);
+ border: 1px solid var(--border-color);
+ border-radius: 6px;
+ padding: 1rem;
+ text-align: center;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ }
+
+ .connection-card:hover {
+ border-color: var(--primary-color);
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ }
+
+ .connection-card .connection-name {
+ font-weight: 600;
+ color: var(--text-color);
+ margin-bottom: 0.25rem;
+ }
+
+ .connection-card .connection-type {
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ }
+
+ @media (max-width: 768px) {
+ .data-sections {
+ grid-template-columns: 1fr;
+ }
+
+ .person-header {
+ flex-direction: column;
+ text-align: center;
+ }
+
+ .person-basic-info h1 {
+ font-size: 1.8rem;
+ }
+
+ .family-connections {
+ grid-template-columns: 1fr;
+ }
+ }
+
.d3-tree-container {
width: 100%;
height: 600px;
@@ -702,8 +904,8 @@
@@ -928,6 +1178,9 @@
updateD3Tree(person, personId);
}
+ // Update comprehensive person view
+ updateComprehensiveView(person, personId);
+
// Update current person info
document.getElementById('current-name').textContent = person.name;
document.getElementById('current-title').textContent = person.title || 'Biblical Figure';
@@ -955,6 +1208,416 @@
// Update D3 tree view
updateD3Tree(person, personId);
+
+ // Update comprehensive person view
+ updateComprehensiveView(person, personId);
+ }
+
+ function updateComprehensiveView(person, personId) {
+ const compView = document.getElementById('comprehensive-person-view');
+ const avatar = document.getElementById('person-avatar');
+ const name = document.getElementById('comp-person-name');
+ const title = document.getElementById('comp-person-title');
+ const lifespan = document.getElementById('comp-person-lifespan');
+
+ // Ensure the comprehensive view is visible
+ compView.style.display = 'block';
+
+ // Update avatar
+ const gender = determineGender(person);
+ avatar.className = `person-avatar ${gender}`;
+ avatar.textContent = gender === 'female' ? '๐ฉ' : '๐จ';
+
+ // Update basic info
+ name.textContent = person.name || 'Unknown';
+ title.textContent = person.title || 'Biblical Figure';
+
+ let lifespanText = '';
+ if (person.birth_year && person.birth_year !== 'Unknown') {
+ lifespanText = person.birth_year;
+ }
+ if (person.death_year && person.death_year !== 'Unknown') {
+ lifespanText += ` - ${person.death_year}`;
+ }
+ if (person.age_at_death && person.age_at_death !== 'Unknown') {
+ lifespanText += ` (${person.age_at_death})`;
+ }
+ lifespan.textContent = lifespanText || 'Lifespan unknown';
+
+ // Update personal information
+ updatePersonalInfo(person);
+
+ // Update family relationships
+ updateFamilyRelationships(person, personId);
+
+ // Update life events
+ updateLifeEvents(person);
+
+ // Update GEDCOM technical details
+ updateGedcomDetails(person, personId);
+
+ // Update genealogy path
+ updateGenealogyPath(person, personId);
+
+ // Update statistical information
+ updateStatisticalInfo(person, personId);
+
+ // Update scripture references
+ updateScriptureReferences(person);
+ }
+
+ function updatePersonalInfo(person) {
+ const container = document.getElementById('personal-info-fields');
+ container.innerHTML = '';
+
+ const fields = [
+ { label: 'Full Name', value: person.name },
+ { label: 'Gender', value: determineGender(person) },
+ { label: 'Title/Occupation', value: person.title },
+ { label: 'Description', value: person.description },
+ { label: 'Birth Year', value: person.birth_year },
+ { label: 'Death Year', value: person.death_year },
+ { label: 'Age at Death', value: person.age_at_death }
+ ];
+
+ fields.forEach(field => {
+ if (field.value && field.value !== 'Unknown') {
+ const fieldDiv = document.createElement('div');
+ fieldDiv.className = 'gedcom-field';
+ fieldDiv.innerHTML = `
+
${field.label}
+
${field.value}
+ `;
+ container.appendChild(fieldDiv);
+ }
+ });
+
+ if (container.children.length === 0) {
+ container.innerHTML = '
No personal information available
';
+ }
+ }
+
+ function updateFamilyRelationships(person, personId) {
+ const container = document.getElementById('family-relationships');
+ container.innerHTML = '';
+
+ const relationships = [];
+
+ // Parents
+ if (person.parents && person.parents.length > 0) {
+ person.parents.forEach(parentId => {
+ const parent = familyData[parentId];
+ if (parent) {
+ relationships.push({
+ name: parent.name,
+ type: 'Parent',
+ id: parentId
+ });
+ }
+ });
+ }
+
+ // Spouse
+ if (person.spouse) {
+ const spouseId = Object.keys(familyData).find(id => familyData[id].name === person.spouse);
+ if (spouseId) {
+ relationships.push({
+ name: person.spouse,
+ type: 'Spouse',
+ id: spouseId
+ });
+ }
+ }
+
+ // Children
+ if (person.children && person.children.length > 0) {
+ person.children.forEach(childId => {
+ const child = familyData[childId];
+ if (child) {
+ relationships.push({
+ name: child.name,
+ type: 'Child',
+ id: childId
+ });
+ }
+ });
+ }
+
+ if (relationships.length > 0) {
+ const connectionsDiv = document.createElement('div');
+ connectionsDiv.className = 'family-connections';
+
+ relationships.forEach(rel => {
+ const card = document.createElement('div');
+ card.className = 'connection-card';
+ card.onclick = () => selectPerson(rel.id);
+ card.innerHTML = `
+
${rel.name}
+
${rel.type}
+ `;
+ connectionsDiv.appendChild(card);
+ });
+
+ container.appendChild(connectionsDiv);
+ } else {
+ container.innerHTML = '
No family relationships recorded
';
+ }
+ }
+
+ function updateLifeEvents(person) {
+ const container = document.getElementById('life-events');
+ container.innerHTML = '';
+
+ const events = [];
+
+ if (person.birth_year && person.birth_year !== 'Unknown') {
+ events.push({
+ label: 'Birth',
+ value: person.birth_year,
+ icon: '๐'
+ });
+ }
+
+ if (person.death_year && person.death_year !== 'Unknown') {
+ events.push({
+ label: 'Death',
+ value: person.death_year,
+ icon: 'โฐ๏ธ'
+ });
+ }
+
+ if (person.spouse) {
+ events.push({
+ label: 'Marriage',
+ value: `Married to ${person.spouse}`,
+ icon: '๐'
+ });
+ }
+
+ if (person.children && person.children.length > 0) {
+ events.push({
+ label: 'Children',
+ value: `${person.children.length} children`,
+ icon: '๐ถ'
+ });
+ }
+
+ if (events.length > 0) {
+ events.forEach(event => {
+ const eventDiv = document.createElement('div');
+ eventDiv.className = 'gedcom-field';
+ eventDiv.innerHTML = `
+
${event.icon} ${event.label}
+
${event.value}
+ `;
+ container.appendChild(eventDiv);
+ });
+ } else {
+ container.innerHTML = '
No life events recorded
';
+ }
+ }
+
+ function updateGedcomDetails(person, personId) {
+ const container = document.getElementById('gedcom-technical');
+ container.innerHTML = '';
+
+ const details = [
+ { label: 'Person ID', value: personId, icon: '๐' },
+ { label: 'Record Type', value: 'GEDCOM Individual', icon: '๐' },
+ { label: 'Lineage', value: determineLineage(person), icon: '๐ณ' },
+ { label: 'Generation', value: getGenerationInfo(person), icon: '๐' },
+ { label: 'Gender', value: determineGender(person), icon: determineGender(person) === 'female' ? '๐ฉ' : '๐จ' },
+ { label: 'Data Source', value: 'Biblical GEDCOM Database', icon: '๐พ' }
+ ];
+
+ details.forEach(detail => {
+ const detailDiv = document.createElement('div');
+ detailDiv.className = 'gedcom-field';
+ detailDiv.innerHTML = `
+
${detail.icon} ${detail.label}
+
${detail.value}
+ `;
+ container.appendChild(detailDiv);
+ });
+ }
+
+ function updateScriptureReferences(person) {
+ const container = document.getElementById('scripture-references');
+ container.innerHTML = '';
+
+ if (person.verses && person.verses.length > 0) {
+ person.verses.forEach(verse => {
+ const verseDiv = document.createElement('div');
+ verseDiv.className = 'verse-reference-item';
+
+ // Parse reference for linking
+ const refParts = verse.reference.split(' ');
+ let book, chapter, verseLink;
+
+ if (refParts.length >= 2) {
+ if (refParts[0] in ['1', '2'] && refParts.length >= 3) {
+ book = refParts[0] + ' ' + refParts[1];
+ chapter = refParts[2].split(':')[0];
+ } else {
+ book = refParts[0];
+ chapter = refParts[1].split(':')[0];
+ }
+ verseLink = `/book/${book}/chapter/${chapter}`;
+ }
+
+ verseDiv.innerHTML = `
+
+
"${verse.text}"
+ `;
+ container.appendChild(verseDiv);
+ });
+ } else {
+ container.innerHTML = '
No scripture references available
';
+ }
+ }
+
+ function updateGenealogyPath(person, personId) {
+ const container = document.getElementById('genealogy-path');
+ container.innerHTML = '';
+
+ // Build path from Adam to current person
+ const path = buildGenealogyPath(personId);
+
+ if (path.length > 0) {
+ const pathDiv = document.createElement('div');
+ pathDiv.className = 'genealogy-path-display';
+ pathDiv.style.cssText = `
+ padding: 1rem;
+ background: var(--card-background);
+ border-radius: 6px;
+ border: 1px solid var(--border-color);
+ font-family: 'Crimson Text', serif;
+ line-height: 2;
+ `;
+
+ const pathText = path.map((ancestor, index) => {
+ return `
${ancestor.name}`;
+ }).join(' โ ');
+
+ pathDiv.innerHTML = `
+
๐ Lineage from Adam
+
${pathText}
+
+ ${path.length} generations from Adam
+
+ `;
+ container.appendChild(pathDiv);
+ } else {
+ container.innerHTML = '
Genealogy path not available
';
+ }
+ }
+
+ function updateStatisticalInfo(person, personId) {
+ const container = document.getElementById('statistical-info');
+ container.innerHTML = '';
+
+ const stats = [];
+
+ // Count descendants
+ const descendantCount = countDescendants(personId);
+ stats.push({ label: 'Total Descendants', value: descendantCount, icon: '๐ถ' });
+
+ // Count ancestors
+ const ancestorCount = countAncestors(personId);
+ stats.push({ label: 'Known Ancestors', value: ancestorCount, icon: '๐ด' });
+
+ // Siblings count
+ const siblingCount = countSiblings(person);
+ stats.push({ label: 'Siblings', value: siblingCount, icon: '๐ซ' });
+
+ // Children count
+ const childrenCount = person.children ? person.children.length : 0;
+ stats.push({ label: 'Children', value: childrenCount, icon: '๐ถ' });
+
+ stats.forEach(stat => {
+ const statDiv = document.createElement('div');
+ statDiv.className = 'gedcom-field';
+ statDiv.innerHTML = `
+
${stat.icon} ${stat.label}
+
${stat.value}
+ `;
+ container.appendChild(statDiv);
+ });
+ }
+
+ function buildGenealogyPath(personId, visited = new Set()) {
+ if (visited.has(personId)) return [];
+ visited.add(personId);
+
+ const person = familyData[personId];
+ if (!person) return [];
+
+ // If this is Adam, start the path
+ if (person.name.toLowerCase() === 'adam') {
+ return [{ id: personId, name: person.name }];
+ }
+
+ // Try to find path through parents
+ if (person.parents && person.parents.length > 0) {
+ for (const parentId of person.parents) {
+ const parentPath = buildGenealogyPath(parentId, visited);
+ if (parentPath.length > 0) {
+ return [...parentPath, { id: personId, name: person.name }];
+ }
+ }
+ }
+
+ return [];
+ }
+
+ function countDescendants(personId, visited = new Set()) {
+ if (visited.has(personId)) return 0;
+ visited.add(personId);
+
+ const person = familyData[personId];
+ if (!person || !person.children) return 0;
+
+ let count = person.children.length;
+ person.children.forEach(childId => {
+ count += countDescendants(childId, visited);
+ });
+
+ return count;
+ }
+
+ function countAncestors(personId, visited = new Set()) {
+ if (visited.has(personId)) return 0;
+ visited.add(personId);
+
+ const person = familyData[personId];
+ if (!person || !person.parents) return 0;
+
+ let count = person.parents.length;
+ person.parents.forEach(parentId => {
+ count += countAncestors(parentId, visited);
+ });
+
+ return count;
+ }
+
+ function countSiblings(person) {
+ if (!person.parents || person.parents.length === 0) return 0;
+
+ let siblings = new Set();
+ person.parents.forEach(parentId => {
+ const parent = familyData[parentId];
+ if (parent && parent.children) {
+ parent.children.forEach(childId => {
+ if (childId !== person.id) {
+ siblings.add(childId);
+ }
+ });
+ }
+ });
+
+ return siblings.size;
}
function showParents(person) {