You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
6.1 KiB
145 lines
6.1 KiB
{{define "content"}} |
|
<article class="ebooks-page"> |
|
<header class="page-header"> |
|
<h1>E-Books</h1> |
|
<p class="page-summary">Top-level publications (index events) from Nostr. These are publications that are not contained in any higher-level index event.</p> |
|
</header> |
|
|
|
<!-- Mobile E-Books Dropdown --> |
|
{{if .EBooks}} |
|
{{template "mobile-dropdown" (dict "Id" "mobile-ebooks-selector" "Items" .EBooks "Profiles" $.Profiles "Type" "ebook")}} |
|
{{end}} |
|
|
|
<div class="ebooks-container"> |
|
<table id="ebooks-table" class="ebooks-table" aria-label="E-Books listing"> |
|
<thead> |
|
<tr> |
|
<th data-sort="title" class="sortable">Title <span class="sort-indicator">↕</span></th> |
|
<th data-sort="author" class="sortable">Author <span class="sort-indicator">↕</span></th> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
{{range .EBooks}} |
|
<tr> |
|
<td> |
|
<strong>{{.Title}}</strong> |
|
{{if .Summary}}<br><small class="text-muted">{{.Summary}}</small>{{end}} |
|
<div style="margin-top: 0.75rem;"> |
|
<a href="https://alexandria.gitcitadel.eu/publication/naddr/{{.Naddr}}" target="_blank" rel="noopener noreferrer" class="btn btn-sm"><span class="icon-inline">{{icon "external-link"}}</span> View on Alexandria</a> |
|
</div> |
|
</td> |
|
<td>{{template "user-badge-simple" (dict "Pubkey" .Author "Profiles" $.Profiles)}}</td> |
|
</tr> |
|
{{else}} |
|
<tr> |
|
<td colspan="2" class="text-center"><span class="icon-inline">{{icon "book-x"}}</span> No e-books found.</td> |
|
</tr> |
|
{{end}} |
|
</tbody> |
|
</table> |
|
</div> |
|
</article> |
|
|
|
<script> |
|
(function() { |
|
const table = document.getElementById('ebooks-table'); |
|
if (!table) return; |
|
|
|
const tbody = table.querySelector('tbody'); |
|
const headers = table.querySelectorAll('th.sortable'); |
|
let currentSort = { column: null, direction: 'asc' }; |
|
|
|
headers.forEach(header => { |
|
header.addEventListener('click', function() { |
|
const column = this.dataset.sort; |
|
const direction = currentSort.column === column && currentSort.direction === 'asc' ? 'desc' : 'asc'; |
|
|
|
// Update sort indicators |
|
headers.forEach(h => { |
|
const indicator = h.querySelector('.sort-indicator'); |
|
if (h === this) { |
|
indicator.textContent = direction === 'asc' ? '↑' : '↓'; |
|
} else { |
|
indicator.textContent = '↕'; |
|
} |
|
}); |
|
|
|
// Sort rows |
|
const rows = Array.from(tbody.querySelectorAll('tr')); |
|
rows.sort((a, b) => { |
|
let aVal, bVal; |
|
const aCell = a.cells[Array.from(headers).indexOf(this)]; |
|
const bCell = b.cells[Array.from(headers).indexOf(this)]; |
|
|
|
if (column === 'title') { |
|
aVal = aCell.querySelector('strong')?.textContent || ''; |
|
bVal = bCell.querySelector('strong')?.textContent || ''; |
|
} else { |
|
aVal = aCell.textContent.trim(); |
|
bVal = bCell.textContent.trim(); |
|
} |
|
|
|
if (direction === 'asc') { |
|
return aVal.localeCompare(bVal); |
|
} else { |
|
return bVal.localeCompare(aVal); |
|
} |
|
}); |
|
|
|
// Re-append sorted rows |
|
rows.forEach(row => tbody.appendChild(row)); |
|
|
|
currentSort = { column, direction }; |
|
}); |
|
|
|
// Add cursor pointer style |
|
header.style.cursor = 'pointer'; |
|
}); |
|
|
|
// Handle mobile e-books custom dropdown |
|
const ebooksToggle = document.getElementById('mobile-ebooks-selector-toggle'); |
|
const ebooksMenu = document.getElementById('mobile-ebooks-selector-menu'); |
|
if (ebooksToggle && ebooksMenu) { |
|
ebooksToggle.addEventListener('click', function(e) { |
|
e.stopPropagation(); |
|
const isExpanded = this.getAttribute('aria-expanded') === 'true'; |
|
this.setAttribute('aria-expanded', !isExpanded); |
|
ebooksMenu.classList.toggle('active'); |
|
}); |
|
|
|
// Close dropdown when clicking outside |
|
document.addEventListener('click', function(e) { |
|
if (!ebooksToggle.contains(e.target) && !ebooksMenu.contains(e.target)) { |
|
ebooksToggle.setAttribute('aria-expanded', 'false'); |
|
ebooksMenu.classList.remove('active'); |
|
} |
|
}); |
|
|
|
// Handle option selection |
|
ebooksMenu.querySelectorAll('li[role="option"]').forEach(function(option) { |
|
option.addEventListener('click', function() { |
|
const naddr = this.dataset.value; |
|
window.open('https://alexandria.gitcitadel.eu/publication/naddr/' + naddr, '_blank', 'noopener,noreferrer'); |
|
|
|
// Update selected state |
|
ebooksMenu.querySelectorAll('li').forEach(li => li.classList.remove('selected')); |
|
this.classList.add('selected'); |
|
this.setAttribute('aria-selected', 'true'); |
|
|
|
// Update toggle button |
|
const avatar = this.querySelector('.mobile-dropdown-avatar, .mobile-dropdown-avatar-placeholder'); |
|
const title = this.querySelector('.mobile-dropdown-title').textContent; |
|
const selected = ebooksToggle.querySelector('.mobile-dropdown-selected'); |
|
selected.innerHTML = avatar.outerHTML + '<span class="mobile-dropdown-title">' + title + '</span>'; |
|
|
|
// Close dropdown |
|
ebooksToggle.setAttribute('aria-expanded', 'false'); |
|
ebooksMenu.classList.remove('active'); |
|
}); |
|
}); |
|
} |
|
})(); |
|
</script> |
|
{{end}} |
|
|
|
{{/* Feed is defined in components.html */}}
|
|
|