diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index d197898..9c83626 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -42,6 +42,10 @@ export default withSentryConfig(nextConfig, { project: 'data-peek-app', silent: !process.env.CI, widenClientFileUpload: true, - disableLogger: true, - automaticVercelMonitors: true, + webpack: { + treeshake: { + removeDebugLogging: true, + }, + automaticVercelMonitors: true, + }, }) diff --git a/apps/web/src/components/marketing/feature-data.ts b/apps/web/src/components/marketing/feature-data.ts index 55903d3..5bc3753 100644 --- a/apps/web/src/components/marketing/feature-data.ts +++ b/apps/web/src/components/marketing/feature-data.ts @@ -19,7 +19,6 @@ import { Bookmark, Gauge, Lock, - AppWindow, Activity, Bell, FlaskConical, diff --git a/apps/web/src/components/marketing/features-bento.tsx b/apps/web/src/components/marketing/features-bento.tsx index c83c10f..5a8c75a 100644 --- a/apps/web/src/components/marketing/features-bento.tsx +++ b/apps/web/src/components/marketing/features-bento.tsx @@ -31,7 +31,6 @@ function BentoCard({ feature }: { feature: Feature }) { const size = getBentoSize(feature) const isLarge = size === 'large' const isTall = size === 'tall' - const isWide = size === 'wide' const hasScreenshot = !!feature.screenshot const isLightning = feature.title === 'Lightning Fast' diff --git a/apps/web/src/components/marketing/features-manifest.tsx b/apps/web/src/components/marketing/features-manifest.tsx index 58359b6..06e1b7a 100644 --- a/apps/web/src/components/marketing/features-manifest.tsx +++ b/apps/web/src/components/marketing/features-manifest.tsx @@ -1,7 +1,6 @@ 'use client' import Image from 'next/image' -import Link from 'next/link' import { useState } from 'react' import { AnimateOnScroll } from '@/components/ui/animate-on-scroll' import { DataSubstrate } from './data-substrate' diff --git a/apps/web/src/components/marketing/hero-terminal.tsx b/apps/web/src/components/marketing/hero-terminal.tsx index 957ce7f..b427bd1 100644 --- a/apps/web/src/components/marketing/hero-terminal.tsx +++ b/apps/web/src/components/marketing/hero-terminal.tsx @@ -1,6 +1,6 @@ 'use client' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react' import { useTypewriter } from '@/hooks/use-typewriter' interface Scene { @@ -118,31 +118,55 @@ function CellValue({ value, column }: { value: string; column: string }) { return {value} } +const reducedMotionQuery = '(prefers-reduced-motion: reduce)' + +function subscribeReducedMotion(callback: () => void) { + const mql = window.matchMedia(reducedMotionQuery) + mql.addEventListener('change', callback) + return () => mql.removeEventListener('change', callback) +} + +function getReducedMotion() { + return window.matchMedia(reducedMotionQuery).matches +} + +function getReducedMotionServer() { + return false +} + +function subscribeResize(callback: () => void) { + window.addEventListener('resize', callback) + return () => window.removeEventListener('resize', callback) +} + +function getIsMobile() { + return window.innerWidth < 640 +} + +function getIsMobileServer() { + return false +} + export function HeroTerminal() { const [sceneIndex, setSceneIndex] = useState(0) const [phase, setPhase] = useState<'typing' | 'executing' | 'results' | 'pause'>('typing') const [visibleRows, setVisibleRows] = useState(0) - const [isMobile, setIsMobile] = useState(false) - const prefersReducedMotion = useRef(false) + const isMobile = useSyncExternalStore(subscribeResize, getIsMobile, getIsMobileServer) + const prefersReducedMotion = useSyncExternalStore( + subscribeReducedMotion, + getReducedMotion, + getReducedMotionServer, + ) const sceneTimerRef = useRef>(undefined) const scene = scenes[sceneIndex] - useEffect(() => { - prefersReducedMotion.current = window.matchMedia('(prefers-reduced-motion: reduce)').matches - setIsMobile(window.innerWidth < 640) - - const handleResize = () => setIsMobile(window.innerWidth < 640) - window.addEventListener('resize', handleResize) - return () => window.removeEventListener('resize', handleResize) - }, []) - const queryText = isMobile && scene.mobileQuery ? scene.mobileQuery : scene.query const columns = isMobile && scene.results.mobileColumns ? scene.results.mobileColumns : scene.results.columns const rows = isMobile && scene.results.mobileRows ? scene.results.mobileRows : scene.results.rows const handleTypingComplete = useCallback(() => { - if (prefersReducedMotion.current) { + if (prefersReducedMotion) { setPhase('results') setVisibleRows(rows.length) return @@ -153,7 +177,7 @@ export function HeroTerminal() { setPhase('results') setVisibleRows(0) }, 400) - }, [rows.length]) + }, [rows.length, prefersReducedMotion]) const { text: typedQuery, isComplete: typingDone } = useTypewriter({ text: queryText, @@ -163,10 +187,7 @@ export function HeroTerminal() { useEffect(() => { if (phase !== 'results') return - if (prefersReducedMotion.current) { - setVisibleRows(rows.length) - return - } + if (prefersReducedMotion) return if (visibleRows < rows.length) { const timer = setTimeout(() => { @@ -187,10 +208,10 @@ export function HeroTerminal() { return () => { if (sceneTimerRef.current) clearTimeout(sceneTimerRef.current) } - }, [phase, visibleRows, rows.length]) + }, [phase, visibleRows, rows.length, prefersReducedMotion]) const showCursor = phase === 'typing' && !typingDone - const showResults = phase === 'results' || (prefersReducedMotion.current && typingDone) + const showResults = phase === 'results' || (prefersReducedMotion && typingDone) const executingDots = useMemo(() => { if (phase !== 'executing') return '' @@ -234,7 +255,7 @@ export function HeroTerminal() {
0 || prefersReducedMotion.current ? 1 : 0, + opacity: visibleRows > 0 || prefersReducedMotion ? 1 : 0, transition: 'opacity 0.2s ease', }} > @@ -280,12 +301,12 @@ export function HeroTerminal() { className="mt-3 pt-2 border-t border-[--color-border-subtle] text-[--color-text-muted] text-[10px] sm:text-xs" style={{ opacity: 1, - animation: prefersReducedMotion.current + animation: prefersReducedMotion ? 'none' : 'fade-in-up 0.3s ease forwards', }} > - {rows.length} row{rows.length !== 1 ? 's' : ''} returned · {(Math.random() * 3 + 0.5).toFixed(1)}ms + {rows.length} row{rows.length !== 1 ? 's' : ''} returned · 1.7ms
)} diff --git a/apps/web/src/instrumentation-client.ts b/apps/web/src/instrumentation-client.ts index ee74ef8..f77e411 100644 --- a/apps/web/src/instrumentation-client.ts +++ b/apps/web/src/instrumentation-client.ts @@ -18,3 +18,5 @@ Sentry.init({ }), ], }) + +export const onRouterTransitionStart = Sentry.captureRouterTransitionStart