Skip to content

Commit 00f714d

Browse files
feat(large): Unify Persistent Footers for Mobile Optimization (#9321)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: arii <342438+arii@users.noreply.github.com>
1 parent c690ada commit 00f714d

19 files changed

Lines changed: 286 additions & 304 deletions

app/client/connect/ConnectView.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import BatteryStdIcon from '@mui/icons-material/BatteryStd'
1111
import BatteryAlertIcon from '@mui/icons-material/BatteryAlert'
1212
import BluetoothDisabledIcon from '@mui/icons-material/BluetoothDisabled'
1313
import HrTile from '../../../components/HrTile'
14-
import BottomNavBar from '../../../components/BottomNavBar'
1514
import WorkoutSummary from './WorkoutSummary'
1615
import UserSettings from './UserSettings'
1716
import { SignalQualityIndicator } from './SignalQualityIndicator'
@@ -118,7 +117,6 @@ export default function ConnectView({
118117
Edge, or Bluefy (on iOS).
119118
</Alert>
120119
<ResetSection onReset={handleFullReset} isResetting={isResetting} />
121-
<BottomNavBar />
122120
</Container>
123121
)
124122
}
@@ -285,7 +283,6 @@ export default function ConnectView({
285283

286284
<ResetSection onReset={handleFullReset} isResetting={isResetting} />
287285
</Container>
288-
<BottomNavBar />
289286
</>
290287
)
291288
}

app/client/mock/page.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import Grid from '@mui/material/Grid'
1010
import TextField from '@mui/material/TextField'
1111
import Typography from '@mui/material/Typography'
1212
import { useCallback, useEffect, useState } from 'react'
13-
import BottomNavBar from '../../../components/BottomNavBar'
1413
import { useWebSocket } from '@/context/WebSocketContext'
1514
import {
1615
HrmInputMessage,
@@ -335,7 +334,6 @@ export default function MockPage() {
335334
</Box>
336335
</Card>
337336
</Container>
338-
<BottomNavBar />
339337
</>
340338
)
341339
}

app/main.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
import { AnimatePresence, motion } from 'framer-motion'
44
import { usePathname } from 'next/navigation'
5-
import BottomNavBar from '@/components/BottomNavBar'
5+
import Box from '@mui/material/Box'
6+
import CombinedFooter from '@/components/CombinedFooter'
67
import ErrorBoundary from '@/components/ErrorBoundary'
78
import ErrorFallback from '@/components/ErrorFallback'
89
import Footer from '@/components/Footer'
@@ -17,6 +18,7 @@ import { UserSettingsProvider } from '@/context/UserSettingsContext'
1718

1819
export default function Main({ children }: { children: React.ReactNode }) {
1920
const pathname = usePathname()
21+
2022
return (
2123
<ErrorBoundary fallback={<ErrorFallback />}>
2224
<ErrorProvider>
@@ -26,27 +28,34 @@ export default function Main({ children }: { children: React.ReactNode }) {
2628
<UserSettingsProvider>
2729
<TimerSoundProvider>
2830
<AnimatePresence mode="wait">
29-
<motion.main
31+
<Box
32+
component={motion.main}
3033
key={pathname}
3134
variants={pageVariants}
3235
initial="initial"
3336
animate="in"
3437
exit="out"
3538
data-testid="main-content-layout"
3639
role="main"
40+
sx={{
41+
pb: 'var(--footer-height, 56px)',
42+
minHeight: '100vh',
43+
display: 'flex',
44+
flexDirection: 'column',
45+
}}
3746
>
38-
{children}
39-
</motion.main>
47+
<Box sx={{ flex: 1 }}>{children}</Box>
48+
<Footer />
49+
</Box>
4050
</AnimatePresence>
51+
<CombinedFooter />
4152
</TimerSoundProvider>
4253
</UserSettingsProvider>
4354
</Providers>
4455
</NotificationProvider>
4556
<LoadingIndicator />
4657
</LoadingProvider>
4758
</ErrorProvider>
48-
<Footer />
49-
<BottomNavBar />
5059
</ErrorBoundary>
5160
)
5261
}

components/BottomNavBar.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,8 @@ export default function BottomNavBar() {
5858
showLabels
5959
sx={{
6060
width: '100%',
61-
position: 'fixed',
62-
bottom: 0,
63-
left: 0,
64-
right: 0,
61+
position: 'static',
6562
zIndex: 1000,
66-
boxShadow: '0px -2px 4px rgba(0, 0, 0, 0.1)',
6763
}}
6864
>
6965
{NAV_ITEMS.map((item, index) => (

components/CombinedFooter.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use client'
2+
3+
import Paper from '@mui/material/Paper'
4+
import Divider from '@mui/material/Divider'
5+
import BottomNavBar from './BottomNavBar'
6+
import { useEffect } from 'react'
7+
import dynamic from 'next/dynamic'
8+
import { useCombinedFooterState } from '@/hooks/useCombinedFooterState'
9+
10+
const SpotifyDisplay = dynamic(() => import('./SpotifyDisplay'), { ssr: false })
11+
12+
export default function CombinedFooter() {
13+
const { showSpotifyBar, footerHeight } = useCombinedFooterState()
14+
15+
useEffect(() => {
16+
document.documentElement.style.setProperty(
17+
'--footer-height',
18+
`${footerHeight}px`
19+
)
20+
return () => {
21+
document.documentElement.style.removeProperty('--footer-height')
22+
}
23+
}, [footerHeight])
24+
25+
return (
26+
<Paper
27+
component="footer"
28+
elevation={10}
29+
data-testid="combined-footer"
30+
role="contentinfo"
31+
sx={{
32+
position: 'fixed',
33+
bottom: 0,
34+
left: 0,
35+
right: 0,
36+
zIndex: 1100,
37+
borderRadius: 0,
38+
display: 'flex',
39+
flexDirection: 'column',
40+
height: footerHeight,
41+
transition: 'height 0.3s ease-in-out',
42+
overflow: 'hidden',
43+
borderTop: '1px solid',
44+
borderColor: 'divider',
45+
}}
46+
>
47+
{showSpotifyBar && (
48+
<>
49+
<SpotifyDisplay />
50+
<Divider sx={{ opacity: 0.1 }} />
51+
</>
52+
)}
53+
<BottomNavBar />
54+
</Paper>
55+
)
56+
}

components/DashboardClient.tsx

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,6 @@ import HrmConnectionPanel from '@/components/HrmConnectionPanel'
1111
import TimerDisplay from '@/components/TimerDisplay'
1212
import { useAudio } from '@/hooks/useAudio'
1313

14-
// Dynamically import SpotifyDisplay with SSR disabled.
15-
const SpotifyDisplay = dynamic(() => import('@/components/SpotifyDisplay'), {
16-
ssr: false,
17-
loading: () => (
18-
<Box
19-
sx={{
20-
position: 'fixed',
21-
bottom: 56,
22-
left: 0,
23-
right: 0,
24-
zIndex: 1100,
25-
width: '100%',
26-
minHeight: '64px',
27-
}}
28-
>
29-
<DashboardSectionLoadingSkeleton height="64px" />
30-
</Box>
31-
),
32-
})
33-
3414
const TestErrorTrigger = dynamic(() => import('./TestErrorTrigger'), {
3515
ssr: false,
3616
})
@@ -104,9 +84,7 @@ const DashboardClient = ({
10484
}}
10585
>
10686
<Box sx={mainGridStyles}>
107-
<Box sx={{ height: '100%' }}>
108-
<TimerDisplay />
109-
</Box>
87+
<TimerDisplay />
11088
<HrmConnectionPanel />
11189
</Box>
11290
<Box sx={{ width: '100%', mt: 2 }}>
@@ -133,8 +111,6 @@ const DashboardClient = ({
133111
)}
134112
</Box>
135113
</Container>
136-
137-
<SpotifyDisplay />
138114
</Box>
139115
)
140116
}

components/HrmConnectionPanel.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ const HrmConnectionPanel = () => {
2727
display: 'flex',
2828
flexWrap: 'wrap',
2929
gap: 2,
30-
height: '100%',
3130
}}
3231
>
3332
{isLoading || tileData.length === 0 ? (
@@ -39,7 +38,7 @@ const HrmConnectionPanel = () => {
3938
justifyContent: 'center',
4039
alignItems: 'center',
4140
width: { xs: '100%', sm: 'calc(50% - 8px)' },
42-
height: '100%', // Ensure the container fills the grid cell
41+
minHeight: 300,
4342
gap: 2,
4443
p: 2,
4544
border: 1,

0 commit comments

Comments
 (0)