mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Using NavLinks on all pages.
This commit is contained in:
parent
d17ad50d56
commit
8da7e984e2
7 changed files with 144 additions and 216 deletions
|
|
@ -23,7 +23,8 @@ import {
|
|||
startDownloads
|
||||
} from "../api";
|
||||
import TimezoneSelect from 'react-timezone-select';
|
||||
import {secondsToDate, secondsToFrequency, textEllipsis, truncateLong, WROLModeMessage} from "./Common";
|
||||
import {secondsToDate, secondsToFrequency, TabLinks, textEllipsis, WROLModeMessage} from "./Common";
|
||||
import {Route} from "react-router-dom";
|
||||
|
||||
class Settings extends React.Component {
|
||||
|
||||
|
|
@ -440,23 +441,21 @@ class Downloads extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
class Admin extends React.Component {
|
||||
export default function Admin(props) {
|
||||
|
||||
render() {
|
||||
const links = [
|
||||
{text: 'Downloads', to: '/admin', exact: true},
|
||||
{text: 'Settings', to: '/admin/settings'},
|
||||
{text: 'WROL Mode', to: '/admin/wrol'},
|
||||
];
|
||||
|
||||
const panes = [
|
||||
{menuItem: 'Downloads', render: () => <Tab.Pane><Downloads/></Tab.Pane>},
|
||||
{menuItem: 'Settings', render: () => <Tab.Pane><Settings/></Tab.Pane>},
|
||||
{menuItem: 'WROL Mode', render: () => <Tab.Pane><WROLMode/></Tab.Pane>},
|
||||
];
|
||||
|
||||
return (
|
||||
<Container fluid>
|
||||
<Tab panes={panes}/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<TabLinks links={links}/>
|
||||
<Route path='/admin' exact component={Downloads}/>
|
||||
<Route path='/admin/settings' exact component={Settings}/>
|
||||
<Route path='/admin/wrol' exact component={WROLMode}/>
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default Admin;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import React, {useState} from "react";
|
||||
import {Card, Confirm, Container, Icon, Image, Placeholder, Tab} from "semantic-ui-react";
|
||||
import {Card, Confirm, Container, Icon, Image, Placeholder} from "semantic-ui-react";
|
||||
import Paginator, {
|
||||
ClearButton,
|
||||
ExternalLink,
|
||||
SearchInput,
|
||||
TabRouter,
|
||||
TabLinks,
|
||||
textEllipsis,
|
||||
uploadDate,
|
||||
WROLModeMessage
|
||||
} from "./Common";
|
||||
import {deleteArchive, postDownload, refreshArchives} from "../api";
|
||||
import Button from "semantic-ui-react/dist/commonjs/elements/Button";
|
||||
import {Link, NavLink} from "react-router-dom";
|
||||
import {Link, Route} from "react-router-dom";
|
||||
import {ArchivePlaceholder} from "./Placeholder";
|
||||
import Table from "semantic-ui-react/dist/commonjs/collections/Table";
|
||||
import {useArchives} from "../hooks/useArchives";
|
||||
|
|
@ -298,40 +298,15 @@ function Domains() {
|
|||
|
||||
|
||||
export function ArchiveRoute(props) {
|
||||
const panes = [
|
||||
{
|
||||
menuItem: {
|
||||
as: NavLink,
|
||||
content: 'Archives',
|
||||
id: 'archive',
|
||||
to: '/archive',
|
||||
exact: true,
|
||||
key: 'home',
|
||||
},
|
||||
render: () => <Tab.Pane><Archives/></Tab.Pane>
|
||||
},
|
||||
{
|
||||
menuItem: {
|
||||
as: NavLink,
|
||||
content: 'Domains',
|
||||
id: 'domains',
|
||||
to: '/archive/domains',
|
||||
exact: true,
|
||||
key: 'domains',
|
||||
},
|
||||
render: () => <Tab.Pane><Domains/></Tab.Pane>
|
||||
},
|
||||
{
|
||||
menuItem: {
|
||||
as: NavLink,
|
||||
content: 'Manage',
|
||||
id: 'manage',
|
||||
to: '/archive/manage',
|
||||
exact: true,
|
||||
key: 'manage',
|
||||
},
|
||||
render: () => <Tab.Pane><ManageArchives/></Tab.Pane>
|
||||
},
|
||||
const links = [
|
||||
{text: 'Archives', to: '/archive', exact: true},
|
||||
{text: 'Domains', to: '/archive/domains'},
|
||||
{text: 'Manage', to: '/archive/manage'},
|
||||
];
|
||||
return <TabRouter panes={panes} {...props} />
|
||||
return <>
|
||||
<TabLinks links={links}/>
|
||||
<Route path='/archive' exact component={Archives}/>
|
||||
<Route path='/archive/domains' component={Domains}/>
|
||||
<Route path='/archive/manage' component={ManageArchives}/>
|
||||
</>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, {useEffect, useState} from "react";
|
||||
import {Card, Container, Form, Icon, Image, Input, Pagination, Progress, Tab} from 'semantic-ui-react';
|
||||
import {Link} from "react-router-dom";
|
||||
import {Card, Container, Form, Icon, Image, Input, Menu, Pagination, Progress} from 'semantic-ui-react';
|
||||
import {Link, NavLink} from "react-router-dom";
|
||||
import Button from "semantic-ui-react/dist/commonjs/elements/Button";
|
||||
import Grid from "semantic-ui-react/dist/commonjs/collections/Grid";
|
||||
import Message from "semantic-ui-react/dist/commonjs/collections/Message";
|
||||
|
|
@ -636,61 +636,18 @@ export function textEllipsis(str, maxLength, {side = "end", ellipsis = "..."} =
|
|||
return str;
|
||||
}
|
||||
|
||||
export class TabRouter extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const panes = props.panes;
|
||||
let paneTos = [];
|
||||
for (let i = 0; i < panes.length; i++) {
|
||||
const pane = panes[i];
|
||||
paneTos = paneTos.concat([pane['menuItem']['to']]);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
activeIndex: this.matchPaneTo(paneTos),
|
||||
paneTos: paneTos,
|
||||
};
|
||||
}
|
||||
|
||||
matchPaneTo = (paneTos) => {
|
||||
const pathname = this.props.location.pathname;
|
||||
// Attempt to find the exact match first.
|
||||
let activeIndex = paneTos.indexOf(pathname);
|
||||
if (activeIndex !== -1) {
|
||||
return activeIndex;
|
||||
}
|
||||
|
||||
// Use the first tab if we can't find one.
|
||||
activeIndex = 0;
|
||||
// Try to find the most-exact match.
|
||||
for (let i = 0; i < paneTos.length; i++) {
|
||||
let to = paneTos[i];
|
||||
if (pathname.startsWith(to) && to.length > paneTos[activeIndex].length) {
|
||||
// "to" is a better match because it is longer than the last one we found.
|
||||
activeIndex = i;
|
||||
}
|
||||
}
|
||||
return activeIndex;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (prevProps.location.pathname !== this.props.location.pathname) {
|
||||
this.setState({activeIndex: this.matchPaneTo(this.state.paneTos)});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {panes, renderActiveOnly} = this.props;
|
||||
return (
|
||||
<>
|
||||
<Tab
|
||||
panes={panes}
|
||||
activeIndex={this.state.activeIndex}
|
||||
renderActiveOnly={renderActiveOnly || true}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function TabLinks({links}) {
|
||||
return (
|
||||
<Menu tabular>
|
||||
{links.map((link) =>
|
||||
<NavLink
|
||||
to={link.to}
|
||||
className={'item'}
|
||||
exact={link.exact || false}
|
||||
>
|
||||
{link.text}
|
||||
</NavLink>
|
||||
)}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,10 +110,8 @@ class Files extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export class FilesRoute extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Files/>
|
||||
);
|
||||
}
|
||||
export function FilesRoute(props) {
|
||||
return (
|
||||
<Files/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,10 @@ import {
|
|||
updateInventory,
|
||||
updateItem
|
||||
} from "../api";
|
||||
import {Button, Checkbox, Dropdown, Form, Grid, Header, Portal, Segment, Tab, Table} from "semantic-ui-react";
|
||||
import {Button, Checkbox, Dropdown, Form, Grid, Header, Portal, Segment, Table} from "semantic-ui-react";
|
||||
import {Route} from "react-router-dom";
|
||||
import Container from "semantic-ui-react/dist/commonjs/elements/Container";
|
||||
import {toast} from 'react-semantic-toasts';
|
||||
import {arraysEqual, enumerate, replaceNullValues} from './Common';
|
||||
import {arraysEqual, enumerate, replaceNullValues, TabLinks} from './Common';
|
||||
import _ from 'lodash';
|
||||
|
||||
class InventorySummary extends React.Component {
|
||||
|
|
@ -1089,27 +1088,16 @@ class InventoryAddList extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
class InventoryTab extends React.Component {
|
||||
|
||||
render() {
|
||||
let panes = [
|
||||
{menuItem: 'List', render: () => <Tab.Pane><InventoryAddList/></Tab.Pane>},
|
||||
{menuItem: 'Summary', render: () => <Tab.Pane><InventorySummary/></Tab.Pane>},
|
||||
];
|
||||
return (
|
||||
<Tab panes={panes}/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class InventoryRoute extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<Container fluid>
|
||||
<Route path='/inventory' exact component={InventoryTab}/>
|
||||
</Container>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export function InventoryRoute(props) {
|
||||
const links = [
|
||||
{text: 'List', to: '/inventory', exact: true},
|
||||
{text: 'Summary', to: '/inventory/summary'},
|
||||
];
|
||||
return (
|
||||
<>
|
||||
<TabLinks links={links}/>
|
||||
<Route path='/inventory' exact component={InventoryAddList}/>
|
||||
<Route path='/inventory/summary' exact component={InventorySummary}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,7 @@ import {Dropdown, Menu, Responsive} from "semantic-ui-react";
|
|||
const responsiveWidth = 500;
|
||||
|
||||
const links = [
|
||||
{
|
||||
text: 'Videos', links: [
|
||||
{to: '/videos', text: 'Newest Videos', exact: true},
|
||||
{to: '/videos/favorites', text: 'Favorites', exact: true},
|
||||
{to: '/videos/channel', text: 'Channels', exact: true},
|
||||
{to: '/videos/manage', text: 'Manage', exact: true},
|
||||
]
|
||||
},
|
||||
{text: 'Videos', to: '/videos'},
|
||||
{text: 'Inventory', to: '/inventory', exact: true},
|
||||
{text: 'Archive', to: '/archive'},
|
||||
{text: 'Files', to: '/files'},
|
||||
|
|
@ -33,7 +26,7 @@ function DropdownLinks(props) {
|
|||
<Dropdown.Menu>
|
||||
{props.link.links.map((l) => {
|
||||
return (
|
||||
<Link key={l.to} link={l}/>
|
||||
<MenuLink key={l.to} link={l}/>
|
||||
)
|
||||
})}
|
||||
</Dropdown.Menu>
|
||||
|
|
@ -41,7 +34,8 @@ function DropdownLinks(props) {
|
|||
)
|
||||
}
|
||||
|
||||
function Link(props) {
|
||||
function MenuLink(props) {
|
||||
// Wrapper around NavLink to handle Navlink/Dropdown change.
|
||||
let classes = 'item';
|
||||
if (props.link.header) {
|
||||
classes = `${classes} header`;
|
||||
|
|
@ -68,17 +62,17 @@ export function NavBar() {
|
|||
return (
|
||||
<Menu>
|
||||
{/*Always show WROLPi home button*/}
|
||||
<Link link={{to: '/', text: 'WROLPi', exact: true}}/>
|
||||
<MenuLink link={{to: '/', text: 'WROLPi', exact: true}}/>
|
||||
|
||||
{/*Show the links in a menu when on desktop*/}
|
||||
{links.map((link) => {
|
||||
return (
|
||||
<Responsive minWidth={responsiveWidth} as={Link} link={link} key={link.to}/>
|
||||
<Responsive minWidth={responsiveWidth} as={MenuLink} link={link} key={link.to}/>
|
||||
)
|
||||
})}
|
||||
<Responsive minWidth={responsiveWidth} as={Menu.Menu} position="right">
|
||||
{rightLinks.map((link) => {
|
||||
return (<Link link={link} key={link.to}/>)
|
||||
return (<MenuLink link={link} key={link.to}/>)
|
||||
})}
|
||||
</Responsive>
|
||||
|
||||
|
|
@ -87,7 +81,7 @@ export function NavBar() {
|
|||
<Dropdown item icon="bars">
|
||||
<Dropdown.Menu>
|
||||
{collapsedLinks.map((link) => {
|
||||
return (<Link link={link} key={link.to}/>)
|
||||
return (<MenuLink link={link} key={link.to}/>)
|
||||
})}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import {Link, Route} from "react-router-dom";
|
||||
import {NavLink, Route} from "react-router-dom";
|
||||
import Paginator, {
|
||||
changePageHistory,
|
||||
DEFAULT_LIMIT,
|
||||
|
|
@ -10,8 +10,10 @@ import Paginator, {
|
|||
scrollToTop,
|
||||
searchOrders,
|
||||
secondsToString,
|
||||
TabLinks,
|
||||
VideoCards,
|
||||
videoOrders, WROLModeMessage
|
||||
videoOrders,
|
||||
WROLModeMessage
|
||||
} from "./Common"
|
||||
import VideoPage from "./VideoPlayer";
|
||||
import {download, getChannel, getStatistics, getVideo, refresh, searchVideos} from "../api";
|
||||
|
|
@ -27,8 +29,7 @@ import {
|
|||
Modal,
|
||||
Radio,
|
||||
Segment,
|
||||
Statistic,
|
||||
Tab
|
||||
Statistic
|
||||
} from "semantic-ui-react";
|
||||
import * as QueryString from 'query-string';
|
||||
import Container from "semantic-ui-react/dist/commonjs/elements/Container";
|
||||
|
|
@ -65,7 +66,6 @@ class ManageVideos extends React.Component {
|
|||
return (
|
||||
<Container fluid>
|
||||
<WROLModeMessage content='Cannot modify Videos'/>
|
||||
<Header as="h1">Manage Videos</Header>
|
||||
|
||||
<p>
|
||||
<Button primary
|
||||
|
|
@ -493,60 +493,77 @@ class Videos extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
class ManageTabs extends React.Component {
|
||||
render() {
|
||||
const panes = [
|
||||
{menuItem: 'Manage', render: () => <Tab.Pane><ManageVideos/></Tab.Pane>},
|
||||
{menuItem: 'Statistics', render: () => <Tab.Pane><Statistics/></Tab.Pane>},
|
||||
]
|
||||
return (
|
||||
<Container fluid>
|
||||
<Tab panes={panes}/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
function ManageTab(props) {
|
||||
return (
|
||||
<Container fluid>
|
||||
<ManageVideos/>
|
||||
<Statistics/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export class VideosRoute extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<Container fluid>
|
||||
<Route path='/videos' exact
|
||||
component={(i) =>
|
||||
<Videos
|
||||
match={i.match}
|
||||
history={i.history}
|
||||
location={i.location}
|
||||
/>}
|
||||
/>
|
||||
<Route path='/videos/favorites' exact
|
||||
component={(i) =>
|
||||
<Videos
|
||||
match={i.match}
|
||||
history={i.history}
|
||||
location={i.location}
|
||||
filter='favorite'
|
||||
header='Favorite Videos'
|
||||
/>
|
||||
}/>
|
||||
<Route path='/videos/channel' exact component={Channels}/>
|
||||
<Route path='/videos/manage' exact component={ManageTabs}/>
|
||||
<Route path='/videos/channel/new' exact component={NewChannel}/>
|
||||
<Route path='/videos/channel/:channel_link/edit' exact
|
||||
component={(i) =>
|
||||
<EditChannel
|
||||
match={i.match}
|
||||
history={i.history}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route path='/videos/channel/:channel_link/video' exact component={Videos}/>
|
||||
</Container>
|
||||
</>
|
||||
)
|
||||
function Link(props) {
|
||||
let classes = 'item';
|
||||
if (props.link.header) {
|
||||
classes = `${classes} header`;
|
||||
}
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
className={classes}
|
||||
exact={props.link.exact || false}
|
||||
to={props.link.to}
|
||||
>
|
||||
{props.link.text}
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
|
||||
export function VideosRoute(props) {
|
||||
|
||||
const links = [
|
||||
{text: 'Videos', to: '/videos', exact: true},
|
||||
{text: 'Favorites', to: '/videos/favorites'},
|
||||
{text: 'Channels', to: '/videos/channel',},
|
||||
{text: 'Manage', to: '/videos/manage'},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<TabLinks links={links}/>
|
||||
|
||||
<Route path='/videos' exact
|
||||
component={(i) =>
|
||||
<Videos
|
||||
match={i.match}
|
||||
history={i.history}
|
||||
location={i.location}
|
||||
/>}
|
||||
/>
|
||||
<Route path='/videos/favorites' exact
|
||||
component={(i) =>
|
||||
<Videos
|
||||
match={i.match}
|
||||
history={i.history}
|
||||
location={i.location}
|
||||
filter='favorite'
|
||||
header='Favorite Videos'
|
||||
/>
|
||||
}/>
|
||||
<Route path='/videos/channel' exact component={Channels}/>
|
||||
<Route path='/videos/manage' exact component={ManageTab}/>
|
||||
<Route path='/videos/channel/new' exact component={NewChannel}/>
|
||||
<Route path='/videos/channel/:channel_link/edit' exact
|
||||
component={(i) =>
|
||||
<EditChannel
|
||||
match={i.match}
|
||||
history={i.history}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route path='/videos/channel/:channel_link/video' exact component={Videos}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
class Statistics extends React.Component {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue