mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Using grey color by default for some Semantic elements when no color is provided.
This commit is contained in:
parent
335ad7ceb0
commit
d82b7c12fb
6 changed files with 143 additions and 138 deletions
|
|
@ -1,103 +1,22 @@
|
|||
import React, {useContext, useState} from 'react';
|
||||
import React, {useContext} from 'react';
|
||||
import './App.css';
|
||||
import {NavBar} from "./components/Nav";
|
||||
import {Link, Route, Routes} from "react-router-dom";
|
||||
import {Route, Routes} from "react-router-dom";
|
||||
import {VideosRoute, VideoWrapper} from "./components/Videos";
|
||||
import Admin from "./components/admin/Admin";
|
||||
import {Container, Divider} from "semantic-ui-react";
|
||||
import {Container} from "semantic-ui-react";
|
||||
import 'semantic-ui-offline/semantic.min.css';
|
||||
import {SemanticToastContainer} from 'react-semantic-toasts';
|
||||
import 'react-semantic-toasts/styles/react-semantic-alert.css';
|
||||
import {AppsRoute} from "./components/Apps";
|
||||
import {InventoryRoute} from "./components/Inventory";
|
||||
import {ArchiveRoute} from "./components/Archive";
|
||||
import {DownloadMenu} from "./components/Upload";
|
||||
import {LoadStatistic, PageContainer, SearchInput, useTitle} from "./components/Common";
|
||||
import {FilesRoute, FilesSearchView} from "./components/Files";
|
||||
import {useSearchFiles, useSettingsInterval, useStatus} from "./hooks/customHooks";
|
||||
import {FilesRoute} from "./components/Files";
|
||||
import {useSettingsInterval} from "./hooks/customHooks";
|
||||
import {MapRoute} from "./components/Map";
|
||||
import {SettingsContext, ThemeContext} from "./contexts/contexts";
|
||||
import {Header, Segment, Statistic, StatisticGroup, ThemeWrapper} from "./components/Theme";
|
||||
import {CPUUsageProgress} from "./components/admin/Status";
|
||||
|
||||
function Dashboard() {
|
||||
useTitle('Dashboard');
|
||||
|
||||
const {searchStr, setSearchStr} = useSearchFiles();
|
||||
|
||||
const [downloadOpen, setDownloadOpen] = useState(false);
|
||||
const onDownloadOpen = (name) => setDownloadOpen(!!name);
|
||||
const {wrol_mode} = useContext(SettingsContext);
|
||||
|
||||
const downloads = <DownloadMenu onOpen={onDownloadOpen}/>;
|
||||
|
||||
// Only show dashboard parts if not searching.
|
||||
let body;
|
||||
if (searchStr) {
|
||||
body = <FilesSearchView showLimit={true} showSelect={true} showSelectButton={true}/>;
|
||||
} else {
|
||||
body = <>
|
||||
{!wrol_mode && downloads}
|
||||
{/* Hide Status when user is starting a download */}
|
||||
{!downloadOpen && <DashboardStatus/>}
|
||||
</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<SearchInput clearable
|
||||
searchStr={searchStr}
|
||||
onSubmit={setSearchStr}
|
||||
size='large'
|
||||
placeholder='Search Everywhere...'
|
||||
actionIcon='search'
|
||||
style={{marginBottom: '2em'}}
|
||||
/>
|
||||
{body}
|
||||
</PageContainer>
|
||||
)
|
||||
}
|
||||
|
||||
function DashboardStatus() {
|
||||
const {status} = useStatus();
|
||||
let percent = 0;
|
||||
let load = {};
|
||||
let cores = 0;
|
||||
let pending_downloads = '?';
|
||||
if (status && status['cpu_info']) {
|
||||
percent = status['cpu_info']['percent'];
|
||||
load = status['load'];
|
||||
cores = status['cpu_info']['cores'];
|
||||
pending_downloads = status['downloads']['pending_downloads'];
|
||||
}
|
||||
|
||||
const {download_manager_disabled, download_manager_stopped} = useContext(SettingsContext);
|
||||
if (pending_downloads === 0 && (download_manager_disabled || download_manager_stopped)) {
|
||||
pending_downloads = 'x';
|
||||
}
|
||||
|
||||
return <Segment>
|
||||
<Link to='/admin/status'>
|
||||
<Header as='h2'>Status</Header>
|
||||
<CPUUsageProgress value={percent} label='CPU Usage'/>
|
||||
<Header as='h3'>Load</Header>
|
||||
<StatisticGroup size='mini'>
|
||||
<LoadStatistic label='1 Minute' value={load['minute_1']} cores={cores}/>
|
||||
<LoadStatistic label='5 Minute' value={load['minute_5']} cores={cores}/>
|
||||
<LoadStatistic label='15 Minute' value={load['minute_15']} cores={cores}/>
|
||||
</StatisticGroup>
|
||||
</Link>
|
||||
|
||||
<Divider/>
|
||||
|
||||
<Link to='/admin'>
|
||||
<StatisticGroup size='mini'>
|
||||
<Statistic label='Downloads' value={pending_downloads}/>
|
||||
</StatisticGroup>
|
||||
</Link>
|
||||
|
||||
</Segment>;
|
||||
}
|
||||
import {ThemeWrapper} from "./components/Theme";
|
||||
import {Dashboard} from "./Dashboard";
|
||||
|
||||
function PageNotFound() {
|
||||
return (
|
||||
|
|
|
|||
89
app/src/Dashboard.js
Normal file
89
app/src/Dashboard.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import {LoadStatistic, PageContainer, SearchInput, useTitle} from "./components/Common";
|
||||
import {useSearchFiles, useStatus} from "./hooks/customHooks";
|
||||
import React, {useContext, useState} from "react";
|
||||
import {SettingsContext} from "./contexts/contexts";
|
||||
import {DownloadMenu} from "./components/Upload";
|
||||
import {FilesSearchView} from "./components/Files";
|
||||
import {Header, Segment, Statistic, StatisticGroup} from "./components/Theme";
|
||||
import {Link} from "react-router-dom";
|
||||
import {CPUUsageProgress} from "./components/admin/Status";
|
||||
import {Divider} from "semantic-ui-react";
|
||||
|
||||
export function Dashboard() {
|
||||
useTitle('Dashboard');
|
||||
|
||||
const {searchStr, setSearchStr} = useSearchFiles();
|
||||
|
||||
const [downloadOpen, setDownloadOpen] = useState(false);
|
||||
const onDownloadOpen = (name) => setDownloadOpen(!!name);
|
||||
const {wrol_mode} = useContext(SettingsContext);
|
||||
|
||||
const downloads = <DownloadMenu onOpen={onDownloadOpen}/>;
|
||||
|
||||
// Only show dashboard parts if not searching.
|
||||
let body;
|
||||
if (searchStr) {
|
||||
body = <FilesSearchView showLimit={true} showSelect={true} showSelectButton={true}/>;
|
||||
} else {
|
||||
body = <>
|
||||
{!wrol_mode && downloads}
|
||||
{/* Hide Status when user is starting a download */}
|
||||
{!downloadOpen && <DashboardStatus/>}
|
||||
</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<SearchInput clearable
|
||||
searchStr={searchStr}
|
||||
onSubmit={setSearchStr}
|
||||
size='large'
|
||||
placeholder='Search Everywhere...'
|
||||
actionIcon='search'
|
||||
style={{marginBottom: '2em'}}
|
||||
/>
|
||||
{body}
|
||||
</PageContainer>
|
||||
)
|
||||
}
|
||||
|
||||
function DashboardStatus() {
|
||||
const {status} = useStatus();
|
||||
let percent = 0;
|
||||
let load = {};
|
||||
let cores = 0;
|
||||
let pending_downloads = '?';
|
||||
if (status && status['cpu_info']) {
|
||||
percent = status['cpu_info']['percent'];
|
||||
load = status['load'];
|
||||
cores = status['cpu_info']['cores'];
|
||||
pending_downloads = status['downloads']['pending_downloads'];
|
||||
}
|
||||
|
||||
const {download_manager_disabled, download_manager_stopped} = useContext(SettingsContext);
|
||||
if (pending_downloads === 0 && (download_manager_disabled || download_manager_stopped)) {
|
||||
pending_downloads = 'x';
|
||||
}
|
||||
|
||||
return <Segment>
|
||||
<Link to='/admin/status'>
|
||||
<Header as='h2'>Status</Header>
|
||||
<CPUUsageProgress value={percent} label='CPU Usage'/>
|
||||
<Header as='h3'>Load</Header>
|
||||
<StatisticGroup size='mini'>
|
||||
<LoadStatistic label='1 Minute' value={load['minute_1']} cores={cores}/>
|
||||
<LoadStatistic label='5 Minute' value={load['minute_5']} cores={cores}/>
|
||||
<LoadStatistic label='15 Minute' value={load['minute_15']} cores={cores}/>
|
||||
</StatisticGroup>
|
||||
</Link>
|
||||
|
||||
<Divider/>
|
||||
|
||||
<Link to='/admin'>
|
||||
<StatisticGroup size='mini'>
|
||||
<Statistic label='Downloading' value={pending_downloads}/>
|
||||
</StatisticGroup>
|
||||
</Link>
|
||||
|
||||
</Segment>;
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import React, {useContext, useEffect, useState} from "react";
|
||||
import {Card, Container, Image, Input, Pagination, Popup, Responsive, TableCell, TableRow} from 'semantic-ui-react';
|
||||
import {Card, Container, Image, Input, Pagination, Responsive, TableCell, TableRow} from 'semantic-ui-react';
|
||||
import {Link, NavLink} from "react-router-dom";
|
||||
import Message from "semantic-ui-react/dist/commonjs/collections/Message";
|
||||
import {useDownloaders, useHotspot, useThrottle} from "../hooks/customHooks";
|
||||
import {getSettings} from "../api";
|
||||
import {darkTheme, SettingsContext, ThemeContext} from "../contexts/contexts";
|
||||
import {Button, CardIcon, Form, Header, Icon, Menu, Statistic} from "./Theme";
|
||||
import {Button, CardIcon, Form, Header, Icon, Menu, Popup, Statistic} from "./Theme";
|
||||
|
||||
export const API_URI = `http://${window.location.host}/api`;
|
||||
export const VIDEOS_API = `${API_URI}/videos`;
|
||||
|
|
@ -835,17 +835,15 @@ export function FileIcon({file, disabled = true, size = 'huge', ...props}) {
|
|||
}
|
||||
|
||||
export function LoadStatistic({label, value, cores, ...props}) {
|
||||
let color;
|
||||
const quarter = cores / 4;
|
||||
if (cores && value >= (quarter * 3)) {
|
||||
color = 'red';
|
||||
props['color'] = 'red';
|
||||
} else if (cores && value >= (quarter * 2)) {
|
||||
color = 'orange';
|
||||
props['color'] = 'orange';
|
||||
}
|
||||
return <Statistic
|
||||
label={label}
|
||||
value={value ? parseFloat(value).toFixed(1) : '?'}
|
||||
color={color}
|
||||
{...props}/>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,21 +105,29 @@ const invertedNull = (props) => {
|
|||
return props;
|
||||
}
|
||||
|
||||
const defaultGrey = (props, inverted) => {
|
||||
// Some elements look softer when grey, use grey only if another color is not provided.
|
||||
if (inverted) {
|
||||
return {color: 'grey', ...props};
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
export function Button(props) {
|
||||
const {i} = useContext(ThemeContext);
|
||||
props = {...i, ...props};
|
||||
const {i, inverted} = useContext(ThemeContext);
|
||||
props = defaultGrey({...i, ...props}, inverted);
|
||||
return <BUTTON {...props}/>
|
||||
}
|
||||
|
||||
export function Accordion(props) {
|
||||
const {i} = useContext(ThemeContext);
|
||||
props = {...i, ...props};
|
||||
const {i, inverted} = useContext(ThemeContext);
|
||||
props = defaultGrey({...i, ...props}, inverted);
|
||||
return <ACCORDION {...props}/>
|
||||
}
|
||||
|
||||
export function Header(props) {
|
||||
const {i} = useContext(ThemeContext);
|
||||
props = {...i, ...props};
|
||||
const {i, inverted} = useContext(ThemeContext);
|
||||
props = defaultGrey({...i, ...props}, inverted);
|
||||
return <HEADER {...props}/>
|
||||
}
|
||||
|
||||
|
|
@ -191,8 +199,8 @@ export function Segment(props) {
|
|||
}
|
||||
|
||||
export function Statistic(props) {
|
||||
const {i} = useContext(ThemeContext);
|
||||
props = {...i, ...props};
|
||||
const {i, inverted} = useContext(ThemeContext);
|
||||
props = defaultGrey({...i, ...props}, inverted);
|
||||
return <STATISTIC {...props}/>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import Icon from "semantic-ui-react/dist/commonjs/elements/Icon";
|
|||
import Message from "semantic-ui-react/dist/commonjs/collections/Message";
|
||||
import {ThemeContext} from "../contexts/contexts";
|
||||
import {Button, Form, FormInput, Header, Loader, TextArea} from "./Theme";
|
||||
import {FormDropdown} from "semantic-ui-react";
|
||||
import {ButtonGroup, FormDropdown} from "semantic-ui-react";
|
||||
|
||||
const validUrl = /^(http|https):\/\/[^ "]+$/;
|
||||
|
||||
|
|
@ -13,10 +13,7 @@ class Downloader extends React.Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
urls: '',
|
||||
valid: true,
|
||||
pending: false,
|
||||
downloader: props.downloader,
|
||||
urls: '', valid: true, pending: false, downloader: props.downloader,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -58,20 +55,18 @@ class Downloader extends React.Component {
|
|||
const {header} = this.props;
|
||||
|
||||
return <ThemeContext.Consumer>
|
||||
{({i}) => (
|
||||
<Form onSubmit={this.submitDownload}>
|
||||
<WROLModeMessage content='Downloading is disabled while WROL Mode is enabled'/>
|
||||
<Header as='h3'>{header}</Header>
|
||||
<TextArea required
|
||||
placeholder={'Enter one URL per line'}
|
||||
name='urls'
|
||||
onChange={this.handleInputChange}
|
||||
value={this.state.urls}
|
||||
/>
|
||||
<Button content='Cancel' onClick={this.props.clearSelected}/>
|
||||
<Button primary style={{marginTop: '1em'}} disabled={disabled}>Download</Button>
|
||||
</Form>
|
||||
)}
|
||||
{({i}) => (<Form onSubmit={this.submitDownload}>
|
||||
<WROLModeMessage content='Downloading is disabled while WROL Mode is enabled'/>
|
||||
<Header as='h3'>{header}</Header>
|
||||
<TextArea required
|
||||
placeholder={'Enter one URL per line'}
|
||||
name='urls'
|
||||
onChange={this.handleInputChange}
|
||||
value={this.state.urls}
|
||||
/>
|
||||
<Button content='Cancel' onClick={this.props.clearSelected}/>
|
||||
<Button primary style={{marginTop: '1em'}} disabled={disabled}>Download</Button>
|
||||
</Form>)}
|
||||
</ThemeContext.Consumer>
|
||||
}
|
||||
}
|
||||
|
|
@ -80,18 +75,9 @@ class ChannelDownload extends React.Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
url: '',
|
||||
frequency: 604800,
|
||||
pending: false,
|
||||
disabled: false,
|
||||
ready: false,
|
||||
error: null,
|
||||
success: null,
|
||||
url: '', frequency: 604800, pending: false, disabled: false, ready: false, error: null, success: null,
|
||||
};
|
||||
this.freqOptions = [
|
||||
{key: 'once', text: 'Once', value: 0},
|
||||
...frequencyOptions,
|
||||
];
|
||||
this.freqOptions = [{key: 'once', text: 'Once', value: 0}, ...frequencyOptions,];
|
||||
this.handleUrlChange = this.handleUrlChange.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleFrequencyChange = this.handleFrequencyChange.bind(this);
|
||||
|
|
@ -289,13 +275,13 @@ export function DownloadMenu({onOpen}) {
|
|||
onOpen(name)
|
||||
}
|
||||
|
||||
let body = (<>
|
||||
<Button content='Videos' onClick={() => localOnOpen('video')} style={{marginBottom: '1em'}}/>
|
||||
<Button content='Archive' onClick={() => localOnOpen('archive')} style={{marginBottom: '1em'}}/>
|
||||
<Button content='Channel/Playlist' onClick={() => localOnOpen('video_channel')}
|
||||
let body = (<ButtonGroup>
|
||||
<Button color='blue' content='Videos' onClick={() => localOnOpen('video')} style={{marginBottom: '1em'}}/>
|
||||
<Button color='green' content='Archive' onClick={() => localOnOpen('archive')} style={{marginBottom: '1em'}}/>
|
||||
<Button color='blue' content='Channel/Playlist' onClick={() => localOnOpen('video_channel')}
|
||||
style={{marginBottom: '1em'}}/>
|
||||
<Button content='RSS Feed' onClick={() => localOnOpen('rss')} style={{marginBottom: '1em'}}/>
|
||||
</>);
|
||||
</ButtonGroup>);
|
||||
|
||||
function clearSelected() {
|
||||
localOnOpen(null);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,11 @@ export class Settings extends React.Component {
|
|||
this.setState({[name]: value});
|
||||
}
|
||||
|
||||
handleQrOpen = async (e) => {
|
||||
e.preventDefault();
|
||||
this.setState({qrOpen: true});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.ready === false) {
|
||||
return <Loader active inline='centered'/>
|
||||
|
|
@ -199,7 +204,7 @@ export class Settings extends React.Component {
|
|||
|
||||
<Modal closeIcon
|
||||
onClose={() => this.setState({qrOpen: false})}
|
||||
onOpen={() => this.setState({qrOpen: true})}
|
||||
onOpen={this.handleQrOpen}
|
||||
open={this.state.qrOpen}
|
||||
trigger={qrButton}
|
||||
>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue