-
Notifications
You must be signed in to change notification settings - Fork 1
Splash screen adding #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rabden
wants to merge
33
commits into
main
Choose a base branch
from
splash-screen-adding
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Splash screen adding #172
Changes from 7 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
609da76
feat: add splash screen with animated logo video
rabden e386994
feat: implement premium splash screen with theme-adaptive animated logo
rabden 3af8f2d
chore: add animated-logo-white.mp4 asset
rabden c403114
fix(a11y): add reduced motion support and error handling to splash sc…
github-actions[bot] fe2d1a8
refactor: improve splash screen robustness and interaction behavior
rabden 857af3b
fix(splash-screen): improve robustness and follow codebase guidelines
github-actions[bot] 23a6c3f
Update src/components/splash-screen.tsx
rabden 2664d66
fix(splash-screen): only modify scroll lock when visible
github-actions[bot] 371caa8
refactor: add test-id and refine scroll-lock logic in splash screen
rabden 86659ef
fix(splash-screen): use useSyncExternalStore for hydration-safe reduc…
github-actions[bot] db75dac
refactor: implement hydration-safe reduced motion detection and refin…
rabden 215b610
Merge branch 'main' into splash-screen-adding
BillChirico 9791412
fix: remove duplicate @types/node entries from lockfile
github-actions[bot] 66325be
feat(intro): implement shiny metallic intro section with theme-specif…
rabden 31ee121
Update src/app/globals.css
rabden cd70db7
refactor(intro): refine UX, accessibility, and reliability
rabden 45f57b4
Merge branch 'main' into splash-screen-adding
rabden 915a177
feat(seo): add structured data, breadcrumbs, and fix metadata across …
BillChirico aec1f0b
chore(deps): update dependencies in package.json and pnpm-lock.yaml
BillChirico 178a0b4
refactor(intro): remove video animation phase
rabden bf2d6ae
refactor(intro): shrink text and replace static logo with video
rabden e50f018
fix: add cleanup handlers and fix JSON-LD serialization
github-actions[bot] dd47bc2
refactor(intro): freeze logo video and add spring pop entrance
rabden 14637bd
refactor(intro): remove drop shadows, make text non-interactible, and…
rabden 636934a
fix: address code review issues in intro section and structured data
github-actions[bot] 00a2f1e
refactor(intro): mandatory cinematic intro, SEO fixes, and accessibil…
rabden 3da1d5b
refactor: `IntroSection` now internally handles bot detection to skip…
rabden 41d9d8d
fix: address code review issues in intro section and structured data
github-actions[bot] 4dc6de3
refactor: fix hydration mismatch, improve intro stability, and reorga…
rabden 5cc9661
Update src/components/homepage-client.tsx
rabden 22619c8
fix: resolve syntax error and stabilize handleComplete callback
github-actions[bot] dc46911
Apply suggestion from @coderabbitai[bot]
rabden 151d943
fix: remove duplicate motion.div in splash-screen.tsx
github-actions[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| "use client"; | ||
|
rabden marked this conversation as resolved.
|
||
|
|
||
| import { useState, useEffect, useRef } from "react"; | ||
| import { motion, AnimatePresence } from "framer-motion"; | ||
| import { reportError } from "@/lib/logger"; | ||
| import { cn } from "@/lib/utils"; | ||
|
|
||
| /** | ||
| * Check if the user prefers reduced motion. | ||
| * Returns true during SSR to avoid animation flash. | ||
| */ | ||
| function getPrefersReducedMotion(): boolean { | ||
| if (typeof window === "undefined") return true; | ||
| return window.matchMedia("(prefers-reduced-motion: reduce)").matches; | ||
| } | ||
|
|
||
| export function SplashScreen(): React.ReactElement | null { | ||
| // Initialize state based on reduced motion preference to avoid setState in useEffect | ||
| const [isVisible, setIsVisible] = useState(() => !getPrefersReducedMotion()); | ||
| const [showVideo, setShowVideo] = useState(false); | ||
| const videoRef = useRef<HTMLVideoElement>(null); | ||
|
rabden marked this conversation as resolved.
Outdated
|
||
|
|
||
| // Timer refs to allow precise clearing | ||
| const initialTimerRef = useRef<NodeJS.Timeout | null>(null); | ||
| const dismissTimerRef = useRef<NodeJS.Timeout | null>(null); | ||
| const fallbackTimerRef = useRef<NodeJS.Timeout | null>(null); | ||
| // Store original overflow value | ||
| const originalOverflowRef = useRef<string>(""); | ||
|
|
||
| const dismissSplash = () => { | ||
| setIsVisible(false); | ||
| // Ensure all timers are cleared when dismissing | ||
| if (initialTimerRef.current) clearTimeout(initialTimerRef.current); | ||
| if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current); | ||
| if (fallbackTimerRef.current) clearTimeout(fallbackTimerRef.current); | ||
| }; | ||
|
|
||
| useEffect(() => { | ||
| // If reduced motion is preferred, splash is already hidden via initial state | ||
| if (!isVisible) return; | ||
|
|
||
| // Phase 1: 1.5s delay before video appears | ||
| initialTimerRef.current = setTimeout(() => { | ||
| setShowVideo(true); | ||
|
|
||
| // Robustness: Start a max-duration fallback timer once we intend to show the video. | ||
| // If the video fails to load or the 'ended' event doesn't fire, we still dismiss. | ||
| fallbackTimerRef.current = setTimeout(() => { | ||
| dismissSplash(); | ||
| }, 10000); | ||
| }, 1500); | ||
|
|
||
| return () => { | ||
| if (initialTimerRef.current) clearTimeout(initialTimerRef.current); | ||
| if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current); | ||
| if (fallbackTimerRef.current) clearTimeout(fallbackTimerRef.current); | ||
| }; | ||
| }, [isVisible]); | ||
|
|
||
| useEffect(() => { | ||
| // Prevent scrolling while splash screen is visible | ||
| if (isVisible) { | ||
| // Store original overflow value before modifying | ||
| originalOverflowRef.current = document.body.style.overflow; | ||
| document.body.style.overflow = "hidden"; | ||
| } else { | ||
| // Restore original overflow value | ||
| document.body.style.overflow = originalOverflowRef.current; | ||
| } | ||
|
|
||
| return () => { | ||
| // Restore original overflow on cleanup | ||
| document.body.style.overflow = originalOverflowRef.current; | ||
| }; | ||
| }, [isVisible]); | ||
|
rabden marked this conversation as resolved.
|
||
|
|
||
| const handleVideoEnd = () => { | ||
| // Phase 3: Hold after video ends before fading out | ||
| dismissTimerRef.current = setTimeout(() => { | ||
| dismissSplash(); | ||
| }, 1500); | ||
| }; | ||
|
|
||
| const handleVideoError = () => { | ||
| reportError("SplashScreen video failed to load", new Error("Video load error")); | ||
| dismissSplash(); | ||
| }; | ||
|
rabden marked this conversation as resolved.
|
||
|
|
||
| return ( | ||
| <AnimatePresence> | ||
| {isVisible && ( | ||
| <motion.div | ||
| initial={{ opacity: 1 }} | ||
| exit={{ opacity: 0 }} | ||
| transition={{ duration: 0.8, ease: "easeInOut" }} | ||
| // Block interactions while splash is visible | ||
| className="fixed inset-0 z-[10000] bg-background flex items-center justify-center pointer-events-auto" | ||
| aria-hidden="true" | ||
|
rabden marked this conversation as resolved.
Outdated
|
||
| data-testid="splash-screen" | ||
| > | ||
|
rabden marked this conversation as resolved.
|
||
| <AnimatePresence> | ||
| {showVideo && ( | ||
| <motion.div | ||
| initial={{ opacity: 0, scale: 0.95 }} | ||
| animate={{ opacity: 1, scale: 1 }} | ||
| transition={{ duration: 1, ease: "easeOut" }} | ||
| className="w-full max-w-[500px] px-6" | ||
| > | ||
| <video | ||
| ref={videoRef} | ||
| src="/animated-logo.webm" | ||
|
rabden marked this conversation as resolved.
rabden marked this conversation as resolved.
rabden marked this conversation as resolved.
rabden marked this conversation as resolved.
|
||
| autoPlay | ||
| muted | ||
| playsInline | ||
|
rabden marked this conversation as resolved.
|
||
| onEnded={handleVideoEnd} | ||
| onError={handleVideoError} | ||
| className={cn( | ||
| "w-full h-auto", | ||
| "invert hue-rotate-180 brightness-125 contrast-110 mix-blend-multiply", | ||
| "dark:invert-0 dark:hue-rotate-0 dark:brightness-110 dark:contrast-100 dark:mix-blend-screen" | ||
| )} | ||
| /> | ||
|
rabden marked this conversation as resolved.
|
||
| </motion.div> | ||
| )} | ||
| </AnimatePresence> | ||
| </motion.div> | ||
| )} | ||
| </AnimatePresence> | ||
| ); | ||
|
rabden marked this conversation as resolved.
|
||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.