I do love my keyboard

This commit is contained in:
2026-07-18 16:11:06 +02:00
parent 9ad6eaefec
commit 3ff1edf8bf
2 changed files with 73 additions and 9 deletions

View File

@@ -4072,6 +4072,7 @@ div.posts>a:not(.notif-item)::before {
} }
div.posts>a:not(.notif-item):hover, div.posts>a:not(.notif-item):hover,
div.posts>a:not(.notif-item):focus-visible,
div.posts>a:not(.notif-item).touch-active { div.posts>a:not(.notif-item).touch-active {
box-shadow: 0 0 0 1px var(--white); box-shadow: 0 0 0 1px var(--white);
} }
@@ -4094,6 +4095,7 @@ div.posts>a:not(.notif-item)::after {
} }
div.posts>a:not(.notif-item):hover::after, div.posts>a:not(.notif-item):hover::after,
div.posts>a:not(.notif-item):focus-visible::after,
div.posts>a:not(.notif-item).touch-active::after { div.posts>a:not(.notif-item).touch-active::after {
visibility: visible; visibility: visible;
} }
@@ -10974,7 +10976,8 @@ div.posts>a.thumb.has-notif {
border: 1px solid var(--accent); border: 1px solid var(--accent);
} }
div.posts>a.thumb.has-notif:hover { div.posts>a.thumb.has-notif:hover,
div.posts>a.thumb.has-notif:focus-visible {
box-shadow: inset 0 0 0 1000px rgba(255, 0, 0, 0.4), 0 0 0 2px var(--accent) !important; box-shadow: inset 0 0 0 1000px rgba(255, 0, 0, 0.4), 0 0 0 2px var(--accent) !important;
} }
@@ -10988,7 +10991,8 @@ div.posts>a.thumb.has-notif::after {
z-index: 10 !important; z-index: 10 !important;
} }
div.posts>a.thumb.has-notif:hover::after { div.posts>a.thumb.has-notif:hover::after,
div.posts>a.thumb.has-notif:focus-visible::after {
visibility: visible !important; visibility: visible !important;
} }

View File

@@ -9388,22 +9388,24 @@ document.addEventListener('DOMContentLoaded', () => {
}; };
window.startHoverPreview = startPreview; window.startHoverPreview = startPreview;
document.addEventListener('mouseover', (e) => { const handleEnter = (e) => {
const thumb = e.target.closest('.thumb'); const thumb = e.target.closest('.thumb');
// If we are hovering a thumb, and it's NOT the active one
if (thumb && thumb !== activeThumb) { if (thumb && thumb !== activeThumb) {
startPreview(thumb, 150); startPreview(thumb, 150);
} }
}); };
document.addEventListener('mouseover', handleEnter);
document.addEventListener('focusin', handleEnter);
document.addEventListener('mouseout', (e) => { const handleLeave = (e) => {
const thumb = e.target.closest('.thumb'); const thumb = e.target.closest('.thumb');
if (thumb) { if (thumb) {
if (e.relatedTarget && thumb.contains(e.relatedTarget)) return; if (e.type === 'mouseout' && e.relatedTarget && thumb.contains(e.relatedTarget)) return;
clearPreview(); clearPreview();
} }
}); };
document.addEventListener('mouseout', handleLeave);
document.addEventListener('focusout', handleLeave);
// Touch handling to support "tap to activate" behavior // Touch handling to support "tap to activate" behavior
// 1. First tap: Activate (visuals + preview) AND prevent navigation // 1. First tap: Activate (visuals + preview) AND prevent navigation
@@ -11281,3 +11283,61 @@ document.addEventListener('click', (e) => {
} }
}, true); }, true);
})(); })();
// --- Grid Keyboard Accessibility ---
document.addEventListener('keydown', (e) => {
const isTab = e.key === 'Tab';
const isArrow = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key);
if (!isTab && !isArrow) return;
const thumbs = Array.from(document.querySelectorAll('.posts .thumb'));
if (thumbs.length === 0) return;
if (isTab && document.activeElement === document.body) {
e.preventDefault();
thumbs[0].focus();
return;
}
const active = document.activeElement;
if (isArrow && active && active.classList.contains('thumb')) {
const currentIndex = thumbs.indexOf(active);
if (currentIndex === -1) return;
let nextIndex = currentIndex;
if (e.key === 'ArrowRight') {
nextIndex = currentIndex + 1;
} else if (e.key === 'ArrowLeft') {
nextIndex = currentIndex - 1;
} else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
const currentRow = thumbs.filter(t => t.offsetTop === active.offsetTop);
const columns = currentRow.length;
let maxCols = columns;
const firstRowTop = thumbs[0].offsetTop;
const firstRow = thumbs.filter(t => t.offsetTop === firstRowTop);
if (firstRow.length > columns) maxCols = firstRow.length;
if (e.key === 'ArrowDown') {
nextIndex = currentIndex + maxCols;
if (nextIndex >= thumbs.length) {
const lastRowTop = thumbs[thumbs.length - 1].offsetTop;
if (active.offsetTop < lastRowTop) {
nextIndex = thumbs.length - 1;
} else {
nextIndex = currentIndex;
}
}
} else {
nextIndex = currentIndex - maxCols;
}
}
if (nextIndex >= 0 && nextIndex < thumbs.length && nextIndex !== currentIndex) {
e.preventDefault();
thumbs[nextIndex].focus();
thumbs[nextIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}
});