From 6e43870d41f355ab1ef8e033d473f947ec39a854 Mon Sep 17 00:00:00 2001 From: gingervitis Date: Thu, 4 Feb 2021 08:04:00 -0800 Subject: [PATCH 1/3] cleanup some forms; break out major config styles into their own files --- web/pages/_app.tsx | 10 +- web/pages/components/config/cpu-usage.tsx | 6 +- .../components/config/edit-server-details.tsx | 4 +- .../components/config/edit-social-links.tsx | 2 +- web/pages/components/config/edit-storage.tsx | 18 +- .../config/social-icons-dropdown.tsx | 2 +- web/pages/components/config/video-latency.tsx | 49 +-- .../components/config/video-variant-form.tsx | 69 +--- .../config/video-variants-table.tsx | 25 +- web/styles/config-socialhandles.scss | 25 ++ web/styles/config-storage.scss | 49 +++ web/styles/config-tags.scss | 37 ++ web/styles/config-video-variants.scss | 85 +++++ web/styles/config.scss | 330 ------------------ web/styles/form-misc-elements.scss | 64 ++++ ...g-formfields.scss => form-textfields.scss} | 64 +--- web/styles/form-toggleswitch.scss | 29 ++ web/utils/alert-message-context.tsx | 36 +- 18 files changed, 374 insertions(+), 530 deletions(-) create mode 100644 web/styles/config-socialhandles.scss create mode 100644 web/styles/config-storage.scss create mode 100644 web/styles/config-tags.scss create mode 100644 web/styles/config-video-variants.scss create mode 100644 web/styles/form-misc-elements.scss rename web/styles/{config-formfields.scss => form-textfields.scss} (67%) create mode 100644 web/styles/form-toggleswitch.scss diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index 208b832ff..cb2c8864e 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -3,10 +3,18 @@ import '../styles/colors.scss'; import '../styles/globals.scss'; import '../styles/ant-overrides.scss'; +import '../styles/form-textfields.scss'; +import '../styles/form-toggleswitch.scss'; +import '../styles/form-misc-elements.scss'; +import '../styles/config-socialhandles.scss'; +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'; -import '../styles/config-formfields.scss'; import { AppProps } from 'next/app'; import ServerStatusProvider from '../utils/server-status-context'; diff --git a/web/pages/components/config/cpu-usage.tsx b/web/pages/components/config/cpu-usage.tsx index 9b54425db..139ea85e7 100644 --- a/web/pages/components/config/cpu-usage.tsx +++ b/web/pages/components/config/cpu-usage.tsx @@ -41,14 +41,14 @@ export default function CPUUsageSelector({ defaultValue, onChange }) { }; return ( -
+
CPU Usage

There are trade-offs when considering CPU usage blah blah more wording here.



