diff --git a/apps/client/src/AppRouter.tsx b/apps/client/src/AppRouter.tsx index 8dbe62385..94a1e1d23 100644 --- a/apps/client/src/AppRouter.tsx +++ b/apps/client/src/AppRouter.tsx @@ -5,7 +5,9 @@ import { OntimeView, OntimeViewPresettable, URLPreset } from 'ontime-types'; import ViewNavigationMenu from './common/components/navigation-menu/ViewNavigationMenu'; import { PresetContext } from './common/context/PresetContext'; import { useClientPath } from './common/hooks/useClientPath'; +import { useIsOnline } from './common/hooks/useSocket'; import useUrlPresets from './common/hooks-query/useUrlPresets'; +import { cx } from './common/utils/styleUtils'; import { getRouteFromPreset } from './common/utils/urlPresets'; import Log from './features/log/Log'; import Loader from './views/common/loader/Loader'; @@ -14,6 +16,8 @@ import ViewLoader from './views/ViewLoader'; import { getIsNavigationLocked, sessionScope } from './externals'; import { initializeSentry } from './sentry.config'; +import style from './views/ViewLoader.module.scss'; + const Timer = lazy(() => import('./views/timer/Timer')); const Countdown = lazy(() => import('./views/countdown/Countdown')); const Backstage = lazy(() => import('./views/backstage/Backstage')); @@ -175,6 +179,7 @@ const PresetViewMap: Record = { function PresetView() { const { data, status } = useUrlPresets(); const { alias } = useParams(); + const { isOnline } = useIsOnline(); const preset: URLPreset | undefined = useMemo(() => { if (status === 'pending' || !alias) return; @@ -198,10 +203,10 @@ function PresetView() { */ if (!preset) { return ( - <> +
- +
); } @@ -214,8 +219,10 @@ function PresetView() { const Component = PresetViewMap[preset.target as OntimeViewPresettable]; return ( - - {Component ? : } +
+ + {Component ? : } +
); } diff --git a/apps/client/src/views/ViewLoader.module.scss b/apps/client/src/views/ViewLoader.module.scss new file mode 100644 index 000000000..480ae68bc --- /dev/null +++ b/apps/client/src/views/ViewLoader.module.scss @@ -0,0 +1,27 @@ +@use '../theme/ontimeStyles' as *; +@use '../theme/ontimeColours' as *; + +.viewLoader { + width: 100%; + height: 100%; + position: relative; +} + +.isOffline { + &::after { + content: 'Disconnected'; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + padding-block: 0.25rem; + background-color: $red-700; + color: $ui-white; + text-align: center; + font-size: $aux-text-size; + font-weight: 600; + z-index: $zindex-sudo; + pointer-events: none; + font-family: $ontime-font-family; + } +} diff --git a/apps/client/src/views/ViewLoader.tsx b/apps/client/src/views/ViewLoader.tsx index ed5df9db4..a6d972f79 100644 --- a/apps/client/src/views/ViewLoader.tsx +++ b/apps/client/src/views/ViewLoader.tsx @@ -2,13 +2,18 @@ import { PropsWithChildren } from 'react'; import { overrideStylesURL } from '../common/api/constants'; import { useRuntimeStylesheet } from '../common/hooks/useRuntimeStylesheet'; +import { useIsOnline } from '../common/hooks/useSocket'; import useViewSettings from '../common/hooks-query/useViewSettings'; +import { cx } from '../common/utils/styleUtils'; import Loader from './common/loader/Loader'; +import style from './ViewLoader.module.scss'; + export default function ViewLoader({ children }: PropsWithChildren) { const { data } = useViewSettings(); const { shouldRender } = useRuntimeStylesheet(data.overrideStyles ? overrideStylesURL : undefined); + const { isOnline } = useIsOnline(); // eventually we would want to leverage suspense here // while the feature is not ready, we simply trigger a loader @@ -18,6 +23,5 @@ export default function ViewLoader({ children }: PropsWithChildren) { return ; } - // eslint-disable-next-line react/jsx-no-useless-fragment -- ensuring JSX return - return <>{children}; + return
{children}
; }