96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import { StrictMode } from 'react'
|
|
import { createRoot } from 'react-dom/client'
|
|
import { AuthProvider } from './context/AuthContext'
|
|
import './index.css'
|
|
import App from './App.tsx'
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
refetchOnWindowFocus: false,
|
|
retry: 1,
|
|
staleTime: 5 * 60 * 1000, // 5 minutes - data stays fresh longer
|
|
gcTime: 10 * 60 * 1000, // 10 minutes - keep in memory longer
|
|
},
|
|
},
|
|
})
|
|
|
|
|
|
createRoot(document.getElementById('root')!).render(
|
|
<StrictMode>
|
|
<QueryClientProvider client={queryClient}>
|
|
<AuthProvider>
|
|
<App />
|
|
</AuthProvider>
|
|
</QueryClientProvider>
|
|
</StrictMode>,
|
|
)
|
|
|
|
// Lightweight scroll-reveal setup for elements with `.section` or `[data-reveal]`.
|
|
// Respects prefers-reduced-motion and observes dynamically added nodes.
|
|
function setupReveal() {
|
|
const w = window as unknown as { __revealSetupDone?: boolean }
|
|
if (w.__revealSetupDone) return
|
|
w.__revealSetupDone = true
|
|
|
|
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
const selector = '.section, [data-reveal]'
|
|
|
|
// If reduced motion is preferred, mark everything visible and skip observers
|
|
if (prefersReduced) {
|
|
document.querySelectorAll(selector).forEach((el) => el.classList.add('reveal-visible'))
|
|
return
|
|
}
|
|
|
|
const seen = new WeakSet<Element>()
|
|
const io = new IntersectionObserver(
|
|
(entries) => {
|
|
for (const entry of entries) {
|
|
if (entry.isIntersecting) {
|
|
entry.target.classList.add('reveal-visible')
|
|
io.unobserve(entry.target)
|
|
}
|
|
}
|
|
},
|
|
{ threshold: 0.12, rootMargin: '0px 0px -10% 0px' },
|
|
)
|
|
|
|
const observeExisting = () => {
|
|
document.querySelectorAll(selector).forEach((el) => {
|
|
if (!seen.has(el)) {
|
|
seen.add(el)
|
|
io.observe(el)
|
|
}
|
|
})
|
|
}
|
|
|
|
// Observe current DOM
|
|
observeExisting()
|
|
|
|
// Observe future DOM mutations (e.g., route changes render new sections)
|
|
const mo = new MutationObserver((mutations) => {
|
|
let needsScan = false
|
|
for (const m of mutations) {
|
|
if (m.type === 'childList' && (m.addedNodes?.length ?? 0) > 0) {
|
|
needsScan = true
|
|
}
|
|
if (needsScan) break
|
|
}
|
|
if (needsScan) observeExisting()
|
|
})
|
|
mo.observe(document.documentElement, { childList: true, subtree: true })
|
|
|
|
// Cleanup on HMR disposal (Vite dev) to avoid duplicate observers
|
|
if (import.meta && import.meta.hot) {
|
|
import.meta.hot.dispose(() => {
|
|
io.disconnect()
|
|
mo.disconnect()
|
|
w.__revealSetupDone = false
|
|
})
|
|
}
|
|
}
|
|
|
|
// Initialize after first render tick
|
|
queueMicrotask(setupReveal)
|