Add sleek mobile navigation buttons to dashboard with theme support and synced scroll tracking

This commit is contained in:
Avery Felts 2026-01-28 08:48:17 -07:00
parent 4f44182b59
commit 35b2ec9e8c

View File

@ -1,6 +1,6 @@
'use client';
import { useState, useEffect, useCallback } from 'react';
import { useState, useEffect, useCallback, useRef } from 'react';
import { User } from '@/lib/session';
import {
fetchPreferences,
@ -34,7 +34,7 @@ import { HealthTimelineCard } from './HealthTimelineCard';
import { SavingsTrackerCard } from './SavingsTrackerCard';
import { MoodTracker } from './MoodTracker';
import { Button } from '@/components/ui/button';
import { PlusCircle } from 'lucide-react';
import { PlusCircle, ChevronLeft, ChevronRight } from 'lucide-react';
import { useTheme } from '@/lib/theme-context';
import { getTodayString } from '@/lib/date-utils';
@ -53,8 +53,29 @@ export function Dashboard({ user }: DashboardProps) {
const [newBadge, setNewBadge] = useState<BadgeDefinition | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [refreshKey, setRefreshKey] = useState(0);
const [currentPage, setCurrentPage] = useState(0);
const swipeContainerRef = useRef<HTMLDivElement>(null);
const { theme } = useTheme();
const handleScroll = useCallback(() => {
if (!swipeContainerRef.current) return;
const scrollLeft = swipeContainerRef.current.scrollLeft;
const width = swipeContainerRef.current.offsetWidth;
const page = Math.round(scrollLeft / width);
if (page !== currentPage) {
setCurrentPage(page);
}
}, [currentPage]);
const scrollToPage = (pageIndex: number) => {
if (!swipeContainerRef.current) return;
const width = swipeContainerRef.current.offsetWidth;
swipeContainerRef.current.scrollTo({
left: pageIndex * width,
behavior: 'smooth'
});
};
const loadData = useCallback(async () => {
const [prefs, usage, achvs, savings] = await Promise.all([
fetchPreferences(),
@ -235,10 +256,41 @@ export function Dashboard({ user }: DashboardProps) {
</div>
{/* Dashboard Sections */}
<div className="space-y-10 sm:space-y-12">
<div className="space-y-10 sm:space-y-12 relative">
{/* Mobile Navigation Buttons */}
<div className="sm:hidden">
{currentPage > 0 && (
<button
onClick={() => scrollToPage(currentPage - 1)}
className="fixed left-2 top-1/2 -translate-y-1/2 z-[60] p-3 rounded-full glass border border-white/10 shadow-2xl active:scale-90 transition-all duration-300 group"
style={{
background: theme === 'light' ? 'rgba(255, 255, 255, 0.7)' : 'rgba(0, 0, 0, 0.4)',
backdropFilter: 'blur(12px)'
}}
>
<ChevronLeft className="h-6 w-6 text-primary group-hover:scale-110" />
</button>
)}
{currentPage < 3 && (
<button
onClick={() => scrollToPage(currentPage + 1)}
className="fixed right-2 top-1/2 -translate-y-1/2 z-[60] p-3 rounded-full glass border border-white/10 shadow-2xl active:scale-90 transition-all duration-300 group"
style={{
background: theme === 'light' ? 'rgba(255, 255, 255, 0.7)' : 'rgba(0, 0, 0, 0.4)',
backdropFilter: 'blur(12px)'
}}
>
<ChevronRight className="h-6 w-6 text-primary group-hover:scale-110" />
</button>
)}
</div>
{/* SECTION: Mobile Swipe Ecosystem */}
<div className="swipe-container sm:space-y-12 sm:block">
<div
ref={swipeContainerRef}
onScroll={handleScroll}
className="swipe-container sm:space-y-12 sm:block"
>
{/* SLIDE 1: Mindset (Mood & Personalized Plan) */}
<div className="swipe-item space-y-4">