-
+
TOOLTIPS[value] } + tipFormatter={value => TOOLTIPS[value]} onChange={handleChange} min={1} max={Object.keys(SLIDER_MARKS).length} diff --git a/web/pages/components/config/edit-server-details.tsx b/web/pages/components/config/edit-server-details.tsx index 82389086f..f09f0d51d 100644 --- a/web/pages/components/config/edit-server-details.tsx +++ b/web/pages/components/config/edit-server-details.tsx @@ -51,8 +51,8 @@ export default function EditInstanceDetails() { }; const showConfigurationRestartMessage = () => { - setMessage('Updating server settings requires a restart of your Owncast server.') - } + setMessage('Updating server settings requires a restart of your Owncast server.'); + }; function generateStreamKey() { let key = ''; diff --git a/web/pages/components/config/edit-social-links.tsx b/web/pages/components/config/edit-social-links.tsx index 4c5f6f92c..af9096f4d 100644 --- a/web/pages/components/config/edit-social-links.tsx +++ b/web/pages/components/config/edit-social-links.tsx @@ -157,7 +157,7 @@ export default function EditSocialLinks() { postUpdateToAPI(postData); }; - const handleDeleteItem = index => { + const handleDeleteItem = (index: number) => { const postData = [...currentSocialHandles]; postData.splice(index, 1); postUpdateToAPI(postData); diff --git a/web/pages/components/config/edit-storage.tsx b/web/pages/components/config/edit-storage.tsx index 2a12a6846..ae9efba22 100644 --- a/web/pages/components/config/edit-storage.tsx +++ b/web/pages/components/config/edit-storage.tsx @@ -1,4 +1,4 @@ -import { Switch, Button, Collapse, Alert } from 'antd'; +import { Switch, Button, Collapse } from 'antd'; import classNames from 'classnames'; import React, { useContext, useState, useEffect } from 'react'; import { UpdateArgs } from '../../../types/config-section'; @@ -32,7 +32,7 @@ function checkSaveable(formValues: any, currentValues: any) { if (enabled) { if (!!endpoint && isValidUrl(endpoint) && !!accessKey && !!secret && !!bucket && !!region) { if ( - enabled !== currentValues.enabled || + enabled !== currentValues.enabled || endpoint !== currentValues.endpoint || accessKey !== currentValues.accessKey || secret !== currentValues.secret || @@ -52,13 +52,12 @@ function checkSaveable(formValues: any, currentValues: any) { export default function EditStorage() { const [formDataValues, setFormDataValues] = useState(null); const [submitStatus, setSubmitStatus] = useState(null); - const [saved, setSaved] = useState(false); const [shouldDisplayForm, setShouldDisplayForm] = useState(false); const serverStatusData = useContext(ServerStatusContext); const { serverConfig, setFieldInConfigState } = serverStatusData || {}; - const {message, setMessage} = useContext(AlertMessageContext); + const { setMessage: setAlertMessage } = useContext(AlertMessageContext); const { s3 } = serverConfig; const { @@ -117,8 +116,9 @@ export default function EditStorage() { setFieldInConfigState({ fieldName: 's3', value: postValue, path: '' }); setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.')); resetTimer = setTimeout(resetStates, RESET_TIMEOUT); - setSaved(true); - setMessage('Changing your storage configuration will take place the next time you start a new stream.'); + setAlertMessage( + 'Changing your storage configuration will take place the next time you start a new stream.', + ); }, onError: (message: string) => { setSubmitStatus(createInputStatus(STATUS_ERROR, message)); @@ -131,12 +131,6 @@ export default function EditStorage() { const handleSwitchChange = (storageEnabled: boolean) => { setShouldDisplayForm(storageEnabled); handleFieldChange({ fieldName: 'enabled', value: storageEnabled }); - - // if current data in current store says s3 is enabled, - // we should save this state - // if (!storageEnabled && s3.enabled) { - // handleSave(); - // } }; const containerClass = classNames({ diff --git a/web/pages/components/config/social-icons-dropdown.tsx b/web/pages/components/config/social-icons-dropdown.tsx index fac0c5374..767c8ea88 100644 --- a/web/pages/components/config/social-icons-dropdown.tsx +++ b/web/pages/components/config/social-icons-dropdown.tsx @@ -11,7 +11,7 @@ interface DropdownProps { } export default function SocialDropdown({ iconList, selectedOption, onSelected }: DropdownProps) { - const handleSelected = value => { + const handleSelected = (value: string) => { if (onSelected) { onSelected(value); } diff --git a/web/pages/components/config/video-latency.tsx b/web/pages/components/config/video-latency.tsx index d337cc43e..82870d643 100644 --- a/web/pages/components/config/video-latency.tsx +++ b/web/pages/components/config/video-latency.tsx @@ -1,12 +1,15 @@ import React, { useContext, useState, useEffect } from 'react'; import { Typography, Slider } from 'antd'; import { ServerStatusContext } from '../../../utils/server-status-context'; +import { API_VIDEO_SEGMENTS, RESET_TIMEOUT, postConfigUpdateToAPI } from './constants'; import { - API_VIDEO_SEGMENTS, - SUCCESS_STATES, - RESET_TIMEOUT, - postConfigUpdateToAPI, -} from './constants'; + createInputStatus, + StatusState, + STATUS_ERROR, + STATUS_PROCESSING, + STATUS_SUCCESS, +} from '../../../utils/input-statuses'; +import FormStatusIndicator from './form-status-indicator'; const { Title } = Typography; @@ -37,8 +40,10 @@ function SegmentToolTip({ value }: SegmentToolTipProps) { } export default function VideoLatency() { - const [submitStatus, setSubmitStatus] = useState(null); - const [submitStatusMessage, setSubmitStatusMessage] = useState(''); + const [submitStatus, setSubmitStatus] = useState(null); + + // const [submitStatus, setSubmitStatus] = useState(null); + // const [submitStatusMessage, setSubmitStatusMessage] = useState(''); const [selectedOption, setSelectedOption] = useState(null); const serverStatusData = useContext(ServerStatusContext); @@ -57,13 +62,15 @@ export default function VideoLatency() { const resetStates = () => { setSubmitStatus(null); - setSubmitStatusMessage(''); + // setSubmitStatusMessage(''); resetTimer = null; clearTimeout(resetTimer); }; // posts all the variants at once as an array obj const postUpdateToAPI = async (postValue: any) => { + setSubmitStatus(createInputStatus(STATUS_PROCESSING)); + await postConfigUpdateToAPI({ apiPath: API_VIDEO_SEGMENTS, data: { value: postValue }, @@ -73,34 +80,28 @@ export default function VideoLatency() { value: postValue, path: 'videoSettings', }); + setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Variants updated.')); - setSubmitStatus('success'); - setSubmitStatusMessage('Variants updated.'); + // setSubmitStatus('success'); + // setSubmitStatusMessage('Variants updated.'); resetTimer = setTimeout(resetStates, RESET_TIMEOUT); }, onError: (message: string) => { - setSubmitStatus('error'); - setSubmitStatusMessage(message); + setSubmitStatus(createInputStatus(STATUS_ERROR, message)); + + // setSubmitStatus('error'); + // setSubmitStatusMessage(message); resetTimer = setTimeout(resetStates, RESET_TIMEOUT); }, }); }; - const { icon: newStatusIcon = null, message: newStatusMessage = '' } = - SUCCESS_STATES[submitStatus] || {}; - - const statusMessage = ( -
- {newStatusIcon} {newStatusMessage} {submitStatusMessage} -
- ); - const handleChange = value => { postUpdateToAPI(value); }; return ( -
+
Latency Buffer

There are trade-offs when cosidering video latency and reliability. Blah blah .. better @@ -108,7 +109,7 @@ export default function VideoLatency() {



-
+
} onChange={handleChange} @@ -119,7 +120,7 @@ export default function VideoLatency() { value={selectedOption} />
- {statusMessage} +
); } diff --git a/web/pages/components/config/video-variant-form.tsx b/web/pages/components/config/video-variant-form.tsx index e82a37788..c5e7b5e83 100644 --- a/web/pages/components/config/video-variant-form.tsx +++ b/web/pages/components/config/video-variant-form.tsx @@ -1,12 +1,11 @@ // This content populates the video variant modal, which is spawned from the variants table. import React from 'react'; -import { Slider, Select, Switch, Divider, Collapse } from 'antd'; -import { FieldUpdaterFunc, CpuUsageLevel, VideoVariant } from '../../../types/config-section'; +import { Slider, Switch, Collapse } from 'antd'; +import { FieldUpdaterFunc, VideoVariant } from '../../../types/config-section'; import { DEFAULT_VARIANT_STATE } from './constants'; import InfoTip from '../info-tip'; import CPUUsageSelector from './cpu-usage'; -const { Option } = Select; const { Panel } = Collapse; const VIDEO_VARIANT_DEFAULTS = { @@ -57,12 +56,6 @@ export default function VideoVariantForm({ const handleVideoBitrateChange = (value: number) => { onUpdateField({ fieldName: 'videoBitrate', value }); }; - const handleAudioBitrateChange = (value: number) => { - onUpdateField({ fieldName: 'audioBitrate', value }); - }; - const handleAudioPassChange = (value: boolean) => { - onUpdateField({ fieldName: 'audioPassthrough', value }); - }; const handleVideoPassChange = (value: boolean) => { onUpdateField({ fieldName: 'videoPassthrough', value }); }; @@ -80,18 +73,12 @@ export default function VideoVariantForm({ const videoBRMax = videoBitrateDefaults.max; const videoBRUnit = videoBitrateDefaults.unit; - const audioBitrateDefaults = VIDEO_VARIANT_DEFAULTS.audioBitrate; - const audioBRMin = audioBitrateDefaults.min; - const audioBRMax = audioBitrateDefaults.max; - const audioBRUnit = audioBitrateDefaults.unit; - const selectedVideoBRnote = `Selected: ${dataState.videoBitrate}${videoBRUnit} - it sucks`; - const selectedAudioBRnote = `Selected: ${dataState.audioBitrate}${audioBRUnit} - too slow`; const selectedFramerateNote = `Selected: ${dataState.framerate}${framerateUnit} - whoa there`; const selectedPresetNote = ''; return ( -
+
Say a thing here about how this all works. Read more{' '} here. @@ -130,6 +117,7 @@ export default function VideoVariantForm({
+ {/* VIDEO BITRATE FIELD */}

@@ -192,55 +180,6 @@ export default function VideoVariantForm({ ) : null}

- - - - {/* AUDIO PASSTHROUGH FIELD */} - {/*
-

- - Use Audio Passthrough? -

-
- - {dataState.audioPassthrough ? Same as source : null} -
-
*/} - - {/* AUDIO BITRATE FIELD */} - {/*
-

- - Audio Bitrate: -

-
- `${value} ${audioBRUnit}`} - disabled={dataState.audioPassthrough === true} - defaultValue={dataState.audioBitrate} - value={dataState.audioBitrate} - onChange={handleAudioBitrateChange} - step={audioBitrateDefaults.incrementBy} - min={audioBRMin} - max={audioBRMax} - marks={{ - [audioBRMin]: `${audioBRMin} ${audioBRUnit}`, - [audioBRMax]: `${audioBRMax} ${audioBRUnit}`, - }} - /> - - {selectedAudioBRnote ? ( - {selectedAudioBRnote} - ) : null} -
-
*/}
diff --git a/web/pages/components/config/video-variants-table.tsx b/web/pages/components/config/video-variants-table.tsx index 83420fb05..e6bb72a39 100644 --- a/web/pages/components/config/video-variants-table.tsx +++ b/web/pages/components/config/video-variants-table.tsx @@ -1,6 +1,5 @@ // Updating a variant will post ALL the variants in an array as an update to the API. -// todo : add DELETE option import React, { useContext, useState } from 'react'; import { Typography, Table, Modal, Button } from 'antd'; import { ColumnsType } from 'antd/lib/table'; @@ -20,11 +19,19 @@ import { const { Title } = Typography; +const CPU_USAGE_LEVEL_MAP = { + 1: 'lowest', + 2: 'low', + 3: 'medium', + 4: 'high', + 5: 'highest', +}; + export default function CurrentVariantsTable() { const [displayModal, setDisplayModal] = useState(false); const [modalProcessing, setModalProcessing] = useState(false); const [editId, setEditId] = useState(0); - const {setMessage} = useContext(AlertMessageContext); + const { setMessage } = useContext(AlertMessageContext); // current data inside modal const [modalDataState, setModalDataState] = useState(DEFAULT_VARIANT_STATE); @@ -76,7 +83,9 @@ export default function CurrentVariantsTable() { setSubmitStatusMessage('Variants updated.'); resetTimer = setTimeout(resetStates, RESET_TIMEOUT); - setMessage('Updating your video configuration will take effect the next time you begin a new stream.'); + setMessage( + 'Updating your video configuration will take effect the next time you begin a new stream.', + ); }, onError: (message: string) => { setSubmitStatus('error'); @@ -117,14 +126,6 @@ export default function CurrentVariantsTable() { const { icon: newStatusIcon = null, message: newStatusMessage = '' } = SUCCESS_STATES[submitStatus] || {}; - const cpuUsageLevelLabelMap = { - 1: 'lowest', - 2: 'low', - 3: 'medium', - 4: 'high', - 5: 'highest', - }; - const videoQualityColumns: ColumnsType = [ { title: 'Video bitrate', @@ -137,7 +138,7 @@ export default function CurrentVariantsTable() { title: 'CPU Usage', dataIndex: 'cpuUsageLevel', key: 'cpuUsageLevel', - render: (level: string) => (!level ? 'n/a' : cpuUsageLevelLabelMap[level]), + render: (level: string) => (!level ? 'n/a' : CPU_USAGE_LEVEL_MAP[level]), }, { title: '', diff --git a/web/styles/config-socialhandles.scss b/web/styles/config-socialhandles.scss new file mode 100644 index 000000000..7cb9591d7 --- /dev/null +++ b/web/styles/config-socialhandles.scss @@ -0,0 +1,25 @@ +// styles for social handles editing section + +.social-option, +.social-dropdown { + .ant-select-item-option-content, + .ant-select-selection-item { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + padding: .25em; + line-height: normal; + + .option-icon { + height: 1.5em; + width: 1.5em; + line-height: normal; + } + .option-label { + display: inline-block; + margin-left: 1em; + line-height: normal; + } + } +} diff --git a/web/styles/config-storage.scss b/web/styles/config-storage.scss new file mode 100644 index 000000000..3f3993509 --- /dev/null +++ b/web/styles/config-storage.scss @@ -0,0 +1,49 @@ +// styles for Storage config section + + +.edit-storage-container { + .form-fields { + display: none; + margin-bottom: 1em; + } + &.enabled { + .form-fields { + display: block; + } + } + + .button-container { + margin: 1em 0; + } + .advanced-section { + margin: 1em 0; + } +} + + +// Do something special for the stream key field +.field-streamkey-container { + margin-bottom: 1.5em; + .field-tip { + color: var(--ant-warning); + } + .left-side { + display: flex; + flex-direction: row; + align-items: flex-start; + } + + .textfield-with-submit-container { + margin-bottom: 0; + } + + .streamkey-actions { + white-space: nowrap; + button { + margin: .25em; + } + @media (max-width: 800px) { + margin-top: 2em; + } + } +} diff --git a/web/styles/config-tags.scss b/web/styles/config-tags.scss new file mode 100644 index 000000000..f1d176693 --- /dev/null +++ b/web/styles/config-tags.scss @@ -0,0 +1,37 @@ +// config tags block + +.tag-current-tags { + .ant-tag { + margin: .1rem; + font-size: .85rem; + border-radius: 10em; + padding: .25em 1em; + background-color: rgba(255,255,255,.5); + + .ant-tag-close-icon { + transform: translateY(-1px); + margin-left: .3rem; + padding: 2px; + border-radius: 5rem; + border: 1px solid #eee; + &:hover { + border-color: #e03; + svg { + fill: black; + transition: fill .3s; + } + } + } + } +} + +.add-new-tag-section { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + + .new-tag-input { + width: 16em; + } +} diff --git a/web/styles/config-video-variants.scss b/web/styles/config-video-variants.scss new file mode 100644 index 000000000..a985d70f2 --- /dev/null +++ b/web/styles/config-video-variants.scss @@ -0,0 +1,85 @@ +// styles for Video variant editor (table + modal) + + +.config-variant-form { + .blurb { + margin: 1em; + opacity: .75; + } + .note { + display: inline-block; + margin-left: 1em; + font-size: .75em; + opacity: .5; + font-style: italic; + } + .section-intro { + margin-bottom: 2em; + } + .field { + margin-bottom: 2em; + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-start; + transform: opacity .15s; + &.disabled { + opacity: .25; + } + + .label { + width: 40%; + text-align: right; + padding-right: 2em; + font-weight: bold; + color: var(--owncast-purple); + } + .info-tip { + margin-right: 1em; + } + .form-component { + width: 60%; + + .selected-value-note { + font-size: .85em; + display: inline-block; + text-align: center; + } + } + } + .ant-collapse { + border: none; + border-radius: 6px; + } + .ant-collapse > .ant-collapse-item:last-child, + .ant-collapse > .ant-collapse-item:last-child > .ant-collapse-header { + border: none; + background-color: rgba(0,0,0,.25); + border-radius: 6px; + } + .ant-collapse-content { + background-color: rgba(0,0,0,.1); + } +} + + + +.config-video-segements-conatiner { + + .status-message { + text-align: center; + } +} + + +.variants-table { + .actions { + display: flex; + align-items: center; + justify-content: center; + } + .delete-button { + margin-left: .5em; + opacity: .8; + } +} \ No newline at end of file diff --git a/web/styles/config.scss b/web/styles/config.scss index 769433842..af2986587 100644 --- a/web/styles/config.scss +++ b/web/styles/config.scss @@ -1,164 +1,7 @@ -// .config-public-details-container { -// display: flex; -// flex-direction: row; -// align-items: flex-start; -// flex-wrap: wrap; - -// .text-fields { -// margin-right: 2rem; -// } -// .misc-fields { -// width: 25em; -// } -// .tag-editor-container, -// .config-directory-details-form { -// border-radius: 1em; -// background-color: rgba(128,99,255,.1); -// padding: 1.5em; -// margin-bottom: 1em; -// } -// } - -.module-container { - border-radius: 1em; - background-color: rgba(128,99,255,.1); - padding: 1.5em; - margin-bottom: 1em; -} -// form-textfield -// form-textfield -// .textfield-container { -// display: flex; -// flex-direction: column; -// align-items: flex-start; -// justify-content: flex-end; -// position: relative; -// width: 314px; - -// // &.type-numeric { -// // .ant-form-item-control { -// // flex-direction: row; -// // .ant-form-item-control-input { -// // margin-right: .75rem; -// // } -// // } -// // } -// } -// .textfield { -// display: flex; -// flex-direction: row; -// align-items: flex-start; - -// .field { -// width: 18rem; - -// &.ant-input-number { -// width: 8em; -// } - -// } -// .info-tip { -// margin-right: .75rem; -// } -// .ant-form-item { -// margin-bottom: 16px; -// &.ant-form-item-with-help { -// margin-bottom: 16px; -// } -// } -// .ant-form-item-label label { -// font-weight: bold; -// color: var(--owncast-purple); -// } -// .ant-form-item-explain { -// width: 70%; -// } -// } -// .submit-button { -// position: absolute; -// right: 0; -// bottom: .5em; -// } -// .ant-form-horizontal { -// .textfield-container.type-numeric { -// width: auto; - -// .submit-button { -// bottom: unset; -// top: 0; -// right: unset; -// } -// } -// } - - -// form-toggleswitch -// form-toggleswitch -// .toggleswitch-container { -// .status-message { -// margin-top: .25rem; -// } -// } -// .toggleswitch { -// display: flex; -// flex-direction: row; -// align-items: center; -// justify-content: flex-start; -// .label { -// font-weight: bold; -// color: var(--owncast-purple); -// } -// .info-tip { -// margin-left: .5rem; -// svg { -// fill: white; -// } -// } -// .ant-form-item { -// margin: 0 .75rem 0 0; -// } -// } - -// TAGS STUFF -// TAGS STUFF -.tag-current-tags { - .ant-tag { - margin: .1rem; - font-size: .85rem; - border-radius: 10em; - padding: .25em 1em; - background-color: rgba(255,255,255,.5); - - .ant-tag-close-icon { - transform: translateY(-1px); - margin-left: .3rem; - padding: 2px; - border-radius: 5rem; - border: 1px solid #eee; - &:hover { - border-color: #e03; - svg { - fill: black; - transition: fill .3s; - } - } - } - } -} -.add-new-tag-section { - display: flex; - flex-direction: row; - justify-content: flex-start; - align-items: center; - - .new-tag-input { - width: 16em; - } -} .config-page-content-form { .page-content-actions { @@ -174,101 +17,9 @@ } } -.config-video-variants { - .config-video-misc { - margin: 2rem 0; - // .ant-form { - // display: flex; - // flex-direction: row; - // align-items: flex-start; - // } - } -} -.variant-form { - .blurb { - margin: 1em; - opacity: .75; - } - .note { - display: inline-block; - margin-left: 1em; - font-size: .75em; - opacity: .5; - font-style: italic; - } - .section-intro { - margin-bottom: 2em; - } - .field { - margin-bottom: 2em; - display: flex; - flex-direction: row; - justify-content: center; - align-items: flex-start; - transform: opacity .15s; - &.disabled { - opacity: .25; - } - .label { - width: 40%; - text-align: right; - padding-right: 2em; - font-weight: bold; - color: var(--owncast-purple); - } - .info-tip { - margin-right: 1em; - } - .form-component { - width: 60%; - - .selected-value-note { - font-size: .85em; - display: inline-block; - text-align: center; - } - } - } - .ant-collapse { - border: none; - border-radius: 6px; - } - .ant-collapse > .ant-collapse-item:last-child, - .ant-collapse > .ant-collapse-item:last-child > .ant-collapse-header { - border: none; - background-color: rgba(0,0,0,.25); - border-radius: 6px; - } - .ant-collapse-content { - background-color: rgba(0,0,0,.1); - } -} -.config-video-segements-conatiner { - .segment-slider { - width: 90%; - margin: auto; - padding: 1em 2em .75em; - background-color: black; - border-radius: 1em; - } - .status-message { - text-align: center; - } -} -.variants-table { - .actions { - display: flex; - align-items: center; - justify-content: center; - } - .delete-button { - margin-left: .5em; - opacity: .8; - } -} .segment-tip { width: 10em; text-align: center; @@ -276,33 +27,6 @@ display: inline-block; } -.social-option, -.social-dropdown { - // .ant-select-selector, - // .ant-select-selection-search-input { - // height: 40px !important; - // } - .ant-select-item-option-content, - .ant-select-selection-item { - display: flex; - flex-direction: row; - justify-content: flex-start; - align-items: center; - padding: .25em; - line-height: normal; - - .option-icon { - height: 1.5em; - width: 1.5em; - line-height: normal; - } - .option-label { - display: inline-block; - margin-left: 1em; - line-height: normal; - } - } -} // .social-option { // .ant-select-item-option-content { // display: flex; @@ -324,57 +48,3 @@ - -// EDIT STORAGE -.edit-storage-container { - .form-fields { - display: none; - margin-bottom: 1em; - } - &.enabled { - .form-fields { - display: block; - } - } - - .button-container { - margin: 1em 0; - } - .advanced-section { - margin: 1em 0; - } -} - -.field-container { - padding: .85em 0 .5em; - &:nth-child(even) { - background-color: rgba(0,0,0,.25); - } -} - - - -.field-streamkey-container { - margin-bottom: 1.5em; - .field-tip { - color: var(--ant-warning); - } - .left-side { - display: flex; - flex-direction: row; - align-items: flex-start; - } - .textfield-with-submit-container { - margin-bottom: 0; - } - - .streamkey-actions { - white-space: nowrap; - button { - margin: .25em; - } - @media (max-width: 800px) { - margin-top: 2em; - } - } -} diff --git a/web/styles/form-misc-elements.scss b/web/styles/form-misc-elements.scss new file mode 100644 index 000000000..dd2abd7cb --- /dev/null +++ b/web/styles/form-misc-elements.scss @@ -0,0 +1,64 @@ +/* Base styles for misc helper components around forms */ + +/* STATUS-CONTAINER BASE */ +.status-container { + &.status-success { + color: var(--ant-success); + } + &.status-error { + color: var(--ant-error); + } + &.status-warning { + color: var(--ant-warning); + } + + &.empty { + display: none; + } + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + font-size: .75rem; + .status-icon { + display: inline-block; + margin-right: .5em; + } +} + + +/* TIP CONTAINER BASE */ +.field-tip { + font-size: .7em; + color: rgba(255,255,255,.5) +} + + +/* +Ideal for wrapping each Textfield on a page with many text fields in a row. This div will alternate colors and look like a table. +*/ +.field-container { + padding: .85em 0 .5em; + &:nth-child(even) { + background-color: rgba(0,0,0,.25); + } +} + + +/* SEGMENT SLIDER */ +.segment-slider-container { + width: 90%; + margin: auto; + padding: 1em 2em .75em; + background-color: black; + border-radius: 1em; +} + + +.segment-tip { + width: 10em; + text-align: center; + margin: auto; + display: inline-block; +} + diff --git a/web/styles/config-formfields.scss b/web/styles/form-textfields.scss similarity index 67% rename from web/styles/config-formfields.scss rename to web/styles/form-textfields.scss index 97b2227c7..29ffbe7f7 100644 --- a/web/styles/config-formfields.scss +++ b/web/styles/form-textfields.scss @@ -1,37 +1,4 @@ -// Base styles for form-textfield, form-textfield-with-submit, and helper components. - -/* STATUS-CONTAINER BASE */ -.status-container { - &.status-success { - color: var(--ant-success); - } - &.status-error { - color: var(--ant-error); - } - &.status-warning { - color: var(--ant-warning); - } - - &.empty { - display: none; - } - display: flex; - flex-direction: row; - justify-content: flex-start; - align-items: center; - font-size: .75rem; - .status-icon { - display: inline-block; - margin-right: .5em; - } -} - - -/* TIP CONTAINER BASE */ -.field-tip { - font-size: .7em; - color: rgba(255,255,255,.5) -} +// Base styles for form-textfield, form-textfield-with-submit /* TEXTFIELD-CONTAINER BASE */ @@ -103,6 +70,8 @@ } } +/* TEXTFIELD-WITH-SUBMIT-CONTAINER BASE */ +/* TEXTFIELD-WITH-SUBMIT-CONTAINER BASE */ /* TEXTFIELD-WITH-SUBMIT-CONTAINER BASE */ .textfield-with-submit-container { display: flex; @@ -169,30 +138,3 @@ } } } - -/* TOGGLE SWITCH-WITH-SUBMIT-CONTAINER BASE */ -.toggleswitch-container { - .status-container { - margin-top: .25rem; - } - - .toggleswitch { - display: flex; - flex-direction: row; - align-items: center; - justify-content: flex-start; - .label { - font-weight: bold; - color: var(--owncast-purple); - } - .info-tip { - margin-left: .5rem; - svg { - fill: white; - } - } - .ant-form-item { - margin: 0 .75rem 0 0; - } - } -} diff --git a/web/styles/form-toggleswitch.scss b/web/styles/form-toggleswitch.scss new file mode 100644 index 000000000..b3abd2080 --- /dev/null +++ b/web/styles/form-toggleswitch.scss @@ -0,0 +1,29 @@ +/* TOGGLE SWITCH-WITH-SUBMIT-CONTAINER BASE */ + + +.toggleswitch-container { + + .status-container { + margin-top: .25rem; + } + + .toggleswitch { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + .label { + font-weight: bold; + color: var(--owncast-purple); + } + .info-tip { + margin-left: .5rem; + svg { + fill: white; + } + } + .ant-form-item { + margin: 0 .75rem 0 0; + } + } +} diff --git a/web/utils/alert-message-context.tsx b/web/utils/alert-message-context.tsx index 1d1a13194..3cf81fc71 100644 --- a/web/utils/alert-message-context.tsx +++ b/web/utils/alert-message-context.tsx @@ -1,27 +1,27 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; export const AlertMessageContext = React.createContext({ - message: null, - setMessage: (text?: string) => { - return text; - } + message: null, + setMessage: (text?: string) => { + return text; + }, }); const AlertMessageProvider = ({ children }) => { - const [message, setMessage] = useState(''); - - const providerValue = { - message, - setMessage - } - return ( - {children} - ) -} + const [message, setMessage] = useState(''); -AlertMessageProvider.propTypes = { - children: PropTypes.element.isRequired + const providerValue = { + message, + setMessage, + }; + return ( + {children} + ); }; -export default AlertMessageProvider; \ No newline at end of file +AlertMessageProvider.propTypes = { + children: PropTypes.element.isRequired, +}; + +export default AlertMessageProvider; From 7786c7e113bded058d2b4b96ea00930a9adb280c Mon Sep 17 00:00:00 2001 From: gingervitis Date: Thu, 4 Feb 2021 09:17:20 -0800 Subject: [PATCH 2/3] separate out styles for markdowneditor; convert mainlayout style module styles to just sass; add style to stream title editor in header; --- web/pages/_app.tsx | 5 +- web/pages/components/chart.tsx | 22 ++- web/pages/components/config/constants.tsx | 2 +- web/pages/components/logo.tsx | 222 ++++++++++++++-------- web/pages/components/main-layout.tsx | 179 +++++++---------- web/pages/offline-notice.tsx | 58 +++--- web/styles/globals.scss | 49 +---- web/styles/main-layout.scss | 138 ++++++++++++++ web/styles/markdown-editor.scss | 46 +++++ web/styles/styles.module.scss | 5 - 10 files changed, 460 insertions(+), 266 deletions(-) create mode 100644 web/styles/main-layout.scss create mode 100644 web/styles/markdown-editor.scss diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index cb2c8864e..49327044c 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 57445d35a..0ee2ec304 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 d8e948c7e..095622b9e 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 320ed7e76..1a87c6b66 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 6c0317df4..308933e18 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 000000000..8cde3017d --- /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 000000000..74186233c --- /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 4d2af6e14..2e4b99bfb 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; From c65c97df85d055d27cd3d7665105563c68dd833f Mon Sep 17 00:00:00 2001 From: gingervitis Date: Thu, 4 Feb 2021 09:19:16 -0800 Subject: [PATCH 3/3] prettify some files --- web/pages/components/chart.tsx | 3 +- web/pages/components/info-tip.tsx | 4 +- web/pages/components/key-value-table.tsx | 20 ++-- web/pages/components/log-table.tsx | 63 ++++++------ .../components/message-visiblity-toggle.tsx | 55 ++++++----- web/pages/components/statistic.tsx | 56 +++++------ web/styles/styles.module.scss | 95 ------------------- 7 files changed, 102 insertions(+), 194 deletions(-) delete mode 100644 web/styles/styles.module.scss diff --git a/web/pages/components/chart.tsx b/web/pages/components/chart.tsx index 0ee2ec304..e324a7c4d 100644 --- a/web/pages/components/chart.tsx +++ b/web/pages/components/chart.tsx @@ -1,7 +1,6 @@ import { LineChart } from 'react-chartkick'; import 'chart.js'; import format from 'date-fns/format'; -import styles from '../../styles/styles.module.scss'; interface TimedValue { time: Date; @@ -22,7 +21,7 @@ function createGraphDataset(dataArray) { const dateObject = new Date(item.time); const dateString = format(dateObject, 'p P'); dataValues[dateString] = item.value; - }) + }); return dataValues; } diff --git a/web/pages/components/info-tip.tsx b/web/pages/components/info-tip.tsx index 28b02e48d..f5b847bb2 100644 --- a/web/pages/components/info-tip.tsx +++ b/web/pages/components/info-tip.tsx @@ -1,5 +1,5 @@ -import { InfoCircleOutlined } from "@ant-design/icons"; -import { Tooltip } from "antd"; +import { InfoCircleOutlined } from '@ant-design/icons'; +import { Tooltip } from 'antd'; interface InfoTipProps { tip: string | null; diff --git a/web/pages/components/key-value-table.tsx b/web/pages/components/key-value-table.tsx index 28e620ead..91bb05e03 100644 --- a/web/pages/components/key-value-table.tsx +++ b/web/pages/components/key-value-table.tsx @@ -1,18 +1,18 @@ -import { Table, Typography } from "antd"; +import { Table, Typography } from 'antd'; const { Title } = Typography; export default function KeyValueTable({ title, data }: KeyValueTableProps) { const columns = [ { - title: "Name", - dataIndex: "name", - key: "name", + title: 'Name', + dataIndex: 'name', + key: 'name', }, { - title: "Value", - dataIndex: "value", - key: "value", + title: 'Value', + dataIndex: 'value', + key: 'value', }, ]; @@ -25,6 +25,6 @@ export default function KeyValueTable({ title, data }: KeyValueTableProps) { } interface KeyValueTableProps { - title: string, - data: any, -}; \ No newline at end of file + title: string; + data: any; +} diff --git a/web/pages/components/log-table.tsx b/web/pages/components/log-table.tsx index 74c819c7e..603d6af56 100644 --- a/web/pages/components/log-table.tsx +++ b/web/pages/components/log-table.tsx @@ -1,32 +1,30 @@ -import React from "react"; -import { Table, Tag, Typography } from "antd"; -import Linkify from "react-linkify"; -import { SortOrder } from "antd/lib/table/interface"; -import format from 'date-fns/format' +import React from 'react'; +import { Table, Tag, Typography } from 'antd'; +import Linkify from 'react-linkify'; +import { SortOrder } from 'antd/lib/table/interface'; +import format from 'date-fns/format'; const { Title } = Typography; function renderColumnLevel(text, entry) { let color = 'black'; - if (entry.level === "warning") { - color = "orange"; + if (entry.level === 'warning') { + color = 'orange'; } else if (entry.level === 'error') { - color = "red"; + color = 'red'; } return {text}; } function renderMessage(text) { - return ( - {text} - ) + return {text}; } interface Props { - logs: object[], - pageSize: number + logs: object[]; + pageSize: number; } export default function LogTable({ logs, pageSize }: Props) { @@ -35,42 +33,42 @@ export default function LogTable({ logs, pageSize }: Props) { } const columns = [ { - title: "Level", - dataIndex: "level", - key: "level", + title: 'Level', + dataIndex: 'level', + key: 'level', filters: [ { - text: "Info", - value: "info", + text: 'Info', + value: 'info', }, { - text: "Warning", - value: "warning", + text: 'Warning', + value: 'warning', }, { - text: "Error", - value: "Error", + text: 'Error', + value: 'Error', }, ], onFilter: (level, row) => row.level.indexOf(level) === 0, render: renderColumnLevel, }, { - title: "Timestamp", - dataIndex: "time", - key: "time", - render: (timestamp) => { + title: 'Timestamp', + dataIndex: 'time', + key: 'time', + render: timestamp => { const dateObject = new Date(timestamp); return format(dateObject, 'p P'); }, sorter: (a, b) => new Date(a.time).getTime() - new Date(b.time).getTime(), - sortDirections: ["descend", "ascend"] as SortOrder[], - defaultSortOrder: "descend" as SortOrder, + sortDirections: ['descend', 'ascend'] as SortOrder[], + defaultSortOrder: 'descend' as SortOrder, }, { - title: "Message", - dataIndex: "message", - key: "message", + title: 'Message', + dataIndex: 'message', + key: 'message', render: renderMessage, }, ]; @@ -82,10 +80,9 @@ export default function LogTable({ logs, pageSize }: Props) { size="middle" dataSource={logs} columns={columns} - rowKey={(row) => row.time} + rowKey={row => row.time} pagination={{ pageSize: pageSize || 20 }} />
); } - diff --git a/web/pages/components/message-visiblity-toggle.tsx b/web/pages/components/message-visiblity-toggle.tsx index c202e8d1e..bd4fdf64c 100644 --- a/web/pages/components/message-visiblity-toggle.tsx +++ b/web/pages/components/message-visiblity-toggle.tsx @@ -1,20 +1,28 @@ -// Custom component for AntDesign Button that makes an api call, then displays a confirmation icon upon -import React, { useState, useEffect } from "react"; -import { Button, Tooltip } from "antd"; -import { EyeOutlined, EyeInvisibleOutlined, CheckCircleFilled, ExclamationCircleFilled } from "@ant-design/icons"; -import { fetchData, UPDATE_CHAT_MESSGAE_VIZ } from "../../utils/apis"; +// Custom component for AntDesign Button that makes an api call, then displays a confirmation icon upon +import React, { useState, useEffect } from 'react'; +import { Button, Tooltip } from 'antd'; +import { + EyeOutlined, + EyeInvisibleOutlined, + CheckCircleFilled, + ExclamationCircleFilled, +} from '@ant-design/icons'; +import { fetchData, UPDATE_CHAT_MESSGAE_VIZ } from '../../utils/apis'; import { MessageType } from '../../types/chat'; -import { OUTCOME_TIMEOUT } from "../chat"; -import { isEmptyObject } from "../../utils/format"; +import { OUTCOME_TIMEOUT } from '../chat'; +import { isEmptyObject } from '../../utils/format'; interface MessageToggleProps { isVisible: boolean; message: MessageType; - setMessage: (message: MessageType) => void, -}; + setMessage: (message: MessageType) => void; +} - -export default function MessageVisiblityToggle({ isVisible, message, setMessage }: MessageToggleProps) { +export default function MessageVisiblityToggle({ + isVisible, + message, + setMessage, +}: MessageToggleProps) { if (!message || isEmptyObject(message)) { return null; } @@ -25,16 +33,17 @@ export default function MessageVisiblityToggle({ isVisible, message, setMessage const { id: messageId } = message || {}; const resetOutcome = () => { - outcomeTimeout = setTimeout(() => { setOutcome(0)}, OUTCOME_TIMEOUT); + outcomeTimeout = setTimeout(() => { + setOutcome(0); + }, OUTCOME_TIMEOUT); }; - + useEffect(() => { return () => { clearTimeout(outcomeTimeout); }; }); - const updateChatMessage = async () => { clearTimeout(outcomeTimeout); setOutcome(0); @@ -47,7 +56,7 @@ export default function MessageVisiblityToggle({ isVisible, message, setMessage }, }); - if (result.success && result.message === "changed") { + if (result.success && result.message === 'changed') { setMessage({ ...message, visible: !isVisible }); setOutcome(1); } else { @@ -55,14 +64,16 @@ export default function MessageVisiblityToggle({ isVisible, message, setMessage setOutcome(-1); } resetOutcome(); - } - + }; let outcomeIcon = ; if (outcome) { - outcomeIcon = outcome > 0 ? - : - ; + outcomeIcon = + outcome > 0 ? ( + + ) : ( + + ); } const toolTipMessage = `Click to ${isVisible ? 'hide' : 'show'} this message`; @@ -74,10 +85,10 @@ export default function MessageVisiblityToggle({ isVisible, message, setMessage shape="circle" size="small" type="text" - icon={ isVisible ? : } + icon={isVisible ? : } onClick={updateChatMessage} />
); -} \ No newline at end of file +} diff --git a/web/pages/components/statistic.tsx b/web/pages/components/statistic.tsx index 62383efe1..a6edd9da9 100644 --- a/web/pages/components/statistic.tsx +++ b/web/pages/components/statistic.tsx @@ -1,18 +1,18 @@ -import { Typography, Statistic, Card, Progress} from "antd"; +import { Typography, Statistic, Card, Progress } from 'antd'; const { Text } = Typography; interface StatisticItemProps { - title?: string, - value?: any, - prefix?: JSX.Element, - color?: string, - progress?: boolean, - centered?: boolean, - formatter?: any, -}; + title?: string; + value?: any; + prefix?: JSX.Element; + color?: string; + progress?: boolean; + centered?: boolean; + formatter?: any; +} const defaultProps = { - title: '', + title: '', value: 0, prefix: null, color: '', @@ -21,16 +21,19 @@ const defaultProps = { formatter: null, }; - function ProgressView({ title, value, prefix, color }: StatisticItemProps) { const endColor = value > 90 ? 'red' : color; const content = (
- {prefix} -
{title}
-
{value}%
+ {prefix} +
+ {title} +
+
+ {value}% +
- ) + ); return ( content} /> - ) + ); } ProgressView.defaultProps = defaultProps; function StatisticView({ title, value, prefix, formatter }: StatisticItemProps) { - return ( - - ); + return ; } StatisticView.defaultProps = defaultProps; @@ -62,14 +58,14 @@ export default function StatisticItem(props: StatisticItemProps) { const { progress, centered } = props; const View = progress ? ProgressView : StatisticView; - const style = centered ? {display: 'flex', alignItems: 'center', justifyContent: 'center'} : {}; + const style = centered ? { display: 'flex', alignItems: 'center', justifyContent: 'center' } : {}; return ( - -
- -
-
+ +
+ +
+
); } StatisticItem.defaultProps = defaultProps; diff --git a/web/styles/styles.module.scss b/web/styles/styles.module.scss deleted file mode 100644 index 2e4b99bfb..000000000 --- a/web/styles/styles.module.scss +++ /dev/null @@ -1,95 +0,0 @@ - -.owncastTitleContainer { - padding: 1rem; - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - -} -.logoContainer { - background-color: #fff; - padding: .35rem; - border-radius: 9999px; -} -.owncastTitle { - 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; -} - -.contentMain { - padding: 3em; -} - -.header { - display: flex; - flex-direction: row; - justify-content: flex-end; - padding-right: 1rem; -} - -.sideNav { - position: fixed; - height: 100vh; - overflow: auto; - z-index: 10; -} - -.layoutMain { - margin-left: 240px; -} - -.statusIndicatorContainer { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - -} -.statusIcon { - font-size: 1.5rem; -} -.statusIcon svg { - fill: #999; -} -.statusLabel { - color: #fff; - text-transform: uppercase; - font-size: .75rem; - display: inline-block; - margin-right: .5rem; - color: #999; -} -.online .statusIcon svg { - fill: var(--online-color) -} -.online .statusLabel { - color: var(--online-color) -} - - -.lineChartContainer { - margin: 2em auto; -} - -.configSection { - margin-bottom: 2em; -} - -.onlineCurrentThumb { - width: 12.5rem; -} - -.globalStreamTitleContainer { - display: flex; - justify-content: center; - align-items: baseline; - width: 100%; - height: 100%; -}