diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index cb2c8864e2..49327044c2 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -1,7 +1,11 @@ +// order matters! import 'antd/dist/antd.css'; import '../styles/colors.scss'; import '../styles/globals.scss'; import '../styles/ant-overrides.scss'; +import '../styles/markdown-editor.scss'; + +import '../styles/main-layout.scss'; import '../styles/form-textfields.scss'; import '../styles/form-toggleswitch.scss'; @@ -11,7 +15,6 @@ import '../styles/config-storage.scss'; import '../styles/config-tags.scss'; import '../styles/config-video-variants.scss'; - import '../styles/home.scss'; import '../styles/chat.scss'; import '../styles/config.scss'; diff --git a/web/pages/components/chart.tsx b/web/pages/components/chart.tsx index 57445d35aa..0ee2ec304a 100644 --- a/web/pages/components/chart.tsx +++ b/web/pages/components/chart.tsx @@ -9,11 +9,11 @@ interface TimedValue { } interface ChartProps { - data?: TimedValue[], - title?: string, - color: string, - unit: string, - dataCollections?: any[], + data?: TimedValue[]; + title?: string; + color: string; + unit: string; + dataCollections?: any[]; } function createGraphDataset(dataArray) { @@ -33,18 +33,20 @@ export default function Chart({ data, title, color, unit, dataCollections }: Cha renderData.push({ name: title, color, - data: createGraphDataset(data) + data: createGraphDataset(data), }); } dataCollections.forEach(collection => { - renderData.push( - {name: collection.name, data: createGraphDataset(collection.data), color: collection.color} - ) + renderData.push({ + name: collection.name, + data: createGraphDataset(collection.data), + color: collection.color, + }); }); return ( -
+
- + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {' '} + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + ); -} \ No newline at end of file +} diff --git a/web/pages/components/main-layout.tsx b/web/pages/components/main-layout.tsx index d8e948c7ef..095622b9e3 100644 --- a/web/pages/components/main-layout.tsx +++ b/web/pages/components/main-layout.tsx @@ -1,8 +1,8 @@ import React, { useContext, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import Link from 'next/link'; -import Head from 'next/head' -import { differenceInSeconds } from "date-fns"; +import Head from 'next/head'; +import { differenceInSeconds } from 'date-fns'; import { useRouter } from 'next/router'; import { Layout, Menu, Popover, Alert } from 'antd'; @@ -16,11 +16,10 @@ import { QuestionCircleOutlined, MessageOutlined, ExperimentOutlined, - } from '@ant-design/icons'; import classNames from 'classnames'; -import { upgradeVersionAvailable } from "../../utils/apis"; -import { parseSecondsToDurationString } from '../../utils/format' +import { upgradeVersionAvailable } from '../../utils/apis'; +import { parseSecondsToDurationString } from '../../utils/format'; import OwncastLogo from './logo'; import { ServerStatusContext } from '../../utils/server-status-context'; @@ -29,7 +28,7 @@ import { AlertMessageContext } from '../../utils/alert-message-context'; import TextFieldWithSubmit from './config/form-textfield-with-submit'; import { TEXTFIELD_PROPS_STREAM_TITLE } from './config/constants'; -import adminStyles from '../../styles/styles.module.scss'; +import { UpdateArgs } from '../../types/config-section'; let performedUpgradeCheck = false; @@ -37,72 +36,47 @@ export default function MainLayout(props) { const { children } = props; const context = useContext(ServerStatusContext); - const { serverConfig, online, broadcaster, versionNumber, streamTitle } = context || {}; + const { serverConfig, online, broadcaster, versionNumber } = context || {}; const { instanceDetails } = serverConfig; - const [currentStreamTitle, setCurrentStreamTitle] = useState(streamTitle); + const [currentStreamTitle, setCurrentStreamTitle] = useState(''); const alertMessage = useContext(AlertMessageContext); - + const router = useRouter(); const { route } = router || {}; const { Header, Footer, Content, Sider } = Layout; const { SubMenu } = Menu; - // status indicator items - const streamDurationString = broadcaster ? parseSecondsToDurationString(differenceInSeconds(new Date(), new Date(broadcaster.time))) : ""; - const currentThumbnail = online ? ( - current thumbnail - ) : null; - const statusIcon = online ? : ; - const statusMessage = online ? `Online ${streamDurationString}` : "Offline"; - const statusIndicator = ( -
- {statusMessage} - {statusIcon} -
- ); - const statusIndicatorWithThumb = online ? ( - - {statusIndicator} - - ) : statusIndicator; - // /////////////// - const [upgradeVersion, setUpgradeVersion] = useState(null); const checkForUpgrade = async () => { try { const result = await upgradeVersionAvailable(versionNumber); setUpgradeVersion(result); } catch (error) { - console.log("==== error", error); + console.log('==== error', error); } }; useEffect(() => { if (!performedUpgradeCheck) { checkForUpgrade(); - performedUpgradeCheck = true + performedUpgradeCheck = true; } }); useEffect(() => { - setCurrentStreamTitle(streamTitle); - }, [streamTitle]); + setCurrentStreamTitle(instanceDetails.streamTitle); + }, [instanceDetails]); const handleStreamTitleChanged = ({ value }: UpdateArgs) => { setCurrentStreamTitle(value); - } - + }; const appClass = classNames({ - "owncast-layout": true, - [adminStyles.online]: online, + 'app-container': true, + online, }); const upgradeMenuItemStyle = upgradeVersion ? 'block' : 'none'; @@ -110,15 +84,36 @@ export default function MainLayout(props) { const clearAlertMessage = () => { alertMessage.setMessage(null); - } + }; + + const headerAlertMessage = alertMessage.message ? ( + + ) : null; + + // status indicator items + const streamDurationString = broadcaster + ? parseSecondsToDurationString(differenceInSeconds(new Date(), new Date(broadcaster.time))) + : ''; + const currentThumbnail = online ? ( + current thumbnail + ) : null; + const statusIcon = online ? : ; + const statusMessage = online ? `Online ${streamDurationString}` : 'Offline'; + + const statusIndicator = ( +
+ {statusMessage} + {statusIcon} +
+ ); + const statusIndicatorWithThumb = online ? ( + + {statusIndicator} + + ) : ( + statusIndicator + ); - const headerAlertMessage = alertMessage.message ? ( ): null; - return ( @@ -126,47 +121,32 @@ export default function MainLayout(props) { - + -

- +

+ - Owncast Admin + Owncast Admin

}> Home - } - title="Current stream" - > + } title="Current stream"> Viewers - } - title="Chat utilities" - > + } title="Chat utilities"> Chat - } - > + }> General @@ -189,11 +169,7 @@ export default function MainLayout(props) { - } - title="Utilities" - > + } title="Utilities"> Hardware @@ -206,11 +182,7 @@ export default function MainLayout(props) { - } - title="Integrations" - > + } title="Integrations"> Webhooks @@ -218,38 +190,33 @@ export default function MainLayout(props) { Access Tokens - } - title="Help" - > + } title="Help"> Help

