fix(home): remove black flash between tab switches
All checks were successful
Deploy / deploy (push) Successful in 2m40s

- AnimatePresence mode=wait keeps the DOM empty while the outgoing tab
  finishes its exit transition (200ms) before mounting the incoming
  tab. On touch devices this shows as a brief black frame — reported
  as экран остается черным.
- Switch to mode=sync: outgoing fades out while incoming fades in,
  no gap. initial=false suppresses the enter animation on first render.
- Drop the y: 12 → -8 slide (cheap jank on hydration), keep just
  opacity. Duration 200ms → 150ms for snappier feel.
This commit is contained in:
Cosmo
2026-04-23 09:22:55 +00:00
parent 8d32e7ebb0
commit dc5c9b3673

View File

@@ -960,9 +960,9 @@ function SettingsTab({ city, onCityChange, onLogout, theme, onThemeChange }: { c
// ————— Tab animation variants ————— // ————— Tab animation variants —————
const tabVariants = { const tabVariants = {
enter: { opacity: 0, y: 12 }, enter: { opacity: 0 },
center: { opacity: 1, y: 0 }, center: { opacity: 1 },
exit: { opacity: 0, y: -8 }, exit: { opacity: 0 },
} }
// ————— Main ————— // ————— Main —————
@@ -1125,15 +1125,15 @@ function HomePageInner() {
<main style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden', minWidth: 0, position: 'relative', zIndex: 1 }}> <main style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden', minWidth: 0, position: 'relative', zIndex: 1 }}>
<TopBar sensors={sensors} haConnected={haConnected} /> <TopBar sensors={sensors} haConnected={haConnected} />
<AnimatePresence mode="wait"> <AnimatePresence mode="sync" initial={false}>
{tab === 'home' && ( {tab === 'home' && (
<motion.div key="home" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.2 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}> <motion.div key="home" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
<HomeTab weather={weather} sensors={sensors} /> <HomeTab weather={weather} sensors={sensors} />
</motion.div> </motion.div>
)} )}
{tab === 'devices' && ( {tab === 'devices' && (
<motion.div key="devices" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.2 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}> <motion.div key="devices" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
<RoomTabs rooms={ROOMS} active={activeRoom} onChange={setActiveRoom} /> <RoomTabs rooms={ROOMS} active={activeRoom} onChange={setActiveRoom} />
<div style={{ flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch' as any, padding: '16px 24px 28px' }}> <div style={{ flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch' as any, padding: '16px 24px 28px' }}>
{devicesInRoom.length === 0 ? ( {devicesInRoom.length === 0 ? (
@@ -1153,19 +1153,19 @@ function HomePageInner() {
)} )}
{tab === 'calendar' && ( {tab === 'calendar' && (
<motion.div key="calendar" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.2 }} style={{ flex: 1, display: 'flex', overflow: 'hidden' }}> <motion.div key="calendar" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
<CalendarTab /> <CalendarTab />
</motion.div> </motion.div>
)} )}
{tab === 'notes' && ( {tab === 'notes' && (
<motion.div key="notes" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.2 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}> <motion.div key="notes" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
<NotesTab /> <NotesTab />
</motion.div> </motion.div>
)} )}
{tab === 'settings' && ( {tab === 'settings' && (
<motion.div key="settings" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.2 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}> <motion.div key="settings" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
<SettingsTab city={city} onCityChange={handleCityChange} onLogout={handleLogout} theme={theme} onThemeChange={setTheme} /> <SettingsTab city={city} onCityChange={handleCityChange} onLogout={handleLogout} theme={theme} onThemeChange={setTheme} />
</motion.div> </motion.div>
)} )}