diff --git a/src/app/components/BuildBanner/index.tsx b/src/app/components/BuildBanner/index.tsx index 1b973c2e50..4ec48a655d 100644 --- a/src/app/components/BuildBanner/index.tsx +++ b/src/app/components/BuildBanner/index.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react' +import { forwardRef, ForwardRefRenderFunction } from 'react' import { useTranslation } from 'react-i18next' import Alert from '@mui/material/Alert' import { styled } from '@mui/material/styles' @@ -22,7 +22,7 @@ const StyledAlert = styled(Alert)(({ theme }) => ({ }, })) -export const BuildBanner: FC = () => { +const BuildBannerCmp: ForwardRefRenderFunction = (_, ref) => { const { t } = useTranslation() if (window.location.origin === deploys.localhost) { @@ -33,7 +33,7 @@ export const BuildBanner: FC = () => { } if (window.location.origin === deploys.staging) { return ( - + {t('banner.buildStaging')} { ) } - return {t('banner.buildPreview')} + return ( + + {t('banner.buildPreview')} + + ) } + +export const BuildBanner = forwardRef(BuildBannerCmp) diff --git a/src/app/components/OfflineBanner/index.tsx b/src/app/components/OfflineBanner/index.tsx index 922072ef6d..bf862bad5d 100644 --- a/src/app/components/OfflineBanner/index.tsx +++ b/src/app/components/OfflineBanner/index.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react' +import { FC, forwardRef, ForwardRefRenderFunction } from 'react' import { useTranslation } from 'react-i18next' import Alert from '@mui/material/Alert' import { styled } from '@mui/material/styles' @@ -22,7 +22,10 @@ const StyledAlert = styled(Alert)(({ theme }) => ({ }, })) -export const NetworkOfflineBanner: FC<{ wantedNetwork?: Network }> = ({ wantedNetwork }) => { +const NetworkOfflineBannerCmp: ForwardRefRenderFunction = ( + { wantedNetwork }, + ref, +) => { const scope = useScopeParam() const { t } = useTranslation() const targetNetwork = wantedNetwork || scope?.network || Network.mainnet @@ -30,11 +33,15 @@ export const NetworkOfflineBanner: FC<{ wantedNetwork?: Network }> = ({ wantedNe const networkNames = getNetworkNames(t) const target = networkNames[targetNetwork] return isNetworkOffline ? ( - {t('home.apiOffline', { target })} + + {t('home.apiOffline', { target })} + ) : null } -export const RuntimeOfflineBanner: FC = () => { +export const NetworkOfflineBanner = forwardRef(NetworkOfflineBannerCmp) + +const RuntimeOfflineBannerCmp: ForwardRefRenderFunction = (_, ref) => { const scope = useRequiredScopeParam() const { t } = useTranslation() @@ -42,10 +49,12 @@ export const RuntimeOfflineBanner: FC = () => { if (!outOfDate) return null const target = getNameForScope(t, scope) return ( - + {lastUpdate ? t('home.runtimeOutOfDateSince', { target, lastUpdate }) : t('home.runtimeOutOfDate', { target })} ) } + +export const RuntimeOfflineBanner = forwardRef(RuntimeOfflineBannerCmp) diff --git a/src/app/components/PageLayout/Header.tsx b/src/app/components/PageLayout/Header.tsx index af648165ed..e4f3d31223 100644 --- a/src/app/components/PageLayout/Header.tsx +++ b/src/app/components/PageLayout/Header.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react' +import { FC, useLayoutEffect, useRef } from 'react' import AppBar from '@mui/material/AppBar' import Grid from '@mui/material/Unstable_Grid2' import useScrollTrigger from '@mui/material/useScrollTrigger' @@ -10,6 +10,7 @@ import Box from '@mui/material/Box' import { useScopeParam } from '../../hooks/useScopeParam' import { BuildBanner } from '../BuildBanner' import { NetworkOfflineBanner, RuntimeOfflineBanner } from '../OfflineBanner' +import Alert from '@mui/material/Alert' export const Header: FC = () => { const theme = useTheme() @@ -19,6 +20,38 @@ export const Header: FC = () => { disableHysteresis: true, threshold: 0, }) + const buildBannerRef = useRef<(typeof Alert & HTMLElement) | null>(null) + const networkOfflineBannerRef = useRef<(typeof Alert & HTMLElement) | null>(null) + const runtimeOfflineBannerRef = useRef<(typeof Alert & HTMLElement) | null>(null) + + useLayoutEffect(() => { + if (!isMobile) { + return + } + + const bodyStyles = document.body.style + + if (buildBannerRef.current !== null) { + const buildBannerHeight = buildBannerRef.current?.clientHeight + bodyStyles.setProperty('--app-build-banner-height', `${buildBannerHeight?.toFixed(2) || 0}px`) + } + + if (networkOfflineBannerRef.current !== null) { + const networkOfflineBannerHeight = networkOfflineBannerRef.current?.clientHeight + bodyStyles.setProperty( + '--app-network-offline-banner-height', + `${networkOfflineBannerHeight?.toFixed(2) || 0}px`, + ) + } + + if (runtimeOfflineBannerRef.current !== null) { + const runtimeOfflineBannerHeight = runtimeOfflineBannerRef.current?.clientHeight + bodyStyles.setProperty( + '--app-runtime-offline-banner-height', + `${runtimeOfflineBannerHeight?.toFixed(2) || 0}px`, + ) + } + }) return ( { : 'none', }} > - - - {scope && } + + + {scope && } void @@ -26,10 +27,16 @@ type ParaTimePickerProps = { open: boolean } +const ParaTimePickerDrawer = styled(Drawer)(() => ({ + [`.${drawerClasses.root}`]: { + height: '100vh', + }, +})) + export const ParaTimePicker: FC = ({ onClose, onConfirm, open }) => ( - + - + ) type ParaTimePickerContentProps = Omit diff --git a/src/styles/index.css b/src/styles/index.css index 7191f7e99f..aed0ab5625 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -1,6 +1,12 @@ @import '../../node_modules/@fontsource/figtree/variable.css'; @import '../../node_modules/@fontsource/roboto-mono/variable.css'; +:root { + --app-build-banner-height: 0px; + --app-network-offline-banner-height: 0px; + --app-runtime-offline-banner-height: 0px; +} + html { scroll-behavior: smooth; } diff --git a/src/styles/theme/defaultTheme.ts b/src/styles/theme/defaultTheme.ts index 496fc1d842..a5656f21b6 100644 --- a/src/styles/theme/defaultTheme.ts +++ b/src/styles/theme/defaultTheme.ts @@ -6,6 +6,8 @@ import { inputBaseClasses } from '@mui/material/InputBase' import { inputAdornmentClasses } from '@mui/material/InputAdornment' import { tabClasses } from '@mui/material/Tab' import { menuItemClasses } from '@mui/material/MenuItem' +import { drawerClasses } from '@mui/material/Drawer' +import { modalClasses, paperClasses } from '@mui/material' declare module '@mui/material/styles' { interface Palette { @@ -35,6 +37,7 @@ declare module '@mui/material/styles' { } interface PaletteColor extends CustomLayoutPalette {} + interface SimplePaletteColorOptions extends CustomLayoutPalette {} } @@ -69,6 +72,7 @@ declare module '@mui/material/Chip' { export interface ChipPropsColorOverrides { tertiary: true } + export interface ChipPropsVariantOverrides { ['outlined-selected']: true } @@ -495,6 +499,23 @@ export const defaultTheme = createTheme({ borderRadius: '0 0 12px 12px', padding: `${theme.spacing(4)} 5%`, }), + modal: ({ theme }) => ({ + [theme.breakpoints.down('sm')]: { + [`& .${modalClasses.backdrop}`]: { + display: 'none', + }, + }, + }), + paper: ({ theme }) => ({ + [theme.breakpoints.down('sm')]: { + height: `calc(100vh - var(--app-build-banner-height) - var(--app-network-offline-banner-height) - var(--app-runtime-offline-banner-height) - ${theme.spacing( + 6, + )})`, + top: `calc(var(--app-build-banner-height) + var(--app-network-offline-banner-height) + var(--app-runtime-offline-banner-height) + ${theme.spacing( + 6, + )})`, + }, + }), }, }, MuiLink: {