hella cleanup - index page items; use more Row/Cols to reduce custom css layout

This commit is contained in:
gingervitis
2021-02-14 22:20:25 -08:00
parent 6d83992ff0
commit 8d5411a0d6
17 changed files with 250 additions and 297 deletions

View File

@@ -42,3 +42,5 @@ There are also a variety of other local states to manage the display of error/su
segment-slider-container
selected-value-note

View File

@@ -221,6 +221,19 @@ export default function EditSocialLinks() {
disabled: !isValidUrl(modalDataState.url), disabled: !isValidUrl(modalDataState.url),
}; };
const otherField = (
<div className="other-field-container formfield-container">
<div className="label-side" />
<div className="input-side">
<Input
placeholder="Other platform name"
defaultValue={modalDataState.platform}
onChange={handleOtherNameChange}
/>
</div>
</div>
);
return ( return (
<div className="social-links-edit-container"> <div className="social-links-edit-container">
<Title level={3} className="section-title"> <Title level={3} className="section-title">
@@ -249,21 +262,13 @@ export default function EditSocialLinks() {
confirmLoading={modalProcessing} confirmLoading={modalProcessing}
okButtonProps={okButtonProps} okButtonProps={okButtonProps}
> >
<div className="social-handle-modal-content">
<SocialDropdown <SocialDropdown
iconList={availableIconsList} iconList={availableIconsList}
selectedOption={selectedOther ? OTHER_SOCIAL_HANDLE_OPTION : modalDataState.platform} selectedOption={selectedOther ? OTHER_SOCIAL_HANDLE_OPTION : modalDataState.platform}
onSelected={handleDropdownSelect} onSelected={handleDropdownSelect}
/> />
{displayOther ? ( {displayOther && otherField}
<>
<Input
placeholder="Other"
defaultValue={modalDataState.platform}
onChange={handleOtherNameChange}
/>
<br />
</>
) : null}
<br /> <br />
<TextField <TextField
fieldName="social-url" fieldName="social-url"
@@ -273,6 +278,7 @@ export default function EditSocialLinks() {
onChange={handleUrlChange} onChange={handleUrlChange}
/> />
<FormStatusIndicator status={submitStatus} /> <FormStatusIndicator status={submitStatus} />
</div>
</Modal> </Modal>
<br /> <br />
<Button <Button

View File

@@ -23,12 +23,12 @@ export default function SocialDropdown({ iconList, selectedOption, onSelected }:
If you are looking for a platform name not on this list, please select Other and type in If you are looking for a platform name not on this list, please select Other and type in
your own name. A logo will not be provided. your own name. A logo will not be provided.
</p> </p>
<p className="description">
If you DO have a logo, drop it in to the <code>/webroot/img/platformicons</code> directory
and update the <code>/socialHandle.go</code> list. Then restart the server and it will show
up in the list.
</p>
<div className="formfield-container">
<div className="label-side">
<span className="formfield-label">Social Platform</span>
</div>
<div className="input-side">
<Select <Select
style={{ width: 240 }} style={{ width: 240 }}
className="social-dropdown" className="social-dropdown"
@@ -57,5 +57,7 @@ export default function SocialDropdown({ iconList, selectedOption, onSelected }:
</Select.Option> </Select.Option>
</Select> </Select>
</div> </div>
</div>
</div>
); );
} }

View File

@@ -156,7 +156,7 @@ export default function VideoVariantForm({
</p> </p>
<Row gutter={16}> <Row gutter={16}>
<Col xs={12} xl={12}> <Col sm={24} md={12}>
{/* ENCODER PRESET FIELD */} {/* ENCODER PRESET FIELD */}
<div className="form-module cpu-usage-container"> <div className="form-module cpu-usage-container">
<CPUUsageSelector <CPUUsageSelector
@@ -177,7 +177,7 @@ export default function VideoVariantForm({
</div> </div>
</Col> </Col>
<Col xs={12} xl={12}> <Col sm={24} md={12}>
{/* VIDEO BITRATE FIELD */} {/* VIDEO BITRATE FIELD */}
<div <div
className={`form-module bitrate-container ${ className={`form-module bitrate-container ${

View File

@@ -75,7 +75,7 @@ export default function LogTable({ logs, pageSize }: Props) {
return ( return (
<div className="logs-section"> <div className="logs-section">
<Title level={2}>Logs</Title> <Title>Logs</Title>
<Table <Table
size="middle" size="middle"
dataSource={logs} dataSource={logs}

View File

@@ -194,7 +194,7 @@ export default function MainLayout(props) {
<TextFieldWithSubmit <TextFieldWithSubmit
fieldName="streamTitle" fieldName="streamTitle"
{...TEXTFIELD_PROPS_STREAM_TITLE} {...TEXTFIELD_PROPS_STREAM_TITLE}
placeholder="What you're streaming right now" placeholder="What are you streaming now"
value={currentStreamTitle} value={currentStreamTitle}
initialValue={instanceDetails.streamTitle} initialValue={instanceDetails.streamTitle}
onChange={handleStreamTitleChanged} onChange={handleStreamTitleChanged}

View File

@@ -202,7 +202,7 @@ export default function Chat() {
return ( return (
<div className="chat-messages"> <div className="chat-messages">
<Title level={2}>Chat Messages</Title> <Title>Chat Messages</Title>
<p>Manage the messages from viewers that show up on your stream.</p> <p>Manage the messages from viewers that show up on your stream.</p>
<div className={bulkDivClasses}> <div className={bulkDivClasses}>
<span className="label">Check multiple messages to change their visibility to: </span> <span className="label">Check multiple messages to change their visibility to: </span>

View File

@@ -16,13 +16,13 @@ export default function ConfigVideoSettings() {
how it impacts your stream performance. how it impacts your stream performance.
</p> </p>
<Row gutter={16}> <Row gutter={[16, 16]}>
<Col xl={12}> <Col md={24} lg={12}>
<div className="form-module variants-table-module"> <div className="form-module variants-table-module">
<VideoVariantsTable /> <VideoVariantsTable />
</div> </div>
</Col> </Col>
<Col xl={12}> <Col md={24} lg={12}>
<div className="form-module latency-module"> <div className="form-module latency-module">
<VideoLatency /> <VideoLatency />
</div> </div>

View File

@@ -1,5 +1,5 @@
import { BulbOutlined, LaptopOutlined, SaveOutlined } from '@ant-design/icons'; import { BulbOutlined, LaptopOutlined, SaveOutlined } from '@ant-design/icons';
import { Row } from 'antd'; import { Row, Typography } from 'antd';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { fetchData, FETCH_INTERVAL, HARDWARE_STATS } from '../utils/apis'; import { fetchData, FETCH_INTERVAL, HARDWARE_STATS } from '../utils/apis';
import Chart from '../components/chart'; import Chart from '../components/chart';
@@ -67,6 +67,8 @@ export default function HardwareInfo() {
return ( return (
<div> <div>
<Typography.Title>Hardware Info</Typography.Title>
<br />
<div> <div>
<Row gutter={[16, 16]} justify="space-around"> <Row gutter={[16, 16]} justify="space-around">
<StatisticItem <StatisticItem

View File

@@ -1,24 +1,13 @@
/*
Will display an overview with the following datasources:
1. Current broadcaster.
2. Viewer count.
3. Video settings.
TODO: Link each overview value to the sub-page that focuses on it.
*/
import React, { useState, useEffect, useContext } from 'react'; import React, { useState, useEffect, useContext } from 'react';
import { Skeleton, Card, Statistic } from 'antd'; import { Skeleton, Card, Statistic, Row, Col } from 'antd';
import { UserOutlined, ClockCircleOutlined } from '@ant-design/icons'; import { UserOutlined, ClockCircleOutlined } from '@ant-design/icons';
import { formatDistanceToNow, formatRelative } from 'date-fns'; import { formatDistanceToNow, formatRelative } from 'date-fns';
import { ServerStatusContext } from '../utils/server-status-context'; import { ServerStatusContext } from '../utils/server-status-context';
import StatisticItem from '../components/statistic';
import LogTable from '../components/log-table'; import LogTable from '../components/log-table';
import Offline from './offline-notice'; import Offline from './offline-notice';
import { LOGS_WARN, fetchData, FETCH_INTERVAL } from '../utils/apis'; import { LOGS_WARN, fetchData, FETCH_INTERVAL } from '../utils/apis';
import { formatIPAddress, isEmptyObject } from '../utils/format'; import { formatIPAddress, isEmptyObject } from '../utils/format';
import { UpdateArgs } from '../types/config-section';
function streamDetailsFormatter(streamDetails) { function streamDetailsFormatter(streamDetails) {
return ( return (
@@ -80,8 +69,7 @@ export default function Home() {
} }
// map out settings // map out settings
const videoQualitySettings = serverStatusData?.currentBroadcast?.outputSettings?.map( const videoQualitySettings = serverStatusData?.currentBroadcast?.outputSettings?.map(setting => {
(setting, index) => {
const { audioPassthrough, videoPassthrough, audioBitrate, videoBitrate, framerate } = setting; const { audioPassthrough, videoPassthrough, audioBitrate, videoBitrate, framerate } = setting;
const audioSetting = audioPassthrough const audioSetting = audioPassthrough
@@ -94,17 +82,21 @@ export default function Home() {
} x ${streamDetails.height}` } x ${streamDetails.height}`
: `${videoBitrate || 'Unknown'} kbps, ${framerate} fps`; : `${videoBitrate || 'Unknown'} kbps, ${framerate} fps`;
let settingTitle = 'Outbound Stream Details';
settingTitle =
videoQualitySettings?.length > 1 ? `${settingTitle} ${index + 1}` : settingTitle;
return ( return (
<Card title={settingTitle} type="inner" key={`${settingTitle}${index}`}> <div className="stream-details-item-container">
<StatisticItem title="Outbound Video Stream" value={videoSetting} prefix={null} /> <Statistic
<StatisticItem title="Outbound Audio Stream" value={audioSetting} prefix={null} /> className="stream-details-item"
</Card> title="Outbound Video Stream"
); value={videoSetting}
}, />
<Statistic
className="stream-details-item"
title="Outbound Audio Stream"
value={audioSetting}
/>
</div>
); );
});
// inbound // inbound
const { viewerCount, sessionPeakViewerCount } = serverStatusData; const { viewerCount, sessionPeakViewerCount } = serverStatusData;
@@ -118,57 +110,60 @@ export default function Home() {
return ( return (
<div className="home-container"> <div className="home-container">
<div className="sections-container"> <div className="sections-container">
<div className="section online-status-section"> <div className="online-status-section">
<Card title="Stream is online" type="inner"> <Card size="small" type="inner" className="online-details-card">
<Row gutter={[16, 16]} align="middle">
<Col span={8} sm={24} md={8}>
<Statistic <Statistic
title={`Stream started ${formatRelative(broadcastDate, Date.now())}`} title={`Stream started ${formatRelative(broadcastDate, Date.now())}`}
value={formatDistanceToNow(broadcastDate)} value={formatDistanceToNow(broadcastDate)}
prefix={<ClockCircleOutlined />} prefix={<ClockCircleOutlined />}
/> />
</Col>
<Col span={8} sm={24} md={8}>
<Statistic title="Viewers" value={viewerCount} prefix={<UserOutlined />} /> <Statistic title="Viewers" value={viewerCount} prefix={<UserOutlined />} />
</Col>
<Col span={8} sm={24} md={8}>
<Statistic <Statistic
title="Peak viewer count" title="Peak viewer count"
value={sessionPeakViewerCount} value={sessionPeakViewerCount}
prefix={<UserOutlined />} prefix={<UserOutlined />}
/> />
</Col>
</Row>
</Card> </Card>
</div> </div>
<div className="section stream-details-section"> <Row gutter={[16, 16]} className="section stream-details-section">
<div className="details outbound-details">{videoQualitySettings}</div> <Col className="outbound-details" span={12} sm={24} md={24} lg={12}>
<Card size="small" title="Outbound Stream Details" type="inner">
{videoQualitySettings}
</Card>
</Col>
<div className="details other-details"> <Col className="inbound-details" span={12} sm={24} md={24} lg={12}>
<Card title="Inbound Stream Details" type="inner"> <Card size="small" title="Inbound Stream Details" type="inner">
<StatisticItem <Statistic
className="stream-details-item"
title="Input" title="Input"
value={`${encoder} ${formatIPAddress(remoteAddr)}`} value={`${encoder} ${formatIPAddress(remoteAddr)}`}
prefix={null}
/> />
<StatisticItem <Statistic
className="stream-details-item"
title="Inbound Video Stream" title="Inbound Video Stream"
value={streamDetails} value={streamDetails}
formatter={streamDetailsFormatter} formatter={streamDetailsFormatter}
prefix={null}
/> />
<StatisticItem <Statistic
className="stream-details-item"
title="Inbound Audio Stream" title="Inbound Audio Stream"
value={streamAudioDetailString} value={streamAudioDetailString}
prefix={null}
/>
</Card>
<div className="server-detail">
<Card title="Server Config" type="inner">
<StatisticItem
title="Directory registration enabled"
value={configData.yp.enabled.toString()}
prefix={null}
/> />
</Card> </Card>
</Col>
</Row>
</div> </div>
</div> <br />
</div>
</div>
<LogTable logs={logsData} pageSize={5} /> <LogTable logs={logsData} pageSize={5} />
</div> </div>
); );

View File

@@ -1,5 +1,5 @@
import Link from 'next/link'; import Link from 'next/link';
import { Result, Card } from 'antd'; import { Result, Card, Row, Col } from 'antd';
import { import {
MessageTwoTone, MessageTwoTone,
QuestionCircleTwoTone, QuestionCircleTwoTone,
@@ -55,22 +55,23 @@ export default function Offline({ logs = [] }) {
return ( return (
<> <>
<div className="offline-content"> <Row gutter={[16, 16]} className="offline-content">
<div className="logo-section"> <Col span={12} xs={24} sm={24} md={24} lg={12} className="logo-section">
<Result <Result
icon={<OwncastLogo />} icon={<OwncastLogo />}
title="No stream is active." title="No stream is active."
subTitle="You should start one." subTitle="You should start one."
/> />
</div> </Col>
<div className="list-section">
<Col span={12} xs={24} sm={24} md={24} lg={12} className="list-section">
{data.map(item => ( {data.map(item => (
<Card key={item.title}> <Card key={item.title} size="small" bordered={false}>
<Meta avatar={item.icon} title={item.title} description={item.content} /> <Meta avatar={item.icon} title={item.title} description={item.content} />
</Card> </Card>
))} ))}
</div> </Col>
</div> </Row>
<LogTable logs={logs} pageSize={5} /> <LogTable logs={logs} pageSize={5} />
</> </>
); );

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect, useContext } from 'react'; import React, { useState, useEffect, useContext } from 'react';
import { Table, Row } from 'antd'; import { Table, Row, Typography } from 'antd';
import { formatDistanceToNow } from 'date-fns'; import { formatDistanceToNow } from 'date-fns';
import { UserOutlined } from '@ant-design/icons'; import { UserOutlined } from '@ant-design/icons';
import { SortOrder } from 'antd/lib/table/interface'; import { SortOrder } from 'antd/lib/table/interface';
@@ -94,7 +94,9 @@ export default function ViewersOverTime() {
]; ];
return ( return (
<div> <>
<Typography.Title>Viewer Info</Typography.Title>
<br />
<Row gutter={[16, 16]} justify="space-around"> <Row gutter={[16, 16]} justify="space-around">
{online && ( {online && (
<StatisticItem <StatisticItem
@@ -117,6 +119,6 @@ export default function ViewersOverTime() {
<Chart title="Viewers" data={viewerInfo} color="#2087E2" unit="" /> <Chart title="Viewers" data={viewerInfo} color="#2087E2" unit="" />
{online && <Table dataSource={clients} columns={columns} rowKey={row => row.clientID} />} {online && <Table dataSource={clients} columns={columns} rowKey={row => row.clientID} />}
</div> </>
); );
} }

View File

@@ -9,6 +9,9 @@
.ant-card, .ant-card,
.ant-collapse, .ant-collapse,
.ant-collapse-content, .ant-collapse-content,
.ant-statistic,
.ant-statistic-title,
.ant-statistic-content,
.ant-table, .ant-table,
.ant-table-thead > tr > th, .ant-table-thead > tr > th,
.ant-table-small .ant-table-thead > tr > th, .ant-table-small .ant-table-thead > tr > th,
@@ -187,12 +190,10 @@ h3.ant-typography {
.ant-card-meta-description { .ant-card-meta-description {
color: var(--white-75); color: var(--white-75);
} }
.ant-card { .ant-card-type-inner .ant-card-head {
.ant-statistic, background-color: var(--black);
.ant-statistic-title, color: var(--white-88);
.ant-statistic-content { border-color: var(--white-25);
color: var(--default-text-color);
}
} }
@@ -262,7 +263,6 @@ textarea.ant-input {
&:hover, &:hover,
&:focus { &:focus {
background-color: var(--button-focused); background-color: var(--button-focused);
border-color: var(--button-focused);
color: var(--white); color: var(--white);
} }
} }
@@ -273,11 +273,16 @@ textarea.ant-input {
.ant-btn-primary:hover, .ant-btn-primary:hover,
.ant-btn-primary:focus { .ant-btn-primary:focus {
background-color: var(--button-focused); background-color: var(--button-focused);
border-color: var(--button-focused); color: var(--white);
} }
.ant-btn.ant-btn-primary:hover { .ant-btn.ant-btn-primary:hover {
border-color: var(--white); border-color: var(--white);
} }
.ant-btn:focus,
.ant-btn-primary:focus {
border-color: var(--white);
}
.ant-btn-primary[disabled] { .ant-btn-primary[disabled] {
background-color: var(--white-25); background-color: var(--white-25);
border-color: var(--white-25); border-color: var(--white-25);
@@ -375,9 +380,29 @@ textarea.ant-input {
// SELECT // SELECT
.ant-select-dropdown { .ant-select-dropdown {
background-color: var(--gray); background-color: var(--black);
}
.ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
background-color: var(--black);
border-color: var(--owncast-purple-50);
}
.ant-select-arrow {
color: var(--owncast-purple);
}
.ant-select-selection-placeholder {
color: var(--owncast-purple-50);
}
.ant-select {
color: var(--white);
}
.ant-select-item {
background-color: var(--gray-dark);
color: var(--white-88);
}
.ant-select-item-option-active:not(.ant-select-item-option-disabled) {
background-color: var(--gray);
color: var(--white-75);
} }
// SLIDER // SLIDER
// .ant-slider-with-marks { // .ant-slider-with-marks {
@@ -460,13 +485,12 @@ textarea.ant-input {
// ANT TAGS // ANT TAGS
.ant-tag-red,
.ant-tag-orange { .ant-tag-orange,
background: #fa8c16; .ant-tag-green,
color: #fff7e6; .ant-tag-blue {
border-color: #ffd591; background-color: var(--black);
} }

View File

@@ -70,3 +70,7 @@
} }
} }
} }
.other-field-container {
margin: .5em 0;
}

View File

@@ -31,7 +31,7 @@
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
color: rgba(255,255,255,.85); color: var(--white-75);
.option-icon { .option-icon {
height: 2em; height: 2em;

View File

@@ -1,121 +1,45 @@
.home-container { .home-container {
max-width: 1000px; max-width: 1000px;
.statistics-list {
li {
margin-left: -.5em;
}
}
.section {
margin: 1rem 0;
.ant-statistic-content {
font-size: 1rem;
}
}
.online-status-section { .online-status-section {
> .ant-card { margin-bottom: 1em;
box-shadow: 0px 1px 10px 2px rgba(0, 22, 40, 0.1); .online-details-card {
border-color: var(--online-color);
} }
.ant-statistic {
.ant-card-head { text-align: center;
background-color: #40b246;
border-color: #ccc;
color:#fff;
@media (prefers-color-scheme: dark) {
background-color: #2a762e;
border-bottom-color: black;
}
}
.ant-card-head-title {
font-size: .88rem;
} }
.ant-statistic-title { .ant-statistic-title {
font-size: .88rem; color: var(--white-50);
} }
.ant-card-body {
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
.ant-statistic {
width: 30%;
text-align: center;
margin: 0 1rem;
}
}
}
.stream-details-section {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
width: 100%;
.details {
width: 49%;
> .ant-card {
margin-bottom: 1rem;
} }
.ant-card-head { .ant-card-head {
background-color: #ccd; color: var(--online-color);
color: black;
@media (prefers-color-scheme: dark) {
background-color: #000;
color: #ccd;
} }
.stream-details-item-container {
margin: 1em 0;
&:first-of-type {
margin-top: 0;
} }
} }
.server-detail { .ant-statistic.stream-details-item {
.ant-card-body { background-color: var(--black-50);
display: flex; padding: 1em;
flex-direction: row; .ant-statistic-title {
justify-content: space-between; color: var(--blue);
align-items: flex-start;
.ant-card {
width: 45%;
text-align: center;
}
}
.ant-card-head {
background-color: #669;
color: #fff;
} }
.ant-statistic-content {
font-size: 1.25em;
white-space: nowrap;
} }
} }
.outbound-details,
@media (max-width: 800px) { .inbound-details {
.online-status-section{ >.ant-card-bordered {
.ant-card-body { border-color: rgba(255,255,255,.1);
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
.ant-statistic {
width: auto;
text-align: left;
margin: 1em;
}
}
}
.stream-details-section {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
width: 100%;
.details {
width: 100%;
}
} }
} }
} }
@@ -124,14 +48,7 @@
.offline-content { .offline-content {
max-width: 1000px; max-width: 1000px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
width: 100%;
.logo-section { .logo-section {
width: 50%;
.ant-result-title { .ant-result-title {
font-size: 2rem; font-size: 2rem;
} }
@@ -144,36 +61,20 @@
} }
} }
.list-section { .list-section {
width: 50%; background-color: var(--container-bg-color-alt);
border-radius: var(--container-border-radius);
padding: 1em;
> .ant-card { > .ant-card {
margin-bottom: 1rem; background-color: var(--black);
.ant-card-head { margin-bottom: 1em;
background-color: #dde;
}
.ant-card-head-title {
font-size: 1rem;
}
.ant-card-meta-avatar { .ant-card-meta-avatar {
margin-top: .25rem; margin-top: .25rem;
svg { svg {
height: 1.25rem; height: 1.5em;
width: 1.25rem; width: 1.5em;
}
}
.ant-card-body {
font-size: .88rem;
} }
} }
} }
@media (max-width: 800px) {
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
.logo-section,
.list-section {
width: 100%
}
} }
} }

View File

@@ -84,7 +84,7 @@
} }
} }
} }
.online { &.online {
.online-status-indicator { .online-status-indicator {
.status-icon { .status-icon {
svg { svg {
@@ -92,6 +92,7 @@
} }
} }
.status-label { .status-label {
white-space: nowrap;
color: var(--online-color); color: var(--online-color);
} }
} }
@@ -111,8 +112,21 @@
align-items: center; align-items: center;
margin-bottom: 0; margin-bottom: 0;
.ant-input-affix-wrapper {
border-color: var(--owncast-purple-50);
}
input.ant-input {
&::placeholder {
color: var(--owncast-purple);
text-align: center;
}
}
.input-side { .input-side {
width: 400px; width: 400px;
@media (max-width: 800px) {
width: auto;
}
} }
.label-side { .label-side {