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;