Update html/account-me.ejs
This commit is contained in:
parent
cae7815aa7
commit
4ea335b0dc
@ -304,9 +304,10 @@
|
|||||||
const $ = (s, root=document) => root.querySelector(s);
|
const $ = (s, root=document) => root.querySelector(s);
|
||||||
const $$ = (s, root=document) => Array.from(root.querySelectorAll(s));
|
const $$ = (s, root=document) => Array.from(root.querySelectorAll(s));
|
||||||
|
|
||||||
const nojsSections = $('#nojs-sections');
|
const nojsSections = $('#nojs-sections'); // static, server-rendered fallback
|
||||||
const app = $('#app');
|
const app = $('#app'); // JS-enhanced container
|
||||||
const grid = $('#grid');
|
const grid = $('#grid'); // managed grid
|
||||||
|
|
||||||
const searchInput = $('#search');
|
const searchInput = $('#search');
|
||||||
const clearBtn = $('#clearSearch');
|
const clearBtn = $('#clearSearch');
|
||||||
const countBadge = $('#count');
|
const countBadge = $('#count');
|
||||||
@ -315,47 +316,43 @@
|
|||||||
const revealBtn = $('#revealUID');
|
const revealBtn = $('#revealUID');
|
||||||
const uidMask = $('.uid .mask');
|
const uidMask = $('.uid .mask');
|
||||||
|
|
||||||
// Pull all server-rendered cards (from the no-JS sections)
|
// Grab cards from server-rendered markup (keeps noscript intact if JS bails)
|
||||||
const originalCards = $$('.card', nojsSections).map(card => {
|
const sourceRoot = nojsSections || document;
|
||||||
const name = (card.getAttribute('data-name') || '').toLowerCase();
|
const originalCards = $$('.card', sourceRoot).map(card => {
|
||||||
|
const name = (card.getAttribute('data-name') || '').toLowerCase().trim();
|
||||||
return { name, el: card };
|
return { name, el: card };
|
||||||
});
|
});
|
||||||
|
|
||||||
// If there are no cards, keep the static sections; nothing to enhance.
|
if (originalCards.length === 0) {
|
||||||
if (originalCards.length === 0) return;
|
// Nothing to enhance; keep the server sections visible
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Build managed copies so no-JS fallback remains intact if JS fails later.
|
// Build managed copies (don’t move originals)
|
||||||
const managedCards = originalCards.map(({ name, el }) => {
|
const managedCards = originalCards.map(({name, el})=>{
|
||||||
const clone = el.cloneNode(true);
|
const clone = el.cloneNode(true);
|
||||||
$$('.pill', clone).forEach(a => a.classList.add('focus-ring')); // keyboard focus ring
|
$$('.pill', clone).forEach(a => a.classList.add('focus-ring')); // ensure focus styling
|
||||||
return { name, el: clone };
|
return { name, el: clone };
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hide static sections; show enhanced app
|
// Hide static sections; show enhanced UI
|
||||||
nojsSections.style.display = 'none';
|
if (nojsSections) nojsSections.style.display = 'none';
|
||||||
app.style.display = '';
|
app.style.display = '';
|
||||||
|
|
||||||
// Initial render
|
// Events
|
||||||
rerender();
|
|
||||||
|
|
||||||
// Search wiring
|
|
||||||
searchInput.addEventListener('input', onFilter);
|
searchInput.addEventListener('input', onFilter);
|
||||||
clearBtn.addEventListener('click', () => {
|
clearBtn.addEventListener('click', () => { searchInput.value=''; onFilter(); searchInput.focus(); });
|
||||||
searchInput.value = '';
|
|
||||||
onFilter();
|
|
||||||
searchInput.focus();
|
|
||||||
});
|
|
||||||
|
|
||||||
// UID reveal/hide toggle (for keyboards/touch)
|
// UID reveal for keyboards/touch (CSS hover still works)
|
||||||
revealBtn.addEventListener('click', () => {
|
revealBtn.addEventListener('click', ()=>{
|
||||||
const pressed = revealBtn.getAttribute('aria-pressed') === 'true';
|
const pressed = revealBtn.getAttribute('aria-pressed') === 'true';
|
||||||
revealBtn.setAttribute('aria-pressed', String(!pressed));
|
revealBtn.setAttribute('aria-pressed', String(!pressed));
|
||||||
uidMask.style.filter = pressed ? 'blur(7px)' : 'blur(0)';
|
uidMask.style.filter = pressed ? 'blur(7px)' : 'blur(0)';
|
||||||
revealBtn.textContent = pressed ? 'Reveal' : 'Hide';
|
revealBtn.textContent = pressed ? 'Reveal' : 'Hide';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Confirm on unsubscribe
|
// Confirm before unsubscribing (event delegation)
|
||||||
app.addEventListener('click', (e) => {
|
app.addEventListener('click', (e)=>{
|
||||||
const a = e.target.closest('a[data-unsub]');
|
const a = e.target.closest('a[data-unsub]');
|
||||||
if (!a) return;
|
if (!a) return;
|
||||||
const card = e.target.closest('.card');
|
const card = e.target.closest('.card');
|
||||||
@ -363,22 +360,26 @@
|
|||||||
if (!confirm('Unsubscribe from "' + name + '"?')) e.preventDefault();
|
if (!confirm('Unsubscribe from "' + name + '"?')) e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Warm image cache for browsers without native lazy-loading
|
// Warm image cache if native lazy-loading not supported
|
||||||
if (!('loading' in HTMLImageElement.prototype)) {
|
if (!('loading' in HTMLImageElement.prototype)) {
|
||||||
managedCards.forEach(({ el }) => {
|
managedCards.forEach(({el})=>{
|
||||||
const img = el.querySelector('img');
|
const img = el.querySelector('img');
|
||||||
if (img) { const i = new Image(); i.src = img.src; }
|
if (img) { const i = new Image(); i.src = img.src; }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- State & functions -----
|
// ---------------- Logic ----------------
|
||||||
let currentTerm = '';
|
let currentTerm = '';
|
||||||
|
|
||||||
function onFilter(){
|
function onFilter(){
|
||||||
currentTerm = (searchInput.value || '').trim().toLowerCase();
|
currentTerm = (searchInput.value || '').toLowerCase().trim();
|
||||||
rerender();
|
rerender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortAZ(arr){
|
||||||
|
return arr.slice().sort((a,b)=> a.name.localeCompare(b.name,'en',{sensitivity:'base'}));
|
||||||
|
}
|
||||||
|
|
||||||
function filterCards(arr){
|
function filterCards(arr){
|
||||||
if (!currentTerm) return arr;
|
if (!currentTerm) return arr;
|
||||||
return arr.filter(c => c.name.includes(currentTerm));
|
return arr.filter(c => c.name.includes(currentTerm));
|
||||||
@ -386,25 +387,34 @@
|
|||||||
|
|
||||||
function rerender(){
|
function rerender(){
|
||||||
const filtered = filterCards(managedCards);
|
const filtered = filterCards(managedCards);
|
||||||
updateCount(filtered.length);
|
const sorted = sortAZ(filtered);
|
||||||
|
updateCount(sorted.length);
|
||||||
|
|
||||||
grid.innerHTML = '';
|
if (sorted.length === 0){
|
||||||
if (filtered.length === 0) {
|
|
||||||
emptyState.hidden = false;
|
emptyState.hidden = false;
|
||||||
|
grid.innerHTML = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emptyState.hidden = true;
|
emptyState.hidden = true;
|
||||||
|
renderGrid(sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderGrid(items){
|
||||||
|
grid.innerHTML = '';
|
||||||
const frag = document.createDocumentFragment();
|
const frag = document.createDocumentFragment();
|
||||||
filtered.forEach(({ el }) => frag.appendChild(el.cloneNode(true)));
|
items.forEach(({el}) => frag.appendChild(el.cloneNode(true)));
|
||||||
grid.appendChild(frag);
|
grid.appendChild(frag);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCount(n){
|
function updateCount(n){
|
||||||
countBadge.textContent = n + (n === 1 ? ' subscription' : ' subscriptions');
|
countBadge.textContent = n + (n === 1 ? ' subscription' : ' subscriptions');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initial paint (sorted A→Z by default)
|
||||||
|
rerender();
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user