Skip to content

Commit

Permalink
add useBreakpoints hook for responsive design
Browse files Browse the repository at this point in the history
  • Loading branch information
ligsnf committed Dec 15, 2024
1 parent 1a7130f commit 72bf70a
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 25 deletions.
15 changes: 2 additions & 13 deletions src/components/results/result-form-row.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useEffect, useState } from "react"

import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { useBreakpoints } from '@/hooks/use-breakpoint'
import { resultSchema, type Result } from "@/schemas/result-schema"
import { CORE_GRADES, EXCLUDED_GRADES } from '@/constants/grades'
import { Trash2 } from "lucide-react"
Expand Down Expand Up @@ -32,17 +31,7 @@ interface ResultFormRowProps {
}

export function ResultFormRow({ defaultValues, onDelete, onChange }: ResultFormRowProps) {
const [isMobile, setIsMobile] = useState(false)

useEffect(() => {
const mediaQuery = window.matchMedia('(max-width: 768px)')
setIsMobile(mediaQuery.matches)

const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches)
mediaQuery.addEventListener('change', handler)

return () => mediaQuery.removeEventListener('change', handler)
}, [])
const { isMobile } = useBreakpoints()

const form = useForm<Result>({
resolver: zodResolver(resultSchema),
Expand Down
53 changes: 53 additions & 0 deletions src/hooks/use-breakpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useState, useEffect, useMemo } from 'react'

const defaultBreakpoints = {
'mobile': 0,
'tablet': 768,
'desktop': 1024,
'wide': 1280,
} as const

type BreakpointConfig = typeof defaultBreakpoints
type BreakpointKey = keyof BreakpointConfig

export function useBreakpoints() {
const breakpoints = useMemo(() => {
return Object.entries(defaultBreakpoints)
.sort(([, a], [, b]) => a - b)
.map(([key, value], index) => ({
key: key as BreakpointKey,
minWidth: value,
maxWidth: index < Object.keys(defaultBreakpoints).length - 1
? Object.values(defaultBreakpoints)[index + 1] - 1
: Infinity
}))
}, [])

const [currentBreakpoint, setCurrentBreakpoint] = useState<BreakpointKey>('mobile')

useEffect(() => {
const updateBreakpoint = () => {
const width = window.innerWidth
const match = breakpoints.find(
bp => width >= bp.minWidth && width <= bp.maxWidth
)
if (match) {
setCurrentBreakpoint(match.key)
}
}

// Initial check
updateBreakpoint()

window.addEventListener('resize', updateBreakpoint)
return () => window.removeEventListener('resize', updateBreakpoint)
}, [breakpoints])

return {
breakpoint: currentBreakpoint,
isMobile: currentBreakpoint === 'mobile',
isTablet: currentBreakpoint === 'tablet',
isDesktop: currentBreakpoint === 'desktop',
isWide: currentBreakpoint === 'wide',
}
}
30 changes: 18 additions & 12 deletions src/routes/index.lazy.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createLazyFileRoute } from '@tanstack/react-router'
import { useLocalStorage } from '@/hooks/use-local-storage'
import { useBreakpoints } from '@/hooks/use-breakpoint'
import { STORAGE_KEYS } from '@/constants/storage-keys'
import { useTheme } from "@/components/theme/theme-provider"
import { calculateWAM, calculateGPA, calculateColor } from "@/lib/calculate"
Expand Down Expand Up @@ -60,6 +61,7 @@ function StatCard({ title, subtitle, value, maxValue }: StatCardProps) {
const { theme } = useTheme()
const isDarkMode = theme === "dark"
const color = calculateColor(value, maxValue, isDarkMode)
const { isMobile } = useBreakpoints()

return (
<Card>
Expand All @@ -69,18 +71,22 @@ function StatCard({ title, subtitle, value, maxValue }: StatCardProps) {
</CardTitle>
</CardHeader>
<CardContent>
<RadialChart
className="hidden md:flex font-mono"
value={value}
maxValue={maxValue}
color={color}
/>
<p
className="md:hidden text-3xl sm:text-4xl font-bold font-mono"
style={{ color: color }}
>
{value}
</p>
{!isMobile && (
<RadialChart
className="font-mono"
value={value}
maxValue={maxValue}
color={color}
/>
)}
{isMobile && (
<p
className="text-3xl sm:text-4xl font-bold font-mono"
style={{ color: color }}
>
{value}
</p>
)}
</CardContent>
</Card>
)
Expand Down

0 comments on commit 72bf70a

Please sign in to comment.