- -
-
- -
+ +
+
+ +
+ {statusIndicatorWithThumb}
{headerAlertMessage} - - {children} -
+ {children} + + @@ -259,4 +226,4 @@ export default function MainLayout(props) { MainLayout.propTypes = { children: PropTypes.element.isRequired, -}; \ No newline at end of file +}; diff --git a/web/pages/offline-notice.tsx b/web/pages/offline-notice.tsx index 320ed7e768..1a87c6b660 100644 --- a/web/pages/offline-notice.tsx +++ b/web/pages/offline-notice.tsx @@ -1,8 +1,13 @@ -import { Result, Card } from "antd"; -import { MessageTwoTone, QuestionCircleTwoTone, BookTwoTone, PlaySquareTwoTone } from '@ant-design/icons'; -import OwncastLogo from "./components/logo" -import LogTable from "./components/log-table"; import Link from 'next/link'; +import { Result, Card } from 'antd'; +import { + MessageTwoTone, + QuestionCircleTwoTone, + BookTwoTone, + PlaySquareTwoTone, +} from '@ant-design/icons'; +import OwncastLogo from './components/logo'; +import LogTable from './components/log-table'; const { Meta } = Card; @@ -10,36 +15,42 @@ export default function Offline({ logs = [] }) { const data = [ { icon: , - title: "Use your broadcasting software", + title: 'Use your broadcasting software', content: ( - ) + ), }, { icon: , - title: "Chat is disabled", - content: "Chat will continue to be disabled until you begin a live stream." + title: 'Chat is disabled', + content: 'Chat will continue to be disabled until you begin a live stream.', }, { icon: , - title: "Embed your video onto other sites", + title: 'Embed your video onto other sites', content: ( - ) + ), }, { icon: , - title: "Not sure what to do next?", + title: 'Not sure what to do next?', content: (
- If you're having issues or would like to know how to customize and configure your Owncast server visit the help page. + If you're having issues or would like to know how to customize and configure your + Owncast server visit the help page.
), - } + }, ]; return ( @@ -53,19 +64,12 @@ export default function Offline({ logs = [] }) { />
- { - data.map(item => ( - - - - )) - } + {data.map(item => ( + + + + ))}
-
diff --git a/web/styles/globals.scss b/web/styles/globals.scss index 6c0317df44..308933e183 100644 --- a/web/styles/globals.scss +++ b/web/styles/globals.scss @@ -36,48 +36,13 @@ code { } -// markdown editor overrides - -.rc-virtual-list-scrollbar { - display: block !important; -} -.rc-md-editor { - // Set the background color of the preview container - .editor-container { - background-color: #E2E8F0; - color: rgba(45,55,72,1); - } - - // Custom CSS for formatting the preview text - .markdown-editor-preview-pane { - // color:lightgrey; - a { - color: var(--owncast-purple);; - } - h1 { - font-size: 2em; - } - } - - // Custom CSS class used to format the text of the editor - .markdown-editor-pane { - color: white !important; - background-color: black; - font-family: monospace; - } - - // Set the background color of the editor text input - textarea { - background-color: rgb(44,44,44) !important; - color:lightgrey !important; - } -.ant-btn { - transition-duration: .15s; - transition-delay: 0s; +.logo-svg { + height: 2rem; + width: 2rem; } - // Hide extra toolbar buttons. - .button-type-undo, .button-type-redo, .button-type-clear, .button-type-image, .button-type-wrap, .button-type-quote, .button-type-strikethrough, .button-type-code-inline, .button-type-code-block { - display: none !important; - } +p.page-description { + margin: 1em 0; + color: #ccc; + width: 80%; } diff --git a/web/styles/main-layout.scss b/web/styles/main-layout.scss new file mode 100644 index 0000000000..8cde3017d9 --- /dev/null +++ b/web/styles/main-layout.scss @@ -0,0 +1,138 @@ +.app-container { + + .side-nav { + position: fixed; + height: 100vh; + overflow: auto; + z-index: 10; + } + + h1.owncast-title { + padding: 1rem; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + + .logo-container { + background-color: #fff; + padding: .35rem; + border-radius: 9999px; + } + + .title-label { + display: inline-block; + margin-left: 1rem; + color: rgba(203,213,224, 1); + font-size: 1.15rem; + font-weight: 200; + text-transform: uppercase; + line-height: normal; + letter-spacing: .05em; + } + } + + .layout-main { + margin-left: 240px; // width of Ant Sider + } + .layout-header { + display: flex; + flex-direction: row; + justify-content: flex-end; + padding-right: 1rem; + } + + + .main-content-container { + padding: 3em; + } + + .footer-container { + text-align: center; + } + + + + .online-status-indicator { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + + .online-thumbnail { + width: 12.5rem; + } + + .status-label { + color: #fff; + text-transform: uppercase; + font-size: .75rem; + display: inline-block; + margin-right: .5rem; + color: #999; + } + .status-icon { + font-size: 1.5rem; + svg { + fill: #999; + } + } + } + .online { + .online-status-indicator { + .status-icon { + svg { + fill: var(--online-color); + } + } + .status-label { + color: var(--online-color); + } + } + } +} + + +// stream title form field in header +.global-stream-title-container { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + .textfield-with-submit-container { + flex-direction: row; + justify-content: center; + align-items: center; + margin-bottom: 0; + + .input-side { + width: 400px; + } + + .label-side { + display: none; + } + .lower-container { + width: auto; + .lower-content { + flex-direction: column-reverse; + position: relative; + } + .label-spacer, + .field-tip { + display: none; + } + .status-container { + line-height: 1; + position: absolute; + bottom: -2em; + } + .update-button-container { + margin: 0; + margin-left: .5em; + line-height: 1; + } + } + } +} + diff --git a/web/styles/markdown-editor.scss b/web/styles/markdown-editor.scss new file mode 100644 index 0000000000..74186233cb --- /dev/null +++ b/web/styles/markdown-editor.scss @@ -0,0 +1,46 @@ + +// markdown editor overrides + +.rc-virtual-list-scrollbar { + display: block !important; +} +.rc-md-editor { + // Set the background color of the preview container + .editor-container { + background-color: #E2E8F0; + color: rgba(45,55,72,1); + } + + // Custom CSS for formatting the preview text + .markdown-editor-preview-pane { + // color:lightgrey; + a { + color: var(--owncast-purple);; + } + h1 { + font-size: 2em; + } + } + + // Custom CSS class used to format the text of the editor + .markdown-editor-pane { + color: white !important; + background-color: black; + font-family: monospace; + } + + // Set the background color of the editor text input + textarea { + background-color: rgb(44,44,44) !important; + color:lightgrey !important; + } +.ant-btn { + transition-duration: .15s; + transition-delay: 0s; +} + + // Hide extra toolbar buttons. + .button-type-undo, .button-type-redo, .button-type-clear, .button-type-image, .button-type-wrap, .button-type-quote, .button-type-strikethrough, .button-type-code-inline, .button-type-code-block { + display: none !important; + } +} diff --git a/web/styles/styles.module.scss b/web/styles/styles.module.scss index 4d2af6e143..2e4b99bfbf 100644 --- a/web/styles/styles.module.scss +++ b/web/styles/styles.module.scss @@ -1,9 +1,4 @@ -.logoSVG { - height: 2rem; - width: 2rem; -} - .owncastTitleContainer { padding: 1rem; display: flex;