diff --git a/src/components/Bars.tsx b/src/components/Bars.tsx index 784293d..fc80583 100644 --- a/src/components/Bars.tsx +++ b/src/components/Bars.tsx @@ -1,6 +1,7 @@ import { Typewriter } from "./Typewriter"; import { useBars } from "~/context/bars"; -import { onMount, createEffect } from "solid-js"; +import { onMount, createEffect, createSignal, Show, For } from "solid-js"; +import { api } from "~/lib/api"; export function LeftBar() { const { setLeftBarSize, leftBarVisible, setLeftBarVisible } = useBars(); @@ -9,7 +10,20 @@ export function LeftBar() { let touchStartX = 0; let touchStartY = 0; - onMount(() => { + const [recentPosts, setRecentPosts] = createSignal( + undefined + ); + + onMount(async () => { + // Fetch recent posts only on client side to avoid hydration mismatch + try { + const posts = await api.blog.getRecentPosts.query(); + setRecentPosts(posts as any[]); + } catch (error) { + console.error("Failed to fetch recent posts:", error); + setRecentPosts([]); + } + if (ref) { const updateSize = () => { actualWidth = ref?.offsetWidth || 0; @@ -36,7 +50,7 @@ export function LeftBar() { 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; @@ -54,18 +68,20 @@ export function LeftBar() { // Focus trap for accessibility on mobile const handleKeyDown = (e: KeyboardEvent) => { const isMobile = window.innerWidth < 768; - + if (!isMobile || !leftBarVisible()) return; - if (e.key === 'Tab') { + 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; + const lastElement = focusableElements[ + focusableElements.length - 1 + ] as HTMLElement; if (e.shiftKey) { // Shift+Tab - going backwards @@ -83,15 +99,15 @@ export function LeftBar() { } }; - ref.addEventListener('touchstart', handleTouchStart, { passive: true }); - ref.addEventListener('touchend', handleTouchEnd, { passive: true }); - ref.addEventListener('keydown', handleKeyDown); + 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); + ref?.removeEventListener("touchstart", handleTouchStart); + ref?.removeEventListener("touchend", handleTouchEnd); + ref?.removeEventListener("keydown", handleKeyDown); }; } }); @@ -104,12 +120,12 @@ export function LeftBar() { // 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])' + "a[href], button:not([disabled]), input:not([disabled])" ) as HTMLElement; - + if (firstFocusable) { // Small delay to ensure animation has started setTimeout(() => firstFocusable.focus(), 100); @@ -120,13 +136,13 @@ export function LeftBar() { return (