reorganize server dashboard into categories

This commit is contained in:
janderedev 2022-03-16 20:34:24 +01:00
parent 180f722ed3
commit b077943e41
Signed by: Lea
GPG key ID: 5D5E18ACB990F57A
4 changed files with 233 additions and 123 deletions

View file

@ -5,7 +5,7 @@ import '@revoltchat/ui/src/styles/dark.css';
import '@revoltchat/ui/src/styles/common.css'; import '@revoltchat/ui/src/styles/common.css';
import RequireAuth from './components/RequireAuth'; import RequireAuth from './components/RequireAuth';
import DashboardHome from './pages/DashboardHome'; import DashboardHome from './pages/DashboardHome';
import ServerDashboard from './pages/ServerDashboard'; import ServerDashboard from './pages/ServerDashboard/ServerDashboard';
const API_URL = import.meta.env.VITE_API_URL?.toString() const API_URL = import.meta.env.VITE_API_URL?.toString()
|| 'http://localhost:9000'; || 'http://localhost:9000';

View file

@ -0,0 +1,20 @@
import { FunctionComponent, useState } from "react";
import './styles/CategorySelector.css';
const CategorySelector: FunctionComponent<{ keys: { id: string, name: string }[], selected: string, onChange: (key: string) => void }> = (props) => {
return (
<div className="category-selector-outer">
{props.keys.map((k) => (
<div
className={`category-selector-inner ${props.selected == k.id ? 'selected' : ''}`}
key={k.id}
onClick={() => props.onChange(k.id)}
>
<span>{k.name}</span>
</div>
))}
</div>
);
}
export default CategorySelector;

View file

@ -0,0 +1,40 @@
.category-selector-outer {
width: calc(100% - 20px);
margin: 8px 10px;
height: 32px;
background-color: var(--secondary-background);
display: flex;
border-radius: 6px;
justify-content: space-evenly;
}
.category-selector-inner {
background-color: var(--tertiary-background);
height: 24px;
margin: 4px;
width: 100vw;
user-select: none;
text-align: center;
overflow: hidden;
border-radius: 4px;
transition: filter .2s, background-color .3s;
}
.category-selector-inner:hover {
filter: brightness(1.1);
}
.category-selector-inner:active {
filter: brightness(1.2);
}
.category-selector-inner.selected {
background-color: var(--accent);
}
.category-selector-inner span {
color: var(--secondary-foreground);
}
.category-selector-inner.selected span {
color: var(--foreground);
}

View file

