almost there for function

This commit is contained in:
Michael Freno
2025-12-18 01:18:38 -05:00
parent 1142d6f126
commit a19ad0cb36
5 changed files with 184 additions and 19 deletions

View File

@@ -3,9 +3,11 @@ import { useBars } from "~/context/bars";
import { onMount, createEffect } from "solid-js";
export function LeftBar() {
const { setLeftBarSize, leftBarVisible } = useBars();
const { setLeftBarSize, leftBarVisible, setLeftBarVisible } = useBars();
let ref: HTMLDivElement | undefined;
let actualWidth = 0;
let touchStartX = 0;
let touchStartY = 0;
onMount(() => {
if (ref) {
@@ -25,7 +27,72 @@ export function LeftBar() {
});
resizeObserver.observe(ref);
return () => resizeObserver.disconnect();
// Swipe-to-dismiss gesture on sidebar itself (mobile only)
const handleTouchStart = (e: TouchEvent) => {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
};
const handleTouchEnd = (e: TouchEvent) => {
const isMobile = window.innerWidth < 768;
if (!isMobile) return; // Only allow dismiss on mobile
const touchEndX = e.changedTouches[0].clientX;
const touchEndY = e.changedTouches[0].clientY;
const deltaX = touchEndX - touchStartX;
const deltaY = touchEndY - touchStartY;
// Only trigger if horizontal swipe is dominant
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Swipe left to dismiss (at least 50px)
if (deltaX < -50 && leftBarVisible()) {
setLeftBarVisible(false);
}
}
};
// Focus trap for accessibility on mobile
const handleKeyDown = (e: KeyboardEvent) => {
const isMobile = window.innerWidth < 768;
if (!isMobile || !leftBarVisible()) return;
if (e.key === 'Tab') {
const focusableElements = ref?.querySelectorAll(
'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
);
if (!focusableElements || focusableElements.length === 0) return;
const firstElement = focusableElements[0] as HTMLElement;
const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
if (e.shiftKey) {
// Shift+Tab - going backwards
if (document.activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
}
} else {
// Tab - going forwards
if (document.activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
}
}
}
};
ref.addEventListener('touchstart', handleTouchStart, { passive: true });
ref.addEventListener('touchend', handleTouchEnd, { passive: true });
ref.addEventListener('keydown', handleKeyDown);
return () => {
resizeObserver.disconnect();
ref?.removeEventListener('touchstart', handleTouchStart);
ref?.removeEventListener('touchend', handleTouchEnd);
ref?.removeEventListener('keydown', handleKeyDown);
};
}
});
@@ -34,6 +101,22 @@ export function LeftBar() {
setLeftBarSize(leftBarVisible() ? actualWidth : 0);
});
// Auto-focus first element when sidebar opens on mobile
createEffect(() => {
const isMobile = window.innerWidth < 768;
if (leftBarVisible() && isMobile && ref) {
const firstFocusable = ref.querySelector(
'a[href], button:not([disabled]), input:not([disabled])'
) as HTMLElement;
if (firstFocusable) {
// Small delay to ensure animation has started
setTimeout(() => firstFocusable.focus(), 100);
}
}
});
return (
<nav
ref={ref}
@@ -113,7 +196,9 @@ export function RightBar() {
});
resizeObserver.observe(ref);
return () => resizeObserver.disconnect();
return () => {
resizeObserver.disconnect();
};
}
});