cleanup some forms; break out major config styles into their own files
This commit is contained in:
@@ -3,10 +3,18 @@ import '../styles/colors.scss';
|
|||||||
import '../styles/globals.scss';
|
import '../styles/globals.scss';
|
||||||
import '../styles/ant-overrides.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/home.scss';
|
||||||
import '../styles/chat.scss';
|
import '../styles/chat.scss';
|
||||||
import '../styles/config.scss';
|
import '../styles/config.scss';
|
||||||
import '../styles/config-formfields.scss';
|
|
||||||
|
|
||||||
import { AppProps } from 'next/app';
|
import { AppProps } from 'next/app';
|
||||||
import ServerStatusProvider from '../utils/server-status-context';
|
import ServerStatusProvider from '../utils/server-status-context';
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ export default function CPUUsageSelector({ defaultValue, onChange }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-container config-video-segements-conatiner">
|
<div className="config-video-segements-conatiner">
|
||||||
<Title level={3}>CPU Usage</Title>
|
<Title level={3}>CPU Usage</Title>
|
||||||
<p>There are trade-offs when considering CPU usage blah blah more wording here.</p>
|
<p>There are trade-offs when considering CPU usage blah blah more wording here.</p>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div className="segment-slider">
|
<div className="segment-slider-container">
|
||||||
<Slider
|
<Slider
|
||||||
tipFormatter={value => TOOLTIPS[value]}
|
tipFormatter={value => TOOLTIPS[value]}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ export default function EditInstanceDetails() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const showConfigurationRestartMessage = () => {
|
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() {
|
function generateStreamKey() {
|
||||||
let key = '';
|
let key = '';
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ export default function EditSocialLinks() {
|
|||||||
postUpdateToAPI(postData);
|
postUpdateToAPI(postData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteItem = index => {
|
const handleDeleteItem = (index: number) => {
|
||||||
const postData = [...currentSocialHandles];
|
const postData = [...currentSocialHandles];
|
||||||
postData.splice(index, 1);
|
postData.splice(index, 1);
|
||||||
postUpdateToAPI(postData);
|
postUpdateToAPI(postData);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Switch, Button, Collapse, Alert } from 'antd';
|
import { Switch, Button, Collapse } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { useContext, useState, useEffect } from 'react';
|
import React, { useContext, useState, useEffect } from 'react';
|
||||||
import { UpdateArgs } from '../../../types/config-section';
|
import { UpdateArgs } from '../../../types/config-section';
|
||||||
@@ -52,13 +52,12 @@ function checkSaveable(formValues: any, currentValues: any) {
|
|||||||
export default function EditStorage() {
|
export default function EditStorage() {
|
||||||
const [formDataValues, setFormDataValues] = useState(null);
|
const [formDataValues, setFormDataValues] = useState(null);
|
||||||
const [submitStatus, setSubmitStatus] = useState<StatusState>(null);
|
const [submitStatus, setSubmitStatus] = useState<StatusState>(null);
|
||||||
const [saved, setSaved] = useState<Boolean>(false);
|
|
||||||
|
|
||||||
const [shouldDisplayForm, setShouldDisplayForm] = useState(false);
|
const [shouldDisplayForm, setShouldDisplayForm] = useState(false);
|
||||||
const serverStatusData = useContext(ServerStatusContext);
|
const serverStatusData = useContext(ServerStatusContext);
|
||||||
const { serverConfig, setFieldInConfigState } = serverStatusData || {};
|
const { serverConfig, setFieldInConfigState } = serverStatusData || {};
|
||||||
|
|
||||||
const {message, setMessage} = useContext(AlertMessageContext);
|
const { setMessage: setAlertMessage } = useContext(AlertMessageContext);
|
||||||
|
|
||||||
const { s3 } = serverConfig;
|
const { s3 } = serverConfig;
|
||||||
const {
|
const {
|
||||||
@@ -117,8 +116,9 @@ export default function EditStorage() {
|
|||||||
setFieldInConfigState({ fieldName: 's3', value: postValue, path: '' });
|
setFieldInConfigState({ fieldName: 's3', value: postValue, path: '' });
|
||||||
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.'));
|
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.'));
|
||||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||||
setSaved(true);
|
setAlertMessage(
|
||||||
setMessage('Changing your storage configuration will take place the next time you start a new stream.');
|
'Changing your storage configuration will take place the next time you start a new stream.',
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onError: (message: string) => {
|
onError: (message: string) => {
|
||||||
setSubmitStatus(createInputStatus(STATUS_ERROR, message));
|
setSubmitStatus(createInputStatus(STATUS_ERROR, message));
|
||||||
@@ -131,12 +131,6 @@ export default function EditStorage() {
|
|||||||
const handleSwitchChange = (storageEnabled: boolean) => {
|
const handleSwitchChange = (storageEnabled: boolean) => {
|
||||||
setShouldDisplayForm(storageEnabled);
|
setShouldDisplayForm(storageEnabled);
|
||||||
handleFieldChange({ fieldName: 'enabled', value: 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({
|
const containerClass = classNames({
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ interface DropdownProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function SocialDropdown({ iconList, selectedOption, onSelected }: DropdownProps) {
|
export default function SocialDropdown({ iconList, selectedOption, onSelected }: DropdownProps) {
|
||||||
const handleSelected = value => {
|
const handleSelected = (value: string) => {
|
||||||
if (onSelected) {
|
if (onSelected) {
|
||||||
onSelected(value);
|
onSelected(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import React, { useContext, useState, useEffect } from 'react';
|
import React, { useContext, useState, useEffect } from 'react';
|
||||||
import { Typography, Slider } from 'antd';
|
import { Typography, Slider } from 'antd';
|
||||||
import { ServerStatusContext } from '../../../utils/server-status-context';
|
import { ServerStatusContext } from '../../../utils/server-status-context';
|
||||||
|
import { API_VIDEO_SEGMENTS, RESET_TIMEOUT, postConfigUpdateToAPI } from './constants';
|
||||||
import {
|
import {
|
||||||
API_VIDEO_SEGMENTS,
|
createInputStatus,
|
||||||
SUCCESS_STATES,
|
StatusState,
|
||||||
RESET_TIMEOUT,
|
STATUS_ERROR,
|
||||||
postConfigUpdateToAPI,
|
STATUS_PROCESSING,
|
||||||
} from './constants';
|
STATUS_SUCCESS,
|
||||||
|
} from '../../../utils/input-statuses';
|
||||||
|
import FormStatusIndicator from './form-status-indicator';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
@@ -37,8 +40,10 @@ function SegmentToolTip({ value }: SegmentToolTipProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function VideoLatency() {
|
export default function VideoLatency() {
|
||||||
const [submitStatus, setSubmitStatus] = useState(null);
|
const [submitStatus, setSubmitStatus] = useState<StatusState>(null);
|
||||||
const [submitStatusMessage, setSubmitStatusMessage] = useState('');
|
|
||||||
|
// const [submitStatus, setSubmitStatus] = useState(null);
|
||||||
|
// const [submitStatusMessage, setSubmitStatusMessage] = useState('');
|
||||||
const [selectedOption, setSelectedOption] = useState(null);
|
const [selectedOption, setSelectedOption] = useState(null);
|
||||||
|
|
||||||
const serverStatusData = useContext(ServerStatusContext);
|
const serverStatusData = useContext(ServerStatusContext);
|
||||||
@@ -57,13 +62,15 @@ export default function VideoLatency() {
|
|||||||
|
|
||||||
const resetStates = () => {
|
const resetStates = () => {
|
||||||
setSubmitStatus(null);
|
setSubmitStatus(null);
|
||||||
setSubmitStatusMessage('');
|
// setSubmitStatusMessage('');
|
||||||
resetTimer = null;
|
resetTimer = null;
|
||||||
clearTimeout(resetTimer);
|
clearTimeout(resetTimer);
|
||||||
};
|
};
|
||||||
|
|
||||||
// posts all the variants at once as an array obj
|
// posts all the variants at once as an array obj
|
||||||
const postUpdateToAPI = async (postValue: any) => {
|
const postUpdateToAPI = async (postValue: any) => {
|
||||||
|
setSubmitStatus(createInputStatus(STATUS_PROCESSING));
|
||||||
|
|
||||||
await postConfigUpdateToAPI({
|
await postConfigUpdateToAPI({
|
||||||
apiPath: API_VIDEO_SEGMENTS,
|
apiPath: API_VIDEO_SEGMENTS,
|
||||||
data: { value: postValue },
|
data: { value: postValue },
|
||||||
@@ -73,34 +80,28 @@ export default function VideoLatency() {
|
|||||||
value: postValue,
|
value: postValue,
|
||||||
path: 'videoSettings',
|
path: 'videoSettings',
|
||||||
});
|
});
|
||||||
|
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Variants updated.'));
|
||||||
|
|
||||||
setSubmitStatus('success');
|
// setSubmitStatus('success');
|
||||||
setSubmitStatusMessage('Variants updated.');
|
// setSubmitStatusMessage('Variants updated.');
|
||||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||||
},
|
},
|
||||||
onError: (message: string) => {
|
onError: (message: string) => {
|
||||||
setSubmitStatus('error');
|
setSubmitStatus(createInputStatus(STATUS_ERROR, message));
|
||||||
setSubmitStatusMessage(message);
|
|
||||||
|
// setSubmitStatus('error');
|
||||||
|
// setSubmitStatusMessage(message);
|
||||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const { icon: newStatusIcon = null, message: newStatusMessage = '' } =
|
|
||||||
SUCCESS_STATES[submitStatus] || {};
|
|
||||||
|
|
||||||
const statusMessage = (
|
|
||||||
<div className={`status-message ${submitStatus || ''}`}>
|
|
||||||
{newStatusIcon} {newStatusMessage} {submitStatusMessage}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleChange = value => {
|
const handleChange = value => {
|
||||||
postUpdateToAPI(value);
|
postUpdateToAPI(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-container config-video-segements-conatiner">
|
<div className="config-video-segements-conatiner">
|
||||||
<Title level={3}>Latency Buffer</Title>
|
<Title level={3}>Latency Buffer</Title>
|
||||||
<p>
|
<p>
|
||||||
There are trade-offs when cosidering video latency and reliability. Blah blah .. better
|
There are trade-offs when cosidering video latency and reliability. Blah blah .. better
|
||||||
@@ -108,7 +109,7 @@ export default function VideoLatency() {
|
|||||||
</p>
|
</p>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div className="segment-slider">
|
<div className="segment-slider-container">
|
||||||
<Slider
|
<Slider
|
||||||
tipFormatter={value => <SegmentToolTip value={SLIDER_COMMENTS[value]} />}
|
tipFormatter={value => <SegmentToolTip value={SLIDER_COMMENTS[value]} />}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
@@ -119,7 +120,7 @@ export default function VideoLatency() {
|
|||||||
value={selectedOption}
|
value={selectedOption}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{statusMessage}
|
<FormStatusIndicator status={submitStatus} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
// This content populates the video variant modal, which is spawned from the variants table.
|
// This content populates the video variant modal, which is spawned from the variants table.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Slider, Select, Switch, Divider, Collapse } from 'antd';
|
import { Slider, Switch, Collapse } from 'antd';
|
||||||
import { FieldUpdaterFunc, CpuUsageLevel, VideoVariant } from '../../../types/config-section';
|
import { FieldUpdaterFunc, VideoVariant } from '../../../types/config-section';
|
||||||
import { DEFAULT_VARIANT_STATE } from './constants';
|
import { DEFAULT_VARIANT_STATE } from './constants';
|
||||||
import InfoTip from '../info-tip';
|
import InfoTip from '../info-tip';
|
||||||
import CPUUsageSelector from './cpu-usage';
|
import CPUUsageSelector from './cpu-usage';
|
||||||
|
|
||||||
const { Option } = Select;
|
|
||||||
const { Panel } = Collapse;
|
const { Panel } = Collapse;
|
||||||
|
|
||||||
const VIDEO_VARIANT_DEFAULTS = {
|
const VIDEO_VARIANT_DEFAULTS = {
|
||||||
@@ -57,12 +56,6 @@ export default function VideoVariantForm({
|
|||||||
const handleVideoBitrateChange = (value: number) => {
|
const handleVideoBitrateChange = (value: number) => {
|
||||||
onUpdateField({ fieldName: 'videoBitrate', value });
|
onUpdateField({ fieldName: 'videoBitrate', value });
|
||||||
};
|
};
|
||||||
const handleAudioBitrateChange = (value: number) => {
|
|
||||||
onUpdateField({ fieldName: 'audioBitrate', value });
|
|
||||||
};
|
|
||||||
const handleAudioPassChange = (value: boolean) => {
|
|
||||||
onUpdateField({ fieldName: 'audioPassthrough', value });
|
|
||||||
};
|
|
||||||
const handleVideoPassChange = (value: boolean) => {
|
const handleVideoPassChange = (value: boolean) => {
|
||||||
onUpdateField({ fieldName: 'videoPassthrough', value });
|
onUpdateField({ fieldName: 'videoPassthrough', value });
|
||||||
};
|
};
|
||||||
@@ -80,18 +73,12 @@ export default function VideoVariantForm({
|
|||||||
const videoBRMax = videoBitrateDefaults.max;
|
const videoBRMax = videoBitrateDefaults.max;
|
||||||
const videoBRUnit = videoBitrateDefaults.unit;
|
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 selectedVideoBRnote = `Selected: ${dataState.videoBitrate}${videoBRUnit} - it sucks`;
|
||||||
const selectedAudioBRnote = `Selected: ${dataState.audioBitrate}${audioBRUnit} - too slow`;
|
|
||||||
const selectedFramerateNote = `Selected: ${dataState.framerate}${framerateUnit} - whoa there`;
|
const selectedFramerateNote = `Selected: ${dataState.framerate}${framerateUnit} - whoa there`;
|
||||||
const selectedPresetNote = '';
|
const selectedPresetNote = '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="variant-form">
|
<div className="config-variant-form">
|
||||||
<div className="section-intro">
|
<div className="section-intro">
|
||||||
Say a thing here about how this all works. Read more{' '}
|
Say a thing here about how this all works. Read more{' '}
|
||||||
<a href="https://owncast.online/docs/configuration/">here</a>.
|
<a href="https://owncast.online/docs/configuration/">here</a>.
|
||||||
@@ -130,6 +117,7 @@ export default function VideoVariantForm({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* VIDEO BITRATE FIELD */}
|
{/* VIDEO BITRATE FIELD */}
|
||||||
<div className={`field ${dataState.videoPassthrough ? 'disabled' : ''}`}>
|
<div className={`field ${dataState.videoPassthrough ? 'disabled' : ''}`}>
|
||||||
<p className="label">
|
<p className="label">
|
||||||
@@ -192,55 +180,6 @@ export default function VideoVariantForm({
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{/* AUDIO PASSTHROUGH FIELD */}
|
|
||||||
{/* <div className="field">
|
|
||||||
<p className="label">
|
|
||||||
<InfoTip tip={VIDEO_VARIANT_DEFAULTS.audioPassthrough.tip} />
|
|
||||||
Use Audio Passthrough?
|
|
||||||
</p>
|
|
||||||
<div className="form-component">
|
|
||||||
<Switch
|
|
||||||
defaultChecked={dataState.audioPassthrough}
|
|
||||||
checked={dataState.audioPassthrough}
|
|
||||||
onChange={handleAudioPassChange}
|
|
||||||
checkedChildren="Yes"
|
|
||||||
unCheckedChildren="No"
|
|
||||||
/>
|
|
||||||
{dataState.audioPassthrough ? <span className="note">Same as source</span> : null}
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
|
|
||||||
{/* AUDIO BITRATE FIELD */}
|
|
||||||
{/* <div className={`field ${dataState.audioPassthrough ? 'disabled' : ''}`}>
|
|
||||||
<p className="label">
|
|
||||||
<InfoTip tip={VIDEO_VARIANT_DEFAULTS.audioBitrate.tip} />
|
|
||||||
Audio Bitrate:
|
|
||||||
</p>
|
|
||||||
<div className="form-component">
|
|
||||||
<Slider
|
|
||||||
// tooltipVisible={dataState.audioPassthrough !== true}
|
|
||||||
tipFormatter={value => `${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 ? (
|
|
||||||
<span className="selected-value-note">{selectedAudioBRnote}</span>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
</Panel>
|
</Panel>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Updating a variant will post ALL the variants in an array as an update to the API.
|
// 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 React, { useContext, useState } from 'react';
|
||||||
import { Typography, Table, Modal, Button } from 'antd';
|
import { Typography, Table, Modal, Button } from 'antd';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
@@ -20,6 +19,14 @@ import {
|
|||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
|
const CPU_USAGE_LEVEL_MAP = {
|
||||||
|
1: 'lowest',
|
||||||
|
2: 'low',
|
||||||
|
3: 'medium',
|
||||||
|
4: 'high',
|
||||||
|
5: 'highest',
|
||||||
|
};
|
||||||
|
|
||||||
export default function CurrentVariantsTable() {
|
export default function CurrentVariantsTable() {
|
||||||
const [displayModal, setDisplayModal] = useState(false);
|
const [displayModal, setDisplayModal] = useState(false);
|
||||||
const [modalProcessing, setModalProcessing] = useState(false);
|
const [modalProcessing, setModalProcessing] = useState(false);
|
||||||
@@ -76,7 +83,9 @@ export default function CurrentVariantsTable() {
|
|||||||
setSubmitStatusMessage('Variants updated.');
|
setSubmitStatusMessage('Variants updated.');
|
||||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
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) => {
|
onError: (message: string) => {
|
||||||
setSubmitStatus('error');
|
setSubmitStatus('error');
|
||||||
@@ -117,14 +126,6 @@ export default function CurrentVariantsTable() {
|
|||||||
const { icon: newStatusIcon = null, message: newStatusMessage = '' } =
|
const { icon: newStatusIcon = null, message: newStatusMessage = '' } =
|
||||||
SUCCESS_STATES[submitStatus] || {};
|
SUCCESS_STATES[submitStatus] || {};
|
||||||
|
|
||||||
const cpuUsageLevelLabelMap = {
|
|
||||||
1: 'lowest',
|
|
||||||
2: 'low',
|
|
||||||
3: 'medium',
|
|
||||||
4: 'high',
|
|
||||||
5: 'highest',
|
|
||||||
};
|
|
||||||
|
|
||||||
const videoQualityColumns: ColumnsType<VideoVariant> = [
|
const videoQualityColumns: ColumnsType<VideoVariant> = [
|
||||||
{
|
{
|
||||||
title: 'Video bitrate',
|
title: 'Video bitrate',
|
||||||
@@ -137,7 +138,7 @@ export default function CurrentVariantsTable() {
|
|||||||
title: 'CPU Usage',
|
title: 'CPU Usage',
|
||||||
dataIndex: 'cpuUsageLevel',
|
dataIndex: 'cpuUsageLevel',
|
||||||
key: 'cpuUsageLevel',
|
key: 'cpuUsageLevel',
|
||||||
render: (level: string) => (!level ? 'n/a' : cpuUsageLevelLabelMap[level]),
|
render: (level: string) => (!level ? 'n/a' : CPU_USAGE_LEVEL_MAP[level]),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '',
|
title: '',
|
||||||
|
|||||||
25
web/styles/config-socialhandles.scss
Normal file
25
web/styles/config-socialhandles.scss
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
web/styles/config-storage.scss
Normal file
49
web/styles/config-storage.scss
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
web/styles/config-tags.scss
Normal file
37
web/styles/config-tags.scss
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
85
web/styles/config-video-variants.scss
Normal file
85
web/styles/config-video-variants.scss
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 {
|
.config-page-content-form {
|
||||||
.page-content-actions {
|
.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 {
|
.segment-tip {
|
||||||
width: 10em;
|
width: 10em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -276,33 +27,6 @@
|
|||||||
display: inline-block;
|
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 {
|
// .social-option {
|
||||||
// .ant-select-item-option-content {
|
// .ant-select-item-option-content {
|
||||||
// display: flex;
|
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
64
web/styles/form-misc-elements.scss
Normal file
64
web/styles/form-misc-elements.scss
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,37 +1,4 @@
|
|||||||
// Base styles for form-textfield, form-textfield-with-submit, and helper components.
|
// Base styles for form-textfield, form-textfield-with-submit
|
||||||
|
|
||||||
/* 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* TEXTFIELD-CONTAINER BASE */
|
/* 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 BASE */
|
||||||
.textfield-with-submit-container {
|
.textfield-with-submit-container {
|
||||||
display: flex;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
web/styles/form-toggleswitch.scss
Normal file
29
web/styles/form-toggleswitch.scss
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export const AlertMessageContext = React.createContext({
|
export const AlertMessageContext = React.createContext({
|
||||||
message: null,
|
message: null,
|
||||||
setMessage: (text?: string) => {
|
setMessage: (text?: string) => {
|
||||||
return text;
|
return text;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const AlertMessageProvider = ({ children }) => {
|
const AlertMessageProvider = ({ children }) => {
|
||||||
@@ -13,15 +13,15 @@ const AlertMessageProvider = ({ children }) => {
|
|||||||
|
|
||||||
const providerValue = {
|
const providerValue = {
|
||||||
message,
|
message,
|
||||||
setMessage
|
setMessage,
|
||||||
}
|
};
|
||||||
return (
|
return (
|
||||||
<AlertMessageContext.Provider value={providerValue}>{children}</AlertMessageContext.Provider>
|
<AlertMessageContext.Provider value={providerValue}>{children}</AlertMessageContext.Provider>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
AlertMessageProvider.propTypes = {
|
AlertMessageProvider.propTypes = {
|
||||||
children: PropTypes.element.isRequired
|
children: PropTypes.element.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlertMessageProvider;
|
export default AlertMessageProvider;
|
||||||
Reference in New Issue
Block a user