@ -10,10 +10,11 @@ import { H3 } from '@revoltchat/ui/lib/components/atoms/heading/H3';
import { H4 } from '@revoltchat/ui/lib/components/atoms/heading/H4'; import { H4 } from '@revoltchat/ui/lib/components/atoms/heading/H4';
import { Icon } from '@mdi/react'; import { Icon } from '@mdi/react';
import { mdiChevronLeft, mdiCloseBox } from '@mdi/js'; import { mdiChevronLeft, mdiCloseBox } from '@mdi/js';
import { API_URL } from "../App"; import { API_URL } from "../../App";
import { getAuthHeaders } from "../utils"; import { getAuthHeaders } from "../../utils";
import { Link, useParams } from "react-router-dom"; import { Link, useParams } from "react-router-dom";
import defaultChannelIcon from '../assets/channel-default-icon.svg'; import defaultChannelIcon from '../../assets/channel-default-icon.svg';
import CategorySelector from '../../components/CategorySelector';
type User = { id: string, username?: string, avatarURL?: string } type User = { id: string, username?: string, avatarURL?: string }
type Channel = { id: string, name: string, icon?: string, type: 'VOICE'|'TEXT', nsfw: boolean } type Channel = { id: string, name: string, icon?: string, type: 'VOICE'|'TEXT', nsfw: boolean }
@ -40,6 +41,8 @@ type AntispamRule = {
} }
const ServerDashboard: FunctionComponent = () => { const ServerDashboard: FunctionComponent = () => {
const [category, setCategory] = useState('home');
const [serverInfo, setServerInfo] = useState({} as Server); const [serverInfo, setServerInfo] = useState({} as Server);
const [status, setStatus] = useState(''); const [status, setStatus] = useState('');
@ -108,18 +111,59 @@ const ServerDashboard: FunctionComponent = () => {
return ( return (
<> <>
<Link to='/dashboard'> {status.length ? <a>{status}</a> : <></>}
<div style={{ display: 'flex', marginTop: '4px' }}> <div
<Icon path={mdiChevronLeft} style={{ height: '24px' }} /> style={{
marginTop: '8px',
marginLeft: '8px',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
color: 'var(--secondary-foreground)',
maxWidth: 'calc(100% - 20px)',
}}
>
<Link to='/dashboard' style={{ float: 'left' }}>
<div style={{ display: 'flex' }}>
<Icon path={mdiChevronLeft} style={{ height: '25px' }} />
<span>Back</span> <span>Back</span>
</div> </div>
</Link> </Link>
<H1 style={{ marginTop: '8px' }}>{serverInfo?.name ?? 'Loading...'}</H1> <span
{status.length ? <a>{status}</a> : <br/>} style={{
color: 'var(--foreground)',
marginLeft: '8px',
}}
>
{serverInfo?.name ?? 'Loading...'}
</span>
<span style={{ color: 'var(--secondary-foreground)', marginLeft: '6px' }}>
</span>
<span
style={{
color: 'var(--secondary-foreground)',
marginLeft: '6px',
}}
>
{serverInfo.description || <i>No server description set</i>}
</span>
</div>
<CategorySelector
keys={[
{ id: 'home', name: 'Home' },
{ id: 'automod', name: 'Moderation Rules' },
]}
selected={category}
onChange={setCategory}
/>
<div hidden={Object.keys(serverInfo).length == 0}> <div hidden={Object.keys(serverInfo).length == 0}>
<H4>{serverInfo.description ?? <i>No server description set</i>}</H4>
<br/>
<div style={{ paddingLeft: '10px', paddingRight: '10px' }}> <div style={{ paddingLeft: '10px', paddingRight: '10px' }}>
{category == 'home' && (
<>
<> <>
<H3>Prefix</H3> <H3>Prefix</H3>
<InputBox <InputBox
@ -182,16 +226,22 @@ const ServerDashboard: FunctionComponent = () => {
</UserListContainer> </UserListContainer>
</UserListTypeContainer> </UserListTypeContainer>
</> </>
</>
)}
<LineDivider /> {category == 'automod' && (
<> <>
<H3>Antispam Rules</H3> <H3>Antispam Rules</H3>
{serverInfo.perms != null && automodSettings && ( {serverInfo.perms != null && automodSettings && (
serverInfo.perms > 0 serverInfo.perms > 0
? ( ? (
<> <>
{automodSettings.antispam.map(r => <AntispamRule rule={r} key={r.id} />)} {automodSettings.antispam.map((r, i) => (
<>
<AntispamRule rule={r} key={r.id} />
{i < automodSettings.antispam.length - 1 && <LineDivider/>}
</>
))}
<Button style={{ <Button style={{
marginTop: '12px', marginTop: '12px',
marginBottom: '8px', marginBottom: '8px',
@ -233,6 +283,7 @@ const ServerDashboard: FunctionComponent = () => {
) )
} }
</> </>
)}
</div> </div>
</div> </div>
</> </>
@ -613,7 +664,6 @@ const ServerDashboard: FunctionComponent = () => {
{props.rule.id} {props.rule.id}
</code> </code>
<div style={{ clear: 'both' }} /> <div style={{ clear: 'both' }} />
<div style={{ maxWidth: 'max(40%, 600px)' }}><LineDivider/></div>
</div> </div>
</div> </div>
) )