2023-03-13 22:58:36 +03:00
/* eslint-disable react/no-invalid-html-attribute */
2022-09-11 01:37:07 +03:00
/* eslint-disable react/no-danger */
/* eslint-disable react/no-unescaped-entities */
2022-12-06 08:04:03 +03:00
import { useRecoilValue } from 'recoil' ;
2022-06-20 02:35:55 +03:00
import Head from 'next/head' ;
2023-05-18 22:13:26 +03:00
import { FC , useEffect , useRef } from 'react' ;
2023-01-16 05:37:21 +03:00
import { Layout } from 'antd' ;
2023-01-09 12:06:39 +03:00
import dynamic from 'next/dynamic' ;
2023-01-19 09:38:24 +03:00
import Script from 'next/script' ;
2023-03-13 09:01:14 +03:00
import { ErrorBoundary } from 'react-error-boundary' ;
2023-04-27 01:31:23 +03:00
import { Footer } from '../../ui/Footer/Footer' ;
2022-05-26 21:08:37 +03:00
import {
ClientConfigStore ,
isChatAvailableSelector ,
clientConfigStateAtom ,
2022-05-28 08:27:20 +03:00
fatalErrorStateAtom ,
2023-01-22 10:19:17 +03:00
appStateAtom ,
2023-02-23 05:39:37 +03:00
serverStatusState ,
2023-05-06 00:37:01 +03:00
isMobileAtom ,
2023-06-26 19:00:27 +03:00
ChatState ,
chatStateAtom ,
2023-01-16 05:37:21 +03:00
} from '../../stores/ClientConfigStore' ;
import { Content } from '../../ui/Content/Content' ;
import { Header } from '../../ui/Header/Header' ;
import { ClientConfig } from '../../../interfaces/client-config.model' ;
import { DisplayableError } from '../../../types/displayable-error' ;
import setupNoLinkReferrer from '../../../utils/no-link-referrer' ;
import { TitleNotifier } from '../../TitleNotifier/TitleNotifier' ;
import { ServerRenderedHydration } from '../../ServerRendered/ServerRenderedHydration' ;
import { Theme } from '../../theme/Theme' ;
import styles from './Main.module.scss' ;
import { PushNotificationServiceWorker } from '../../workers/PushNotificationServiceWorker/PushNotificationServiceWorker' ;
2023-01-22 10:19:17 +03:00
import { AppStateOptions } from '../../stores/application-state' ;
2023-02-01 22:04:24 +03:00
import { Noscript } from '../../ui/Noscript/Noscript' ;
2023-02-23 05:39:37 +03:00
import { ServerStatus } from '../../../interfaces/server-status.model' ;
2023-05-18 22:13:26 +03:00
import { DYNAMIC_PADDING_VALUE } from '../../../utils/constants' ;
2023-01-16 05:37:21 +03:00
2023-01-09 12:06:39 +03:00
// Lazy loaded components
const FatalErrorStateModal = dynamic (
( ) = >
2023-01-16 05:37:21 +03:00
import ( '../../modals/FatalErrorStateModal/FatalErrorStateModal' ) . then (
2023-01-09 12:06:39 +03:00
mod = > mod . FatalErrorStateModal ,
) ,
{
ssr : false ,
} ,
) ;
2022-09-07 10:00:28 +03:00
export const Main : FC = ( ) = > {
2022-05-09 04:05:37 +03:00
const clientConfig = useRecoilValue < ClientConfig > ( clientConfigStateAtom ) ;
2023-02-23 05:39:37 +03:00
const clientStatus = useRecoilValue < ServerStatus > ( serverStatusState ) ;
2023-04-27 01:31:23 +03:00
const { name } = clientConfig ;
2022-05-26 21:08:37 +03:00
const isChatAvailable = useRecoilValue < boolean > ( isChatAvailableSelector ) ;
2022-05-28 08:27:20 +03:00
const fatalError = useRecoilValue < DisplayableError > ( fatalErrorStateAtom ) ;
2023-01-22 10:19:17 +03:00
const appState = useRecoilValue < AppStateOptions > ( appStateAtom ) ;
2023-05-06 00:37:01 +03:00
const isMobile = useRecoilValue < boolean | undefined > ( isMobileAtom ) ;
2023-06-26 19:00:27 +03:00
const chatState = useRecoilValue < ChatState > ( chatStateAtom ) ;
2022-06-27 06:09:07 +03:00
const layoutRef = useRef < HTMLDivElement > ( null ) ;
2023-04-29 06:47:25 +03:00
const { chatDisabled } = clientConfig ;
2023-01-22 10:19:17 +03:00
const { videoAvailable } = appState ;
2023-05-18 22:13:26 +03:00
const { online , streamTitle } = clientStatus ;
2022-06-27 06:09:07 +03:00
2023-05-06 00:37:01 +03:00
// accounts for sidebar width when online in desktop
2023-06-26 19:00:27 +03:00
const showChat = online && ! chatDisabled && chatState === ChatState . VISIBLE ;
2023-05-18 22:13:26 +03:00
const dynamicFooterPadding = showChat && ! isMobile ? DYNAMIC_PADDING_VALUE : '' ;
2023-05-06 00:37:01 +03:00
2022-06-27 06:09:07 +03:00
useEffect ( ( ) = > {
setupNoLinkReferrer ( layoutRef . current ) ;
} , [ ] ) ;
2022-10-09 01:33:23 +03:00
const isProduction = process . env . NODE_ENV === 'production' ;
2023-02-23 05:39:37 +03:00
const headerText = online ? streamTitle || name : name ;
2022-10-09 01:33:23 +03:00
2022-04-26 09:10:07 +03:00
return (
< >
2022-06-20 02:35:55 +03:00
< Head >
2022-10-23 02:51:05 +03:00
{ isProduction && < ServerRenderedHydration / > }
2022-06-20 02:35:55 +03:00
< link rel = "apple-touch-icon" sizes = "57x57" href = "/img/favicon/apple-icon-57x57.png" / >
< link rel = "apple-touch-icon" sizes = "60x60" href = "/img/favicon/apple-icon-60x60.png" / >
< link rel = "apple-touch-icon" sizes = "72x72" href = "/img/favicon/apple-icon-72x72.png" / >
< link rel = "apple-touch-icon" sizes = "76x76" href = "/img/favicon/apple-icon-76x76.png" / >
< link rel = "apple-touch-icon" sizes = "114x114" href = "/img/favicon/apple-icon-114x114.png" / >
< link rel = "apple-touch-icon" sizes = "120x120" href = "/img/favicon/apple-icon-120x120.png" / >
< link rel = "apple-touch-icon" sizes = "144x144" href = "/img/favicon/apple-icon-144x144.png" / >
< link rel = "apple-touch-icon" sizes = "152x152" href = "/img/favicon/apple-icon-152x152.png" / >
< link rel = "apple-touch-icon" sizes = "180x180" href = "/img/favicon/apple-icon-180x180.png" / >
< link
rel = "icon"
type = "image/png"
sizes = "192x192"
href = "/img/favicon/android-icon-192x192.png"
/ >
< link rel = "icon" type = "image/png" sizes = "32x32" href = "/img/favicon/favicon-32x32.png" / >
< link rel = "icon" type = "image/png" sizes = "96x96" href = "/img/favicon/favicon-96x96.png" / >
< link rel = "icon" type = "image/png" sizes = "16x16" href = "/img/favicon/favicon-16x16.png" / >
< link rel = "manifest" href = "/manifest.json" / >
2023-03-13 22:58:36 +03:00
< link rel = "authorization_endpoint" href = "/api/auth/provider/indieauth" / >
2022-06-20 02:35:55 +03:00
< meta name = "msapplication-TileColor" content = "#ffffff" / >
< meta name = "msapplication-TileImage" content = "/img/favicon/ms-icon-144x144.png" / >
2023-04-28 23:57:37 +03:00
< meta
name = "viewport"
content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/ >
< meta name = "apple-mobile-web-app-status-bar-style" content = "black-translucent" / >
2022-10-21 06:12:57 +03:00
< base target = "_blank" / >
2022-06-20 02:35:55 +03:00
< / Head >
2022-10-25 04:27:01 +03:00
{ isProduction ? (
2022-10-23 02:51:05 +03:00
< Head >
2022-12-26 03:03:54 +03:00
{ name ? < title > { name } < / title > : < title > { '{{.Name}}' } < / title > }
2022-10-23 02:51:05 +03:00
< meta name = "description" content = "{{.Summary}}" / >
< meta property = "og:title" content = "{{.Name}}" / >
< meta property = "og:site_name" content = "{{.Name}}" / >
< meta property = "og:url" content = "{{.RequestedURL}}" / >
< meta property = "og:description" content = "{{.Summary}}" / >
< meta property = "og:type" content = "video.other" / >
< meta property = "video:tag" content = "{{.TagsString}}" / >
2022-11-19 08:37:54 +03:00
< meta property = "og:image" content = "{{.RequestedURL}}{{.Thumbnail}}" / >
< meta property = "og:image:url" content = "{{.RequestedURL}}{{.Thumbnail}}" / >
< meta property = "og:image:alt" content = "{{.RequestedURL}}{{.Image}}" / >
2022-10-23 02:51:05 +03:00
2023-06-14 05:28:35 +03:00
< meta property = "og:video" content = "{{.RequestedURL}}{{.EmbedVideo}}" / >
< meta property = "og:video:secure_url" content = "{{.RequestedURL}}{{.EmbedVideo}}" / >
2022-10-23 02:51:05 +03:00
< meta property = "og:video:height" content = "315" / >
< meta property = "og:video:width" content = "560" / >
< meta property = "og:video:type" content = "text/html" / >
< meta property = "og:video:actor" content = "{{.Name}}" / >
< meta property = "twitter:title" content = "{{.Name}}" / >
< meta property = "twitter:url" content = "{{.RequestedURL}}" / >
< meta property = "twitter:description" content = "{{.Summary}}" / >
< meta property = "twitter:image" content = "{{.Image}}" / >
< meta property = "twitter:card" content = "player" / >
2023-06-14 05:28:35 +03:00
< meta property = "twitter:player" content = "{{.RequestedURL}}{{.EmbedVideo}}" / >
2022-10-23 02:51:05 +03:00
< meta property = "twitter:player:width" content = "560" / >
< meta property = "twitter:player:height" content = "315" / >
< / Head >
2022-10-25 04:27:01 +03:00
) : (
< Head >
< title > { name } < / title >
< / Head >
2022-10-23 02:51:05 +03:00
) }
2023-03-13 09:01:14 +03:00
< ErrorBoundary
// eslint-disable-next-line react/no-unstable-nested-components
fallbackRender = { ( { error } ) = > (
< FatalErrorStateModal
title = "Error"
message = { ` There was an unexpected error. Please refresh the page to retry. If this error continues please file a bug with the Owncast project: ${ error } ` }
/ >
) }
>
< ClientConfigStore / >
< / ErrorBoundary >
2023-01-09 12:06:39 +03:00
< PushNotificationServiceWorker / >
2022-12-26 03:03:54 +03:00
< TitleNotifier name = { name } / >
2022-11-13 07:26:55 +03:00
< Theme / >
2023-01-19 09:38:24 +03:00
< Script strategy = "afterInteractive" src = "/customjavascript" / >
2023-01-16 05:37:21 +03:00
< Layout ref = { layoutRef } className = { styles . layout } >
2023-01-22 10:19:17 +03:00
< Header
2023-02-23 05:39:37 +03:00
name = { headerText }
2023-01-22 10:19:17 +03:00
chatAvailable = { isChatAvailable }
chatDisabled = { chatDisabled }
online = { videoAvailable }
/ >
2022-05-04 00:55:13 +03:00
< Content / >
2022-05-28 08:27:20 +03:00
{ fatalError && (
< FatalErrorStateModal title = { fatalError . title } message = { fatalError . message } / >
) }
2023-05-18 22:13:26 +03:00
2023-05-23 04:56:44 +03:00
< div className = { styles . footerContainer } >
< Footer dynamicPaddingValue = { dynamicFooterPadding } / >
< / div >
2023-01-16 05:37:21 +03:00
< / Layout >
2023-02-01 22:04:24 +03:00
< Noscript / >
2022-04-26 09:10:07 +03:00
< / >
) ;
2022-09-07 10:00:28 +03:00
} ;